diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-12 16:34:40 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-12 16:34:40 +0000 |
commit | b2b0fceea58bf7e13cc73020133aff6d6b4f4640 (patch) | |
tree | 4e6991eb82096663c5072a3c28183036d1215acd | |
parent | 76fcc3e9dc467366b9d1938834d7faff595ab873 (diff) | |
download | chromium_src-b2b0fceea58bf7e13cc73020133aff6d6b4f4640.zip chromium_src-b2b0fceea58bf7e13cc73020133aff6d6b4f4640.tar.gz chromium_src-b2b0fceea58bf7e13cc73020133aff6d6b4f4640.tar.bz2 |
When printing a page containing alpha blending on a printer which doesn't support alpha blending, post-process the
metafile to replace the AlphaBlend calls with BitBlts from a software-composited rendering of the page so far.
BUG=7434
TEST=see bug
Review URL: http://codereview.chromium.org/5362002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71177 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/renderer_host/render_message_filter.cc | 1 | ||||
-rw-r--r-- | chrome/common/render_messages_params.cc | 13 | ||||
-rw-r--r-- | chrome/common/render_messages_params.h | 5 | ||||
-rw-r--r-- | chrome/renderer/print_web_view_helper_win.cc | 102 | ||||
-rw-r--r-- | printing/emf_win.cc | 2 | ||||
-rw-r--r-- | printing/print_settings.cc | 4 | ||||
-rw-r--r-- | printing/print_settings.h | 7 | ||||
-rw-r--r-- | printing/print_settings_initializer_win.cc | 3 | ||||
-rw-r--r-- | skia/ext/vector_platform_device_win.cc | 5 | ||||
-rw-r--r-- | skia/ext/vector_platform_device_win.h | 4 |
10 files changed, 134 insertions, 12 deletions
diff --git a/chrome/browser/renderer_host/render_message_filter.cc b/chrome/browser/renderer_host/render_message_filter.cc index 73af165..a0696b5 100644 --- a/chrome/browser/renderer_host/render_message_filter.cc +++ b/chrome/browser/renderer_host/render_message_filter.cc @@ -162,6 +162,7 @@ void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, // Always use an invalid cookie. params->document_cookie = 0; params->selection_only = settings.selection_only; + params->supports_alpha_blend = settings.supports_alpha_blend(); } class ClearCacheCompletion : public net::CompletionCallback { diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc index 7fab193..a05266c 100644 --- a/chrome/common/render_messages_params.cc +++ b/chrome/common/render_messages_params.cc @@ -81,7 +81,8 @@ ViewMsg_Print_Params::ViewMsg_Print_Params() max_shrink(0), desired_dpi(0), document_cookie(0), - selection_only(false) { + selection_only(false), + supports_alpha_blend(true) { } ViewMsg_Print_Params::~ViewMsg_Print_Params() { @@ -96,13 +97,15 @@ bool ViewMsg_Print_Params::Equals(const ViewMsg_Print_Params& rhs) const { min_shrink == rhs.min_shrink && max_shrink == rhs.max_shrink && desired_dpi == rhs.desired_dpi && - selection_only == rhs.selection_only; + selection_only == rhs.selection_only && + supports_alpha_blend == rhs.supports_alpha_blend; } bool ViewMsg_Print_Params::IsEmpty() const { return !document_cookie && !desired_dpi && !max_shrink && !min_shrink && !dpi && printable_size.IsEmpty() && !selection_only && - page_size.IsEmpty() && !margin_top && !margin_left; + page_size.IsEmpty() && !margin_top && !margin_left && + !supports_alpha_blend; } ViewMsg_PrintPage_Params::ViewMsg_PrintPage_Params() @@ -952,6 +955,7 @@ void ParamTraits<ViewMsg_Print_Params>::Write(Message* m, const param_type& p) { WriteParam(m, p.desired_dpi); WriteParam(m, p.document_cookie); WriteParam(m, p.selection_only); + WriteParam(m, p.supports_alpha_blend); } bool ParamTraits<ViewMsg_Print_Params>::Read(const Message* m, @@ -966,7 +970,8 @@ bool ParamTraits<ViewMsg_Print_Params>::Read(const Message* m, ReadParam(m, iter, &p->max_shrink) && ReadParam(m, iter, &p->desired_dpi) && ReadParam(m, iter, &p->document_cookie) && - ReadParam(m, iter, &p->selection_only); + ReadParam(m, iter, &p->selection_only) && + ReadParam(m, iter, &p->supports_alpha_blend); } void ParamTraits<ViewMsg_Print_Params>::Log(const param_type& p, diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h index 97817d2..0523fdf 100644 --- a/chrome/common/render_messages_params.h +++ b/chrome/common/render_messages_params.h @@ -520,6 +520,9 @@ struct ViewMsg_Print_Params { // Should only print currently selected text. bool selection_only; + // Does the printer support alpha blending? + bool supports_alpha_blend; + // Warning: do not compare document_cookie. bool Equals(const ViewMsg_Print_Params& rhs) const; @@ -552,7 +555,7 @@ struct ViewMsg_PrintPages_Params { std::vector<int> pages; }; -//Parameters to describe a rendered document. +// Parameters to describe a rendered document. struct ViewHostMsg_DidPreviewDocument_Params { ViewHostMsg_DidPreviewDocument_Params(); ~ViewHostMsg_DidPreviewDocument_Params(); diff --git a/chrome/renderer/print_web_view_helper_win.cc b/chrome/renderer/print_web_view_helper_win.cc index bd1e595..22c6e00 100644 --- a/chrome/renderer/print_web_view_helper_win.cc +++ b/chrome/renderer/print_web_view_helper_win.cc @@ -8,11 +8,13 @@ #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" #include "chrome/renderer/render_view.h" +#include "gfx/gdi_util.h" #include "gfx/size.h" #include "grit/generated_resources.h" #include "printing/native_metafile.h" #include "printing/units.h" #include "skia/ext/vector_canvas.h" +#include "skia/ext/vector_platform_device.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" using printing::ConvertUnitDouble; @@ -20,6 +22,46 @@ using printing::kPointsPerInch; using WebKit::WebFrame; using WebKit::WebString; +int CALLBACK EnhMetaFileProc(HDC dc, + HANDLETABLE* handle_table, + const ENHMETARECORD *record, + int num_objects, + LPARAM data) { + HDC* bitmap_dc = reinterpret_cast<HDC*>(data); + // Play this command to the bitmap DC. + PlayEnhMetaFileRecord(*bitmap_dc, handle_table, record, num_objects); + if (record->iType == EMR_ALPHABLEND) { + const EMRALPHABLEND* emr_alpha_blend = + reinterpret_cast<const EMRALPHABLEND*>(record); + XFORM bitmap_dc_transform, metafile_dc_transform; + XFORM identity = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; + // Temporarily set the world transforms of both DC's to identity. + GetWorldTransform(dc, &metafile_dc_transform); + SetWorldTransform(dc, &identity); + GetWorldTransform(*bitmap_dc, &bitmap_dc_transform); + SetWorldTransform(*bitmap_dc, &identity); + const RECTL& rect = emr_alpha_blend->rclBounds; + // Since the printer does not support alpha blend, copy the alpha blended + // region from our (software-rendered) bitmap DC to the metafile DC. + BitBlt(dc, + rect.left, + rect.top, + rect.right - rect.left + 1, + rect.bottom - rect.top + 1, + *bitmap_dc, + rect.left, + rect.top, + SRCCOPY); + // Restore the world transforms of both DC's. + SetWorldTransform(dc, &metafile_dc_transform); + SetWorldTransform(*bitmap_dc, &bitmap_dc_transform); + } else { + // Play this command to the metafile DC. + PlayEnhMetaFileRecord(dc, handle_table, record, num_objects); + } + return 1; // Continue enumeration +} + void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, const gfx::Size& canvas_size, WebFrame* frame) { @@ -64,8 +106,8 @@ void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, // Mix of Skia and GDI based. skia::PlatformCanvas canvas(size_x, size_y, true); - canvas.drawARGB(255, 255, 255, 255, SkPorterDuff::kSrc_Mode); - float webkit_shrink = frame->PrintPage(params.page_number, &canvas); + canvas.drawARGB(255, 255, 255, 255, SkXfermode::kSrc_Mode); + float webkit_shrink = frame->printPage(params.page_number, &canvas); if (shrink <= 0 || webkit_shrink <= 0) { NOTREACHED() << "Printing page " << params.page_number << " failed."; } else { @@ -105,9 +147,59 @@ void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, if (!metafile.CloseDc()) { NOTREACHED() << "metafile failed"; } + printing::NativeMetafile* mf = &metafile; + printing::NativeMetafile metafile2; + + skia::VectorPlatformDevice* platform_device = + static_cast<skia::VectorPlatformDevice*>(canvas.getDevice()); + if (platform_device->alpha_blend_used() && + !params.params.supports_alpha_blend) { + // Page used alpha blend, but printer doesn't support it. Rewrite the + // metafile and flatten out the transparency. + HDC bitmap_dc = CreateCompatibleDC(GetDC(NULL)); + if (!bitmap_dc) { + NOTREACHED() << "Bitmap DC creation failed"; + } + SetGraphicsMode(bitmap_dc, GM_ADVANCED); + void* bits = NULL; + BITMAPINFO hdr; + gfx::CreateBitmapHeader(size_x, size_y, &hdr.bmiHeader); + HBITMAP hbitmap = CreateDIBSection( + bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0); + if (!hbitmap) { + NOTREACHED() << "Raster bitmap creation for printing failed"; + } + + HGDIOBJ old_bitmap = SelectObject(bitmap_dc, hbitmap); + RECT rect = {0, 0, size_x, size_y }; + HBRUSH whiteBrush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)); + FillRect(bitmap_dc, &rect, whiteBrush); + + metafile2.CreateDc(NULL, NULL); + HDC hdc = metafile2.hdc(); + DCHECK(hdc); + skia::PlatformDevice::InitializeDC(hdc); + + RECT metafile_bounds = metafile.GetBounds().ToRECT(); + // Process the old metafile, placing all non-AlphaBlend calls into the + // new metafile, and copying the results of all the AlphaBlend calls + // from the bitmap DC. + EnumEnhMetaFile(hdc, + metafile.emf(), + EnhMetaFileProc, + &bitmap_dc, + &metafile_bounds); + + SelectObject(bitmap_dc, old_bitmap); + + if (!metafile2.CloseDc()) { + NOTREACHED() << "metafile failed"; + } + mf = &metafile2; + } // Get the size of the compiled metafile. - uint32 buf_size = metafile.GetDataSize(); + uint32 buf_size = mf->GetDataSize(); DCHECK_GT(buf_size, 128u); ViewHostMsg_DidPrintPage_Params page_params; page_params.data_size = 0; @@ -144,7 +236,7 @@ void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, // Allocate a shared memory buffer to hold the generated metafile data. if (shared_buf.CreateAndMapAnonymous(buf_size)) { // Copy the bits into shared memory. - if (metafile.GetData(shared_buf.memory(), buf_size)) { + if (mf->GetData(shared_buf.memory(), buf_size)) { page_params.metafile_data_handle = shared_buf.handle(); page_params.data_size = buf_size; } else { @@ -157,7 +249,7 @@ void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params, } else { NOTREACHED() << "Buffer too large: " << buf_size; } - metafile.CloseEmf(); + mf->CloseEmf(); if (Send(new ViewHostMsg_DuplicateSection( routing_id(), page_params.metafile_data_handle, diff --git a/printing/emf_win.cc b/printing/emf_win.cc index 9629bb2..5de962b 100644 --- a/printing/emf_win.cc +++ b/printing/emf_win.cc @@ -396,6 +396,8 @@ bool Emf::Record::SafePlayback(const XFORM* base_matrix) const { } else { res = Play(); } + } else { + res = true; } break; } diff --git a/printing/print_settings.cc b/printing/print_settings.cc index cf8c50a..3f0f842 100644 --- a/printing/print_settings.cc +++ b/printing/print_settings.cc @@ -19,7 +19,8 @@ PrintSettings::PrintSettings() selection_only(false), use_overlays(true), dpi_(0), - landscape_(false) { + landscape_(false), + supports_alpha_blend_(true) { } PrintSettings::~PrintSettings() { @@ -36,6 +37,7 @@ void PrintSettings::Clear() { page_setup_device_units_.Clear(); dpi_ = 0; landscape_ = false; + supports_alpha_blend_ = true; } void PrintSettings::SetPrinterPrintableArea( diff --git a/printing/print_settings.h b/printing/print_settings.h index bc9cbaf..298fcd2 100644 --- a/printing/print_settings.h +++ b/printing/print_settings.h @@ -42,6 +42,10 @@ class PrintSettings { const std::wstring& device_name() const { return device_name_; } void set_dpi(int dpi) { dpi_ = dpi; } int dpi() const { return dpi_; } + void set_supports_alpha_blend(bool supports_alpha_blend) { + supports_alpha_blend_ = supports_alpha_blend; + } + bool supports_alpha_blend() const { return supports_alpha_blend_; } const PageSetup& page_setup_device_units() const { return page_setup_device_units_; } @@ -108,6 +112,9 @@ class PrintSettings { // Is the orientation landscape or portrait. bool landscape_; + + // True if this printer supports AlphaBlend. + bool supports_alpha_blend_; }; } // namespace printing diff --git a/printing/print_settings_initializer_win.cc b/printing/print_settings_initializer_win.cc index f840f4d..065a8db 100644 --- a/printing/print_settings_initializer_win.cc +++ b/printing/print_settings_initializer_win.cc @@ -29,6 +29,9 @@ void PrintSettingsInitializerWin::InitPrintSettings( int dpi = GetDeviceCaps(hdc, LOGPIXELSX); print_settings->set_dpi(dpi); + const int kAlphaCaps = SB_CONST_ALPHA | SB_PIXEL_ALPHA; + print_settings->set_supports_alpha_blend( + (GetDeviceCaps(hdc, SHADEBLENDCAPS) & kAlphaCaps) == kAlphaCaps); // No printer device is known to advertise different dpi in X and Y axis; even // the fax device using the 200x100 dpi setting. It's ought to break so many // applications that it's not even needed to care about. WebKit doesn't diff --git a/skia/ext/vector_platform_device_win.cc b/skia/ext/vector_platform_device_win.cc index 31ac722..6ec4e39 100644 --- a/skia/ext/vector_platform_device_win.cc +++ b/skia/ext/vector_platform_device_win.cc @@ -104,7 +104,8 @@ VectorPlatformDevice::VectorPlatformDevice(HDC dc, const SkBitmap& bitmap) : PlatformDevice(bitmap), hdc_(dc), previous_brush_(NULL), - previous_pen_(NULL) { + previous_pen_(NULL), + alpha_blend_used_(false) { transform_.reset(); } @@ -698,6 +699,8 @@ void VectorPlatformDevice::InternalDrawBitmap(const SkBitmap& bitmap, result = SetStretchBltMode(dc, previous_mode); SkASSERT(result); + alpha_blend_used_ = true; + ::SelectObject(bitmap_dc, static_cast<HBITMAP>(old_bitmap)); DeleteObject(hbitmap); DeleteDC(bitmap_dc); diff --git a/skia/ext/vector_platform_device_win.h b/skia/ext/vector_platform_device_win.h index 2a5057e..3050a90 100644 --- a/skia/ext/vector_platform_device_win.h +++ b/skia/ext/vector_platform_device_win.h @@ -81,6 +81,7 @@ class VectorPlatformDevice : public PlatformDevice { virtual bool IsVectorial() { return true; } void LoadClipRegion(); + bool alpha_blend_used() const { return alpha_blend_used_; } private: // Applies the SkPaint's painting properties in the current GDI context, if @@ -129,6 +130,9 @@ class VectorPlatformDevice : public PlatformDevice { // Previously selected pen before the current drawing. HGDIOBJ previous_pen_; + // True if AlphaBlend() was called during this print. + bool alpha_blend_used_; + // Copy & assign are not supported. VectorPlatformDevice(const VectorPlatformDevice&); const VectorPlatformDevice& operator=(const VectorPlatformDevice&); |