[Webkit-unassigned] [Bug 59597] wrong page height is assumed during (regular HTML page) printing (concerning page breaks) when page is scaled down

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Thu Apr 28 00:57:25 PDT 2011


https://bugs.webkit.org/show_bug.cgi?id=59597





--- Comment #9 from Christophe Saout <christophe at saout.de>  2011-04-28 00:57:25 PST ---
Ok, a few more details and a test case.

We wanted to add a simple PDF creator to an existing Python application. We thought Webkit was a rather awesome solution and went for the WebKit-GTK+ python bindings to use its PDF printing feature. We soon found out that it would be nice to have some control over the page breaks.

The GTK+ port by default doesn't do page breaks in printing. Not sure why, but it's trivially enabled and I have asked for this feature in a separate bug.

Note that in Source/WebCore/page/FrameView.cpp FrameView::forceLayoutForPagination is key to understanding the issue.  Therefore I've added some debug here to clarify the issue:

--- a/Source/WebCore/page/FrameView.cpp
+++ b/Source/WebCore/page/FrameView.cpp
@@ -2512,10 +2512,15 @@ void FrameView::forceLayoutForPagination(const FloatSize& pageSize, float maximu
         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
         // implementation should not do this!
         int docLogicalWidth = root->style()->isHorizontalWritingMode() ? root->docWidth() : root->docHeight();
+fprintf(stderr, "pageLogicalWidth = %f, pageLogicalHeight = %f, docLogicalWidth = %d\n", pageLogicalWidth, pageLogicalHeight, docLogicalWidth);
         if (docLogicalWidth > pageLogicalWidth) {
+fprintf(stderr, "docLogicalWidth > pageLogicalWidth!\n");
             flooredPageLogicalWidth = std::min<int>(docLogicalWidth, pageLogicalWidth * maximumShrinkFactor);
             if (pageLogicalHeight)
+{
+fprintf(stderr, "setting pageLogicalHeight = %d\n", (int)(flooredPageLogicalWidth / pageSize.width() * pageSize.height()));
                 root->setPageLogicalHeight(flooredPageLogicalWidth / pageSize.width() * pageSize.height());
+}
             root->setLogicalWidth(flooredPageLogicalWidth);
             root->setNeedsLayoutAndPrefWidthsRecalc();
             forceLayout();

Ok, so now running the test case:
> python print.py pdf1.html
produces an output.pdf (which is attached as test case1: output1.pdf)

pageLogicalWidth = 699,094482, pageLogicalHeight = 0,000000, docLogicalWidth = 699

As you can see, the GTK+ port is not passing the page height, therefore page breaks are ignored. This is not the issue I'm reporting here, and changed the port to pass the page height.  The issue I am reporting is not related to the GTK port (at least I'm 99.999% sure of that).

--- a/Source/WebKit/gtk/webkit/webkitwebframe.cpp
+++ b/Source/WebKit/gtk/webkit/webkitwebframe.cpp
@@ -756,7 +756,7 @@ static void begin_print_callback(GtkPrintOperation* op, GtkPrintContext* context
     float height = gtk_print_context_get_height(context);
     FloatRect printRect = FloatRect(0, 0, width, height);

-    printContext->begin(width);
+    printContext->begin(width, height);

     // TODO: Margin adjustments and header/footer support
     float headerHeight = 0;

Rerunning the test case now yields output2.pdf and everything is as it should be:

pageLogicalWidth = 699,094482, pageLogicalHeight = 979,462219, docLogicalWidth = 699

The page internally is 699 pixels wide and 979 pixels high.

Now I'm going to trigger the issue I am reporting.  I am adding an image to the page that is larger than the 699 pixels, forcing the large if() block in FrameView::forceLayoutForPagination to be entered, which tries to scale down the page again to fit it to the printing page.

Running  "python print.py pdf2.html" produces the output3.pdf:

pageLogicalWidth = 699,094482, pageLogicalHeight = 979,462219, docLogicalWidth = 744
docLogicalWidth > pageLogicalWidth!
setting pageLogicalHeight = 1042

The document is now 744 pixels wide, so the page is being rescale.  Because the page is now wider, it also implicitly gets higher than before.  In fact, the new height is computed as 1042 pixels.

But, if you look at the output3.pdf, the page breaks are now in the wrong place!  In fact, I traced it down to the layout code is still using the old page breaks at 979 pixels instead of the new one at 1042.

I then chased it down to the second ::forceLayout call below:

            root->setLogicalWidth(flooredPageLogicalWidth);
            root->setNeedsLayoutAndPrefWidthsRecalc();
            forceLayout();

I noticed that this forceLayout() does not relayout the document (as probably intended to) but bails out early, because it notices that the document width hasn't changed. (the new prefererred width of 744 is identical to the docLogicalWidth that was used before)

This means, that the vertical position of the blocks is also never recomputed using the new page height.

If I add in my hack from above, which goes through all the childs and sets "needsLayout" recursively to force a full re-layout, the resulting PDF is then correct again: see output4.pdf

So, essentially the problem boils down to the relayout in case the page is enlargened internally due to the scale-down feature does not take the need to relayout page breaks into account.

-- 
Configure bugmail: https://bugs.webkit.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.



More information about the webkit-unassigned mailing list