]>
git.saurik.com Git - wxWidgets.git/blob - src/html/m_layout.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/html/m_layout.cpp 
   3 // Purpose:     wxHtml module for basic paragraphs/layout handling 
   4 // Author:      Vaclav Slavik 
   6 // Copyright:   (c) 1999 Vaclav Slavik 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #include "wx/wxprec.h" 
  16 #if wxUSE_HTML && wxUSE_STREAMS 
  22 #include "wx/html/forcelnk.h" 
  23 #include "wx/html/m_templ.h" 
  25 #include "wx/html/htmlwin.h" 
  27 FORCE_LINK_ME(m_layout
) 
  30     #include "wx/msw/wince/missing.h"       // for bsearch() 
  32     #include <stdlib.h>                     // bsearch() 
  35 //----------------------------------------------------------------------------- 
  36 // wxHtmlPageBreakCell 
  37 //----------------------------------------------------------------------------- 
  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"> 
  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. 
  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 
  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. 
  68 class wxHtmlPageBreakCell 
: public wxHtmlCell
 
  71     wxHtmlPageBreakCell() {} 
  73     bool AdjustPagebreak(int* pagebreak
, 
  74                          wxArrayInt
& known_pagebreaks
) const; 
  76     void Draw(wxDC
& WXUNUSED(dc
), 
  77               int WXUNUSED(x
), int WXUNUSED(y
), 
  78               int WXUNUSED(view_y1
), int WXUNUSED(view_y2
), 
  79               wxHtmlRenderingInfo
& WXUNUSED(info
)) {} 
  82     DECLARE_NO_COPY_CLASS(wxHtmlPageBreakCell
) 
  85 // Comparison routine for bsearch into an int* array of pagebreaks. 
  86 extern "C" int wxCMPFUNC_CONV 
wxInteger_compare(void const* i0
, void const* i1
) 
  88     return *(int*)i0 
- *(int*)i1
; 
  91 bool wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak
, wxArrayInt
& known_pagebreaks
) const 
  93     // When we are counting pages, 'known_pagebreaks' is non-NULL. 
  94     // That's the only time we change 'pagebreak'. Otherwise, pages 
  95     // were already counted, 'known_pagebreaks' is NULL, and we don't 
  96     // do anything except return false. 
  98     // We also simply return false if the 'pagebreak' argument is 
  99     // less than (vertically above) or the same as the current 
 100     // vertical position. Otherwise we'd be setting a pagebreak above 
 101     // the current cell, which is incorrect, or duplicating a 
 102     // pagebreak that has already been set. 
 103     if( known_pagebreaks
.Count() == 0 || *pagebreak 
<= m_PosY
) 
 108     // m_PosY is only the vertical offset from the parent. The pagebreak 
 109     // required here is the total page offset, so m_PosY must be added 
 110     // to the parent's offset and height. 
 111     int total_height 
= m_PosY 
+ GetParent()->GetPosY() + GetParent()->GetHeight(); 
 113     // Search the array of pagebreaks to see whether we've already set 
 114     // a pagebreak here. The standard bsearch() function is appropriate 
 115     // because the array of pagebreaks through known_pagebreaks[number_of_pages] 
 116     // is known to be sorted in strictly increasing order. '1 + number_of_pages' 
 117     // is used as a bsearch() argument because the array contains a leading 
 118     // zero plus one element for each page. 
 119     int where 
= known_pagebreaks
.Index( total_height
); 
 120     // Add a pagebreak only if there isn't one already set here. 
 121     if( wxNOT_FOUND 
!= where
) 
 134 TAG_HANDLER_BEGIN(P
, "P") 
 135     TAG_HANDLER_CONSTR(P
) { } 
 137     TAG_HANDLER_PROC(tag
) 
 139         if (m_WParser
->GetContainer()->GetFirstChild() != NULL
) 
 141             m_WParser
->CloseContainer(); 
 142             m_WParser
->OpenContainer(); 
 144         m_WParser
->GetContainer()->SetIndent(m_WParser
->GetCharHeight(), wxHTML_INDENT_TOP
); 
 145         m_WParser
->GetContainer()->SetAlign(tag
); 
 153 TAG_HANDLER_BEGIN(BR
, "BR") 
 154     TAG_HANDLER_CONSTR(BR
) { } 
 156     TAG_HANDLER_PROC(tag
) 
 158         int al 
= m_WParser
->GetContainer()->GetAlignHor(); 
 159         wxHtmlContainerCell 
*c
; 
 161         m_WParser
->CloseContainer(); 
 162         c 
= m_WParser
->OpenContainer(); 
 165         c
->SetMinHeight(m_WParser
->GetCharHeight()); 
 173 TAG_HANDLER_BEGIN(CENTER
, "CENTER") 
 174     TAG_HANDLER_CONSTR(CENTER
) { } 
 176     TAG_HANDLER_PROC(tag
) 
 178         int old 
= m_WParser
->GetAlign(); 
 179         wxHtmlContainerCell 
*c 
= m_WParser
->GetContainer(); 
 181         m_WParser
->SetAlign(wxHTML_ALIGN_CENTER
); 
 182         if (c
->GetFirstChild() != NULL
) 
 184             m_WParser
->CloseContainer(); 
 185             m_WParser
->OpenContainer(); 
 188             c
->SetAlignHor(wxHTML_ALIGN_CENTER
); 
 194             m_WParser
->SetAlign(old
); 
 195             if (c
->GetFirstChild() != NULL
) 
 197                 m_WParser
->CloseContainer(); 
 198                 m_WParser
->OpenContainer(); 
 208 TAG_HANDLER_END(CENTER
) 
 212 TAG_HANDLER_BEGIN(DIV
, "DIV") 
 213     TAG_HANDLER_CONSTR(DIV
) { } 
 215     TAG_HANDLER_PROC(tag
) 
 217         if(tag
.HasParam(wxT("STYLE"))) 
 219             if(tag
.GetParam(wxT("STYLE")).IsSameAs(wxT("PAGE-BREAK-BEFORE:ALWAYS"), false)) 
 221                 m_WParser
->CloseContainer(); 
 222                 m_WParser
->OpenContainer()->InsertCell(new wxHtmlPageBreakCell
); 
 223                 m_WParser
->CloseContainer(); 
 224                 m_WParser
->OpenContainer(); 
 229                 // Treat other STYLE parameters here when they're supported. 
 233         else if(tag
.HasParam(wxT("ALIGN"))) 
 235             int old 
= m_WParser
->GetAlign(); 
 236             wxHtmlContainerCell 
*c 
= m_WParser
->GetContainer(); 
 237             if (c
->GetFirstChild() != NULL
) 
 239                 m_WParser
->CloseContainer(); 
 240                 m_WParser
->OpenContainer(); 
 241                 c 
= m_WParser
->GetContainer(); 
 243                 m_WParser
->SetAlign(c
->GetAlignHor()); 
 248                 m_WParser
->SetAlign(c
->GetAlignHor()); 
 253             m_WParser
->SetAlign(old
); 
 254             if (c
->GetFirstChild() != NULL
) 
 256                 m_WParser
->CloseContainer(); 
 257                 m_WParser
->OpenContainer(); 
 267             int al 
= m_WParser
->GetContainer()->GetAlignHor(); 
 268             wxHtmlContainerCell 
*c
; 
 270             m_WParser
->CloseContainer(); 
 271             c 
= m_WParser
->OpenContainer(); 
 274             c
->SetMinHeight(m_WParser
->GetCharHeight()); 
 284 TAG_HANDLER_BEGIN(TITLE
, "TITLE") 
 285     TAG_HANDLER_CONSTR(TITLE
) { } 
 287     TAG_HANDLER_PROC(tag
) 
 289         wxHtmlWindowInterface 
*winIface 
= m_WParser
->GetWindowInterface(); 
 292             wxString title 
= m_WParser
->GetSource()->Mid( 
 294                                     tag
.GetEndPos1()-tag
.GetBeginPos()); 
 295 #if !wxUSE_UNICODE && wxUSE_WCHAR_T 
 296             const wxFontEncoding enc 
= m_WParser
->GetInputEncoding(); 
 297             if ( enc 
!= wxFONTENCODING_DEFAULT 
) 
 299                 // need to convert to the current one 
 300                 title 
= wxString(title
.wc_str(wxCSConv(enc
)), wxConvLocal
); 
 302 #endif // !wxUSE_UNICODE 
 304             title 
= m_WParser
->GetEntitiesParser()->Parse(title
); 
 306             winIface
->SetHTMLWindowTitle(title
); 
 311 TAG_HANDLER_END(TITLE
) 
 316 TAG_HANDLER_BEGIN(BODY
, "BODY") 
 317     TAG_HANDLER_CONSTR(BODY
) { } 
 319     TAG_HANDLER_PROC(tag
) 
 323         if (tag
.GetParamAsColour(wxT("TEXT"), &clr
)) 
 325             m_WParser
->SetActualColor(clr
); 
 326             m_WParser
->GetContainer()->InsertCell(new wxHtmlColourCell(clr
)); 
 329         if (tag
.GetParamAsColour(wxT("LINK"), &clr
)) 
 330             m_WParser
->SetLinkColor(clr
); 
 332         wxHtmlWindowInterface 
*winIface 
= m_WParser
->GetWindowInterface(); 
 333         // the rest of this function requires a window: 
 337         if (tag
.HasParam(wxT("BACKGROUND"))) 
 339             wxFSFile 
*fileBgImage 
= m_WParser
->OpenURL
 
 342                                                 tag
.GetParam(wxT("BACKGROUND")) 
 346                 wxInputStream 
*is 
= fileBgImage
->GetStream(); 
 349 #if !defined(__WXMSW__) || wxUSE_WXDIB 
 352                         winIface
->SetHTMLBackgroundImage(image
); 
 358         if (tag
.GetParamAsColour(wxT("BGCOLOR"), &clr
)) 
 360             m_WParser
->GetContainer()->InsertCell( 
 361                 new wxHtmlColourCell(clr
, wxHTML_CLR_BACKGROUND
)); 
 362             winIface
->SetHTMLBackgroundColour(clr
); 
 368 TAG_HANDLER_END(BODY
) 
 372 TAG_HANDLER_BEGIN(BLOCKQUOTE
, "BLOCKQUOTE") 
 373     TAG_HANDLER_CONSTR(BLOCKQUOTE
) { } 
 375     TAG_HANDLER_PROC(tag
) 
 377         wxHtmlContainerCell 
*c
; 
 379         m_WParser
->CloseContainer(); 
 380         c 
= m_WParser
->OpenContainer(); 
 382         if (c
->GetAlignHor() == wxHTML_ALIGN_RIGHT
) 
 383             c
->SetIndent(5 * m_WParser
->GetCharWidth(), wxHTML_INDENT_RIGHT
); 
 385             c
->SetIndent(5 * m_WParser
->GetCharWidth(), wxHTML_INDENT_LEFT
); 
 387         c
->SetIndent(m_WParser
->GetCharHeight(), wxHTML_INDENT_TOP
); 
 388         m_WParser
->OpenContainer(); 
 390         c 
= m_WParser
->CloseContainer(); 
 391         c
->SetIndent(m_WParser
->GetCharHeight(), wxHTML_INDENT_BOTTOM
); 
 392         m_WParser
->CloseContainer(); 
 393         m_WParser
->OpenContainer(); 
 397 TAG_HANDLER_END(BLOCKQUOTE
) 
 401 TAG_HANDLER_BEGIN(SUBSUP
, "SUB,SUP") 
 403     TAG_HANDLER_PROC(tag
) 
 405         bool issub 
= (tag
.GetName() == wxT("SUB")); 
 406         wxHtmlScriptMode oldmode 
= m_WParser
->GetScriptMode(); 
 407         int oldbase 
= m_WParser
->GetScriptBaseline(); 
 408         int oldsize 
= m_WParser
->GetFontSize(); 
 410         wxHtmlContainerCell 
*cont 
= m_WParser
->GetContainer(); 
 411         wxHtmlCell 
*c 
= cont
->GetLastChild(); 
 413         m_WParser
->SetScriptMode(issub 
? wxHTML_SCRIPT_SUB 
: wxHTML_SCRIPT_SUP
); 
 414         m_WParser
->SetScriptBaseline( 
 415                 oldbase 
+ c 
? c
->GetScriptBaseline() : 0); 
 417         // select smaller font 
 418         m_WParser
->SetFontSize(m_WParser
->GetFontSize()-2); 
 419         cont
->InsertCell(new wxHtmlFontCell(m_WParser
->CreateCurrentFont())); 
 424         m_WParser
->SetFontSize(oldsize
); 
 425         m_WParser
->GetContainer()->InsertCell( 
 426             new wxHtmlFontCell(m_WParser
->CreateCurrentFont())); 
 428         // restore base and alignment 
 429         m_WParser
->SetScriptBaseline(oldbase
); 
 430         m_WParser
->SetScriptMode(oldmode
); 
 435 TAG_HANDLER_END(SUBSUP
) 
 438 // Tag handler for tags that we have to ignore, otherwise non-text data 
 439 // would show up as text: 
 440 TAG_HANDLER_BEGIN(DoNothing
, "SCRIPT") 
 441     TAG_HANDLER_CONSTR(DoNothing
) { } 
 443     TAG_HANDLER_PROC(WXUNUSED(tag
)) 
 447 TAG_HANDLER_END(DoNothing
) 
 453 TAGS_MODULE_BEGIN(Layout
) 
 457     TAGS_MODULE_ADD(CENTER
) 
 459     TAGS_MODULE_ADD(TITLE
) 
 460     TAGS_MODULE_ADD(BODY
) 
 461     TAGS_MODULE_ADD(BLOCKQUOTE
) 
 462     TAGS_MODULE_ADD(SUBSUP
) 
 463     TAGS_MODULE_ADD(DoNothing
) 
 465 TAGS_MODULE_END(Layout
)