backported HTML pagebreak code

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@20690 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2003-05-21 23:05:46 +00:00
parent cc715ad02b
commit 5009d37d51
7 changed files with 261 additions and 34 deletions

View File

@@ -253,6 +253,8 @@ wxHTML:
- added SetFonts methods to wxHtmlDCRenderer and wxHtmlPrintout classes - added SetFonts methods to wxHtmlDCRenderer and wxHtmlPrintout classes
- 'sizes' argument to SetFonts can now be NULL to use default font sizes - 'sizes' argument to SetFonts can now be NULL to use default font sizes
(both by Adrian Philip Look) (both by 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)
wxXRC: wxXRC:

View File

@@ -29,6 +29,15 @@ class WXDLLEXPORT wxHtmlLinkInfo;
class WXDLLEXPORT wxHtmlCell; class WXDLLEXPORT wxHtmlCell;
class WXDLLEXPORT wxHtmlContainerCell; class WXDLLEXPORT wxHtmlContainerCell;
// Temporary kludge for backporting html pagebreaks to 2.4.0;
// Do not use, this will NOT be part of wx 2.5!
struct WXDLLEXPORT wxHtmlKludge
{
int pbreak;
int *known_pagebreaks;
int number_of_pages;
};
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// wxHtmlCell // wxHtmlCell
// Internal data structure. It represents fragments of parsed HTML // Internal data structure. It represents fragments of parsed HTML
@@ -109,6 +118,8 @@ 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) const;
// wx 2.5 will use this signature:
// 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
@@ -190,6 +201,8 @@ public:
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) const;
// wx 2.5 will use this signature:
// 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,32 @@ 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;
// 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 Render(int x, int y, int from = 0, int dont_render = FALSE);
// wx 2.5 will use this signature instead of the preceding:
// 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);
// but for this backport we have to get rid of the default arguments
// so that the following signature is distinct from the original. This is
// OK because the implementation never uses those defaults, and user code
// wouldn't know about the extra arguments anyway. The default argument
// on the original signature above still works.
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)
@@ -214,7 +233,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,6 +68,14 @@ void wxHtmlCell::OnMouseClick(wxWindow *parent, int x, int y,
// wx 2.5 will use this signature:
// bool wxHtmlCell::AdjustPagebreak(int *pagebreak, int* WXUNUSED(known_pagebreaks), int WXUNUSED(number_of_pages)) const
//
// Workaround to backport html pagebreaks to 2.4.0:
// Actually, we're passing a pointer to struct wxHtmlKludge, casting
// that pointer to an int* . We don't need to do anything special
// here because that struct's first element is an int* to 'pagebreak'.
// Other struct members can be ignored because they'd be unused anyway.
bool wxHtmlCell::AdjustPagebreak(int *pagebreak) const bool wxHtmlCell::AdjustPagebreak(int *pagebreak) const
{ {
if ((!m_CanLiveOnPagebreak) && if ((!m_CanLiveOnPagebreak) &&
@@ -215,9 +223,19 @@ int wxHtmlContainerCell::GetIndentUnits(int ind) const
// wx 2.5 will use this signature:
// bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int* known_pagebreaks, int number_of_pages) const
//
// Workaround to backport html pagebreaks to 2.4.0:
// Actually, we're passing a pointer to struct wxHtmlKludge, casting
// that pointer to an int* . We don't need to do anything special
// here because that struct's first element is an int* to 'pagebreak'.
// Other struct members aren't used here and can be ignored.
bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak) const bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak) const
{ {
if (!m_CanLiveOnPagebreak) if (!m_CanLiveOnPagebreak)
// wx 2.5 will use this call:
// return wxHtmlCell::AdjustPagebreak(pagebreak, known_pagebreaks, number_of_pages);
return wxHtmlCell::AdjustPagebreak(pagebreak); return wxHtmlCell::AdjustPagebreak(pagebreak);
else else
@@ -226,14 +244,24 @@ bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak) const
bool rt = FALSE; bool rt = FALSE;
int pbrk = *pagebreak - m_PosY; int pbrk = *pagebreak - m_PosY;
// Temporary kludge for backporting html pagebreaks to 2.4.0;
// remove in 2.4.1 .
wxHtmlKludge kludge = *(wxHtmlKludge*)pagebreak;
kludge.pbreak = pbrk;
while (c) while (c)
{ {
if (c->AdjustPagebreak(&pbrk)) // wx 2.5 will use this call:
// if (c->AdjustPagebreak(&pbrk, known_pagebreaks, number_of_pages))
if (c->AdjustPagebreak((int*)&kludge))
rt = TRUE; rt = TRUE;
c = c->GetNext(); c = c->GetNext();
} }
if (rt) if (rt)
{
pbrk = kludge.pbreak;
*pagebreak = pbrk + m_PosY; *pagebreak = pbrk + m_PosY;
}
return rt; return rt;
} }
} }

View File

@@ -99,17 +99,42 @@ void wxHtmlDCRenderer::SetFonts(wxString normal_face, wxString fixed_face,
m_Parser->SetFonts(normal_face, fixed_face, sizes); m_Parser->SetFonts(normal_face, fixed_face, sizes);
if (m_DC == NULL && m_Cells != NULL) m_Cells->Layout(m_Width); if (m_DC == NULL && m_Cells != NULL) m_Cells->Layout(m_Width);
} }
// Backport note: this signature will be replaced in wx 2.5.
// It just forwards to the new function for backward binary compatibility.
int wxHtmlDCRenderer::Render(int x, int y, int from, int dont_render) int wxHtmlDCRenderer::Render(int x, int y, int from, int dont_render)
{
return Render(x, y, from, dont_render, INT_MAX, NULL, 0);
}
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)) {}
// Temporary kludge for backporting html pagebreaks to 2.4.0;
// remove in 2.4.1 .
wxHtmlKludge kludge;
kludge.pbreak = pbreak;
kludge.known_pagebreaks = known_pagebreaks;
kludge.number_of_pages = number_of_pages;
while (m_Cells->AdjustPagebreak((int*)&kludge)) {}
// wx 2.5 will use this:
// while (m_Cells->AdjustPagebreak(&pbreak, known_pagebreaks, number_of_pages)) {}
pbreak = kludge.pbreak;
// We don't need to copy back
// kludge.number_of_pages or
// kludge.known_pagebreaks
// because their values aren't changed by AdjustPagebreak().
// Thus, known_pagebreaks probably ought to be const.
hght = pbreak - from; hght = pbreak - from;
if(to < hght)
hght = to;
if (!dont_render) if (!dont_render)
{ {
@@ -336,7 +361,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());
} }
@@ -370,7 +395,11 @@ 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]
// Backporting note: we need to specify every argument for backporting (see
// include/wx/htmprint.h), but wx 2.5 will be able to default the
// last two arguments here.
,NULL, 0);
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,118 @@
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() {}
// wx 2.5 will use this signature:
// bool AdjustPagebreak(int* pagebreak, int* known_pagebreaks = NULL, int number_of_pages = 0) const;
bool AdjustPagebreak(int* pagebreak) 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;
}
// wx 2.5 will use this signature:
// bool wxHtmlContainerCell::AdjustPagebreak(int *pagebreak, int* known_pagebreaks, int number_of_pages) const
//
// Workaround to backport html pagebreaks to 2.4.0:
// Actually, we're passing a pointer to struct wxHtmlKludge, casting
// that pointer to an int* . We don't need to do anything special
// here because that struct's first element is an int* to 'pagebreak'.
// Other struct members are addressed by casting that int* back to
// wxHtmlKludge*; they don't get modified, so we don't have to pass
// them back to the caller.
bool wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak) const
{
// Workaround to backport html pagebreaks to 2.4.0:
wxHtmlKludge* kludge = (wxHtmlKludge*)pagebreak;
int* known_pagebreaks = kludge->known_pagebreaks;
int number_of_pages = kludge->number_of_pages;
// 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 +222,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)