Skip to content

Commit

Permalink
When printing a page containing alpha blending on a printer which doe…
Browse files Browse the repository at this point in the history
…sn'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
  • Loading branch information
senorblanco@chromium.org committed Jan 12, 2011
1 parent 76fcc3e commit b2b0fce
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 12 deletions.
1 change: 1 addition & 0 deletions chrome/browser/renderer_host/render_message_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
13 changes: 9 additions & 4 deletions chrome/common/render_messages_params.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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()
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
5 changes: 4 additions & 1 deletion chrome/common/render_messages_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down
102 changes: 97 additions & 5 deletions chrome/renderer/print_web_view_helper_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,60 @@
#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;
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) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions printing/emf_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ bool Emf::Record::SafePlayback(const XFORM* base_matrix) const {
} else {
res = Play();
}
} else {
res = true;
}
break;
}
Expand Down
4 changes: 3 additions & 1 deletion printing/print_settings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ PrintSettings::PrintSettings()
selection_only(false),
use_overlays(true),
dpi_(0),
landscape_(false) {
landscape_(false),
supports_alpha_blend_(true) {
}

PrintSettings::~PrintSettings() {
Expand All @@ -36,6 +37,7 @@ void PrintSettings::Clear() {
page_setup_device_units_.Clear();
dpi_ = 0;
landscape_ = false;
supports_alpha_blend_ = true;
}

void PrintSettings::SetPrinterPrintableArea(
Expand Down
7 changes: 7 additions & 0 deletions printing/print_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
}
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions printing/print_settings_initializer_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion skia/ext/vector_platform_device_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions skia/ext/vector_platform_device_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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&);
Expand Down

0 comments on commit b2b0fce

Please sign in to comment.