diff --git a/docs/changes.txt b/docs/changes.txt index 108b3ba36e..f5b2e3ba67 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -66,6 +66,12 @@ Changes in behaviour which may result in build errors - wx/treebook.h doesn't include wx/treectrl.h (and, via it, wx/textctrl.h) any more, include these headers explicitly from your code if necessary. +- wxHtmlDCRenderer::Render() arguments have changed, simply omit the ones not + existing in the function signature any more to update the code using it. + +- wxHtmlCell::AdjustPagebreak() has lost its "known_pagebreaks" argument, + update your code if you override this method (you shouldn't be calling it). + 3.1.2: (released 2018-??-??) ---------------------------- diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h index 6f726b2795..282b7cd964 100644 --- a/include/wx/html/htmlcell.h +++ b/include/wx/html/htmlcell.h @@ -279,17 +279,20 @@ public: const wxPoint& pos, const wxMouseEvent& event); - // This method used to adjust pagebreak position. The parameter is variable - // that contains y-coordinate of page break (= horizontal line that should - // not be crossed by words, images etc.). If this cell cannot be divided - // into two pieces (each one on another page) then it moves the pagebreak - // few pixels up. + // This method is called when paginating HTML, e.g. when printing. + // + // On input, pagebreak contains y-coordinate of page break (i.e. the + // horizontal line that should not be crossed by words, images etc.) + // relative to the parent cell on entry and may be modified to request a + // page break at a position before it if this cell cannot be divided into + // two pieces (each one on its own page). + // + // Note that page break must still happen on the current page, i.e. the + // returned value must be strictly greater than "*pagebreak - pageHeight" + // and less or equal to "*pagebreak" for the value of pagebreak on input. // // Returned value : true if pagebreak was modified, false otherwise - // Usage : while (container->AdjustPagebreak(&p)) {} - virtual bool AdjustPagebreak(int *pagebreak, - const wxArrayInt& known_pagebreaks, - int pageHeight) const; + virtual bool AdjustPagebreak(int *pagebreak, int pageHeight) const; // Sets cell's behaviour on pagebreaks (see AdjustPagebreak). Default // is true - the cell can be split on two pages @@ -451,9 +454,7 @@ public: virtual void DrawInvisible(wxDC& dc, int x, int y, wxHtmlRenderingInfo& info) wxOVERRIDE; - virtual bool AdjustPagebreak(int *pagebreak, - const wxArrayInt& known_pagebreaks, - int pageHeight) const wxOVERRIDE; + virtual bool AdjustPagebreak(int *pagebreak, int pageHeight) const wxOVERRIDE; // 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 6098b9bd94..3c0d12f6ab 100644 --- a/include/wx/html/htmprint.h +++ b/include/wx/html/htmprint.h @@ -20,6 +20,7 @@ #include "wx/print.h" #include "wx/printdlg.h" +#include "wx/vector.h" #include // INT_MAX @@ -62,30 +63,19 @@ public: const wxString& normal_face = wxEmptyString, const wxString& fixed_face = wxEmptyString); + // Finds the next page break after the specified (vertical) position. + // Returns wxNOT_FOUND if passed in position is the last page break. + int FindNextPageBreak(int pos) const; + // [x,y] is position of upper-left corner of printing rectangle (see SetSize) // 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 - // - // 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, wxArrayInt& known_pagebreaks, int from = 0, - int dont_render = false, int to = INT_MAX); + void Render(int x, int y, int from = 0, int to = INT_MAX); // returns total width of the html document int GetTotalWidth() const; // returns total height of the html document - // (compare Render's return value with this) int GetTotalHeight() const; private: @@ -121,7 +111,6 @@ class WXDLLIMPEXP_HTML wxHtmlPrintout : public wxPrintout { public: wxHtmlPrintout(const wxString& title = wxT("Printout")); - virtual ~wxHtmlPrintout(); void SetHtmlText(const wxString& html, const wxString &basepath = wxEmptyString, bool isdir = true); // prepares the class for printing this html document. @@ -195,23 +184,22 @@ private: wxString TranslateHeader(const wxString& instr, int page); // substitute @PAGENUM@ and @PAGESCNT@ by real values void CountPages(); - // counts pages and fills m_NumPages and m_PageBreaks + // fills m_PageBreaks, which indirectly gives the number of pages private: - int m_NumPages; - wxArrayInt m_PageBreaks; + wxVector m_PageBreaks; wxString m_Document, m_BasePath; bool m_BasePathIsDir; wxString m_Headers[2], m_Footers[2]; int m_HeaderHeight, m_FooterHeight; - wxHtmlDCRenderer *m_Renderer, *m_RendererHdr; + wxHtmlDCRenderer m_Renderer, m_RendererHdr; float m_MarginTop, m_MarginBottom, m_MarginLeft, m_MarginRight, m_MarginSpace; // list of HTML filters - static wxList m_Filters; + static wxVector m_Filters; wxDECLARE_NO_COPY_CLASS(wxHtmlPrintout); }; diff --git a/include/wx/prntbase.h b/include/wx/prntbase.h index 18987fffb3..1056e27d0e 100644 --- a/include/wx/prntbase.h +++ b/include/wx/prntbase.h @@ -281,6 +281,10 @@ public: virtual wxString GetTitle() const { return m_printoutTitle; } + // Port-specific code should call this function to initialize this object + // with everything it needs, instead of using individual accessors below. + bool SetUp(wxDC& dc); + wxDC *GetDC() const { return m_printoutDC; } void SetDC(wxDC *dc) { m_printoutDC = dc; } diff --git a/interface/wx/html/htmlcell.h b/interface/wx/html/htmlcell.h index 665de5f5b4..18b05a8a00 100644 --- a/interface/wx/html/htmlcell.h +++ b/interface/wx/html/htmlcell.h @@ -187,34 +187,31 @@ public: wxHtmlCell(); /** - This method is used to adjust pagebreak position. - The first parameter is a variable that contains the y-coordinate of the page break - (= horizontal line that should not be crossed by words, images etc.). - If this cell cannot be divided into two pieces (each one on another page) - then it either moves the pagebreak a few pixels up, if possible, or, if - the cell cannot fit on the page at all, then the cell is forced to - split unconditionally. + This method is called when paginating HTML, e.g.\ when printing. - Returns @true if pagebreak was modified, @false otherwise. + User code should never call this function, but may need to override it + in custom HTML cell classes with any specific page breaking + requirements. + + On input, @a pagebreak contains y-coordinate of page break (i.e. the + horizontal line that should not be crossed by words, images etc.) + relative to the parent cell on entry and may be modified to request a + page break at a position before it if this cell cannot be divided into + two pieces (each one on its own page). + + Note that page break must still happen on the current page, i.e. the + returned value must be strictly greater than @code *pagebreak - + pageHeight @endcode and less or equal to @c *pagebreak for the value of + @a pagebreak on input. @param pagebreak - position in pixel of the pagebreak. - - @param known_pagebreaks - the list of the previous pagebreaks - + position in pixels of the pagebreak. @param pageHeight - the height in pixel of the page drawable area - - Usage: - @code - while (container->AdjustPagebreak(&p, kp, ph)) {} - @endcode + the height in pixels of the page drawable area + @return @true if pagebreak was modified, @false otherwise. */ - virtual bool AdjustPagebreak(int* pagebreak, - const wxArrayInt& known_pagebreaks, - int pageHeight) const; + virtual bool AdjustPagebreak(int* pagebreak, int pageHeight) const; /** Renders the cell. diff --git a/interface/wx/html/htmprint.h b/interface/wx/html/htmprint.h index 7d0ceaf15e..6e6a0908dc 100644 --- a/interface/wx/html/htmprint.h +++ b/interface/wx/html/htmprint.h @@ -38,33 +38,54 @@ public: /** Returns the height of the HTML text in pixels. - This is important if area height (see wxHtmlDCRenderer::SetSize) is - smaller that total height and thus the page cannot fit into it. In that - case you're supposed to call Render() as long as its return value is - smaller than GetTotalHeight()'s. + If the height of the area used with this renderer (see + wxHtmlDCRenderer::SetSize) is smaller that total height, the renderer + will produce more than one page of output. @see GetTotalWidth() */ int GetTotalHeight() const; + /** + Finds the next page break after the specified (vertical) position. + + An example of using this method: + + @code + std::vector pages; + for ( int pos = 0; pos != wxNOT_FOUND; pos = renderer.FindNextPageBreak(pos) ) + { + pages.push_back(pos); + } + + // "pages" vector now contains all page break positions and, in + // particular, its size() returns the number of pages + @endcode + + @param pos Absolute position of the last page break. For the initial + call of this function, it should be 0 and for the subsequent ones + it should be the previous return value. + @return Position of the next page break or @c wxNOT_FOUND if there are + no more of them. + + @since 3.1.2 + */ + int FindNextPageBreak(int pos) const; + /** Renders HTML text to the DC. + When using multi-page documents, FindNextPageBreak() can be used to + find the values for @a from and @a to, which should be the consecutive + page breaks returned by that function. + @param x,y position of upper-left corner of printing rectangle (see SetSize()). - @param known_pagebreaks - @todo docme @param from y-coordinate of the very first visible cell. - @param dont_render - if @true then this method only returns y coordinate of the next page - and does not output anything. @param to - y-coordinate of the last visible cell. - - 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 - multipages document. + y-coordinate of the last visible cell or @c INT_MAX to use the full + page height. @note The following three methods @b must always be called before any call to @@ -72,11 +93,8 @@ public: - SetDC() - SetSize() - SetHtmlText() - - @note Render() changes the DC's user scale and does NOT restore it. */ - int Render(int x, int y, wxArrayInt& known_pagebreaks, int from = 0, - int dont_render = false, int to = INT_MAX); + void Render(int x, int y, int from = 0, int to = INT_MAX); /** Assign DC instance to the renderer. diff --git a/src/common/prntbase.cpp b/src/common/prntbase.cpp index 6eb4f9a396..eb046f1840 100644 --- a/src/common/prntbase.cpp +++ b/src/common/prntbase.cpp @@ -638,6 +638,33 @@ void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toP *toPage = 1; } +bool wxPrintout::SetUp(wxDC& dc) +{ + SetPPIScreen(wxGetDisplayPPI()); + + // We need to know printer PPI. In most ports, this can be retrieved from + // the printer DC, but in others it is computed (probably for legacy + // reasons) outside of wxDC code, so don't override it if it had been + // already set. + if ( !m_PPIPrinterX || !m_PPIPrinterY ) + { + SetPPIPrinter(dc.GetPPI()); + if ( !m_PPIPrinterX || !m_PPIPrinterY ) + { + // But if we couldn't get it in any way, we can't continue. + return false; + } + } + + SetDC(&dc); + + dc.GetSize(&m_pageWidthPixels, &m_pageHeightPixels); + m_paperRectPixels = wxRect(0, 0, m_pageWidthPixels, m_pageHeightPixels); + dc.GetSizeMM(&m_pageWidthMM, &m_pageHeightMM); + + return true; +} + void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize) { // Set the DC scale and origin so that the given image size fits within the diff --git a/src/generic/printps.cpp b/src/generic/printps.cpp index cedf7278f7..efcdb879b6 100644 --- a/src/generic/printps.cpp +++ b/src/generic/printps.cpp @@ -105,24 +105,8 @@ bool wxPostScriptPrinter::Print(wxWindow *parent, wxPrintout *printout, bool pro return false; } - wxSize ScreenPixels = wxGetDisplaySize(); - wxSize ScreenMM = wxGetDisplaySizeMM(); - - printout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()), - (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) ); - printout->SetPPIPrinter( dc->GetResolution(), - dc->GetResolution() ); - // Set printout parameters - printout->SetDC(dc); - - int w, h; - dc->GetSize(&w, &h); - printout->SetPageSizePixels((int)w, (int)h); - printout->SetPaperRectPixels(wxRect(0, 0, w, h)); - int mw, mh; - dc->GetSizeMM(&mw, &mh); - printout->SetPageSizeMM((int)mw, (int)mh); + printout->SetUp(*dc); // Create an abort window wxBeginBusyCursor(); diff --git a/src/gtk/print.cpp b/src/gtk/print.cpp index b43a1f148b..2a5fde7348 100644 --- a/src/gtk/print.cpp +++ b/src/gtk/print.cpp @@ -1023,19 +1023,8 @@ void wxGtkPrinter::BeginPrint(wxPrintout *printout, GtkPrintOperation *operation return; } - printout->SetPPIScreen(wxGetDisplayPPI()); - printout->SetPPIPrinter( printDC->GetResolution(), - printDC->GetResolution() ); + printout->SetUp(*m_dc); - printout->SetDC(m_dc); - - int w, h; - m_dc->GetSize(&w, &h); - printout->SetPageSizePixels((int)w, (int)h); - printout->SetPaperRectPixels(wxRect(0, 0, w, h)); - int mw, mh; - m_dc->GetSizeMM(&mw, &mh); - printout->SetPageSizeMM((int)mw, (int)mh); printout->OnPreparePrinting(); // Get some parameters from the printout, if defined. diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp index bf16620db8..176c5e79c4 100644 --- a/src/html/htmlcell.cpp +++ b/src/html/htmlcell.cpp @@ -157,9 +157,7 @@ wxHtmlCell::GetMouseCursorAt(wxHtmlWindowInterface *window, bool -wxHtmlCell::AdjustPagebreak(int *pagebreak, - const wxArrayInt& WXUNUSED(known_pagebreaks), - int pageHeight) const +wxHtmlCell::AdjustPagebreak(int *pagebreak, int pageHeight) const { // Notice that we always break the cells bigger than the page height here // as otherwise we wouldn't be able to break them at all. @@ -697,22 +695,18 @@ int wxHtmlContainerCell::GetIndentUnits(int ind) const bool -wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, - const wxArrayInt& known_pagebreaks, - int pageHeight) const +wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int pageHeight) const { if (!m_CanLiveOnPagebreak) - return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks, pageHeight); + return wxHtmlCell::AdjustPagebreak(pagebreak, pageHeight); - wxHtmlCell *c = GetFirstChild(); bool rt = false; int pbrk = *pagebreak - m_PosY; - while (c) + for ( wxHtmlCell *c = GetFirstChild(); c; c = c->GetNext() ) { - if (c->AdjustPagebreak(&pbrk, known_pagebreaks, pageHeight)) + if (c->AdjustPagebreak(&pbrk, pageHeight)) rt = true; - c = c->GetNext(); } if (rt) *pagebreak = pbrk + m_PosY; diff --git a/src/html/htmprint.cpp b/src/html/htmprint.cpp index 5709a798e1..781c9f4d98 100644 --- a/src/html/htmprint.cpp +++ b/src/html/htmprint.cpp @@ -140,37 +140,43 @@ void wxHtmlDCRenderer::SetStandardFonts(int size, // else: SetHtmlText() not yet called, no need for relayout } -int wxHtmlDCRenderer::Render(int x, int y, - wxArrayInt& known_pagebreaks, - int from, int dont_render, int to) +int wxHtmlDCRenderer::FindNextPageBreak(int pos) const { - wxCHECK_MSG( m_Cells, 0, "SetHtmlText() must be called before Render()" ); - wxCHECK_MSG( m_DC, 0, "SetDC() must be called before Render()" ); + // Stop looking for page breaks if the previous one was already at the end + // of the last page. + // + // For an empty HTML document total height is 0, but we still must have at + // least a single page in it, so handle the case of pos == 0 specially. + if ( pos != 0 && pos >= GetTotalHeight() ) + return wxNOT_FOUND; - int pbreak, hght; - - pbreak = (int)(from + m_Height); - while (m_Cells->AdjustPagebreak(&pbreak, known_pagebreaks, m_Height)) {} - hght = pbreak - from; - if(to < hght) - hght = to; - - if (!dont_render) + int posNext = pos + m_Height; + if ( m_Cells->AdjustPagebreak(&posNext, m_Height) ) { - wxHtmlRenderingInfo rinfo; - wxDefaultHtmlRenderingStyle rstyle; - rinfo.SetStyle(&rstyle); - m_DC->SetBrush(*wxWHITE_BRUSH); - m_DC->SetClippingRegion(x, y, m_Width, hght); - m_Cells->Draw(*m_DC, - x, (y - from), - y, y + hght, - rinfo); - m_DC->DestroyClippingRegion(); + // Check that AdjustPagebreak() returns the page break at a strictly + // greater position than that of the previous page, otherwise + // CountPages() would enter into an infinite loop. + wxCHECK_MSG( posNext > pos, wxNOT_FOUND, "Bug in AdjustPagebreak()" ); } - if (pbreak < m_Cells->GetHeight()) return pbreak; - else return GetTotalHeight(); + return posNext; +} + +void wxHtmlDCRenderer::Render(int x, int y, int from, int to) +{ + wxCHECK_RET( m_DC, "SetDC() must be called before Render()" ); + + const int hght = to == INT_MAX ? m_Height : to - from; + + wxHtmlRenderingInfo rinfo; + wxDefaultHtmlRenderingStyle rstyle; + rinfo.SetStyle(&rstyle); + m_DC->SetBrush(*wxWHITE_BRUSH); + wxDCClipper clip(*m_DC, x, y, m_Width, hght); + m_Cells->Draw(*m_DC, + x, (y - from), + y, y + hght, + rinfo); } int wxHtmlDCRenderer::GetTotalWidth() const @@ -189,16 +195,11 @@ int wxHtmlDCRenderer::GetTotalHeight() const //-------------------------------------------------------------------------------- -wxList wxHtmlPrintout::m_Filters; +wxVector wxHtmlPrintout::m_Filters; wxHtmlPrintout::wxHtmlPrintout(const wxString& title) : wxPrintout(title) { - m_Renderer = new wxHtmlDCRenderer; - m_RendererHdr = new wxHtmlDCRenderer; - m_NumPages = INT_MAX; - m_Document = m_BasePath = wxEmptyString; m_BasePathIsDir = true; - m_Headers[0] = m_Headers[1] = wxEmptyString; - m_Footers[0] = m_Footers[1] = wxEmptyString; + m_BasePathIsDir = true; m_HeaderHeight = m_FooterHeight = 0; SetMargins(); // to default values SetStandardFonts(DEFAULT_PRINT_FONT_SIZE); @@ -206,21 +207,18 @@ wxHtmlPrintout::wxHtmlPrintout(const wxString& title) : wxPrintout(title) -wxHtmlPrintout::~wxHtmlPrintout() -{ - delete m_Renderer; - delete m_RendererHdr; -} - void wxHtmlPrintout::CleanUpStatics() { - WX_CLEAR_LIST(wxList, m_Filters); + for ( size_t n = 0; n < m_Filters.size(); ++n ) + delete m_Filters[n]; + + m_Filters.clear(); } // Adds input filter void wxHtmlPrintout::AddFilter(wxHtmlFilter *filter) { - m_Filters.Append(filter); + m_Filters.push_back(filter); } bool @@ -315,34 +313,34 @@ void wxHtmlPrintout::OnPreparePrinting() /* prepare headers/footers renderer: */ - m_RendererHdr->SetDC(GetDC(), + m_RendererHdr.SetDC(GetDC(), (double)ppiPrinterY / TYPICAL_SCREEN_DPI, (double)ppiPrinterY / (double)ppiScreenY); - m_RendererHdr->SetSize((int) (ppmm_h * (mm_w - m_MarginLeft - m_MarginRight)), + m_RendererHdr.SetSize((int) (ppmm_h * (mm_w - m_MarginLeft - m_MarginRight)), (int) (ppmm_v * (mm_h - m_MarginTop - m_MarginBottom))); if (!m_Headers[0].empty()) { - m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[0], 1)); - m_HeaderHeight = m_RendererHdr->GetTotalHeight(); + m_RendererHdr.SetHtmlText(TranslateHeader(m_Headers[0], 1)); + m_HeaderHeight = m_RendererHdr.GetTotalHeight(); } else if (!m_Headers[1].empty()) { - m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[1], 1)); - m_HeaderHeight = m_RendererHdr->GetTotalHeight(); + m_RendererHdr.SetHtmlText(TranslateHeader(m_Headers[1], 1)); + m_HeaderHeight = m_RendererHdr.GetTotalHeight(); } if (!m_Footers[0].empty()) { - m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[0], 1)); - m_FooterHeight = m_RendererHdr->GetTotalHeight(); + m_RendererHdr.SetHtmlText(TranslateHeader(m_Footers[0], 1)); + m_FooterHeight = m_RendererHdr.GetTotalHeight(); } else if (!m_Footers[1].empty()) { - m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[1], 1)); - m_FooterHeight = m_RendererHdr->GetTotalHeight(); + m_RendererHdr.SetHtmlText(TranslateHeader(m_Footers[1], 1)); + m_FooterHeight = m_RendererHdr.GetTotalHeight(); } /* prepare main renderer: */ - m_Renderer->SetDC(GetDC(), + m_Renderer.SetDC(GetDC(), (double)ppiPrinterY / TYPICAL_SCREEN_DPI, (double)ppiPrinterY / (double)ppiScreenY); @@ -353,12 +351,12 @@ void wxHtmlPrintout::OnPreparePrinting() if ( m_FooterHeight ) printAreaH -= int(m_FooterHeight + m_MarginSpace * ppmm_v); - m_Renderer->SetSize(printAreaW, printAreaH); - m_Renderer->SetHtmlText(m_Document, m_BasePath, m_BasePathIsDir); + m_Renderer.SetSize(printAreaW, printAreaH); + m_Renderer.SetHtmlText(m_Document, m_BasePath, m_BasePathIsDir); if ( CheckFit(wxSize(printAreaW, printAreaH), - wxSize(m_Renderer->GetTotalWidth(), - m_Renderer->GetTotalHeight())) || IsPreview() ) + wxSize(m_Renderer.GetTotalWidth(), + m_Renderer.GetTotalHeight())) || IsPreview() ) { // do paginate the document CountPages(); @@ -392,19 +390,19 @@ bool wxHtmlPrintout::OnPrintPage(int page) void wxHtmlPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) { *minPage = 1; - if ( m_NumPages >= (signed)m_PageBreaks.GetCount()-1) - *maxPage = m_NumPages; + if ( m_PageBreaks.empty() ) + *maxPage = INT_MAX; else - *maxPage = (signed)m_PageBreaks.GetCount()-1; + *maxPage = (signed)m_PageBreaks.size()-1; *selPageFrom = 1; - *selPageTo = (signed)m_PageBreaks.GetCount()-1; + *selPageTo = (signed)m_PageBreaks.size()-1; } bool wxHtmlPrintout::HasPage(int pageNum) { - return pageNum > 0 && (unsigned)pageNum < m_PageBreaks.GetCount(); + return pageNum > 0 && (unsigned)pageNum < m_PageBreaks.size(); } @@ -436,17 +434,15 @@ void wxHtmlPrintout::SetHtmlFile(const wxString& htmlfile) wxHtmlFilterHTML defaultFilter; wxString doc; - wxList::compatibility_iterator node = m_Filters.GetFirst(); - while (node) + for ( size_t n = 0; n < m_Filters.size(); ++n ) { - wxHtmlFilter *h = (wxHtmlFilter*) node->GetData(); + wxHtmlFilter* const h = m_Filters[n]; if (h->CanRead(*ff)) { doc = h->ReadFile(*ff); done = true; break; } - node = node->GetNext(); } if (!done) @@ -481,27 +477,14 @@ void wxHtmlPrintout::SetFooter(const wxString& footer, int pg) void wxHtmlPrintout::CountPages() { wxBusyCursor wait; - int pageWidth, pageHeight, mm_w, mm_h; - float ppmm_h, ppmm_v; - GetPageSizePixels(&pageWidth, &pageHeight); - GetPageSizeMM(&mm_w, &mm_h); - ppmm_h = (float)pageWidth / mm_w; - ppmm_v = (float)pageHeight / mm_h; + m_PageBreaks.clear(); - int pos = 0; - m_NumPages = 0; - - m_PageBreaks.Clear(); - m_PageBreaks.Add( 0); - do + for ( int pos = 0; pos != wxNOT_FOUND; ) { - pos = m_Renderer->Render((int)( ppmm_h * m_MarginLeft), - (int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), - m_PageBreaks, - pos, true, INT_MAX); - m_PageBreaks.Add( pos); - } while (pos < m_Renderer->GetTotalHeight()); + m_PageBreaks.push_back(pos); + pos = m_Renderer.FindNextPageBreak(pos); + } } @@ -529,29 +512,29 @@ void wxHtmlPrintout::RenderPage(wxDC *dc, int page) dc->SetUserScale((double)dc_w / (double)pageWidth, (double)dc_h / (double)pageHeight); - m_Renderer->SetDC(dc, + m_Renderer.SetDC(dc, (double)ppiPrinterY / TYPICAL_SCREEN_DPI, (double)ppiPrinterY / (double)ppiScreenY); dc->SetBackgroundMode(wxTRANSPARENT); - m_Renderer->Render((int) (ppmm_h * m_MarginLeft), - (int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), m_PageBreaks, - m_PageBreaks[page-1], false, m_PageBreaks[page]-m_PageBreaks[page-1]); + 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]); - m_RendererHdr->SetDC(dc, + m_RendererHdr.SetDC(dc, (double)ppiPrinterY / TYPICAL_SCREEN_DPI, (double)ppiPrinterY / (double)ppiScreenY); if (!m_Headers[page % 2].empty()) { - m_RendererHdr->SetHtmlText(TranslateHeader(m_Headers[page % 2], page)); - m_RendererHdr->Render((int) (ppmm_h * m_MarginLeft), (int) (ppmm_v * m_MarginTop), m_PageBreaks); + m_RendererHdr.SetHtmlText(TranslateHeader(m_Headers[page % 2], page)); + m_RendererHdr.Render((int) (ppmm_h * m_MarginLeft), (int) (ppmm_v * m_MarginTop)); } if (!m_Footers[page % 2].empty()) { - m_RendererHdr->SetHtmlText(TranslateHeader(m_Footers[page % 2], page)); - m_RendererHdr->Render((int) (ppmm_h * m_MarginLeft), (int) (pageHeight - ppmm_v * m_MarginBottom - m_FooterHeight), m_PageBreaks); + m_RendererHdr.SetHtmlText(TranslateHeader(m_Footers[page % 2], page)); + m_RendererHdr.Render((int) (ppmm_h * m_MarginLeft), (int) (pageHeight - ppmm_v * m_MarginBottom - m_FooterHeight)); } } @@ -565,7 +548,7 @@ wxString wxHtmlPrintout::TranslateHeader(const wxString& instr, int page) num.Printf(wxT("%i"), page); r.Replace(wxT("@PAGENUM@"), num); - num.Printf(wxT("%lu"), (unsigned long)(m_PageBreaks.GetCount() - 1)); + num.Printf(wxT("%lu"), (unsigned long)(m_PageBreaks.size() - 1)); r.Replace(wxT("@PAGESCNT@"), num); #if wxUSE_DATETIME @@ -604,16 +587,16 @@ void wxHtmlPrintout::SetMargins(const wxPageSetupDialogData& pageSetupData) void wxHtmlPrintout::SetFonts(const wxString& normal_face, const wxString& fixed_face, const int *sizes) { - m_Renderer->SetFonts(normal_face, fixed_face, sizes); - m_RendererHdr->SetFonts(normal_face, fixed_face, sizes); + m_Renderer.SetFonts(normal_face, fixed_face, sizes); + m_RendererHdr.SetFonts(normal_face, fixed_face, sizes); } void wxHtmlPrintout::SetStandardFonts(int size, const wxString& normal_face, const wxString& fixed_face) { - m_Renderer->SetStandardFonts(size, normal_face, fixed_face); - m_RendererHdr->SetStandardFonts(size, normal_face, fixed_face); + m_Renderer.SetStandardFonts(size, normal_face, fixed_face); + m_RendererHdr.SetStandardFonts(size, normal_face, fixed_face); } diff --git a/src/html/m_layout.cpp b/src/html/m_layout.cpp index 619ec2bb08..95b0afbab2 100644 --- a/src/html/m_layout.cpp +++ b/src/html/m_layout.cpp @@ -65,9 +65,7 @@ class wxHtmlPageBreakCell : public wxHtmlCell public: wxHtmlPageBreakCell() {} - bool AdjustPagebreak(int* pagebreak, - const wxArrayInt& known_pagebreaks, - int pageHeight) const wxOVERRIDE; + bool AdjustPagebreak(int* pagebreak, int pageHeight) const wxOVERRIDE; void Draw(wxDC& WXUNUSED(dc), int WXUNUSED(x), int WXUNUSED(y), @@ -79,48 +77,18 @@ private: }; bool -wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak, - const wxArrayInt& known_pagebreaks, - int WXUNUSED(pageHeight)) const +wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak, int pageHeight) 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( known_pagebreaks.GetCount() == 0 || *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; - for ( wxHtmlCell *parent = GetParent(); parent; parent = parent->GetParent() ) - { - total_height += parent->GetPosY(); - } - - - // Search the array of pagebreaks to see whether we've already set - // a pagebreak here. - int where = known_pagebreaks.Index( total_height); - // Add a pagebreak only if there isn't one already set here. - if( wxNOT_FOUND != where) - { - return false; - } - else + // Request a page break at the position of this cell if it's on the current + // page. Note that it's important not to do it unconditionally or we could + // end up in an infinite number of page breaks at this cell position. + if ( m_PosY < *pagebreak && m_PosY > *pagebreak - pageHeight ) { *pagebreak = m_PosY; return true; } + + return false; } diff --git a/src/msw/printwin.cpp b/src/msw/printwin.cpp index 6d1e9c40c7..48e61003c1 100644 --- a/src/msw/printwin.cpp +++ b/src/msw/printwin.cpp @@ -115,36 +115,14 @@ bool wxWindowsPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt return false; } - wxPrinterDCImpl *impl = (wxPrinterDCImpl*) dc->GetImpl(); - - HDC hdc = ::GetDC(NULL); - int logPPIScreenX = ::GetDeviceCaps(hdc, LOGPIXELSX); - int logPPIScreenY = ::GetDeviceCaps(hdc, LOGPIXELSY); - ::ReleaseDC(NULL, hdc); - - int logPPIPrinterX = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSX); - int logPPIPrinterY = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSY); - if (logPPIPrinterX == 0 || logPPIPrinterY == 0) + // Set printout parameters + if (!printout->SetUp(*dc)) { delete dc; sm_lastError = wxPRINTER_ERROR; return false; } - printout->SetPPIScreen(logPPIScreenX, logPPIScreenY); - printout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY); - - // Set printout parameters - printout->SetDC(dc); - - int w, h; - dc->GetSize(&w, &h); - printout->SetPageSizePixels((int)w, (int)h); - printout->SetPaperRectPixels(dc->GetPaperRect()); - - dc->GetSizeMM(&w, &h); - printout->SetPageSizeMM((int)w, (int)h); - // Create an abort window wxBusyCursor busyCursor; @@ -169,7 +147,7 @@ bool wxWindowsPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt wxPrintAbortDialog *win = CreateAbortWindow(parent, printout); wxYield(); - ::SetAbortProc(GetHdcOf(*impl), wxAbortProc); + ::SetAbortProc(GetHdcOf(*dc), wxAbortProc); if (!win) { diff --git a/src/osx/core/printmac.cpp b/src/osx/core/printmac.cpp index 9bc7f7fccf..c14c376226 100644 --- a/src/osx/core/printmac.cpp +++ b/src/osx/core/printmac.cpp @@ -585,8 +585,6 @@ bool wxMacPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) return false; } - printout->SetPPIScreen(wxGetDisplayPPI()); - PMResolution res; PMPrinter printer; wxOSXPrintData* nativeData = (wxOSXPrintData*) @@ -607,15 +605,7 @@ bool wxMacPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) printout->SetPPIPrinter(int(res.hRes), int(res.vRes)); // Set printout parameters - printout->SetDC(dc); - - int w, h; - dc->GetSize(&w, &h); - printout->SetPageSizePixels((int)w, (int)h); - printout->SetPaperRectPixels(dc->GetPaperRect()); - wxCoord mw, mh; - dc->GetSizeMM(&mw, &mh); - printout->SetPageSizeMM((int)mw, (int)mh); + printout->SetUp(*dc); // Create an abort window wxBeginBusyCursor(); diff --git a/tests/Makefile.in b/tests/Makefile.in index d20559e8fe..bc37e442f9 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -243,6 +243,7 @@ TEST_GUI_OBJECTS = \ test_gui_rawbmp.o \ test_gui_htmlparser.o \ test_gui_htmlwindow.o \ + test_gui_htmprint.o \ test_gui_accelentry.o \ test_gui_menu.o \ test_gui_guifuncs.o \ @@ -997,6 +998,9 @@ test_gui_htmlparser.o: $(srcdir)/html/htmlparser.cpp $(TEST_GUI_ODEP) test_gui_htmlwindow.o: $(srcdir)/html/htmlwindow.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/html/htmlwindow.cpp +test_gui_htmprint.o: $(srcdir)/html/htmprint.cpp $(TEST_GUI_ODEP) + $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/html/htmprint.cpp + test_gui_accelentry.o: $(srcdir)/menu/accelentry.cpp $(TEST_GUI_ODEP) $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/menu/accelentry.cpp diff --git a/tests/html/htmprint.cpp b/tests/html/htmprint.cpp new file mode 100644 index 0000000000..34560d9cb8 --- /dev/null +++ b/tests/html/htmprint.cpp @@ -0,0 +1,112 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: tests/html/htmprint.cpp +// Purpose: wxHtmlPrintout tests +// Author: Vadim Zeitlin +// Created: 2018-05-22 +// Copyright: (c) 2018 Vadim Zeitlin +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "testprec.h" + +#if wxUSE_HTML + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dcmemory.h" +#endif // WX_PRECOMP + +#include "wx/html/htmprint.h" + +namespace +{ + +// Return the number of pages in the printout. +int CountPages(wxHtmlPrintout& pr) +{ + REQUIRE_NOTHROW( pr.OnPreparePrinting() ); + + int pageMin = -1, + pageMax = -1, + selFrom = -1, + selTo = -1; + REQUIRE_NOTHROW( pr.GetPageInfo(&pageMin, &pageMax, &selFrom, &selTo) ); + + // This should be always the case. + CHECK( pageMin == 1 ); + + // Return the really interesting value to the caller. + return pageMax; +} + +} // anonymous namespace + +TEST_CASE("wxHtmlPrintout::Pagination", "[html][print]") +{ + wxHtmlPrintout pr; + + // Pagination works in terms of printer page size, which is obtained by + // subtracting margins from the total size and margins are expressed in + // millimeters, so their conversion to pixels depends on DPI. To ensure + // that we get the same results for all values of DPI, get just get rid + // of the margins entirely (it would also be possible to adjust them by + // the DPI-dependent factor, but it doesn't seem to be worth doing it). + pr.SetMargins(0, 0, 0, 0, 0); + + wxBitmap bmp(1000, 1000); + wxMemoryDC dc(bmp); + pr.SetUp(dc); + + // Empty or short HTML documents should be printed on a single page only. + CHECK( CountPages(pr) == 1 ); + + pr.SetHtmlText("

Hello world!

"); + CHECK( CountPages(pr) == 1 ); + + // This one should be too big to fit on a single page. + pr.SetHtmlText + ( + "" + "
" + "" + ); + CHECK( CountPages(pr) == 2 ); + + // Special case: normally images are not split, but if the image height is + // greater than the page height, it should be. + pr.SetHtmlText + ( + "" + ); + CHECK( CountPages(pr) == 3 ); + + // Test explicit page breaks too. + pr.SetHtmlText + ( + "First page" + "
" + "Second page" + ); + CHECK( CountPages(pr) == 2 ); + + pr.SetHtmlText + ( + "Something" + "
" + "
" + "
" + "whatever" + "
" + "
" + "
" + ); + CHECK( CountPages(pr) == 2 ); +} + +#endif //wxUSE_HTML diff --git a/tests/makefile.bcc b/tests/makefile.bcc index 30897885eb..69ff216d07 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -229,6 +229,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_rawbmp.obj \ $(OBJS)\test_gui_htmlparser.obj \ $(OBJS)\test_gui_htmlwindow.obj \ + $(OBJS)\test_gui_htmprint.obj \ $(OBJS)\test_gui_accelentry.obj \ $(OBJS)\test_gui_menu.obj \ $(OBJS)\test_gui_guifuncs.obj \ @@ -1050,6 +1051,9 @@ $(OBJS)\test_gui_htmlparser.obj: .\html\htmlparser.cpp $(OBJS)\test_gui_htmlwindow.obj: .\html\htmlwindow.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\html\htmlwindow.cpp +$(OBJS)\test_gui_htmprint.obj: .\html\htmprint.cpp + $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\html\htmprint.cpp + $(OBJS)\test_gui_accelentry.obj: .\menu\accelentry.cpp $(CXX) -q -c -P -o$@ $(TEST_GUI_CXXFLAGS) .\menu\accelentry.cpp diff --git a/tests/makefile.gcc b/tests/makefile.gcc index b9a05edb64..9855000899 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -224,6 +224,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_rawbmp.o \ $(OBJS)\test_gui_htmlparser.o \ $(OBJS)\test_gui_htmlwindow.o \ + $(OBJS)\test_gui_htmprint.o \ $(OBJS)\test_gui_accelentry.o \ $(OBJS)\test_gui_menu.o \ $(OBJS)\test_gui_guifuncs.o \ @@ -1027,6 +1028,9 @@ $(OBJS)\test_gui_htmlparser.o: ./html/htmlparser.cpp $(OBJS)\test_gui_htmlwindow.o: ./html/htmlwindow.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< +$(OBJS)\test_gui_htmprint.o: ./html/htmprint.cpp + $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< + $(OBJS)\test_gui_accelentry.o: ./menu/accelentry.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< diff --git a/tests/makefile.vc b/tests/makefile.vc index 8ae6c6c439..60ecf9ff0c 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -235,6 +235,7 @@ TEST_GUI_OBJECTS = \ $(OBJS)\test_gui_rawbmp.obj \ $(OBJS)\test_gui_htmlparser.obj \ $(OBJS)\test_gui_htmlwindow.obj \ + $(OBJS)\test_gui_htmprint.obj \ $(OBJS)\test_gui_accelentry.obj \ $(OBJS)\test_gui_menu.obj \ $(OBJS)\test_gui_guifuncs.obj \ @@ -1229,6 +1230,9 @@ $(OBJS)\test_gui_htmlparser.obj: .\html\htmlparser.cpp $(OBJS)\test_gui_htmlwindow.obj: .\html\htmlwindow.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\html\htmlwindow.cpp +$(OBJS)\test_gui_htmprint.obj: .\html\htmprint.cpp + $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\html\htmprint.cpp + $(OBJS)\test_gui_accelentry.obj: .\menu\accelentry.cpp $(CXX) /c /nologo /TP /Fo$@ $(TEST_GUI_CXXFLAGS) .\menu\accelentry.cpp diff --git a/tests/test.bkl b/tests/test.bkl index 47016bcf33..4db76b86cb 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -249,6 +249,7 @@ image/rawbmp.cpp html/htmlparser.cpp html/htmlwindow.cpp + html/htmprint.cpp menu/accelentry.cpp menu/menu.cpp misc/guifuncs.cpp diff --git a/tests/test_gui.vcxproj b/tests/test_gui.vcxproj index af4d68b517..d7710c370f 100644 --- a/tests/test_gui.vcxproj +++ b/tests/test_gui.vcxproj @@ -535,6 +535,7 @@ + @@ -564,4 +565,4 @@ - + \ No newline at end of file diff --git a/tests/test_gui.vcxproj.filters b/tests/test_gui.vcxproj.filters index 40ab41a51d..bd3fbfdc4d 100644 --- a/tests/test_gui.vcxproj.filters +++ b/tests/test_gui.vcxproj.filters @@ -293,10 +293,13 @@ Source Files + + Source Files + Resource Files - + \ No newline at end of file diff --git a/tests/test_vc7_test_gui.vcproj b/tests/test_vc7_test_gui.vcproj index 484c4776ac..eade1cba94 100644 --- a/tests/test_vc7_test_gui.vcproj +++ b/tests/test_vc7_test_gui.vcproj @@ -439,6 +439,9 @@ + + diff --git a/tests/test_vc8_test_gui.vcproj b/tests/test_vc8_test_gui.vcproj index 15fda65a98..8ab1a7002d 100644 --- a/tests/test_vc8_test_gui.vcproj +++ b/tests/test_vc8_test_gui.vcproj @@ -1054,6 +1054,10 @@ RelativePath=".\html\htmlwindow.cpp" > + + diff --git a/tests/test_vc9_test_gui.vcproj b/tests/test_vc9_test_gui.vcproj index 6e99dc8de7..6852c292ab 100644 --- a/tests/test_vc9_test_gui.vcproj +++ b/tests/test_vc9_test_gui.vcproj @@ -1026,6 +1026,10 @@ RelativePath=".\html\htmlwindow.cpp" > + +