0

Printing: Avoid points<->pixels roundtrips, untangle magical scaling.

Use CSS pixels where we can, most prominently, in WebPrintParams.
Convert directly from device pixels to CSS pixels. We used to convert
from device pixels to points, then pass this to Blink, and Blink would
convert it to CSS pixels. The fact that this conversion was
taking place wasn't exactly obvious. The values were multiplied by
PrintContext::kPrintingMinimumShrinkFactor, which was documented as a
somewhat mysterious factor, that, according to the documentation, used
to be 1.25, but more recent research had shown that 1.33333 was a better
factor. But there's really nothing magical or heuristic about this.
There are 96 CSS pixels per inch, and there are 72 points per inch.
96/72 = 4/3 ~= 1.33333

Don't expose internal Blink scaling (remove WebLocalFrame::
GetPrintPageShrink()). Blink sometimes scales down content to fit more
content in the inline direction (as an attempt to avoid clipping and
thus losing content). Take care of that internally, which is more
consistent. Blink used to do it internally for web tests
(SpoolPagesWithBoundariesForTesting() in WebLocalFrameImpl), whereas for
printing in actual Chrome, it was done on the outside, by
PrintRenderFrameHelper::PrintPageInternal().

This also improves media query evaluation "for free". We used to perform
some strange conversions in PrepareFrameAndViewForPrint::
ResizeForPrinting(). The input size used to be in points, and then we'd
*divide* the height (but not the width!) by 1.333, and then pretend that
the result was in pixels. Now that "everything" is in pixels, things
will improve automatically, unless we make an effort to prevent it. It's
still not quite right, and this CL isn't about that anyway (added TODO).

Also update the header/footer template. PrintHeaderAndFooter() used to
cancel out scaling, including the internal 1/1.333 (3/4) scaling in
Blink, so that content in headers and footers would appear 1.333 (4/3)
times as large as it should be. This has now been untangled and cleaned
up, so we need to ask for the sizes we actually want to see, rather than
3/4 of that. This includes the options passed to
setupHeaderFooterTemplate(). setupHeaderFooterTemplate() specifies the
page size in pixels, although it was actually passed in points. But that
looked just fine, since everything was accidentally (?) zoomed in by
4/3.

There was some confusion on the web tests side of things.
PrintFrameToBitmap() thinks that it takes a page size in pixels, but
this value was multiplied with 1.333 inside Blink afterwards, so it was
effectively points, not pixels. We need to rebaseline or rewrite quite a
few of the tests before we can remove it, so, for now, keep the magical
1.333 scaling thing for tests. Will follow up with a CL that removes
this and rebaselines / rewrites the tests that need it.

Four tests still need to be rebaselined in this CL, though. The
down-scaling of content inside Blink produces slightly different results
now. Since we're using pixels instead of points, and they are passed as
integer values, we end up with a slightly different aspect ratio, so
that LocalFrame::ResizePageRectsKeepingRatio() doesn't behave exactly
like before. Since this CL fixes some rounding errors, two layout tree
dump tests also need to be rebaselined.

Added a few browser tests, both for crbug.com/1444579 (which was the
main motivation for making this change), and also for crbug.com/1117050
since media query evaluation has improved, because we're now using CSS
pixels.

Two of the new tests are disabled. Since we don't support fractional
page sizes, and round down everything to the nearest integer (e.g.
123.9px -> 123px), content that the author would expect to fit on one
page will fragment. Will deal with this in a follow-up.

Bug: 1444579, 1117050
Change-Id: I076cc9f84591b74925465e364ef2f5f4908bb794
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4567866
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: danakj <danakj@chromium.org>
Commit-Queue: Morten Stenshorne <mstensho@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1161059}
This commit is contained in:
Morten Stenshorne
2023-06-22 06:53:00 +00:00
committed by Chromium LUCI CQ
parent 286d6c89c8
commit f6529c7990
43 changed files with 408 additions and 270 deletions

@ -109,9 +109,6 @@ enum PrintPreviewHelperEvents {
PREVIEW_EVENT_MAX,
};
// Also set in third_party/WebKit/Source/core/page/PrintContext.h
constexpr float kPrintingMinimumShrinkFactor = 1.33333333f;
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
bool g_is_preview_enabled = true;
#else
@ -260,7 +257,6 @@ mojom::PageSizeMarginsPtr CalculatePageLayoutFromPrintParams(
const mojom::PrintParams& params,
double scale_factor) {
bool fit_to_page = IsPrintScalingOptionFitToPage(params);
int dpi = GetDPI(params);
float content_width = params.content_size.width();
float content_height = params.content_size.height();
// Scale the content to its normal size for purpose of computing page layout.
@ -276,20 +272,56 @@ mojom::PageSizeMarginsPtr CalculatePageLayoutFromPrintParams(
float margin_right =
params.page_size.width() - content_width - params.margin_left;
auto page_layout_in_points = mojom::PageSizeMargins::New();
page_layout_in_points->content_width =
ConvertUnitFloat(content_width, dpi, kPointsPerInch);
page_layout_in_points->content_height =
ConvertUnitFloat(content_height, dpi, kPointsPerInch);
page_layout_in_points->margin_top =
ConvertUnitFloat(params.margin_top, dpi, kPointsPerInch);
page_layout_in_points->margin_right =
ConvertUnitFloat(margin_right, dpi, kPointsPerInch);
page_layout_in_points->margin_bottom =
ConvertUnitFloat(margin_bottom, dpi, kPointsPerInch);
page_layout_in_points->margin_left =
ConvertUnitFloat(params.margin_left, dpi, kPointsPerInch);
return page_layout_in_points;
return mojom::PageSizeMargins::New(content_width, content_height,
params.margin_top, margin_right,
margin_bottom, params.margin_left);
}
mojom::PageSizeMarginsPtr ConvertedPageSizeMargins(
const mojom::PageSizeMarginsPtr& orig_page_layout,
float old_unit,
float new_unit) {
mojom::PageSizeMarginsPtr page_layout = orig_page_layout.Clone();
page_layout->content_width =
ConvertUnitFloat(page_layout->content_width, old_unit, new_unit);
page_layout->content_height =
ConvertUnitFloat(page_layout->content_height, old_unit, new_unit);
page_layout->margin_top =
ConvertUnitFloat(page_layout->margin_top, old_unit, new_unit);
page_layout->margin_right =
ConvertUnitFloat(page_layout->margin_right, old_unit, new_unit);
page_layout->margin_bottom =
ConvertUnitFloat(page_layout->margin_bottom, old_unit, new_unit);
page_layout->margin_left =
ConvertUnitFloat(page_layout->margin_left, old_unit, new_unit);
return page_layout;
}
// Get size and offset information from `page_layout`.
//
// `page_size` is the size of the page box (i.e. outside the margin area).
//
// `content_area` is the page area within `page_size`.
//
// `canvas_area` is the area that can be drawn on. If headers and footers are to
// be included, it will simply be `page_size` at offset 0,0. Otherwise it will
// be the same as `content_area`.
void GetPageSizeAndContentAreaFromPageLayout(
const mojom::PrintParams& params,
const mojom::PageSizeMargins& page_layout,
gfx::Size* page_size,
gfx::Rect* content_area,
gfx::Rect* canvas_area) {
*page_size = gfx::Size(page_layout.content_width + page_layout.margin_right +
page_layout.margin_left,
page_layout.content_height + page_layout.margin_top +
page_layout.margin_bottom);
*content_area =
gfx::Rect(page_layout.margin_left, page_layout.margin_top,
page_layout.content_width, page_layout.content_height);
*canvas_area =
params.display_header_footer ? gfx::Rect(*page_size) : *content_area;
}
void EnsureOrientationMatches(const mojom::PrintParams& css_params,
@ -337,22 +369,22 @@ blink::WebPrintParams ComputeWebKitPrintParamsInDesiredDpi(
webkit_print_params.rasterize_pdf = print_params.rasterize_pdf;
webkit_print_params.print_scaling_option = print_params.print_scaling_option;
webkit_print_params.print_content_area.set_size(gfx::SizeF(
ConvertUnitFloat(print_params.content_size.width(), dpi, kPointsPerInch),
webkit_print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(
ConvertUnitFloat(print_params.content_size.width(), dpi, kPixelsPerInch),
ConvertUnitFloat(print_params.content_size.height(), dpi,
kPointsPerInch)));
kPixelsPerInch)));
webkit_print_params.printable_area = gfx::RectF(
ConvertUnitFloat(print_params.printable_area.x(), dpi, kPointsPerInch),
ConvertUnitFloat(print_params.printable_area.y(), dpi, kPointsPerInch),
webkit_print_params.printable_area_in_css_pixels = gfx::RectF(
ConvertUnitFloat(print_params.printable_area.x(), dpi, kPixelsPerInch),
ConvertUnitFloat(print_params.printable_area.y(), dpi, kPixelsPerInch),
ConvertUnitFloat(print_params.printable_area.width(), dpi,
kPointsPerInch),
kPixelsPerInch),
ConvertUnitFloat(print_params.printable_area.height(), dpi,
kPointsPerInch));
kPixelsPerInch));
webkit_print_params.paper_size = gfx::SizeF(
ConvertUnitFloat(print_params.page_size.width(), dpi, kPointsPerInch),
ConvertUnitFloat(print_params.page_size.height(), dpi, kPointsPerInch));
webkit_print_params.paper_size_in_css_pixels = gfx::SizeF(
ConvertUnitFloat(print_params.page_size.width(), dpi, kPixelsPerInch),
ConvertUnitFloat(print_params.page_size.height(), dpi, kPixelsPerInch));
// The following settings is for N-up mode.
webkit_print_params.pages_per_sheet = print_params.pages_per_sheet;
@ -588,8 +620,8 @@ mojom::PrintParamsPtr CalculatePrintParamsForCss(
return result_params;
}
// Get page layout in points and fit to page if needed.
mojom::PageSizeMarginsPtr ComputePageLayoutInPointsForCss(
// Get page layout and fit to page if needed. The layout is in device pixels.
mojom::PageSizeMarginsPtr ComputePageLayoutForCss(
blink::WebLocalFrame* frame,
uint32_t page_index,
const mojom::PrintParams& page_params,
@ -648,15 +680,17 @@ void PrintHeaderAndFooter(cc::PaintCanvas* canvas,
uint32_t page_number,
uint32_t total_pages,
const blink::WebLocalFrame& source_frame,
float webkit_scale_factor,
float scale_factor,
const mojom::PageSizeMargins& page_layout,
const mojom::PrintParams& params) {
DCHECK_LE(total_pages, kMaxPageCount);
// |page_number| is 1-based here, so it could be equal to kMaxPageCount.
DCHECK_LE(page_number, kMaxPageCount);
// Scaling has already been applied to the canvas, but headers and footers
// should not be affected by that, so cancel it out.
cc::PaintCanvasAutoRestore auto_restore(canvas, true);
canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor);
canvas->scale(1 / scale_factor, 1 / scale_factor);
gfx::SizeF page_size(page_layout.margin_left + page_layout.margin_right +
page_layout.content_width,
@ -977,18 +1011,11 @@ PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
void PrepareFrameAndViewForPrint::ResizeForPrinting() {
TRACE_EVENT0("print", "PrepareFrameAndViewForPrint::ResizeForPrinting");
// Layout page according to printer page size. Since WebKit shrinks the
// size of the page automatically (from 133.3% to 200%) we trick it to
// think the page is 133.3% larger so the size of the page is correct for
// minimum (default) scaling.
// The scaling factor 1.25 was originally chosen as a magic number that
// was 'about right'. However per https://crbug.com/273306 1.333 seems to be
// the number that produces output with the correct physical size for elements
// that are specified in cm, mm, pt etc.
// This is important for sites that try to fill the page.
gfx::SizeF print_layout_size(web_print_params_.print_content_area.size());
print_layout_size.set_height(InverseScaleDouble(
print_layout_size.height(), kPrintingMinimumShrinkFactor));
// TODO(crbug.com/1117050): This is an attempt at handling media queries, but
// it's not quite right. We're passing the page area instead of the page box
// here, so any page margins will cause inaccuracies.
gfx::SizeF print_layout_size(
web_print_params_.print_content_area_in_css_pixels.size());
if (!frame())
return;
@ -1704,21 +1731,6 @@ void PrintRenderFrameHelper::SnapshotForContentAnalysis(
}
#endif // BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS)
void PrintRenderFrameHelper::GetPageSizeAndContentAreaFromPageLayout(
const mojom::PageSizeMargins& page_layout_in_points,
gfx::Size* page_size,
gfx::Rect* content_area) {
*page_size = gfx::Size(
page_layout_in_points.content_width + page_layout_in_points.margin_right +
page_layout_in_points.margin_left,
page_layout_in_points.content_height + page_layout_in_points.margin_top +
page_layout_in_points.margin_bottom);
*content_area = gfx::Rect(page_layout_in_points.margin_left,
page_layout_in_points.margin_top,
page_layout_in_points.content_width,
page_layout_in_points.content_height);
}
void PrintRenderFrameHelper::UpdateFrameMarginsCssInfo(
const base::Value::Dict& settings) {
constexpr int kDefault = static_cast<int>(mojom::MarginType::kDefaultMargins);
@ -1816,17 +1828,19 @@ PrintRenderFrameHelper::CreatePreviewDocument() {
/*is_pdf=*/!print_preview_context_.IsModifiable());
mojom::PageSizeMarginsPtr default_page_layout =
ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(),
0, print_params, ignore_css_margins_,
&scale_factor);
ComputePageLayoutForCss(print_preview_context_.prepared_frame(), 0,
print_params, ignore_css_margins_, &scale_factor);
int dpi = GetDPI(print_params);
// Convert to points.
default_page_layout =
ConvertedPageSizeMargins(default_page_layout, dpi, kPointsPerInch);
bool all_pages_have_custom_size;
bool all_pages_have_custom_orientation;
GetPageSizeAndOrientationInfo(print_preview_context_.prepared_frame(),
print_preview_context_.total_page_count(),
&all_pages_have_custom_size,
&all_pages_have_custom_orientation);
int dpi = GetDPI(print_params);
gfx::RectF printable_area_in_points(
ConvertUnitFloat(print_params.printable_area.x(), dpi, kPointsPerInch),
ConvertUnitFloat(print_params.printable_area.y(), dpi, kPointsPerInch),
@ -2563,24 +2577,46 @@ void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
double scale_factor,
blink::WebLocalFrame* frame,
MetafileSkia* metafile) {
double css_scale_factor = scale_factor;
mojom::PageSizeMarginsPtr page_layout_in_points =
ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &css_scale_factor);
mojom::PageSizeMarginsPtr page_layout_in_device_pixels =
ComputePageLayoutForCss(frame, page_number, params, ignore_css_margins_,
&scale_factor);
mojom::PageSizeMarginsPtr page_layout_in_css_pixels =
ConvertedPageSizeMargins(page_layout_in_device_pixels, GetDPI(params),
kPixelsPerInch);
gfx::Size page_size;
gfx::Size page_size_ignored;
gfx::Rect content_area;
GetPageSizeAndContentAreaFromPageLayout(*page_layout_in_points, &page_size,
&content_area);
gfx::Rect canvas_area;
GetPageSizeAndContentAreaFromPageLayout(params, *page_layout_in_css_pixels,
&page_size_ignored, &content_area,
&canvas_area);
gfx::Rect canvas_area =
params.display_header_footer ? gfx::Rect(page_size) : content_area;
cc::PaintCanvas* canvas;
{
// Explicit scope for stuff in points. Blink renders in CSS pixels. Convert
// to points for Skia metafile / PDF, since that's what they want. The PDF
// generation code expects the values to be in points, so that if we had
// passed them as pixels, the pages would be 1/kPointsPerPixel (33.333%)
// larger than they should be. It may be a cleaner approach if the metafile
// code handled this, so that this code could simply deal with CSS
// pixels. But for now the conversion is performed here.
mojom::PageSizeMarginsPtr page_layout_in_points = ConvertedPageSizeMargins(
page_layout_in_device_pixels, GetDPI(params), kPointsPerInch);
gfx::Size page_size_in_points;
gfx::Rect content_area_ignored;
gfx::Rect canvas_area_in_points;
GetPageSizeAndContentAreaFromPageLayout(
params, *page_layout_in_points, &page_size_in_points,
&content_area_ignored, &canvas_area_in_points);
float webkit_page_shrink_factor = frame->GetPrintPageShrink(page_number);
float final_scale_factor = css_scale_factor * webkit_page_shrink_factor;
double scale_factor_for_points = scale_factor *
static_cast<double>(kPointsPerInch) /
static_cast<double>(kPixelsPerInch);
cc::PaintCanvas* canvas = metafile->GetVectorCanvasForNewPage(
page_size, canvas_area, final_scale_factor, params.page_orientation);
canvas = metafile->GetVectorCanvasForNewPage(
page_size_in_points, canvas_area_in_points, scale_factor_for_points,
params.page_orientation);
}
if (!canvas)
return;
@ -2589,11 +2625,11 @@ void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
if (params.display_header_footer) {
// |page_number| is 0-based, so 1 is added.
PrintHeaderAndFooter(canvas, page_number + 1, page_count, *frame,
final_scale_factor, *page_layout_in_points, params);
scale_factor, *page_layout_in_css_pixels, params);
}
RenderPageContent(frame, page_number, canvas_area, content_area,
final_scale_factor, canvas);
RenderPageContent(frame, page_number, canvas_area, content_area, scale_factor,
canvas);
// Done printing. Close the canvas to retrieve the compiled metafile.
bool ret = metafile->FinishPage();

@ -272,13 +272,6 @@ class PrintRenderFrameHelper
SnapshotForContentAnalysisCallback callback) override;
#endif // BUILDFLAG(ENABLE_PRINT_CONTENT_ANALYSIS)
// Get |page_size| and |content_area| information from
// |page_layout_in_points|.
void GetPageSizeAndContentAreaFromPageLayout(
const mojom::PageSizeMargins& page_layout_in_points,
gfx::Size* page_size,
gfx::Rect* content_area);
// Update |ignore_css_margins_| based on settings.
void UpdateFrameMarginsCssInfo(const base::Value::Dict& settings);

@ -17,12 +17,12 @@
#header {
align-items: flex-start;
padding-top: 0.4cm;
padding-top: 0.5cm;
}
#footer {
align-items: flex-end;
padding-bottom: 0.4cm;
padding-bottom: 0.5cm;
}
#content {
@ -31,22 +31,22 @@
.left {
flex: none;
padding-left: 0.7cm;
padding-right: 0.1cm;
padding-left: 0.9cm; /* csschecker-disable-line left-right */
padding-right: 0.2cm; /* csschecker-disable-line left-right */
}
.center {
flex: auto;
padding-left: 0.7cm;
padding-right: 0.7cm;
padding-left: 0.9cm; /* csschecker-disable-line left-right */
padding-right: 0.9cm; /* csschecker-disable-line left-right */
text-align: center;
}
.right {
flex: none;
/* historically does not account for RTL */
padding-left: 0.1cm;
padding-right: 0.7cm;
padding-left: 0.2cm; /* csschecker-disable-line left-right */
padding-right: 0.9cm; /* csschecker-disable-line left-right */
}
.grow {
@ -54,7 +54,7 @@
}
.text {
font-size: 8px;
font-size: 8pt;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

@ -835,6 +835,85 @@ TEST_F(MAYBE_PrintRenderFrameHelperTest, MonolithicAbsposOverflowingParent) {
OnPrintPages();
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, SpecifiedPageSize1) {
LoadHTML(R"HTML(
<style>
@page {
size: 400px 123px;
margin: 0;
}
body {
margin: 0;
}
</style>
<div style="width:400px; height:123px;"></div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
// TODO(crbug.com/1444579): Fix the remaining issues, and enable this test.
TEST_F(MAYBE_PrintRenderFrameHelperTest, DISABLED_SpecifiedPageSize2) {
LoadHTML(R"HTML(
<style>
@page {
size: 400px 123.1px;
margin: 0;
}
body {
margin: 0;
}
</style>
<div style="width:400px; height:123.1px;"></div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
// TODO(crbug.com/1444579): Fix the remaining issues, and enable this test.
TEST_F(MAYBE_PrintRenderFrameHelperTest, DISABLED_SpecifiedPageSize3) {
LoadHTML(R"HTML(
<style>
@page {
size: 400px 123.9px;
margin: 0;
}
body {
margin: 0;
}
</style>
<div style="width:400px; height:123.9px;"></div>
)HTML");
print_manager()->SetExpectedPagesCount(1);
OnPrintPages();
VerifyPagesPrinted(true);
}
TEST_F(MAYBE_PrintRenderFrameHelperTest, MediaQueryNoCSSPageMargins) {
// The default page size in these tests is US Letter.
LoadHTML(R"HTML(
<style>
@page {
margin: 0;
}
@media (width: 8.5in) and (height: 11in) {
div { break-before: page; }
}
</style>
First page
<div>Second page</div>
)HTML");
print_manager()->SetExpectedPagesCount(2);
OnPrintPages();
VerifyPagesPrinted(true);
}
#if BUILDFLAG(IS_APPLE)
// TODO(estade): I don't think this test is worth porting to Linux. We will have
// to rip out and replace most of the IPC code if we ever plan to improve

@ -520,13 +520,6 @@ static void PrintDocument(blink::WebLocalFrame* frame, SkDocument* doc) {
cc::SkiaPaintCanvas canvas(sk_canvas);
cc::PaintCanvasAutoRestore auto_restore(&canvas, true);
canvas.translate(kMarginLeft, kMarginTop);
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
float page_shrink = frame->GetPrintPageShrink(i);
DCHECK_GT(page_shrink, 0);
canvas.scale(page_shrink, page_shrink);
#endif
frame->PrintPage(i, &canvas);
}
frame->PrintEnd();

@ -358,6 +358,39 @@ void PrintPDFOutput(PP_Resource print_output,
#endif // BUILDFLAG(ENABLE_PRINTING)
}
// Stolen from //printing/units.{cc,h}
// Length of an inch in CSS's 1pt unit.
// http://dev.w3.org/csswg/css3-values/#absolute-length-units-cm-mm.-in-pt-pc
constexpr int kPointsPerInch = 72;
// Length of an inch in CSS's 1px unit.
// http://dev.w3.org/csswg/css3-values/#the-px-unit
constexpr int kPixelsPerInch = 96;
float ConvertUnitFloat(float value, float old_unit, float new_unit) {
CHECK_GT(new_unit, 0);
CHECK_GT(old_unit, 0);
return value * new_unit / old_unit;
}
PP_Rect CSSPixelsToPoints(const gfx::RectF& rect) {
const gfx::Rect points_rect = gfx::ToEnclosedRect(gfx::RectF(
ConvertUnitFloat(rect.x(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(rect.y(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(rect.width(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(rect.height(), kPixelsPerInch, kPointsPerInch)));
return PP_MakeRectFromXYWH(points_rect.x(), points_rect.y(),
points_rect.width(), points_rect.height());
}
PP_Size CSSPixelsToPoints(const gfx::SizeF& size) {
const gfx::Size points_size = gfx::ToFlooredSize(gfx::SizeF(
ConvertUnitFloat(size.width(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(size.height(), kPixelsPerInch, kPointsPerInch)));
return PP_MakeSize(points_size.width(), points_size.height());
}
} // namespace
// static
@ -1578,11 +1611,11 @@ int PepperPluginInstanceImpl::PrintBegin(const WebPrintParams& print_params) {
PP_PrintSettings_Dev print_settings;
print_settings.printable_area =
PP_FromGfxRect(gfx::ToEnclosedRect(print_params.printable_area));
CSSPixelsToPoints(print_params.printable_area_in_css_pixels);
print_settings.content_area =
PP_FromGfxRect(gfx::ToEnclosedRect(print_params.print_content_area));
CSSPixelsToPoints(print_params.print_content_area_in_css_pixels);
print_settings.paper_size =
PP_FromGfxSize(gfx::ToFlooredSize(print_params.paper_size));
CSSPixelsToPoints(print_params.paper_size_in_css_pixels);
print_settings.dpi = print_params.printer_dpi;
print_settings.orientation = PP_PRINTORIENTATION_NORMAL;
print_settings.grayscale = PP_FALSE;

@ -39,17 +39,32 @@
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_widget.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size_conversions.h"
namespace content {
SkBitmap PrintFrameToBitmap(blink::WebLocalFrame* web_frame,
const gfx::Size& page_size_in_pixels,
const printing::PageRanges& page_ranges) {
// TODO(crbug.com/1450167): Get rid of this conversion, and rebaseline /
// rewrite tests, and use page_size_in_pixels everywhere. There used to be
// some pixel vs points confusion. The test runner code passed the window
// size, thinking that the API took pixels, although it did in fact take
// points. This is no longer the case, now that we use CSS pixels everywhere
// we can. So we compensate here for now.
gfx::SizeF borked_size(page_size_in_pixels);
static constexpr float kPrintingMinimumShrinkFactor = 1.33333333f;
borked_size.set_width(
floorf(borked_size.width() * kPrintingMinimumShrinkFactor));
borked_size.set_height(
floorf(borked_size.height() * borked_size.width() /
static_cast<float>(page_size_in_pixels.width())));
auto* frame_widget = web_frame->LocalRoot()->FrameWidget();
frame_widget->UpdateAllLifecyclePhases(blink::DocumentUpdateReason::kTest);
uint32_t page_count = web_frame->PrintBegin(
blink::WebPrintParams(gfx::SizeF(page_size_in_pixels)), blink::WebNode());
blink::WebPrintParams(borked_size), blink::WebNode());
blink::WebVector<uint32_t> pages(
printing::PageNumber::GetPages(page_ranges, page_count));

@ -30,6 +30,7 @@
using printing::ConvertUnit;
using printing::ConvertUnitFloat;
using printing::kPixelsPerInch;
using printing::kPointsPerInch;
namespace chrome_pdf {
@ -246,6 +247,20 @@ bool FlattenPrintData(FPDF_DOCUMENT doc) {
return true;
}
gfx::RectF CSSPixelsToPoints(const gfx::RectF& rect) {
return gfx::RectF(
ConvertUnitFloat(rect.x(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(rect.y(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(rect.width(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(rect.height(), kPixelsPerInch, kPointsPerInch));
}
gfx::SizeF CSSPixelsToPoints(const gfx::SizeF& size) {
return gfx::SizeF(
ConvertUnitFloat(size.width(), kPixelsPerInch, kPointsPerInch),
ConvertUnitFloat(size.height(), kPixelsPerInch, kPointsPerInch));
}
} // namespace
PDFiumPrint::PDFiumPrint(PDFiumEngine* engine) : engine_(engine) {}
@ -324,8 +339,10 @@ ScopedFPDFDocument PDFiumPrint::CreatePrintPdf(
return nullptr;
}
gfx::Size int_paper_size = ToFlooredSize(print_params.paper_size);
gfx::Rect int_printable_area = ToEnclosedRect(print_params.printable_area);
gfx::Size int_paper_size =
ToFlooredSize(CSSPixelsToPoints(print_params.paper_size_in_css_pixels));
gfx::Rect int_printable_area = ToEnclosedRect(
CSSPixelsToPoints(print_params.printable_area_in_css_pixels));
float scale_factor = print_params.scale_factor / 100.0f;
FitContentsToPrintableAreaIfRequired(output_doc.get(), scale_factor,

@ -34,9 +34,10 @@ using ::testing::ElementsAre;
namespace {
constexpr gfx::SizeF kUSLetterSize = {612, 792};
// blink::WebPrintParams takes values in CSS pixels, not points.
constexpr gfx::SizeF kUSLetterSize = {816, 1056};
constexpr gfx::RectF kUSLetterRect = {{0, 0}, kUSLetterSize};
constexpr gfx::RectF kPrintableAreaRect = {{18, 18}, {576, 733}};
constexpr gfx::RectF kPrintableAreaRect = {{24, 24}, {768, 977.33333}};
using ExpectedDimensions = std::vector<gfx::SizeF>;
@ -53,9 +54,9 @@ base::FilePath GetReferenceFilePath(base::StringPiece test_filename) {
blink::WebPrintParams GetDefaultPrintParams() {
blink::WebPrintParams params;
params.print_content_area = kUSLetterRect;
params.printable_area = kUSLetterRect;
params.paper_size = kUSLetterSize;
params.print_content_area_in_css_pixels = kUSLetterRect;
params.printable_area_in_css_pixels = kUSLetterRect;
params.paper_size_in_css_pixels = kUSLetterSize;
params.print_scaling_option = printing::mojom::PrintScalingOption::kNone;
return params;
}
@ -168,7 +169,7 @@ TEST_P(PDFiumPrintTest, AlterScalingDefault) {
const std::vector<int> pages = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area = kPrintableAreaRect;
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
std::vector<uint8_t> pdf_data = print.PrintPagesAsPdf(pages, print_params);
CheckPdfDimensions(pdf_data, kExpectedDimensions);
CheckPdfRendering(
@ -196,7 +197,7 @@ TEST_P(PDFiumPrintTest, AlterScalingFitPaper) {
const std::vector<int> pages = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area = kPrintableAreaRect;
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kFitToPaper;
std::vector<uint8_t> pdf_data = print.PrintPagesAsPdf(pages, print_params);
@ -226,7 +227,7 @@ TEST_P(PDFiumPrintTest, AlterScalingFitPrintable) {
const std::vector<int> pages = {0};
blink::WebPrintParams print_params = GetDefaultPrintParams();
print_params.printable_area = kPrintableAreaRect;
print_params.printable_area_in_css_pixels = kPrintableAreaRect;
print_params.print_scaling_option =
printing::mojom::PrintScalingOption::kFitToPrintableArea;
std::vector<uint8_t> pdf_data = print.PrintPagesAsPdf(pages, print_params);

@ -773,11 +773,6 @@ class BLINK_EXPORT WebLocalFrame : public WebFrame {
// printing. It returns whether any resources will need to load.
virtual bool WillPrintSoon() = 0;
// Returns the page shrinking factor calculated by webkit (usually
// between 1/1.33 and 1/2). Returns 0 if the page number is invalid or
// not in printing mode.
virtual float GetPrintPageShrink(uint32_t page) = 0;
// Prints one page.
virtual void PrintPage(uint32_t page_to_print, cc::PaintCanvas*) = 0;

@ -38,15 +38,16 @@
namespace blink {
struct WebPrintParams {
// Specifies printable content rect in points (a point is 1/72 of an inch).
gfx::RectF print_content_area;
// Specifies printable content rect in CSS pixels (a CSS pixel is 1/96 of an
// inch).
gfx::RectF print_content_area_in_css_pixels;
// Specifies the selected printer default printable area details in
// points.
gfx::RectF printable_area;
// pixels.
gfx::RectF printable_area_in_css_pixels;
// Specifies the selected printer default paper size in points.
gfx::SizeF paper_size;
// Specifies the selected printer default paper size in pixels.
gfx::SizeF paper_size_in_css_pixels;
// Specifies user selected DPI for printing.
int printer_dpi = 72;
@ -74,9 +75,9 @@ struct WebPrintParams {
: WebPrintParams(paper_size, true) {}
WebPrintParams(const gfx::SizeF& paper_size, bool use_printing_layout)
: print_content_area(paper_size),
printable_area(print_content_area),
paper_size(paper_size),
: print_content_area_in_css_pixels(paper_size),
printable_area_in_css_pixels(paper_size),
paper_size_in_css_pixels(paper_size),
print_scaling_option(printing::mojom::PrintScalingOption::kSourceSize),
use_printing_layout(use_printing_layout) {}
};

@ -709,7 +709,7 @@ TEST_F(ContainerQueryEvaluatorTest, Printing) {
Color(0, 128, 0));
constexpr gfx::SizeF initial_page_size(400, 400);
GetDocument().GetFrame()->StartPrinting(initial_page_size, initial_page_size);
GetDocument().GetFrame()->StartPrinting(initial_page_size);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
EXPECT_EQ(

@ -1880,7 +1880,7 @@ TEST_F(StyleResolverTest, CascadeLayersAndPageRules) {
constexpr gfx::SizeF initial_page_size(800, 600);
GetDocument().GetFrame()->StartPrinting(initial_page_size, initial_page_size);
GetDocument().GetFrame()->StartPrinting(initial_page_size);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
WebPrintPageDescription description;

@ -575,7 +575,7 @@ TEST_F(StyleEngineTest, AnalyzedInject) {
t8->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor()));
gfx::SizeF page_size(400, 400);
GetDocument().GetFrame()->StartPrinting(page_size, page_size, 1);
GetDocument().GetFrame()->StartPrinting(page_size, 1);
ASSERT_TRUE(t8->GetComputedStyle());
EXPECT_EQ(
Color::FromRGB(0, 0, 0),
@ -3145,7 +3145,7 @@ TEST_F(StyleEngineTest, PrintNoDarkColorScheme) {
body->GetComputedStyle()->VisitedDependentColor(GetCSSPropertyColor()));
gfx::SizeF page_size(400, 400);
GetDocument().GetFrame()->StartPrinting(page_size, page_size, 1);
GetDocument().GetFrame()->StartPrinting(page_size, 1);
EXPECT_EQ(Color::kBlack, root->GetComputedStyle()->VisitedDependentColor(
GetCSSPropertyColor()));
EXPECT_EQ(mojom::blink::ColorScheme::kLight,
@ -3180,7 +3180,7 @@ TEST_F(StyleEngineTest, PrintNoForceDarkMode) {
true);
gfx::SizeF page_size(400, 400);
GetDocument().GetFrame()->StartPrinting(page_size, page_size, 1);
GetDocument().GetFrame()->StartPrinting(page_size, 1);
EXPECT_EQ(frame_view->DocumentBackgroundColor(), Color::kWhite);
EXPECT_EQ(GetDocument().documentElement()->GetComputedStyle()->ForceDark(),
false);
@ -4288,7 +4288,7 @@ TEST_F(StyleEngineTest, AudioUAStyleNameSpace) {
EXPECT_FALSE(html_audio->GetComputedStyle());
gfx::SizeF page_size(400, 400);
GetDocument().GetFrame()->StartPrinting(page_size, page_size, 1);
GetDocument().GetFrame()->StartPrinting(page_size, 1);
// Also for printing.
EXPECT_TRUE(audio->GetComputedStyle());

@ -439,8 +439,7 @@ TEST_F(DocumentTest, PrintRelayout) {
gfx::SizeF page_size(400, 400);
float maximum_shrink_ratio = 1.6;
GetDocument().GetFrame()->StartPrinting(page_size, page_size,
maximum_shrink_ratio);
GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio);
EXPECT_EQ(GetDocument().documentElement()->OffsetWidth(), 400);
GetDocument().GetFrame()->EndPrinting();
EXPECT_EQ(GetDocument().documentElement()->OffsetWidth(), 800);
@ -1107,7 +1106,7 @@ TEST_F(DocumentTest, AtPageMarginWithDeviceScaleFactor) {
constexpr gfx::SizeF initial_page_size(800, 600);
GetDocument().GetFrame()->StartPrinting(initial_page_size, initial_page_size);
GetDocument().GetFrame()->StartPrinting(initial_page_size);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
WebPrintPageDescription description;

@ -282,7 +282,6 @@ class WebViewTest : public testing::Test {
bool SimulateTapEventAtElementById(WebInputEvent::Type,
int tap_event_count,
const WebString& id);
gfx::Size PrintICBSizeFromPageSize(const gfx::Size& page_size);
ExternalDateTimeChooser* GetExternalDateTimeChooser(
WebViewImpl* web_view_impl);
@ -2824,17 +2823,6 @@ bool WebViewTest::SimulateTapEventAtElementById(WebInputEvent::Type type,
return SimulateTapEventAtElement(type, tap_event_count, element);
}
gfx::Size WebViewTest::PrintICBSizeFromPageSize(const gfx::Size& page_size) {
// The expected layout size comes from the calculation done in
// ResizePageRectsKeepingRatio() which is used from PrintContext::begin() to
// scale the page size.
float ratio = static_cast<float>(page_size.height()) / page_size.width();
int icb_width =
floor(page_size.width() * PrintContext::kPrintingMinimumShrinkFactor);
int icb_height = floor(icb_width * ratio);
return gfx::Size(icb_width, icb_height);
}
ExternalDateTimeChooser* WebViewTest::GetExternalDateTimeChooser(
WebViewImpl* web_view_impl) {
return web_view_impl->GetChromeClient()
@ -5486,9 +5474,9 @@ TEST_F(WebViewTest, ResizeForPrintingViewportUnits) {
gfx::Size page_size(300, 360);
WebPrintParams print_params;
print_params.print_content_area.set_size(gfx::SizeF(page_size));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(page_size));
gfx::Size expected_size = PrintICBSizeFromPageSize(page_size);
gfx::Size expected_size = page_size;
frame->PrintBegin(print_params, WebNode());
@ -5532,7 +5520,7 @@ TEST_F(WebViewTest, WidthMediaQueryWithPageZoomAfterPrinting) {
gfx::SizeF page_size(300, 360);
WebPrintParams print_params;
print_params.print_content_area.set_size(page_size);
print_params.print_content_area_in_css_pixels.set_size(page_size);
frame->PrintBegin(print_params, WebNode());
frame->PrintEnd();
@ -5567,10 +5555,10 @@ TEST_F(WebViewTest, ViewportUnitsPrintingWithPageZoom) {
EXPECT_EQ(400, t2->OffsetWidth());
gfx::Size page_size(600, 720);
int expected_width = PrintICBSizeFromPageSize(page_size).width();
int expected_width = page_size.width();
WebPrintParams print_params;
print_params.print_content_area.set_size(gfx::SizeF(page_size));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(page_size));
frame->PrintBegin(print_params, WebNode());
@ -5589,7 +5577,7 @@ TEST_F(WebViewTest, ResizeWithFixedPosCrash) {
WebLocalFrameImpl* frame = web_view->MainFrameImpl();
gfx::Size page_size(300, 360);
WebPrintParams print_params;
print_params.print_content_area.set_size(gfx::SizeF(page_size));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(page_size));
frame->PrintBegin(print_params, WebNode());
web_view->MainFrameWidget()->Resize(page_size);
frame->PrintEnd();

@ -1254,20 +1254,18 @@ scoped_refptr<InspectorTaskRunner> LocalFrame::GetInspectorTaskRunner() {
}
void LocalFrame::StartPrinting(const gfx::SizeF& page_size,
const gfx::SizeF& aspect_ratio,
float maximum_shrink_ratio) {
DCHECK(!saved_scroll_offsets_);
SetPrinting(true, page_size, aspect_ratio, maximum_shrink_ratio);
SetPrinting(true, page_size, maximum_shrink_ratio);
}
void LocalFrame::EndPrinting() {
RestoreScrollOffsets();
SetPrinting(false, gfx::SizeF(), gfx::SizeF(), 0);
SetPrinting(false, gfx::SizeF(), 0);
}
void LocalFrame::SetPrinting(bool printing,
const gfx::SizeF& page_size,
const gfx::SizeF& aspect_ratio,
float maximum_shrink_ratio) {
// In setting printing, we should not validate resources already cached for
// the document. See https://bugs.webkit.org/show_bug.cgi?id=43704
@ -1282,8 +1280,7 @@ void LocalFrame::SetPrinting(bool printing,
text_autosizer->UpdatePageInfo();
if (ShouldUsePrintingLayout()) {
View()->ForceLayoutForPagination(page_size, aspect_ratio,
maximum_shrink_ratio);
View()->ForceLayoutForPagination(page_size, maximum_shrink_ratio);
} else {
if (LayoutView* layout_view = View()->GetLayoutView()) {
layout_view->SetIntrinsicLogicalWidthsDirty();

@ -387,7 +387,6 @@ class CORE_EXPORT LocalFrame final
// If this frame doesn't need to fit into a page size, default values are
// used.
void StartPrinting(const gfx::SizeF& page_size = gfx::SizeF(),
const gfx::SizeF& aspect_ratio = gfx::SizeF(),
float maximum_shrink_ratio = 0);
void EndPrinting();
@ -943,11 +942,10 @@ class CORE_EXPORT LocalFrame final
// Internal implementation for starting or ending printing.
// |printing| is true when printing starts, false when printing ends.
// |page_size|, |aspect_ratio|, and |maximum_shrink_ratio| are only
// meaningful when we should use printing layout for this frame.
// |page_size| and |maximum_shrink_ratio| are only meaningful when we should
// use printing layout for this frame.
void SetPrinting(bool printing,
const gfx::SizeF& page_size,
const gfx::SizeF& aspect_ratio,
float maximum_shrink_ratio);
// FrameScheduler::Delegate overrides:

@ -3239,7 +3239,6 @@ void LocalFrameView::DisableAutoSizeMode() {
}
void LocalFrameView::ForceLayoutForPagination(const gfx::SizeF& page_size,
const gfx::SizeF& aspect_ratio,
float maximum_shrink_factor) {
// Dumping externalRepresentation(m_frame->layoutObject()).ascii() is a good
// trick to see the state of things before and after the layout
@ -3272,8 +3271,8 @@ void LocalFrameView::ForceLayoutForPagination(const gfx::SizeF& page_size,
page_size.width() * maximum_shrink_factor),
std::min<float>(document_rect.Height().Round(),
page_size.height() * maximum_shrink_factor));
gfx::SizeF max_page_size =
frame_->ResizePageRectsKeepingRatio(aspect_ratio, expected_page_size);
gfx::SizeF max_page_size = frame_->ResizePageRectsKeepingRatio(
/* aspect_ratio */ page_size, expected_page_size);
page_logical_width = horizontal_writing_mode ? max_page_size.width()
: max_page_size.height();
layout_view->SetPageSize({LayoutUnit(max_page_size.width()),

@ -419,7 +419,6 @@ class CORE_EXPORT LocalFrameView final
void DisableAutoSizeMode();
void ForceLayoutForPagination(const gfx::SizeF& page_size,
const gfx::SizeF& aspect_ratio,
float maximum_shrink_factor);
// Updates the fragment anchor element based on URL's fragment identifier.

@ -156,7 +156,7 @@ TEST_F(LocalFrameViewTest, UpdateLifecyclePhasesForPrintingDetachedFrame) {
SetBodyInnerHTML("<iframe style='display: none'></iframe>");
SetChildFrameHTML("A");
ChildFrame().StartPrinting(gfx::SizeF(200, 200), gfx::SizeF(200, 200), 1);
ChildFrame().StartPrinting(gfx::SizeF(200, 200), 1);
ChildDocument().View()->UpdateLifecyclePhasesForPrinting();
// The following checks that the detached frame has been walked for PrePaint.
@ -172,7 +172,7 @@ TEST_F(LocalFrameViewTest, PrintFrameUpdateAllLifecyclePhases) {
SetBodyInnerHTML("<iframe></iframe>");
SetChildFrameHTML("A");
ChildFrame().StartPrinting(gfx::SizeF(200, 200), gfx::SizeF(200, 200), 1);
ChildFrame().StartPrinting(gfx::SizeF(200, 200), 1);
ChildDocument().View()->UpdateLifecyclePhasesForPrinting();
EXPECT_EQ(DocumentLifecycle::kPrePaintClean,

@ -9117,7 +9117,7 @@ TEST_F(WebFrameTest, PrintingBasic)
WebLocalFrame* frame = web_view_helper.LocalMainFrame();
WebPrintParams print_params;
print_params.print_content_area.set_size(gfx::SizeF(500, 500));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(500, 500));
uint32_t page_count = frame->PrintBegin(print_params, WebNode());
EXPECT_EQ(1u, page_count);
@ -13086,8 +13086,7 @@ TEST_F(WebFrameSimTest, DisplayNoneIFramePrints) {
gfx::SizeF page_size(400, 400);
float maximum_shrink_ratio = 1.0;
iframe_doc->GetFrame()->StartPrinting(page_size, page_size,
maximum_shrink_ratio);
iframe_doc->GetFrame()->StartPrinting(page_size, maximum_shrink_ratio);
EXPECT_TRUE(iframe_doc->documentElement()->GetLayoutObject());
iframe_doc->GetFrame()->EndPrinting();
@ -13537,7 +13536,7 @@ TEST_F(WebFrameTest, AltTextOnAboutBlankPage) {
static void TestFramePrinting(WebLocalFrameImpl* frame) {
WebPrintParams print_params;
gfx::Size page_size(500, 500);
print_params.print_content_area.set_size(gfx::SizeF(page_size));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(page_size));
EXPECT_EQ(1u, frame->PrintBegin(print_params, WebNode()));
cc::PaintRecorder recorder;
frame->PrintPagesForTesting(recorder.beginRecording(), page_size, page_size);
@ -13601,7 +13600,7 @@ std::vector<TextRunDOMNodeIdInfo> GetPrintedTextRunDOMNodeIds(
const WebVector<uint32_t>* pages = nullptr) {
WebPrintParams print_params;
gfx::Size page_size(500, 500);
print_params.print_content_area.set_size(gfx::SizeF(page_size));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(page_size));
frame->PrintBegin(print_params, WebNode());
cc::PaintRecorder recorder;
@ -13838,7 +13837,7 @@ TEST_F(WebFrameSimTest, PageOrientation) {
auto* frame = WebView().MainFrame()->ToWebLocalFrame();
WebPrintParams print_params;
print_params.print_content_area.set_size(gfx::SizeF(page_size));
print_params.print_content_area_in_css_pixels.set_size(gfx::SizeF(page_size));
EXPECT_EQ(4u, frame->PrintBegin(print_params, WebNode()));
WebPrintPageDescription description;

@ -339,7 +339,7 @@ class ChromePrintContext : public PrintContext {
~ChromePrintContext() override = default;
void BeginPrintMode(float width, float height) override {
void BeginPrintMode(gfx::SizeF page_size) override {
DCHECK(!printed_page_width_);
// Although layout itself can handle subpixels, we'll round down to the
@ -352,11 +352,11 @@ class ChromePrintContext : public PrintContext {
//
// TODO(mstensho): Refactor page rectangle calculation, and update the
// comment above.
width = floorf(width);
height = floorf(height);
page_size.set_width(floorf(page_size.width()));
page_size.set_height(floorf(page_size.height()));
printed_page_width_ = width;
PrintContext::BeginPrintMode(printed_page_width_, height);
printed_page_width_ = page_size.width();
PrintContext::BeginPrintMode(page_size);
}
virtual float GetPageShrink(uint32_t page_number) const {
@ -459,11 +459,14 @@ class ChromePrintContext : public PrintContext {
current_height += page_size_in_pixels.width() + 1;
}
// Account for the disabling of scaling in spoolPage. In the context of
// SpoolPagesWithBoundariesForTesting the scale HAS NOT been
// pre-applied.
float scale = GetPageShrink(page_index);
// TODO(crbug.com/1450167): Remove weird scaling, and rebaseline / rewrite
// tests instead. We previously converted from points to pixels inside
// PrintContext, but not anymore. In order to avoid minor pixel
// differences in tests, we need to use the actual widths involved, rather
// than 72/96 directly.
float scale = page_size_in_pixels.width() / printed_page_width_;
transform.Scale(scale, scale);
context.Save();
context.ConcatCTM(transform);
@ -479,6 +482,12 @@ class ChromePrintContext : public PrintContext {
virtual void SpoolPage(GraphicsContext& context, int page_number) {
gfx::Rect page_rect = page_rects_[page_number];
AffineTransform transform;
// Layout may have scaled down content in order to fit more unbreakable
// content in the inline direction.
float scale = GetPageShrink(page_number);
transform.Scale(scale, scale);
transform.Translate(static_cast<float>(-page_rect.x()),
static_cast<float>(-page_rect.y()));
context.Save();
@ -545,9 +554,9 @@ class ChromePluginPrintContext final : public ChromePrintContext {
ChromePrintContext::Trace(visitor);
}
void BeginPrintMode(float width, float height) override {
gfx::Rect rect(gfx::ToFlooredSize(gfx::SizeF(width, height)));
print_params_.print_content_area = gfx::RectF(rect);
void BeginPrintMode(gfx::SizeF page_size) override {
gfx::Rect rect(gfx::ToFlooredSize(page_size));
print_params_.print_content_area_in_css_pixels = gfx::RectF(page_size);
page_rects_.Fill(rect, plugin_->PrintBegin(print_params_));
}
@ -1918,17 +1927,12 @@ uint32_t WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
GetFrame(), print_params.use_printing_layout);
}
gfx::SizeF size(print_params.print_content_area.size());
print_context_->BeginPrintMode(size.width(), size.height());
gfx::SizeF size(print_params.print_content_area_in_css_pixels.size());
print_context_->BeginPrintMode(size);
return print_context_->PageCount();
}
float WebLocalFrameImpl::GetPrintPageShrink(uint32_t page) {
DCHECK(print_context_);
return print_context_->GetPageShrink(page);
}
void WebLocalFrameImpl::PrintPage(uint32_t page, cc::PaintCanvas* canvas) {
DCHECK(print_context_);
DCHECK(GetFrame());

@ -311,7 +311,6 @@ class CORE_EXPORT WebLocalFrameImpl final
uint32_t PrintBegin(const WebPrintParams&,
const WebNode& constrain_to_node) override;
bool WillPrintSoon() override;
float GetPrintPageShrink(uint32_t page) override;
void PrintPage(uint32_t page_to_print, cc::PaintCanvas*) override;
void PrintEnd() override;
void DispatchAfterPrintEvent() override;

@ -715,8 +715,18 @@ String ExternalRepresentation(LocalFrame* frame,
PrintContext print_context(frame, /*use_printing_layout=*/true);
bool is_text_printing_mode = !!(behavior & kLayoutAsTextPrintingMode);
if (is_text_printing_mode) {
print_context.BeginPrintMode(layout_box->ClientWidth(),
layout_box->ClientHeight());
gfx::SizeF page_size(layout_box->ClientWidth(), layout_box->ClientHeight());
// TODO(crbug.com/1450167): Get rid of this conversion, and rebaseline /
// rewrite tests, and use page_size_in_pixels everywhere. There used to be
// some pixel vs points confusion.
static constexpr float kPrintingMinimumShrinkFactor = 1.33333333f;
page_size.set_width(
floorf(page_size.width() * kPrintingMinimumShrinkFactor));
page_size.set_height(
floorf(page_size.height() * kPrintingMinimumShrinkFactor));
print_context.BeginPrintMode(page_size);
// The lifecycle needs to be run again after changing printing mode,
// to account for any style updates due to media query change.

@ -103,7 +103,7 @@ TEST_F(LayoutViewTest, NamedPages) {
ASSERT_TRUE(view);
ScopedPrintContext print_context(&GetDocument().View()->GetFrame());
print_context->BeginPrintMode(500, 500);
print_context->BeginPrintMode(gfx::SizeF(500, 500));
EXPECT_EQ(view->NamedPageAtIndex(0), AtomicString());
EXPECT_EQ(view->NamedPageAtIndex(1), AtomicString());
@ -139,7 +139,7 @@ TEST_F(LayoutViewTest, NamedPagesAbsPos) {
ASSERT_TRUE(view);
ScopedPrintContext print_context(&GetDocument().View()->GetFrame());
print_context->BeginPrintMode(500, 500);
print_context->BeginPrintMode(gfx::SizeF(500, 500));
EXPECT_EQ(view->NamedPageAtIndex(0), "woohoo");
EXPECT_EQ(view->NamedPageAtIndex(1), "woohoo");

@ -1104,7 +1104,7 @@ TEST_F(TextAutosizerTest, AfterPrint) {
Element* target = GetDocument().getElementById("target");
EXPECT_FLOAT_EQ(20.0f * device_scale,
target->GetLayoutObject()->StyleRef().ComputedFontSize());
GetDocument().GetFrame()->StartPrinting(print_size, print_size, 1.0);
GetDocument().GetFrame()->StartPrinting(print_size, 1.0);
EXPECT_FLOAT_EQ(8.0f,
target->GetLayoutObject()->StyleRef().ComputedFontSize());
GetDocument().GetFrame()->EndPrinting();

@ -120,31 +120,29 @@ void PrintContext::ComputePageRects(const gfx::SizeF& print_size) {
}
}
void PrintContext::BeginPrintMode(float width, float height) {
DCHECK_GT(width, 0);
DCHECK_GT(height, 0);
void PrintContext::BeginPrintMode(gfx::SizeF page_size) {
DCHECK_GT(page_size.width(), 0);
DCHECK_GT(page_size.height(), 0);
// This function can be called multiple times to adjust printing parameters
// without going back to screen mode.
is_printing_ = true;
gfx::SizeF aspect_ratio(width, height);
gfx::SizeF floored_min_layout_size = frame_->ResizePageRectsKeepingRatio(
aspect_ratio, gfx::SizeF(width * kPrintingMinimumShrinkFactor,
height * kPrintingMinimumShrinkFactor));
const Settings* settings = frame_->GetSettings();
DCHECK(settings);
// TODO(crbug.com/1296099): It would be better if the actual shrink factor was
// stored in settings, rather than something that has to be divided by
// 1.3333...
static constexpr float kPrintingMinimumShrinkFactor = 1.33333333f;
float printingMaximumShrinkFactor =
settings->GetPrintingMaximumShrinkFactor();
// This changes layout, so callers need to make sure that they don't paint to
// screen while in printing mode.
frame_->StartPrinting(
floored_min_layout_size, aspect_ratio,
printingMaximumShrinkFactor / kPrintingMinimumShrinkFactor);
page_size, printingMaximumShrinkFactor / kPrintingMinimumShrinkFactor);
ComputePageRects(gfx::SizeF(width, height));
ComputePageRects(page_size);
}
void PrintContext::EndPrintMode() {
@ -168,9 +166,8 @@ int PrintContext::PageNumberForElement(Element* element,
element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kPrinting);
LocalFrame* frame = element->GetDocument().GetFrame();
gfx::RectF page_rect(page_size_in_pixels);
ScopedPrintContext print_context(frame);
print_context->BeginPrintMode(page_rect.width(), page_rect.height());
print_context->BeginPrintMode(page_size_in_pixels);
LayoutBoxModelObject* box =
EnclosingBoxModelObject(element->GetLayoutObject());
@ -237,7 +234,7 @@ String PrintContext::PageProperty(LocalFrame* frame,
// Any non-zero size is OK here. We don't care about actual layout. We just
// want to collect @page rules and figure out what declarations apply on a
// given page (that may or may not exist).
print_context->BeginPrintMode(800, 1000);
print_context->BeginPrintMode(gfx::SizeF(800, 1000));
scoped_refptr<const ComputedStyle> style =
document->StyleForPage(page_number);
@ -297,8 +294,7 @@ int PrintContext::NumberOfPages(LocalFrame* frame,
frame->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kPrinting);
ScopedPrintContext print_context(frame);
print_context->BeginPrintMode(page_size_in_pixels.width(),
page_size_in_pixels.height());
print_context->BeginPrintMode(page_size_in_pixels);
return print_context->PageCount();
}

@ -29,10 +29,7 @@
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "ui/gfx/geometry/rect.h"
namespace gfx {
class SizeF;
}
#include "ui/gfx/geometry/size_f.h"
namespace blink {
@ -43,13 +40,6 @@ class Node;
class CORE_EXPORT PrintContext : public GarbageCollected<PrintContext> {
public:
// By shrinking to a width of 75%, we will render the correct physical
// dimensions in paged media (i.e. cm, pt,). The shrinkage used
// to be 80% to match other browsers - they have since moved on.
// Wide pages will be scaled down more than this.
// This value is the percentage inverted.
static constexpr float kPrintingMinimumShrinkFactor = 1.33333333f;
PrintContext(LocalFrame*, bool use_printing_layout);
virtual ~PrintContext();
@ -65,7 +55,7 @@ class CORE_EXPORT PrintContext : public GarbageCollected<PrintContext> {
// Enter print mode, updating layout for new page size.
// This function can be called multiple times to apply new print options
// without going back to screen mode.
virtual void BeginPrintMode(float width, float height = 0);
virtual void BeginPrintMode(gfx::SizeF page_size);
// Return to screen mode.
virtual void EndPrintMode();

@ -134,7 +134,7 @@ class PrintContextTest : public PaintTestConfigurations, public RenderingTest {
GetDocument().SetPrinting(Document::kBeforePrinting);
Event* event = MakeGarbageCollected<BeforePrintEvent>();
GetPrintContext().GetFrame()->DomWindow()->DispatchEvent(*event);
GetPrintContext().BeginPrintMode(kPageWidth, kPageHeight);
GetPrintContext().BeginPrintMode(gfx::SizeF(kPageWidth, kPageHeight));
GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
DocumentUpdateReason::kTest);
@ -678,7 +678,7 @@ TEST_P(PrintContextTest, SvgMarkersOnMultiplePages) {
PrintSinglePage(first_page_canvas, 0);
MockCanvas second_page_canvas;
EXPECT_CALL(second_page_canvas, didTranslate(0, 799)).Times(1);
EXPECT_CALL(second_page_canvas, didTranslate(0, kPageHeight)).Times(1);
EXPECT_CALL(second_page_canvas, didTranslate(2, 0)).Times(1);
EXPECT_CALL(second_page_canvas, onDrawRect(SkRect::MakeWH(50, 25), _))
.Times(1);
@ -753,8 +753,7 @@ TEST_P(PrintContextFrameTest, BasicPrintPageLayout) {
float maximum_shrink_ratio = 1.1;
auto* node = GetDocument().documentElement();
GetDocument().GetFrame()->StartPrinting(page_size, page_size,
maximum_shrink_ratio);
GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio);
EXPECT_EQ(node->OffsetWidth(), 400);
GetDocument().GetFrame()->EndPrinting();
EXPECT_EQ(node->OffsetWidth(), 800);
@ -762,8 +761,7 @@ TEST_P(PrintContextFrameTest, BasicPrintPageLayout) {
SetBodyInnerHTML(R"HTML(
<div style='border: 0px; margin: 0px; background-color: #0000FF;
width:800px; height:400px'></div>)HTML");
GetDocument().GetFrame()->StartPrinting(page_size, page_size,
maximum_shrink_ratio);
GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio);
EXPECT_EQ(node->OffsetWidth(), 440);
GetDocument().GetFrame()->EndPrinting();
EXPECT_EQ(node->OffsetWidth(), 800);
@ -1110,8 +1108,7 @@ TEST_P(PrintContextFrameTest, DISABLED_SubframePrintPageLayout) {
// The iframe element in the document.
auto* target = GetDocument().getElementById("target");
GetDocument().GetFrame()->StartPrinting(page_size, page_size,
maximum_shrink_ratio);
GetDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio);
EXPECT_EQ(parent->OffsetWidth(), 440);
EXPECT_EQ(child->OffsetWidth(), 800);
EXPECT_EQ(target->OffsetWidth(), 440);
@ -1130,8 +1127,7 @@ TEST_P(PrintContextFrameTest, DISABLED_SubframePrintPageLayout) {
EXPECT_EQ(target->OffsetWidth(), 800);
ASSERT_TRUE(ChildDocument() != GetDocument());
ChildDocument().GetFrame()->StartPrinting(page_size, page_size,
maximum_shrink_ratio);
ChildDocument().GetFrame()->StartPrinting(page_size, maximum_shrink_ratio);
EXPECT_EQ(parent->OffsetWidth(), 800);
EXPECT_EQ(child->OffsetWidth(), 400);
EXPECT_EQ(target->OffsetWidth(), 800);

@ -5442,7 +5442,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameClipWhenPrinting) {
// When the main frame is printing, it should not have content clip.
gfx::SizeF page_size(100, 100);
GetFrame().StartPrinting(page_size, page_size, 1);
GetFrame().StartPrinting(page_size, 1);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
EXPECT_EQ(nullptr, DocContentClip(main_frame_doc));
EXPECT_CLIP_RECT(gfx::RectF(0, 0, 300, 150), DocContentClip(child_frame_doc));
@ -5452,7 +5452,7 @@ TEST_P(PaintPropertyTreeBuilderTest, FrameClipWhenPrinting) {
// When only the child frame is printing, it should not have content clip but
// the main frame still have (which doesn't matter though).
ChildFrame().StartPrinting(page_size, page_size, 1);
ChildFrame().StartPrinting(page_size, 1);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
ASSERT_NE(nullptr, DocContentClip(main_frame_doc));
EXPECT_CLIP_RECT(gfx::RectF(0, 0, 800, 600), DocContentClip(main_frame_doc));
@ -5773,7 +5773,7 @@ TEST_P(PaintPropertyTreeBuilderTest, RepeatingFixedPositionInPagedMedia) {
EXPECT_EQ(1u, NumFragments(normal));
gfx::SizeF page_size(300, 400);
GetFrame().StartPrinting(page_size, page_size, 1);
GetFrame().StartPrinting(page_size, 1);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
fixed = GetLayoutObjectByElementId("fixed");
fixed_child = GetLayoutObjectByElementId("fixed-child");
@ -5836,7 +5836,7 @@ TEST_P(PaintPropertyTreeBuilderTest,
EXPECT_EQ(1u, NumFragments(fixed_child));
gfx::SizeF page_size(300, 400);
GetFrame().StartPrinting(page_size, page_size, 1);
GetFrame().StartPrinting(page_size, 1);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
fixed = GetLayoutObjectByElementId("fixed");
fixed_child = GetLayoutObjectByElementId("fixed-child");

@ -141,7 +141,7 @@ TEST_F(TextPainterTest,
CSSPropertyID::kWebkitPrintColorAdjust, CSSValueID::kEconomy);
GetDocument().GetSettings()->SetShouldPrintBackgrounds(false);
gfx::SizeF page_size(500, 800);
GetFrame().StartPrinting(page_size, page_size, 1);
GetFrame().StartPrinting(page_size, 1);
UpdateAllLifecyclePhasesForTest();
// In LayoutNG, printing currently forces layout tree reattachment,
// so we need to re-get layout_text_.
@ -166,7 +166,7 @@ TEST_F(TextPainterTest, TextPaintingStyle_ForceBackgroundToWhite_Darkened) {
CSSPropertyID::kWebkitPrintColorAdjust, CSSValueID::kEconomy);
GetDocument().GetSettings()->SetShouldPrintBackgrounds(false);
gfx::SizeF page_size(500, 800);
GetFrame().StartPrinting(page_size, page_size, 1);
GetFrame().StartPrinting(page_size, 1);
GetDocument().View()->UpdateLifecyclePhasesForPrinting();
// In LayoutNG, printing currently forces layout tree reattachment,
// so we need to re-get layout_text_.

@ -1,8 +1,8 @@
layer at (0,0) scrollHeight 1598
LayoutNGView at (0,0) size 1066x799
layer at (0,0) scrollHeight 1600
LayoutNGView at (0,0) size 1066x800
layer at (0,0)
LayoutNGBlockFlow {HTML} at (0,0) size 1066x827
LayoutNGBlockFlow {BODY} at (8,16) size 1050x803
LayoutNGBlockFlow {HTML} at (0,0) size 1066x828
LayoutNGBlockFlow {BODY} at (8,16) size 1050x804
LayoutNGBlockFlow {P} at (0,0) size 1050x40
LayoutText {#text} at (0,0) size 1010x39
text run at (0,0) width 1010: "This is a test that only dumps the layout tree, and doesn't actually display the page. This tests some peculiarities in the test framework for printing. To run this test"
@ -10,6 +10,6 @@ layer at (0,0)
LayoutNGBlockFlow {DIV} at (0,56) size 1050x20
LayoutText {#text} at (0,0) size 163x19
text run at (0,0) width 163: "This should be on page 1."
LayoutNGBlockFlow {DIV} at (0,783) size 1050x20
LayoutNGBlockFlow {DIV} at (0,784) size 1050x20
LayoutText {#text} at (0,0) size 163x19
text run at (0,0) width 163: "This should be on page 2."

@ -0,0 +1 @@
Document has 36 pages.

Binary file not shown.

Before

(image error) Size: 32 KiB

After

(image error) Size: 32 KiB

@ -1,8 +1,8 @@
layer at (0,0) scrollHeight 1598
LayoutNGView at (0,0) size 1066x799
layer at (0,0) scrollHeight 1600
LayoutNGView at (0,0) size 1066x800
layer at (0,0)
LayoutNGBlockFlow {HTML} at (0,0) size 1066x825
LayoutNGBlockFlow {BODY} at (8,16) size 1050x801
LayoutNGBlockFlow {HTML} at (0,0) size 1066x826
LayoutNGBlockFlow {BODY} at (8,16) size 1050x802
LayoutNGBlockFlow {P} at (0,0) size 1050x36
LayoutText {#text} at (0,0) size 1035x36
text run at (0,0) width 1035: "This is a test that only dumps the layout tree, and doesn't actually display the page. This tests some peculiarities in the test framework for printing. To run this test"
@ -10,6 +10,6 @@ layer at (0,0)
LayoutNGBlockFlow {DIV} at (0,52) size 1050x18
LayoutText {#text} at (0,0) size 165x18
text run at (0,0) width 165: "This should be on page 1."
LayoutNGBlockFlow {DIV} at (0,783) size 1050x18
LayoutNGBlockFlow {DIV} at (0,784) size 1050x18
LayoutText {#text} at (0,0) size 165x18
text run at (0,0) width 165: "This should be on page 2."

@ -0,0 +1 @@
Document has 31 pages.

Binary file not shown.

Before

(image error) Size: 22 KiB

After

(image error) Size: 22 KiB

@ -1,8 +1,8 @@
layer at (0,0) scrollHeight 1598
LayoutNGView at (0,0) size 1066x799
layer at (0,0) scrollHeight 1600
LayoutNGView at (0,0) size 1066x800
layer at (0,0)
LayoutNGBlockFlow {HTML} at (0,0) size 1066x827
LayoutNGBlockFlow {BODY} at (8,16) size 1050x803
LayoutNGBlockFlow {HTML} at (0,0) size 1066x828
LayoutNGBlockFlow {BODY} at (8,16) size 1050x804
LayoutNGBlockFlow {P} at (0,0) size 1050x40
LayoutText {#text} at (0,0) size 1041x39
text run at (0,0) width 1041: "This is a test that only dumps the layout tree, and doesn't actually display the page. This tests some peculiarities in the test framework for printing. To run this test manually, run"
@ -10,6 +10,6 @@ layer at (0,0)
LayoutNGBlockFlow {DIV} at (0,56) size 1050x20
LayoutText {#text} at (0,0) size 155x19
text run at (0,0) width 155: "This should be on page 1."
LayoutNGBlockFlow {DIV} at (0,783) size 1050x20
LayoutNGBlockFlow {DIV} at (0,784) size 1050x20
LayoutText {#text} at (0,0) size 155x19
text run at (0,0) width 155: "This should be on page 2."

@ -1 +1 @@
Document has 34 pages.
Document has 38 pages.

Binary file not shown.

Before

(image error) Size: 22 KiB

After

(image error) Size: 22 KiB

@ -1,8 +1,8 @@
layer at (0,0)
LayoutNGView at (0,0) size 1066x799
LayoutNGView at (0,0) size 1066x800
layer at (0,0)
LayoutNGBlockFlow {HTML} at (0,0) size 1066x799
LayoutNGBlockFlow {BODY} at (8,8) size 1050x783
LayoutNGBlockFlow {HTML} at (0,0) size 1066x800
LayoutNGBlockFlow {BODY} at (8,8) size 1050x784
LayoutText {#text} at (0,0) size 0x0
layer at (8,8)
LayoutIFrame {IFRAME} at (0,0) size 204x204 [border: (2px inset #EEEEEE)]