applied HTML pagebreaks patch

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20617 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2003-05-12 22:33:51 +00:00
parent 6769d0cbf3
commit f2034f1b6e
7 changed files with 172 additions and 39 deletions

View File

@@ -150,6 +150,8 @@ wxUniv:
wxHTML: wxHTML:
- added SetFonts to HTML printing classes (Adrian Philip Look) - added SetFonts to HTML printing classes (Adrian Philip Look)
- it is now possible to force page break when printing by inserting
<div style="page-break-before:always"> into the markup (Greg Chicares)
OLD CHANGES OLD CHANGES

View File

@@ -108,7 +108,7 @@ public:
// //
// Returned value : true if pagebreak was modified, false otherwise // Returned value : true if pagebreak was modified, false otherwise
// Usage : while (container->AdjustPagebreak(&p)) {} // 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 // Sets cell's behaviour on pagebreaks (see AdjustPagebreak). Default
// is true - the cell can be split on two pages // is true - the cell can be split on two pages
@@ -191,7 +191,7 @@ public:
virtual void Layout(int w); virtual void Layout(int w);
virtual void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2); 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 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 // insert cell at the end of m_Cells list
void InsertCell(wxHtmlCell *cell); void InsertCell(wxHtmlCell *cell);

View File

@@ -25,6 +25,8 @@
#include "wx/print.h" #include "wx/print.h"
#include "wx/printdlg.h" #include "wx/printdlg.h"
#include <limits.h> // INT_MAX
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// wxHtmlDCRenderer // wxHtmlDCRenderer
// This class is capable of rendering HTML into specified // 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: // 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); void SetDC(wxDC *dc, double pixel_scale = 1.0);
// Sets size of output rectangle, in pixels. Note that you *can't* change // 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); 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) // [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. // 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 // Use this value as 'from' in next call to Render in order to print multiple pages
// document // document
// If dont_render is TRUE then nothing is rendered into DC and it only counts // If dont_render is TRUE then nothing is rendered into DC and it only counts
// pixels and return y coord of the next page // pixels and return y coord of the next page
// //
// CAUTION! Render() changes DC's user scale and does NOT restore it! // known_pagebreaks and number_of_pages are used only when counting pages;
int Render(int x, int y, int from = 0, int dont_render = FALSE); // 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, 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 // returns total height of the html document
// (compare Render's return value with this) // (compare Render's return value with this)
@@ -221,7 +231,7 @@ public:
// return page setting data objects. // return page setting data objects.
// (You can set their parameters.) // (You can set their parameters.)
protected: protected:
virtual wxHtmlPrintout *CreatePrintout(); virtual wxHtmlPrintout *CreatePrintout();
virtual bool DoPreview(wxHtmlPrintout *printout1, wxHtmlPrintout *printout2); virtual bool DoPreview(wxHtmlPrintout *printout1, wxHtmlPrintout *printout2);
virtual bool DoPrint(wxHtmlPrintout *printout); virtual bool DoPrint(wxHtmlPrintout *printout);

View File

@@ -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 its own development path. Also, minor snapshot releases for specific platforms may be
available at dates convenient to the developers.<P> available at dates convenient to the developers.<P>
<div style="page-break-before:always"></div>
<HR> <FONT SIZE=+2><I><B><a name="schedule">Schedule</a></B></I></FONT> <HR> <HR> <FONT SIZE=+2><I><B><a name="schedule">Schedule</a></B></I></FONT> <HR>
<P> <P>
@@ -120,7 +121,7 @@ combined base/GUI library for GUI applications only.
<P> <P>
<HR> <FONT SIZE=+2><I><B><a name="todo">To-Do List</a></B></I></FONT> <HR> <HR> <FONT SIZE=+2><I><B><a name="todo"><div style="page-break-before:always">To-Do List</div></a></B></I></FONT> <HR>
<P> <P>

View File

@@ -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) && if ((!m_CanLiveOnPagebreak) &&
m_PosY < *pagebreak && m_PosY + m_Height > *pagebreak) 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) if (!m_CanLiveOnPagebreak)
return wxHtmlCell::AdjustPagebreak(pagebreak); return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks, number_of_pages);
else else
{ {
@@ -228,7 +228,7 @@ bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak) const
while (c) while (c)
{ {
if (c->AdjustPagebreak(&pbrk)) if (c->AdjustPagebreak(&pbrk, known_pagebreaks, number_of_pages))
rt = TRUE; rt = TRUE;
c = c->GetNext(); c = c->GetNext();
} }

View File

@@ -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; int pbreak, hght;
if (m_Cells == NULL || m_DC == NULL) return 0; if (m_Cells == NULL || m_DC == NULL) return 0;
pbreak = (int)(from + m_Height); pbreak = (int)(from + m_Height);
while (m_Cells->AdjustPagebreak(&pbreak)) {} while (m_Cells->AdjustPagebreak(&pbreak, known_pagebreaks, number_of_pages)) {}
hght = pbreak - from; hght = pbreak - from;
if(to < hght)
hght = to;
if (!dont_render) if (!dont_render)
{ {
@@ -335,7 +337,7 @@ void wxHtmlPrintout::CountPages()
{ {
pos = m_Renderer->Render((int)( ppmm_h * m_MarginLeft), pos = m_Renderer->Render((int)( ppmm_h * m_MarginLeft),
(int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), (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; m_PageBreaks[++m_NumPages] = pos;
} while (pos < m_Renderer->GetTotalHeight()); } while (pos < m_Renderer->GetTotalHeight());
} }
@@ -369,7 +371,7 @@ void wxHtmlPrintout::RenderPage(wxDC *dc, int page)
m_Renderer->Render((int) (ppmm_h * m_MarginLeft), m_Renderer->Render((int) (ppmm_h * m_MarginLeft),
(int) (ppmm_v * (m_MarginTop + (m_HeaderHeight == 0 ? 0 : m_MarginSpace)) + m_HeaderHeight), (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); m_RendererHdr->SetDC(dc, (double)ppiPrinterY / (double)ppiScreenY);
if (m_Headers[page % 2] != wxEmptyString) if (m_Headers[page % 2] != wxEmptyString)

View File

@@ -31,6 +31,101 @@
FORCE_LINK_ME(m_layout) FORCE_LINK_ME(m_layout)
#include <stdlib.h> // 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
// <div style="page-break-before:always">
//
// 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_BEGIN(P, "P")
TAG_HANDLER_PROC(tag) TAG_HANDLER_PROC(tag)
@@ -110,34 +205,57 @@ TAG_HANDLER_BEGIN(DIV, "DIV")
TAG_HANDLER_PROC(tag) TAG_HANDLER_PROC(tag)
{ {
int old = m_WParser->GetAlign(); if(tag.HasParam("STYLE"))
wxHtmlContainerCell *c = m_WParser->GetContainer();
if (c->GetFirstCell() != NULL)
{ {
m_WParser->CloseContainer(); if(tag.GetParam("STYLE").IsSameAs(wxString("PAGE-BREAK-BEFORE:ALWAYS"), FALSE))
m_WParser->OpenContainer(); {
c = m_WParser->GetContainer(); m_WParser->CloseContainer();
c->SetAlign(tag); m_WParser->OpenContainer()->InsertCell(new wxHtmlPageBreakCell);
m_WParser->SetAlign(c->GetAlignHor()); m_WParser->CloseContainer();
m_WParser->OpenContainer();
return FALSE;
}
else
{
// Treat other STYLE parameters here when they're supported.
return FALSE;
}
}
else if(tag.HasParam("ALIGN"))
{
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);
m_WParser->SetAlign(old);
if (c->GetFirstCell() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
else
c->SetAlignHor(old);
return TRUE;
} }
else else
{ {
c->SetAlign(tag); return FALSE;
m_WParser->SetAlign(c->GetAlignHor());
} }
ParseInner(tag);
m_WParser->SetAlign(old);
if (c->GetFirstCell() != NULL)
{
m_WParser->CloseContainer();
m_WParser->OpenContainer();
}
else
c->SetAlignHor(old);
return TRUE;
} }
TAG_HANDLER_END(DIV) TAG_HANDLER_END(DIV)