From f2034f1b6e04a39f6d882cf6cdd53c11bf39f5d7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Mon, 12 May 2003 22:33:51 +0000 Subject: [PATCH] applied HTML pagebreaks patch git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20617 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 2 + include/wx/html/htmlcell.h | 4 +- include/wx/html/htmprint.h | 20 +++-- samples/html/printing/test.htm | 3 +- src/html/htmlcell.cpp | 8 +- src/html/htmprint.cpp | 10 ++- src/html/m_layout.cpp | 160 ++++++++++++++++++++++++++++----- 7 files changed, 170 insertions(+), 37 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 2e6c7ff105..d46885f33f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -150,6 +150,8 @@ wxUniv: wxHTML: - added SetFonts to HTML printing classes (Adrian Philip Look) +- it is now possible to force page break when printing by inserting +
into the markup (Greg Chicares) OLD CHANGES diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h index f5bc99c58b..5f10a0bed1 100644 --- a/include/wx/html/htmlcell.h +++ b/include/wx/html/htmlcell.h @@ -108,7 +108,7 @@ public: // // Returned value : true if pagebreak was modified, false otherwise // Usage : while (container->AdjustPagebreak(&p)) {} - virtual bool AdjustPagebreak(int *pagebreak) const; + virtual bool AdjustPagebreak(int *pagebreak, int *known_pagebreaks = NULL, int number_of_pages = 0) const; // Sets cell's behaviour on pagebreaks (see AdjustPagebreak). Default // is true - the cell can be split on two pages @@ -191,7 +191,7 @@ public: virtual void Layout(int w); virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); virtual void DrawInvisible(wxDC& dc, int x, int y); - virtual bool AdjustPagebreak(int *pagebreak) const; + virtual bool AdjustPagebreak(int *pagebreak, int *known_pagebreaks = NULL, int number_of_pages = 0) const; // insert cell at the end of m_Cells list void InsertCell(wxHtmlCell *cell); diff --git a/include/wx/html/htmprint.h b/include/wx/html/htmprint.h index e05d01d903..71448016c7 100644 --- a/include/wx/html/htmprint.h +++ b/include/wx/html/htmprint.h @@ -25,6 +25,8 @@ #include "wx/print.h" #include "wx/printdlg.h" +#include // INT_MAX + //-------------------------------------------------------------------------------- // wxHtmlDCRenderer // This class is capable of rendering HTML into specified @@ -39,7 +41,7 @@ public: // Following 3 methods *must* be called before any call to Render: - // Asign DC to this render + // Assign DC to this render void SetDC(wxDC *dc, double pixel_scale = 1.0); // Sets size of output rectangle, in pixels. Note that you *can't* change @@ -57,15 +59,23 @@ public: void SetFonts(wxString normal_face, wxString fixed_face, const int *sizes = NULL); // [x,y] is position of upper-left corner of printing rectangle (see SetSize) - // from is y-coordinate of the very first visible cell + // from is y-coordinate of the very first visible cell + // to is y-coordinate of the next following page break, if any // Returned value is y coordinate of first cell than didn't fit onto page. // Use this value as 'from' in next call to Render in order to print multiple pages // document // If dont_render is TRUE then nothing is rendered into DC and it only counts // pixels and return y coord of the next page // - // CAUTION! Render() changes DC's user scale and does NOT restore it! - int Render(int x, int y, int from = 0, int dont_render = FALSE); + // known_pagebreaks and number_of_pages are used only when counting pages; + // otherwise, their default values should be used. Their purpose is to + // support pagebreaks using a subset of CSS2's
. The
handler + // needs to know what pagebreaks have already been set so that it doesn't + // set the same pagebreak twice. + // + // CAUTION! Render() changes DC's user scale and does NOT restore it! + int Render(int x, int y, int from = 0, int dont_render = FALSE, int to = INT_MAX, + int *known_pagebreaks = NULL, int number_of_pages = 0); // returns total height of the html document // (compare Render's return value with this) @@ -221,7 +231,7 @@ public: // return page setting data objects. // (You can set their parameters.) -protected: +protected: virtual wxHtmlPrintout *CreatePrintout(); virtual bool DoPreview(wxHtmlPrintout *printout1, wxHtmlPrintout *printout2); virtual bool DoPrint(wxHtmlPrintout *printout); diff --git a/samples/html/printing/test.htm b/samples/html/printing/test.htm index 8cf983737a..3bb5be3a20 100644 --- a/samples/html/printing/test.htm +++ b/samples/html/printing/test.htm @@ -40,6 +40,7 @@ Note (2): the releases described are for wxGTK, wxMSW and wxMotif ports. wxMac c its own development path. Also, minor snapshot releases for specific platforms may be available at dates convenient to the developers.

+


Schedule

@@ -120,7 +121,7 @@ combined base/GUI library for GUI applications only.

-


To-Do List
+
To-Do List

diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp index e7d104e8c0..7881b478f0 100644 --- a/src/html/htmlcell.cpp +++ b/src/html/htmlcell.cpp @@ -68,7 +68,7 @@ void wxHtmlCell::OnMouseClick(wxWindow *parent, int x, int y, -bool wxHtmlCell::AdjustPagebreak(int *pagebreak) const +bool wxHtmlCell::AdjustPagebreak(int *pagebreak, int* WXUNUSED(known_pagebreaks), int WXUNUSED(number_of_pages)) const { if ((!m_CanLiveOnPagebreak) && m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak) @@ -215,10 +215,10 @@ int wxHtmlContainerCell::GetIndentUnits(int ind) const -bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak) const +bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int* known_pagebreaks, int number_of_pages) const { if (!m_CanLiveOnPagebreak) - return wxHtmlCell::AdjustPagebreak(pagebreak); + return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks, number_of_pages); else { @@ -228,7 +228,7 @@ bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak) const while (c) { - if (c->AdjustPagebreak(&pbrk)) + if (c->AdjustPagebreak(&pbrk, known_pagebreaks, number_of_pages)) rt = TRUE; c = c->GetNext(); } diff --git a/src/html/htmprint.cpp b/src/html/htmprint.cpp index 62ff13af35..89f5e3c83c 100644 --- a/src/html/htmprint.cpp +++ b/src/html/htmprint.cpp @@ -100,15 +100,17 @@ void wxHtmlDCRenderer::SetFonts(wxString normal_face, wxString fixed_face, } -int wxHtmlDCRenderer::Render(int x, int y, int from, int dont_render) +int wxHtmlDCRenderer::Render(int x, int y, int from, int dont_render, int to, int *known_pagebreaks, int number_of_pages) { int pbreak, hght; if (m_Cells == NULL || m_DC == NULL) return 0; pbreak = (int)(from + m_Height); - while (m_Cells->AdjustPagebreak(&pbreak)) {} + while (m_Cells->AdjustPagebreak(&pbreak, known_pagebreaks, number_of_pages)) {} hght = pbreak - from; + if(to < hght) + hght = to; if (!dont_render) { @@ -335,7 +337,7 @@ void wxHtmlPrintout::CountPages() { pos = m_Renderer->Render((int)( ppmm_h * m_MarginLeft), (int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), - pos, TRUE); + pos, TRUE, INT_MAX, m_PageBreaks, m_NumPages); m_PageBreaks[++m_NumPages] = pos; } while (pos < m_Renderer->GetTotalHeight()); } @@ -369,7 +371,7 @@ void wxHtmlPrintout::RenderPage(wxDC *dc, int page) m_Renderer->Render((int) (ppmm_h * m_MarginLeft), (int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), - m_PageBreaks[page-1]); + m_PageBreaks[page-1], FALSE, m_PageBreaks[page]-m_PageBreaks[page-1]); m_RendererHdr->SetDC(dc, (double)ppiPrinterY / (double)ppiScreenY); if (m_Headers[page % 2] != wxEmptyString) diff --git a/src/html/m_layout.cpp b/src/html/m_layout.cpp index e042da6e6a..15aa9a2fa4 100644 --- a/src/html/m_layout.cpp +++ b/src/html/m_layout.cpp @@ -31,6 +31,101 @@ 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; + + 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) @@ -110,34 +205,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("STYLE")) { - m_WParser->CloseContainer(); - m_WParser->OpenContainer(); - c = m_WParser->GetContainer(); - c->SetAlign(tag); - m_WParser->SetAlign(c->GetAlignHor()); + if(tag.GetParam("STYLE").IsSameAs(wxString("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("ALIGN")) { - c->SetAlign(tag); - m_WParser->SetAlign(c->GetAlignHor()); - } + int old = m_WParser->GetAlign(); + wxHtmlContainerCell *c = m_WParser->GetContainer(); + if (c->GetFirstCell() != 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->GetFirstCell() != 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) -- 2.47.2