]> git.saurik.com Git - wxWidgets.git/blame - src/html/m_layout.cpp
Support using GetTextExtent() with empty string to get descent in wxOSX.
[wxWidgets.git] / src / html / m_layout.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
93763ad5 2// Name: src/html/m_layout.cpp
5526e819
VS
3// Purpose: wxHtml module for basic paragraphs/layout handling
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
5526e819 6// Copyright: (c) 1999 Vaclav Slavik
65571936 7// Licence: wxWindows licence
5526e819 8/////////////////////////////////////////////////////////////////////////////
3364ab79 9
314260fb 10#include "wx/wxprec.h"
5526e819 11
2b5f62a0 12#ifdef __BORLANDC__
97e490f8 13 #pragma hdrstop
3364ab79
RS
14#endif
15
93763ad5
WS
16#if wxUSE_HTML && wxUSE_STREAMS
17
b4f4d3dd 18#ifndef WX_PRECOMP
155ecd4c 19 #include "wx/image.h"
3364ab79
RS
20#endif
21
69941f05
VS
22#include "wx/html/forcelnk.h"
23#include "wx/html/m_templ.h"
5526e819 24
69941f05 25#include "wx/html/htmlwin.h"
5526e819 26
c88293a4 27FORCE_LINK_ME(m_layout)
5526e819 28
7127d129
RR
29#ifdef __WXWINCE__
30 #include "wx/msw/wince/missing.h" // for bsearch()
31#else
32 #include <stdlib.h> // bsearch()
33#endif
f2034f1b
VS
34
35//-----------------------------------------------------------------------------
36// wxHtmlPageBreakCell
37//-----------------------------------------------------------------------------
38
39// Since html isn't a page-layout language, it doesn't support page
40// page breaks directly--that requires CSS2 support. But a page-break
41// facility is handy, and has been requested more than once on the
42// mailing lists. This wxHtml tag handler implements just enough of
43// CSS2 to support a page break by recognizing only
44// <div style="page-break-before:always">
45//
46// wxHtml maintains page breaks in wxHtmlPrintout::m_PageBreaks. The
47// tag handler below adds appropriate offsets to that array member.
48// wxHtmlDCRenderer::Render() accesses that array and makes a new page
49// begin after each page-break tag.
50
51// The page-break handler does all its work in AdjustPagebreak(). For
52// all tag handlers, that function adjusts the page-break position.
53// For other tags, it determines whether the html element can fit on
54// the remainder of the page; if it cannot fit, but must not be split,
55// then the function moves the page break provided in the argument up,
56// and returns 'true' to inform the caller that the argument was
57// modified.
58//
59// Due to its special purpose, the page-break facility differs from
60// other tags. It takes up no space, but it behaves as though there is
61// never enough room to fit it on the remainder of the page--it always
62// forces a page break. Therefore, unlike other elements that trigger
63// a page break, it would never 'fit' on the following page either.
64// Therefore it's necessary to compare each pagebreak candidate to the
65// array wxHtmlPrintout::m_PageBreaks of pagebreaks already set, and
66// set a new one only if it's not in that array.
67
4460b6c4 68class wxHtmlPageBreakCell : public wxHtmlCell
f2034f1b 69{
36c4ff4d 70public:
f2034f1b
VS
71 wxHtmlPageBreakCell() {}
72
36c4ff4d 73 bool AdjustPagebreak(int* pagebreak,
846f4568
VZ
74 const wxArrayInt& known_pagebreaks,
75 int pageHeight) const;
fd0bab43 76
36c4ff4d
VS
77 void Draw(wxDC& WXUNUSED(dc),
78 int WXUNUSED(x), int WXUNUSED(y),
79 int WXUNUSED(view_y1), int WXUNUSED(view_y2),
e3ac6ee1 80 wxHtmlRenderingInfo& WXUNUSED(info)) {}
f2034f1b 81
36c4ff4d 82private:
c0c133e1 83 wxDECLARE_NO_COPY_CLASS(wxHtmlPageBreakCell);
f2034f1b
VS
84};
85
846f4568
VZ
86bool
87wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak,
88 const wxArrayInt& known_pagebreaks,
89 int WXUNUSED(pageHeight)) const
f2034f1b
VS
90{
91 // When we are counting pages, 'known_pagebreaks' is non-NULL.
92 // That's the only time we change 'pagebreak'. Otherwise, pages
93 // were already counted, 'known_pagebreaks' is NULL, and we don't
d1da8872 94 // do anything except return false.
f2034f1b 95 //
d1da8872 96 // We also simply return false if the 'pagebreak' argument is
f2034f1b
VS
97 // less than (vertically above) or the same as the current
98 // vertical position. Otherwise we'd be setting a pagebreak above
99 // the current cell, which is incorrect, or duplicating a
100 // pagebreak that has already been set.
b4a980f4 101 if( known_pagebreaks.GetCount() == 0 || *pagebreak <= m_PosY)
fd0bab43 102 {
d1da8872 103 return false;
fd0bab43 104 }
f2034f1b
VS
105
106 // m_PosY is only the vertical offset from the parent. The pagebreak
107 // required here is the total page offset, so m_PosY must be added
108 // to the parent's offset and height.
c3485a4e
VS
109 int total_height = m_PosY;
110 for ( wxHtmlCell *parent = GetParent(); parent; parent = parent->GetParent() )
111 {
112 total_height += parent->GetPosY();
113 }
114
f2034f1b
VS
115
116 // Search the array of pagebreaks to see whether we've already set
e92b9e69 117 // a pagebreak here.
fd0bab43 118 int where = known_pagebreaks.Index( total_height);
f2034f1b 119 // Add a pagebreak only if there isn't one already set here.
fd0bab43
VZ
120 if( wxNOT_FOUND != where)
121 {
d1da8872 122 return false;
fd0bab43 123 }
f2034f1b 124 else
fd0bab43 125 {
f2034f1b 126 *pagebreak = m_PosY;
d1da8872 127 return true;
fd0bab43 128 }
f2034f1b
VS
129}
130
fd0bab43
VZ
131
132
5526e819 133TAG_HANDLER_BEGIN(P, "P")
fc7a2a60 134 TAG_HANDLER_CONSTR(P) { }
5526e819
VS
135
136 TAG_HANDLER_PROC(tag)
137 {
e3774124 138 if (m_WParser->GetContainer()->GetFirstChild() != NULL)
04dbb646 139 {
4f9297b0
VS
140 m_WParser->CloseContainer();
141 m_WParser->OpenContainer();
8c651ab7 142 }
4f9297b0
VS
143 m_WParser->GetContainer()->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
144 m_WParser->GetContainer()->SetAlign(tag);
d1da8872 145 return false;
5526e819
VS
146 }
147
148TAG_HANDLER_END(P)
149
150
151
152TAG_HANDLER_BEGIN(BR, "BR")
fc7a2a60 153 TAG_HANDLER_CONSTR(BR) { }
5526e819
VS
154
155 TAG_HANDLER_PROC(tag)
156 {
4f9297b0 157 int al = m_WParser->GetContainer()->GetAlignHor();
5526e819 158 wxHtmlContainerCell *c;
33ac7e6f 159
4f9297b0
VS
160 m_WParser->CloseContainer();
161 c = m_WParser->OpenContainer();
162 c->SetAlignHor(al);
163 c->SetAlign(tag);
164 c->SetMinHeight(m_WParser->GetCharHeight());
d1da8872 165 return false;
5526e819
VS
166 }
167
168TAG_HANDLER_END(BR)
169
170
171
172TAG_HANDLER_BEGIN(CENTER, "CENTER")
fc7a2a60 173 TAG_HANDLER_CONSTR(CENTER) { }
5526e819
VS
174
175 TAG_HANDLER_PROC(tag)
176 {
4f9297b0
VS
177 int old = m_WParser->GetAlign();
178 wxHtmlContainerCell *c = m_WParser->GetContainer();
179
180 m_WParser->SetAlign(wxHTML_ALIGN_CENTER);
e3774124 181 if (c->GetFirstChild() != NULL)
04dbb646 182 {
4f9297b0
VS
183 m_WParser->CloseContainer();
184 m_WParser->OpenContainer();
5526e819
VS
185 }
186 else
4f9297b0 187 c->SetAlignHor(wxHTML_ALIGN_CENTER);
5526e819 188
33ac7e6f 189 if (tag.HasEnding())
04dbb646 190 {
5526e819
VS
191 ParseInner(tag);
192
4f9297b0 193 m_WParser->SetAlign(old);
e3774124 194 if (c->GetFirstChild() != NULL)
04dbb646 195 {
4f9297b0
VS
196 m_WParser->CloseContainer();
197 m_WParser->OpenContainer();
5526e819
VS
198 }
199 else
4f9297b0 200 c->SetAlignHor(old);
5526e819 201
d1da8872 202 return true;
5526e819 203 }
d1da8872 204 else return false;
5526e819
VS
205 }
206
207TAG_HANDLER_END(CENTER)
208
209
210
211TAG_HANDLER_BEGIN(DIV, "DIV")
fc7a2a60 212 TAG_HANDLER_CONSTR(DIV) { }
5526e819
VS
213
214 TAG_HANDLER_PROC(tag)
215 {
92337e39 216 if(tag.HasParam(wxT("STYLE")))
04dbb646 217 {
d1da8872 218 if(tag.GetParam(wxT("STYLE")).IsSameAs(wxT("PAGE-BREAK-BEFORE:ALWAYS"), false))
f2034f1b
VS
219 {
220 m_WParser->CloseContainer();
221 m_WParser->OpenContainer()->InsertCell(new wxHtmlPageBreakCell);
222 m_WParser->CloseContainer();
223 m_WParser->OpenContainer();
d1da8872 224 return false;
f2034f1b
VS
225 }
226 else
227 {
228 // Treat other STYLE parameters here when they're supported.
d1da8872 229 return false;
f2034f1b 230 }
5526e819 231 }
92337e39 232 else if(tag.HasParam(wxT("ALIGN")))
04dbb646 233 {
f2034f1b
VS
234 int old = m_WParser->GetAlign();
235 wxHtmlContainerCell *c = m_WParser->GetContainer();
e3774124 236 if (c->GetFirstChild() != NULL)
f2034f1b
VS
237 {
238 m_WParser->CloseContainer();
239 m_WParser->OpenContainer();
240 c = m_WParser->GetContainer();
241 c->SetAlign(tag);
242 m_WParser->SetAlign(c->GetAlignHor());
243 }
244 else
245 {
246 c->SetAlign(tag);
247 m_WParser->SetAlign(c->GetAlignHor());
248 }
5526e819 249
f2034f1b 250 ParseInner(tag);
5526e819 251
f2034f1b 252 m_WParser->SetAlign(old);
e3774124 253 if (c->GetFirstChild() != NULL)
f2034f1b
VS
254 {
255 m_WParser->CloseContainer();
256 m_WParser->OpenContainer();
257 }
258 else
259 c->SetAlignHor(old);
260
c5448f38 261 return true;
5526e819
VS
262 }
263 else
f2034f1b 264 {
c5448f38
VS
265 // Same as BR
266 int al = m_WParser->GetContainer()->GetAlignHor();
267 wxHtmlContainerCell *c;
268
269 m_WParser->CloseContainer();
270 c = m_WParser->OpenContainer();
271 c->SetAlignHor(al);
272 c->SetAlign(tag);
273 c->SetMinHeight(m_WParser->GetCharHeight());
274 return false;
f2034f1b 275 }
5526e819
VS
276 }
277
278TAG_HANDLER_END(DIV)
279
280
281
282
283TAG_HANDLER_BEGIN(TITLE, "TITLE")
fc7a2a60 284 TAG_HANDLER_CONSTR(TITLE) { }
5526e819
VS
285
286 TAG_HANDLER_PROC(tag)
287 {
bc55e31b
VS
288 wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface();
289 if (winIface)
04dbb646 290 {
b1a3a964 291 wxString title(tag.GetBeginIter(), tag.GetEndIter1());
8d94819c 292#if !wxUSE_UNICODE
4d70ab08
VZ
293 const wxFontEncoding enc = m_WParser->GetInputEncoding();
294 if ( enc != wxFONTENCODING_DEFAULT )
295 {
296 // need to convert to the current one
297 title = wxString(title.wc_str(wxCSConv(enc)), wxConvLocal);
298 }
299#endif // !wxUSE_UNICODE
300
bc55e31b
VS
301 title = m_WParser->GetEntitiesParser()->Parse(title);
302
303 winIface->SetHTMLWindowTitle(title);
5526e819 304 }
d1da8872 305 return true;
5526e819
VS
306 }
307
308TAG_HANDLER_END(TITLE)
309
310
311
312
313TAG_HANDLER_BEGIN(BODY, "BODY")
fc7a2a60 314 TAG_HANDLER_CONSTR(BODY) { }
5526e819
VS
315
316 TAG_HANDLER_PROC(tag)
317 {
5526e819
VS
318 wxColour clr;
319
8bd72d90 320 if (tag.GetParamAsColour(wxT("TEXT"), &clr))
04dbb646 321 {
8bd72d90
VS
322 m_WParser->SetActualColor(clr);
323 m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(clr));
5526e819
VS
324 }
325
8bd72d90
VS
326 if (tag.GetParamAsColour(wxT("LINK"), &clr))
327 m_WParser->SetLinkColor(clr);
328
bc55e31b
VS
329 wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface();
330 // the rest of this function requires a window:
331 if ( !winIface )
332 return false;
333
97e490f8
VZ
334 if (tag.HasParam(wxT("BACKGROUND")))
335 {
336 wxFSFile *fileBgImage = m_WParser->OpenURL
337 (
338 wxHTML_URL_IMAGE,
339 tag.GetParam(wxT("BACKGROUND"))
340 );
341 if ( fileBgImage )
342 {
343 wxInputStream *is = fileBgImage->GetStream();
344 if ( is )
345 {
346 wxImage image(*is);
a1b806b9 347 if ( image.IsOk() )
bc55e31b 348 winIface->SetHTMLBackgroundImage(image);
97e490f8 349 }
a237d7ed
VZ
350
351 delete fileBgImage;
97e490f8
VZ
352 }
353 }
354
8bd72d90 355 if (tag.GetParamAsColour(wxT("BGCOLOR"), &clr))
04dbb646 356 {
8bd72d90 357 m_WParser->GetContainer()->InsertCell(
be9cae51 358 new wxHtmlColourCell(clr, wxHTML_CLR_TRANSPARENT_BACKGROUND));
bc55e31b 359 winIface->SetHTMLBackgroundColour(clr);
5526e819 360 }
97e490f8 361
d1da8872 362 return false;
5526e819
VS
363 }
364
365TAG_HANDLER_END(BODY)
366
367
368
369TAG_HANDLER_BEGIN(BLOCKQUOTE, "BLOCKQUOTE")
fc7a2a60 370 TAG_HANDLER_CONSTR(BLOCKQUOTE) { }
5526e819
VS
371
372 TAG_HANDLER_PROC(tag)
373 {
374 wxHtmlContainerCell *c;
33ac7e6f 375
4f9297b0
VS
376 m_WParser->CloseContainer();
377 c = m_WParser->OpenContainer();
33ac7e6f 378
04dbb646 379 if (c->GetAlignHor() == wxHTML_ALIGN_RIGHT)
4f9297b0 380 c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_RIGHT);
5526e819 381 else
4f9297b0 382 c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT);
33ac7e6f 383
04dbb646 384 c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP);
4f9297b0 385 m_WParser->OpenContainer();
5526e819 386 ParseInner(tag);
4f9297b0
VS
387 c = m_WParser->CloseContainer();
388 c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_BOTTOM);
389 m_WParser->CloseContainer();
390 m_WParser->OpenContainer();
d1da8872 391 return true;
5526e819
VS
392 }
393
394TAG_HANDLER_END(BLOCKQUOTE)
395
396
397
3c115835
VS
398TAG_HANDLER_BEGIN(SUBSUP, "SUB,SUP")
399
400 TAG_HANDLER_PROC(tag)
401 {
402 bool issub = (tag.GetName() == wxT("SUB"));
403 wxHtmlScriptMode oldmode = m_WParser->GetScriptMode();
404 int oldbase = m_WParser->GetScriptBaseline();
405 int oldsize = m_WParser->GetFontSize();
406
407 wxHtmlContainerCell *cont = m_WParser->GetContainer();
408 wxHtmlCell *c = cont->GetLastChild();
409
410 m_WParser->SetScriptMode(issub ? wxHTML_SCRIPT_SUB : wxHTML_SCRIPT_SUP);
198d7c6c
VS
411 m_WParser->SetScriptBaseline(
412 oldbase + c ? c->GetScriptBaseline() : 0);
3c115835
VS
413
414 // select smaller font
415 m_WParser->SetFontSize(m_WParser->GetFontSize()-2);
416 cont->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
417
418 ParseInner(tag);
419
420 // restore font size
421 m_WParser->SetFontSize(oldsize);
422 m_WParser->GetContainer()->InsertCell(
423 new wxHtmlFontCell(m_WParser->CreateCurrentFont()));
424
425 // restore base and alignment
426 m_WParser->SetScriptBaseline(oldbase);
427 m_WParser->SetScriptMode(oldmode);
428
429 return true;
430 }
431
432TAG_HANDLER_END(SUBSUP)
433
434
8829fa82
VS
435// Tag handler for tags that we have to ignore, otherwise non-text data
436// would show up as text:
437TAG_HANDLER_BEGIN(DoNothing, "SCRIPT")
fc7a2a60
VZ
438 TAG_HANDLER_CONSTR(DoNothing) { }
439
440 TAG_HANDLER_PROC(WXUNUSED(tag))
8829fa82
VS
441 {
442 return true;
443 }
444TAG_HANDLER_END(DoNothing)
5526e819
VS
445
446
447
3c115835
VS
448
449
5526e819
VS
450TAGS_MODULE_BEGIN(Layout)
451
452 TAGS_MODULE_ADD(P)
453 TAGS_MODULE_ADD(BR)
454 TAGS_MODULE_ADD(CENTER)
455 TAGS_MODULE_ADD(DIV)
456 TAGS_MODULE_ADD(TITLE)
457 TAGS_MODULE_ADD(BODY)
458 TAGS_MODULE_ADD(BLOCKQUOTE)
3c115835 459 TAGS_MODULE_ADD(SUBSUP)
8829fa82 460 TAGS_MODULE_ADD(DoNothing)
5526e819
VS
461
462TAGS_MODULE_END(Layout)
463
464#endif