X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9eeca6dfe8f5e2cf5ea3f2aeef445de86d80beb3..0ea0359bca1ce9640aa5f75c9aa106311176509e:/src/html/m_layout.cpp diff --git a/src/html/m_layout.cpp b/src/html/m_layout.cpp index e828f01e1d..abd44132e9 100644 --- a/src/html/m_layout.cpp +++ b/src/html/m_layout.cpp @@ -15,7 +15,7 @@ #include "wx/defs.h" #if wxUSE_HTML && wxUSE_STREAMS -#ifdef __BORDLANDC__ +#ifdef __BORLANDC__ #pragma hdrstop #endif @@ -31,11 +31,112 @@ FORCE_LINK_ME(m_layout) +#include // bsearch() + +//----------------------------------------------------------------------------- +// wxHtmlPageBreakCell +//----------------------------------------------------------------------------- + +// Since html isn't a page-layout language, it doesn't support page +// page breaks directly--that requires CSS2 support. But a page-break +// facility is handy, and has been requested more than once on the +// mailing lists. This wxHtml tag handler implements just enough of +// CSS2 to support a page break by recognizing only +//
+// +// wxHtml maintains page breaks in wxHtmlPrintout::m_PageBreaks. The +// tag handler below adds appropriate offsets to that array member. +// wxHtmlDCRenderer::Render() accesses that array and makes a new page +// begin after each page-break tag. + +// The page-break handler does all its work in AdjustPagebreak(). For +// all tag handlers, that function adjusts the page-break position. +// For other tags, it determines whether the html element can fit on +// the remainder of the page; if it cannot fit, but must not be split, +// then the function moves the page break provided in the argument up, +// and returns 'true' to inform the caller that the argument was +// modified. +// +// Due to its special purpose, the page-break facility differs from +// other tags. It takes up no space, but it behaves as though there is +// never enough room to fit it on the remainder of the page--it always +// forces a page break. Therefore, unlike other elements that trigger +// a page break, it would never 'fit' on the following page either. +// Therefore it's necessary to compare each pagebreak candidate to the +// array wxHtmlPrintout::m_PageBreaks of pagebreaks already set, and +// set a new one only if it's not in that array. + +class WXDLLEXPORT wxHtmlPageBreakCell : public wxHtmlCell +{ +public: + wxHtmlPageBreakCell() {} + + bool AdjustPagebreak(int* pagebreak, + int* known_pagebreaks = NULL, + int number_of_pages = 0) const; + void Draw(wxDC& WXUNUSED(dc), + int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(view_y1), int WXUNUSED(view_y2), + wxHtmlRenderingState& WXUNUSED(state)) {} + +private: + DECLARE_NO_COPY_CLASS(wxHtmlPageBreakCell) +}; + +// Comparison routine for bsearch into an int* array of pagebreaks. +static int integer_compare(void const* i0, void const* i1) +{ + return *(int*)i0 - *(int*)i1; +} + +bool wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak, int* known_pagebreaks, int number_of_pages) const +{ + // When we are counting pages, 'known_pagebreaks' is non-NULL. + // That's the only time we change 'pagebreak'. Otherwise, pages + // were already counted, 'known_pagebreaks' is NULL, and we don't + // do anything except return FALSE. + // + // We also simply return FALSE if the 'pagebreak' argument is + // less than (vertically above) or the same as the current + // vertical position. Otherwise we'd be setting a pagebreak above + // the current cell, which is incorrect, or duplicating a + // pagebreak that has already been set. + if(NULL == known_pagebreaks || *pagebreak <= m_PosY) + { + return FALSE; + } + + // m_PosY is only the vertical offset from the parent. The pagebreak + // required here is the total page offset, so m_PosY must be added + // to the parent's offset and height. + int total_height = m_PosY + GetParent()->GetPosY() + GetParent()->GetHeight(); + + // Search the array of pagebreaks to see whether we've already set + // a pagebreak here. The standard bsearch() function is appropriate + // because the array of pagebreaks through known_pagebreaks[number_of_pages] + // is known to be sorted in strictly increasing order. '1 + number_of_pages' + // is used as a bsearch() argument because the array contains a leading + // zero plus one element for each page. + int* where = (int*) bsearch(&total_height, known_pagebreaks, + 1 + number_of_pages, sizeof(int), + integer_compare); + // Add a pagebreak only if there isn't one already set here. + if(NULL != where) + { + return FALSE; + } + else + { + *pagebreak = m_PosY; + return TRUE; + } +} + TAG_HANDLER_BEGIN(P, "P") TAG_HANDLER_PROC(tag) { - if (m_WParser->GetContainer()->GetFirstCell() != NULL) + if (m_WParser->GetContainer()->GetFirstChild() != NULL) { m_WParser->CloseContainer(); m_WParser->OpenContainer(); @@ -76,7 +177,7 @@ TAG_HANDLER_BEGIN(CENTER, "CENTER") wxHtmlContainerCell *c = m_WParser->GetContainer(); m_WParser->SetAlign(wxHTML_ALIGN_CENTER); - if (c->GetFirstCell() != NULL) + if (c->GetFirstChild() != NULL) { m_WParser->CloseContainer(); m_WParser->OpenContainer(); @@ -89,7 +190,7 @@ TAG_HANDLER_BEGIN(CENTER, "CENTER") ParseInner(tag); m_WParser->SetAlign(old); - if (c->GetFirstCell() != NULL) + if (c->GetFirstChild() != NULL) { m_WParser->CloseContainer(); m_WParser->OpenContainer(); @@ -110,34 +211,57 @@ TAG_HANDLER_BEGIN(DIV, "DIV") TAG_HANDLER_PROC(tag) { - int old = m_WParser->GetAlign(); - wxHtmlContainerCell *c = m_WParser->GetContainer(); - if (c->GetFirstCell() != NULL) + if(tag.HasParam(wxT("STYLE"))) { - m_WParser->CloseContainer(); - m_WParser->OpenContainer(); - c = m_WParser->GetContainer(); - c->SetAlign(tag); - m_WParser->SetAlign(c->GetAlignHor()); + if(tag.GetParam(wxT("STYLE")).IsSameAs(wxT("PAGE-BREAK-BEFORE:ALWAYS"), FALSE)) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer()->InsertCell(new wxHtmlPageBreakCell); + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + return FALSE; + } + else + { + // Treat other STYLE parameters here when they're supported. + return FALSE; + } } - else + else if(tag.HasParam(wxT("ALIGN"))) { - c->SetAlign(tag); - m_WParser->SetAlign(c->GetAlignHor()); - } + int old = m_WParser->GetAlign(); + wxHtmlContainerCell *c = m_WParser->GetContainer(); + if (c->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + c = m_WParser->GetContainer(); + c->SetAlign(tag); + m_WParser->SetAlign(c->GetAlignHor()); + } + else + { + c->SetAlign(tag); + m_WParser->SetAlign(c->GetAlignHor()); + } - ParseInner(tag); + ParseInner(tag); - m_WParser->SetAlign(old); - if (c->GetFirstCell() != NULL) - { - m_WParser->CloseContainer(); - m_WParser->OpenContainer(); + m_WParser->SetAlign(old); + if (c->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + } + else + c->SetAlignHor(old); + + return TRUE; } else - c->SetAlignHor(old); - - return TRUE; + { + return FALSE; + } } TAG_HANDLER_END(DIV) @@ -224,6 +348,14 @@ TAG_HANDLER_END(BLOCKQUOTE) +// Tag handler for tags that we have to ignore, otherwise non-text data +// would show up as text: +TAG_HANDLER_BEGIN(DoNothing, "SCRIPT") + TAG_HANDLER_PROC(tag) + { + return true; + } +TAG_HANDLER_END(DoNothing) @@ -236,6 +368,7 @@ TAGS_MODULE_BEGIN(Layout) TAGS_MODULE_ADD(TITLE) TAGS_MODULE_ADD(BODY) TAGS_MODULE_ADD(BLOCKQUOTE) + TAGS_MODULE_ADD(DoNothing) TAGS_MODULE_END(Layout)