summaryrefslogtreecommitdiffstats
path: root/printing
diff options
context:
space:
mode:
authorvitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-22 00:10:07 +0000
committervitalybuka@chromium.org <vitalybuka@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-22 00:10:07 +0000
commit60d77bde7e6aac08a05b00ce2b82f94144934965 (patch)
treee259f3205b1017c549b87e08497ad4172f990bdd /printing
parentf26c77082295b9fc277cd7a5eb75cdf0edee1bbb (diff)
downloadchromium_src-60d77bde7e6aac08a05b00ce2b82f94144934965.zip
chromium_src-60d77bde7e6aac08a05b00ce2b82f94144934965.tar.gz
chromium_src-60d77bde7e6aac08a05b00ce2b82f94144934965.tar.bz2
Some printers has issue with metafiles produces from PDF so added switch and about:flag as workaround for affected users.
Rasterisation is implemented and RasterizeMetafile function. It replace metafile with new one where content is only bitmap created by playback of original metafile. FlattenTransparency replaced with full rasterisation. Fixed rectangle returned by Emf::GetPageBounds. Removed SkDevice::AlphaBlendUsed(). Removed return value from PrintWebViewHelper::RenderPage on windows. BUG=133527 Review URL: https://chromiumcodereview.appspot.com/10836330 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152681 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'printing')
-rw-r--r--printing/emf_win.cc109
-rw-r--r--printing/emf_win.h12
-rw-r--r--printing/emf_win_unittest.cc25
3 files changed, 135 insertions, 11 deletions
diff --git a/printing/emf_win.cc b/printing/emf_win.cc
index 3634cbd..a5d4c02 100644
--- a/printing/emf_win.cc
+++ b/printing/emf_win.cc
@@ -7,6 +7,9 @@
#include "base/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/scoped_hdc.h"
+#include "base/win/scoped_select_object.h"
#include "skia/ext/vector_platform_device_emf_win.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/jpeg_codec.h"
@@ -16,6 +19,7 @@
#include "ui/gfx/size.h"
namespace {
+
const int kCustomGdiCommentSignature = 0xdeadbabe;
struct PageBreakRecord {
int signature;
@@ -31,8 +35,27 @@ struct PageBreakRecord {
(type >= START_PAGE) && (type <= END_PAGE);
}
};
+
+int CALLBACK IsAlphaBlendUsedEnumProc(HDC,
+ HANDLETABLE*,
+ const ENHMETARECORD *record,
+ int,
+ LPARAM data) {
+ bool* result = reinterpret_cast<bool*>(data);
+ if (!result)
+ return 0;
+ switch (record->iType) {
+ case EMR_ALPHABLEND: {
+ *result = true;
+ return 0;
+ break;
+ }
+ }
+ return 1;
}
+} // namespace
+
namespace printing {
bool DIBFormatNativelySupported(HDC dc, uint32 escape, const BYTE* bits,
@@ -126,19 +149,12 @@ gfx::Rect Emf::GetPageBounds(unsigned int page_number) const {
NOTREACHED();
return gfx::Rect();
}
- if (header.rclBounds.left == 0 &&
- header.rclBounds.top == 0 &&
- header.rclBounds.right == -1 &&
- header.rclBounds.bottom == -1) {
- // A freshly created EMF buffer that has no drawing operation has invalid
- // bounds. Instead of having an (0,0) size, it has a (-1,-1) size. Detect
- // this special case and returns an empty Rect instead of an invalid one.
- return gfx::Rect();
- }
+ // Add 1 to right and bottom because it's inclusive rectangle.
+ // See ENHMETAHEADER.
return gfx::Rect(header.rclBounds.left,
header.rclBounds.top,
- header.rclBounds.right - header.rclBounds.left,
- header.rclBounds.bottom - header.rclBounds.top);
+ header.rclBounds.right - header.rclBounds.left + 1,
+ header.rclBounds.bottom - header.rclBounds.top + 1);
}
uint32 Emf::GetDataSize() const {
@@ -478,4 +494,75 @@ int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc,
return 1;
}
+bool Emf::IsAlphaBlendUsed() const {
+ bool result = false;
+ ::EnumEnhMetaFile(NULL,
+ emf(),
+ &IsAlphaBlendUsedEnumProc,
+ &result,
+ NULL);
+ return result;
+}
+
+Emf* Emf::RasterizeMetafile(int raster_area_in_pixels) const {
+ gfx::Rect page_bounds = GetPageBounds(1);
+ gfx::Size page_size(page_bounds.size());
+ if (page_size.GetArea() <= 0) {
+ NOTREACHED() << "Metafile is empty";
+ page_bounds = gfx::Rect(1, 1);
+ }
+
+ float scale = sqrt(float(raster_area_in_pixels) / page_size.GetArea());
+ page_size.set_width(std::max<int>(1, page_size.width() * scale));
+ page_size.set_height(std::max<int>(1, page_size.height() * scale));
+
+ base::win::ScopedCreateDC bitmap_dc(::CreateCompatibleDC(NULL));
+ if (!bitmap_dc) {
+ NOTREACHED() << "Bitmap DC creation failed";
+ return NULL;
+ }
+ ::SetGraphicsMode(bitmap_dc, GM_ADVANCED);
+ void* bits = NULL;
+ BITMAPINFO hdr;
+ gfx::CreateBitmapHeader(page_size.width(), page_size.height(),
+ &hdr.bmiHeader);
+ base::win::ScopedBitmap hbitmap(CreateDIBSection(
+ bitmap_dc, &hdr, DIB_RGB_COLORS, &bits, NULL, 0));
+ if (!hbitmap)
+ NOTREACHED() << "Raster bitmap creation for printing failed";
+
+ base::win::ScopedSelectObject selectBitmap(bitmap_dc, hbitmap);
+ RECT rect = { 0, 0, page_size.width(), page_size.height() };
+ HBRUSH white_brush = static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH));
+ FillRect(bitmap_dc, &rect, white_brush);
+
+ gfx::Rect bitmap_rect(page_size);
+ Playback(bitmap_dc, &bitmap_rect.ToRECT());
+
+ scoped_ptr<Emf> result(new Emf);
+ result->Init();
+ HDC hdc = result->context();
+ DCHECK(hdc);
+ skia::InitializeDC(hdc);
+
+ // Params are ignored.
+ result->StartPage(page_bounds.size(), page_bounds, 1);
+
+ ::ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
+ XFORM xform = {
+ float(page_bounds.width()) / bitmap_rect.width(), 0,
+ 0, float(page_bounds.height()) / bitmap_rect.height(),
+ page_bounds.x(),
+ page_bounds.y(),
+ };
+ ::SetWorldTransform(hdc, &xform);
+ ::BitBlt(hdc, 0, 0, bitmap_rect.width(), bitmap_rect.height(),
+ bitmap_dc, bitmap_rect.x(), bitmap_rect.y(), SRCCOPY);
+
+ result->FinishPage();
+ result->FinishDocument();
+
+ return result.release();
+}
+
} // namespace printing
diff --git a/printing/emf_win.h b/printing/emf_win.h
index b593e24..0800250 100644
--- a/printing/emf_win.h
+++ b/printing/emf_win.h
@@ -23,6 +23,11 @@ class Size;
namespace printing {
+// http://msdn2.microsoft.com/en-us/library/ms535522.aspx
+// Windows 2000/XP: When a page in a spooled file exceeds approximately 350
+// MB, it can fail to print and not send an error message.
+const size_t kMetafileMaxSize = 350*1024*1024;
+
// Simple wrapper class that manage an EMF data stream and its virtual HDC.
class PRINTING_EXPORT Emf : public Metafile {
public:
@@ -86,6 +91,13 @@ class PRINTING_EXPORT Emf : public Metafile {
return emf_;
}
+ // Returns true if metafile contains alpha blend.
+ bool IsAlphaBlendUsed() const;
+
+ // Returns new metafile with only bitmap created by playback of the current
+ // metafile. Returns NULL if fails.
+ Emf* RasterizeMetafile(int raster_area_in_pixels) const;
+
private:
FRIEND_TEST_ALL_PREFIXES(EmfTest, DC);
FRIEND_TEST_ALL_PREFIXES(EmfPrintingTest, PageBreak);
diff --git a/printing/emf_win_unittest.cc b/printing/emf_win_unittest.cc
index 8d07213..ac30fd0 100644
--- a/printing/emf_win_unittest.cc
+++ b/printing/emf_win_unittest.cc
@@ -202,4 +202,29 @@ TEST(EmfTest, FileBackedEmf) {
EXPECT_TRUE(DeleteDC(hdc));
}
+TEST(EmfTest, RasterizeMetafile) {
+ Emf emf;
+ EXPECT_TRUE(emf.Init());
+ EXPECT_TRUE(emf.context() != NULL);
+ HBRUSH brush = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
+ for (int i = 0; i < 4; ++i) {
+ RECT rect = { 5 + i, 5 + i, 5 + i + 1, 5 + i + 2};
+ FillRect(emf.context(), &rect, brush);
+ }
+ EXPECT_TRUE(emf.FinishDocument());
+
+ scoped_ptr<Emf> raster(emf.RasterizeMetafile(1));
+ // Just 1px bitmap but should be stretched to the same bounds.
+ EXPECT_EQ(emf.GetPageBounds(1), raster->GetPageBounds(1));
+
+ raster.reset(emf.RasterizeMetafile(20));
+ EXPECT_EQ(emf.GetPageBounds(1), raster->GetPageBounds(1));
+
+ raster.reset(emf.RasterizeMetafile(16*1024*1024));
+ // Expected size about 64MB.
+ EXPECT_LE(abs(int(raster->GetDataSize()) - 64*1024*1024), 1024*1024);
+ // Bounds should still be the same.
+ EXPECT_EQ(emf.GetPageBounds(1), raster->GetPageBounds(1));
+}
+
} // namespace printing