Merge branch 'html-print-cleanup'

Simplify wxHTML pagination code and make it easier to reuse from
applications.

See https://github.com/wxWidgets/wxWidgets/pull/817
This commit is contained in:
Vadim Zeitlin
2018-06-10 14:56:33 +02:00
25 changed files with 360 additions and 289 deletions

View File

@@ -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-??-??)
----------------------------

View File

@@ -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);

View File

@@ -20,6 +20,7 @@
#include "wx/print.h"
#include "wx/printdlg.h"
#include "wx/vector.h"
#include <limits.h> // 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 <DIV>. The <DIV> 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<int> 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<wxHtmlFilter*> m_Filters;
wxDECLARE_NO_COPY_CLASS(wxHtmlPrintout);
};

View File

@@ -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; }

View File

@@ -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.

View File

@@ -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<int> 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.

View File

@@ -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

View File

@@ -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();

View File

@@ -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.

View File

@@ -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;

View File

@@ -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<wxHtmlFilter*> 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);
}

View File

@@ -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;
}

View File

@@ -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)
{

View File

@@ -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();

View File

@@ -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

112
tests/html/htmprint.cpp Normal file
View File

@@ -0,0 +1,112 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/html/htmprint.cpp
// Purpose: wxHtmlPrintout tests
// Author: Vadim Zeitlin
// Created: 2018-05-22
// Copyright: (c) 2018 Vadim Zeitlin <vadim@wxwidgets.org>
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// 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("<p>Hello world!</p>");
CHECK( CountPages(pr) == 1 );
// This one should be too big to fit on a single page.
pr.SetHtmlText
(
"<img width=\"100\" height=\"600\" src=\"dummy\"/>"
"<br/>"
"<img width=\"100\" height=\"600\" src=\"dummy\"/>"
);
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
(
"<img width=\"100\" height=\"2500\" src=\"dummy\"/>"
);
CHECK( CountPages(pr) == 3 );
// Test explicit page breaks too.
pr.SetHtmlText
(
"First page"
"<div style=\"page-break-before:always\"/>"
"Second page"
);
CHECK( CountPages(pr) == 2 );
pr.SetHtmlText
(
"Something"
"<div style=\"page-break-before:always\">"
"<div style=\"page-break-before:always\">"
"<div style=\"page-break-before:always\">"
"whatever"
"</div>"
"</div>"
"</div>"
);
CHECK( CountPages(pr) == 2 );
}
#endif //wxUSE_HTML

View File

@@ -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

View File

@@ -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) $<

View File

@@ -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

View File

@@ -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

View File

@@ -535,6 +535,7 @@
<ClCompile Include="graphics\measuring.cpp" />
<ClCompile Include="html\htmlparser.cpp" />
<ClCompile Include="html\htmlwindow.cpp" />
<ClCompile Include="html\htmprint.cpp" />
<ClCompile Include="image\image.cpp" />
<ClCompile Include="image\rawbmp.cpp" />
<ClCompile Include="menu\accelentry.cpp" />
@@ -564,4 +565,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@@ -293,10 +293,13 @@
<ClCompile Include="graphics\graphmatrix.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="html\htmprint.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\samples\sample.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>

View File

@@ -439,6 +439,9 @@
<File
RelativePath=".\html\htmlwindow.cpp">
</File>
<File
RelativePath=".\html\htmprint.cpp">
</File>
<File
RelativePath=".\controls\hyperlinkctrltest.cpp">
</File>

View File

@@ -1054,6 +1054,10 @@
RelativePath=".\html\htmlwindow.cpp"
>
</File>
<File
RelativePath=".\html\htmprint.cpp"
>
</File>
<File
RelativePath=".\controls\hyperlinkctrltest.cpp"
>

View File

@@ -1026,6 +1026,10 @@
RelativePath=".\html\htmlwindow.cpp"
>
</File>
<File
RelativePath=".\html\htmprint.cpp"
>
</File>
<File
RelativePath=".\controls\hyperlinkctrltest.cpp"
>