/////////////////////////////////////////////////////////////////////////////// // Name: tests/html/htmprint.cpp // Purpose: wxHtmlPrintout tests // Author: Vadim Zeitlin // Created: 2018-05-22 // Copyright: (c) 2018 Vadim Zeitlin // (c) 2026 wxWidgets development team /////////////////////////////////////////////////////////////////////////////// // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- #include "testprec.h" #if wxUSE_HTML #if wxUSE_PRINTING_ARCHITECTURE #ifndef WX_PRECOMP #include "wx/bitmap.h" #include "wx/brush.h" #include "wx/dcmemory.h" #include "wx/image.h" #endif // WX_PRECOMP #include "wx/display.h" #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("wxHtmlDCRenderer::BodyBgColour", "[html][print]") { const wxColour bg(0x12, 0x34, 0x56); wxBitmap bmp(100, 100); { wxMemoryDC dc(bmp); dc.SetBackground(*wxWHITE_BRUSH); dc.Clear(); wxHtmlDCRenderer renderer; renderer.SetDC(&dc); renderer.SetSize(bmp.GetWidth(), bmp.GetHeight()); renderer.SetHtmlText("" "

Hello world!

" ""); renderer.Render(0, 0); } const wxImage image = bmp.ConvertToImage(); const wxColour actual(image.GetRed(90, 90), image.GetGreen(90, 90), image.GetBlue(90, 90)); CHECK(actual == bg); } TEST_CASE("wxHtmlPrintout::HeaderDoesNotEraseBody", "[html][print]") { // Mirror the dimensions and scaling used by print preview and verify that // rendering the header after the body only affects the header area. const wxColour bg(0x12, 0x34, 0x56); wxBitmap bmp(560, 790); { wxMemoryDC dc(bmp); dc.SetBackground(*wxWHITE_BRUSH); dc.Clear(); wxHtmlPrintout pr; pr.SetHtmlText("

Body

"); pr.SetHeader("Header
", wxPAGE_ALL); REQUIRE( pr.SetUp(dc) ); pr.SetPPIScreen(96, 96); pr.SetPPIPrinter(600, 600); pr.SetPageSizePixels(4960, 7016); pr.SetPageSizeMM(210, 297); pr.SetPaperRectPixels(wxRect(0, 0, 4960, 7016)); REQUIRE_NOTHROW( pr.OnPreparePrinting() ); REQUIRE( pr.HasPage(1) ); REQUIRE( pr.OnPrintPage(1) ); } const wxImage image = bmp.ConvertToImage(); const wxColour actual(image.GetRed(280, 395), image.GetGreen(280, 395), image.GetBlue(280, 395)); CHECK( actual == bg ); } 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); // Ensure that the fonts are not scaled when rendering: the scale used by // wxHtmlPrintout::OnPreparePrinting() is the ratio of the printer and the // screen PPI, and SetUp() below always uses wxDisplay::GetStdPPI() for the // latter, so use the same value for the former to make the ratio 1. // // Note that this must be done before SetUp() which would otherwise use the // PPI of the DC below for the printer. pr.SetPPIPrinter(wxDisplay::GetStdPPI()); wxBitmap bmp(1000, 1000); wxMemoryDC dc(bmp); REQUIRE( pr.SetUp(dc) ); // Pagination depends on the height of the text in pixels, so the base font // must have a fixed size in pixels for the results to be the same on all // systems, whatever their DPI is. As SetStandardFonts() takes the size in // points, convert the size we want using the PPI of the DC we're going to // render on -- we can't use wxFont::GetPointSize() of a font created with // the fixed pixel size for this, as the conversion performed by it doesn't // necessarily use the same DPI, and doesn't under wxGTK, resulting in a // different font size and hence different number of pages here. // // We could also make the page height proportional to the DPI, but this // would be more complicated as we also wouldn't be able to use hardcoded // height attribute values in the HTML snippets below then. const int ppi = dc.GetPPI().y; REQUIRE( ppi > 0 ); const int fontSize = 16 * 72 / ppi; pr.SetStandardFonts(fontSize, "Helvetica"); // 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 ); // Also test that forbidding page breaks inside a paragraph works: it // should move it entirely to the next page, resulting in one extra page // compared to the version without "page-break-inside: avoid". static const char* const text = R"( Early in the morning on the fourteenth of the spring month of Nisan the
Procurator of Judea, Pontius Pilate, in a white cloak lined with blood red,
emerged with his shuffling cavalryman's walk into the arcade connecting the two
wings of the palace of Herod the Great.

More than anything else in the world the Procurator hated the smell of attar of
roses. The omens for the day were bad, as this scent had been haunting him
since dawn.

It seemed to the Procurator that the very cypresses and palms in the garden
were exuding the smell of roses, that this damned stench of roses was even
mingling with the smell of leather tackle and sweat from his mounted bodyguard.

A haze of smoke was drifting toward the arcade across the upper courtyard of
the garden, coming from the wing at the rear of the palace, the quarters of the
first cohort of the XII Legion; known as the "Lightning," it had been
stationed in Jerusalem since the Procurator's arrival. The same oily perfume
of roses was mixed with the acrid smoke that showed that the centuries' cooks
had started to prepare breakfast

"Oh, gods, what are you punishing me for?.. No, there's no doubt, I have it
again, this terrible incurable pain... hemicrania, when half the head aches...
There's no cure for it, nothing helps... I must try not to move my head..."

A chair had already been placed on the mosaic floor by the fountain; without a
glance around, the Procurator sat in it and stretched out his hand to one side.
His secretary deferentially laid a piece of parchment in his hand. Unable to
restrain a grimace of agony, the Procurator gave a fleeting sideways look at
its contents, returned the parchment to his secretary and said painfully, "The
accused comes from Galilee, does he? Was the case sent to the tetrarch?"

"Yes, Procurator," replied the secretary. "He declined to confirm the
finding of the court and passed the Sanhedrin's sentence of death to you for
confirmation."

The Procurator's cheek twitched, and he said quietly, "Bring in the accused."
)"; pr.SetHtmlText ( wxString::Format ( "" "
%s
" "
" "", text ) ); CHECK( CountPages(pr) == 2 ); pr.SetHtmlText ( wxString::Format ( "" "
%s
" "
" "", text ) ); INFO("Using base font size " << fontSize); CHECK( CountPages(pr) == 3 ); } #endif //wxUSE_PRINTING_ARCHITECTURE #endif //wxUSE_HTML