0

PrintPreview: Printing preview of a PDF on Mac with Skia only previews the last page of the PDF

BUG=93145
TEST=Please refer to bug report.

Review URL: http://codereview.chromium.org/7719014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103021 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
kmadhusu@chromium.org
2011-09-27 21:59:34 +00:00
parent fce166e202
commit c73df9dfae
10 changed files with 101 additions and 65 deletions

@ -234,7 +234,8 @@ class PrintWebViewHelper : public RenderViewObserver,
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
void RenderPage(const gfx::Size& page_size, const gfx::Rect& content_area, void RenderPage(const gfx::Size& page_size, const gfx::Rect& content_area,
const float& scale_factor, int page_number, const float& scale_factor, int page_number,
WebKit::WebFrame* frame, printing::Metafile* metafile); WebKit::WebFrame* frame, bool is_preview,
printing::Metafile* metafile);
#elif defined(OS_POSIX) #elif defined(OS_POSIX)
bool RenderPages(const PrintMsg_PrintPages_Params& params, bool RenderPages(const PrintMsg_PrintPages_Params& params,
WebKit::WebFrame* frame, const WebKit::WebNode& node, WebKit::WebFrame* frame, const WebKit::WebNode& node,

@ -14,6 +14,7 @@
#include "printing/metafile_impl.h" #include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h" #include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h" #include "printing/page_size_margins.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/vector_canvas.h" #include "skia/ext/vector_canvas.h"
#include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
@ -208,9 +209,8 @@ void PrintWebViewHelper::PrintPageInternal(
// can't be a stack object. // can't be a stack object.
SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device); SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device);
canvas->unref(); // SkRefPtr and new both took a reference. canvas->unref(); // SkRefPtr and new both took a reference.
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile); printing::MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
printing::MetafileSkiaWrapper::SetDraftMode(canvas.get(), skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
is_print_ready_metafile_sent_);
frame->printPage(params.page_number, canvas.get()); frame->printPage(params.page_number, canvas.get());
if (params.params.display_header_footer) { if (params.params.display_header_footer) {

@ -17,6 +17,7 @@
#if defined(USE_SKIA) #if defined(USE_SKIA)
#include "printing/metafile_skia_wrapper.h" #include "printing/metafile_skia_wrapper.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/vector_canvas.h" #include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCanvas.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCanvas.h"
#endif #endif
@ -37,7 +38,7 @@ void PrintWebViewHelper::PrintPageInternal(
// Render page for printing. // Render page for printing.
gfx::Rect content_area(params.params.printable_size); gfx::Rect content_area(params.params.printable_size);
RenderPage(params.params.printable_size, content_area, scale_factor, RenderPage(params.params.printable_size, content_area, scale_factor,
page_number, frame, &metafile); page_number, frame, false, &metafile);
metafile.FinishDocument(); metafile.FinishDocument();
PrintHostMsg_DidPrintPage_Params page_params; PrintHostMsg_DidPrintPage_Params page_params;
@ -96,7 +97,7 @@ bool PrintWebViewHelper::RenderPreviewPage(int page_number) {
base::TimeTicks begin_time = base::TimeTicks::Now(); base::TimeTicks begin_time = base::TimeTicks::Now();
RenderPage(printParams.page_size, content_area, scale_factor, page_number, RenderPage(printParams.page_size, content_area, scale_factor, page_number,
print_preview_context_.frame(), initial_render_metafile); print_preview_context_.frame(), true, initial_render_metafile);
print_preview_context_.RenderedPreviewPage( print_preview_context_.RenderedPreviewPage(
base::TimeTicks::Now() - begin_time); base::TimeTicks::Now() - begin_time);
@ -144,7 +145,7 @@ bool PrintWebViewHelper::RenderPreviewPage(int page_number) {
void PrintWebViewHelper::RenderPage( void PrintWebViewHelper::RenderPage(
const gfx::Size& page_size, const gfx::Rect& content_area, const gfx::Size& page_size, const gfx::Rect& content_area,
const float& scale_factor, int page_number, WebFrame* frame, const float& scale_factor, int page_number, WebFrame* frame,
printing::Metafile* metafile) { bool is_preview, printing::Metafile* metafile) {
{ {
#if defined(USE_SKIA) #if defined(USE_SKIA)
@ -156,9 +157,9 @@ void PrintWebViewHelper::RenderPage(
SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device); SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device);
canvas->unref(); // SkRefPtr and new both took a reference. canvas->unref(); // SkRefPtr and new both took a reference.
WebKit::WebCanvas* canvas_ptr = canvas.get(); WebKit::WebCanvas* canvas_ptr = canvas.get();
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile); printing::MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
printing::MetafileSkiaWrapper::SetDraftMode(canvas.get(), skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
is_print_ready_metafile_sent_); skia::SetIsPreviewMetafile(*canvas, is_preview);
#else #else
bool success = metafile->StartPage(page_size, content_area, scale_factor); bool success = metafile->StartPage(page_size, content_area, scale_factor);
DCHECK(success); DCHECK(success);

@ -193,9 +193,9 @@ Metafile* PrintWebViewHelper::RenderPage(
SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device); SkRefPtr<skia::VectorCanvas> canvas = new skia::VectorCanvas(device);
canvas->unref(); // SkRefPtr and new both took a reference. canvas->unref(); // SkRefPtr and new both took a reference.
if (is_preview) { if (is_preview) {
printing::MetafileSkiaWrapper::SetMetafileOnCanvas(canvas.get(), metafile); printing::MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
printing::MetafileSkiaWrapper::SetDraftMode(canvas.get(), skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
is_print_ready_metafile_sent_); skia::SetIsPreviewMetafile(*canvas, is_preview);
} }
float webkit_scale_factor = frame->printPage(page_number, canvas.get()); float webkit_scale_factor = frame->printPage(page_number, canvas.get());

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/logging.h"
#include "printing/metafile_skia_wrapper.h" #include "printing/metafile_skia_wrapper.h"
#include "skia/ext/platform_device.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkDevice.h" #include "third_party/skia/include/core/SkDevice.h"
#include "third_party/skia/include/core/SkMetaData.h" #include "third_party/skia/include/core/SkMetaData.h"
@ -12,34 +12,25 @@ namespace printing {
namespace { namespace {
const char* kDraftModeKey = "CrDraftMode";
const char* kMetafileKey = "CrMetafile"; const char* kMetafileKey = "CrMetafile";
SkMetaData& getMetaData(SkCanvas* canvas) {
DCHECK(canvas != NULL);
SkDevice* device = canvas->getDevice();
DCHECK(device != NULL);
return device->getMetaData();
}
} // namespace } // namespace
// static // static
void MetafileSkiaWrapper::SetMetafileOnCanvas(SkCanvas* canvas, void MetafileSkiaWrapper::SetMetafileOnCanvas(const SkCanvas& canvas,
Metafile* metafile) { Metafile* metafile) {
MetafileSkiaWrapper* wrapper = NULL; MetafileSkiaWrapper* wrapper = NULL;
if (metafile) if (metafile)
wrapper = new MetafileSkiaWrapper(metafile); wrapper = new MetafileSkiaWrapper(metafile);
SkMetaData& meta = getMetaData(canvas); SkMetaData& meta = skia::getMetaData(canvas);
meta.setRefCnt(kMetafileKey, wrapper); meta.setRefCnt(kMetafileKey, wrapper);
SkSafeUnref(wrapper); SkSafeUnref(wrapper);
} }
// static // static
Metafile* MetafileSkiaWrapper::GetMetafileFromCanvas(SkCanvas* canvas) { Metafile* MetafileSkiaWrapper::GetMetafileFromCanvas(const SkCanvas& canvas) {
SkMetaData& meta = getMetaData(canvas); SkMetaData& meta = skia::getMetaData(canvas);
SkRefCnt* value; SkRefCnt* value;
if (!meta.findRefCnt(kMetafileKey, &value) || !value) if (!meta.findRefCnt(kMetafileKey, &value) || !value)
return NULL; return NULL;
@ -47,21 +38,6 @@ Metafile* MetafileSkiaWrapper::GetMetafileFromCanvas(SkCanvas* canvas) {
return static_cast<MetafileSkiaWrapper*>(value)->metafile_; return static_cast<MetafileSkiaWrapper*>(value)->metafile_;
} }
// static
void MetafileSkiaWrapper::SetDraftMode(SkCanvas* canvas, bool draft_mode) {
SkMetaData& meta = getMetaData(canvas);
meta.setBool(kDraftModeKey, draft_mode);
}
// static
bool MetafileSkiaWrapper::GetDraftMode(SkCanvas* canvas) {
SkMetaData& meta = getMetaData(canvas);
bool draft_mode;
if (!meta.findBool(kDraftModeKey, &draft_mode))
draft_mode = false;
return draft_mode;
}
MetafileSkiaWrapper::MetafileSkiaWrapper(Metafile* metafile) MetafileSkiaWrapper::MetafileSkiaWrapper(Metafile* metafile)
: metafile_(metafile) { : metafile_(metafile) {
} }

@ -20,13 +20,9 @@ class Metafile;
// as long as the canvas. // as long as the canvas.
class PRINTING_EXPORT MetafileSkiaWrapper : public SkRefCnt { class PRINTING_EXPORT MetafileSkiaWrapper : public SkRefCnt {
public: public:
static void SetMetafileOnCanvas(SkCanvas* canvas, Metafile* metafile); static void SetMetafileOnCanvas(const SkCanvas& canvas, Metafile* metafile);
static Metafile* GetMetafileFromCanvas(SkCanvas* canvas); static Metafile* GetMetafileFromCanvas(const SkCanvas& canvas);
static void SetDraftMode(SkCanvas* canvas, bool draft_mode);
static bool GetDraftMode(SkCanvas* canvas);
private: private:
explicit MetafileSkiaWrapper(Metafile* metafile); explicit MetafileSkiaWrapper(Metafile* metafile);

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/logging.h"
#include "skia/ext/platform_device.h" #include "skia/ext/platform_device.h"
#include "third_party/skia/include/core/SkMetaData.h" #include "third_party/skia/include/core/SkMetaData.h"
@ -9,9 +10,29 @@
namespace skia { namespace skia {
namespace { namespace {
const char* kDevicePlatformBehaviour = "CrDevicePlatformBehaviour"; const char* kDevicePlatformBehaviour = "CrDevicePlatformBehaviour";
const char* kDraftModeKey = "CrDraftMode";
#if defined(OS_MACOSX) || defined(OS_WIN)
const char* kIsPreviewMetafileKey = "CrIsPreviewMetafile";
#endif
void SetBoolMetaData(const SkCanvas& canvas, const char* key, bool value) {
SkMetaData& meta = skia::getMetaData(canvas);
meta.setBool(key, value);
} }
bool GetBoolMetaData(const SkCanvas& canvas, const char* key) {
bool value;
SkMetaData& meta = skia::getMetaData(canvas);
if (!meta.findBool(key, &value))
value = false;
return value;
}
} // namespace
void SetPlatformDevice(SkDevice* device, PlatformDevice* platform_behaviour) { void SetPlatformDevice(SkDevice* device, PlatformDevice* platform_behaviour) {
SkMetaData& meta_data = device->getMetaData(); SkMetaData& meta_data = device->getMetaData();
meta_data.setPtr(kDevicePlatformBehaviour, platform_behaviour); meta_data.setPtr(kDevicePlatformBehaviour, platform_behaviour);
@ -27,6 +48,30 @@ PlatformDevice* GetPlatformDevice(SkDevice* device) {
return NULL; return NULL;
} }
SkMetaData& getMetaData(const SkCanvas& canvas) {
SkDevice* device = canvas.getDevice();
DCHECK(device != NULL);
return device->getMetaData();
}
void SetIsDraftMode(const SkCanvas& canvas, bool draft_mode) {
SetBoolMetaData(canvas, kDraftModeKey, draft_mode);
}
bool IsDraftMode(const SkCanvas& canvas) {
return GetBoolMetaData(canvas, kDraftModeKey);
}
#if defined(OS_MACOSX) || defined(OS_WIN)
void SetIsPreviewMetafile(const SkCanvas& canvas, bool is_preview) {
SetBoolMetaData(canvas, kIsPreviewMetafileKey, is_preview);
}
bool IsPreviewMetafile(const SkCanvas& canvas) {
return GetBoolMetaData(canvas, kIsPreviewMetafileKey);
}
#endif
bool PlatformDevice::IsNativeFontRenderingAllowed() { bool PlatformDevice::IsNativeFontRenderingAllowed() {
return true; return true;
} }

@ -18,6 +18,7 @@
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
class SkMatrix; class SkMatrix;
class SkMetaData;
class SkPath; class SkPath;
class SkRegion; class SkRegion;
@ -78,6 +79,17 @@ SK_API void InitializeDC(HDC context);
SK_API CGContextRef GetBitmapContext(SkDevice* device); SK_API CGContextRef GetBitmapContext(SkDevice* device);
#endif #endif
// Following routines are used in print preview workflow to mark the draft mode
// metafile and preview metafile.
SkMetaData& getMetaData(const SkCanvas& canvas);
void SetIsDraftMode(const SkCanvas& canvas, bool draft_mode);
bool IsDraftMode(const SkCanvas& canvas);
#if defined(OS_MACOSX) || defined(OS_WIN)
void SetIsPreviewMetafile(const SkCanvas& canvas, bool is_preview);
bool IsPreviewMetafile(const SkCanvas& canvas);
#endif
// A SkDevice is basically a wrapper around SkBitmap that provides a surface for // A SkDevice is basically a wrapper around SkBitmap that provides a surface for
// SkCanvas to draw into. PlatformDevice provides a surface Windows can also // SkCanvas to draw into. PlatformDevice provides a surface Windows can also
// write to. It also provides functionality to play well with GDI drawing // write to. It also provides functionality to play well with GDI drawing

@ -851,10 +851,10 @@ int PluginInstance::PrintBegin(const gfx::Rect& printable_area,
if (!num_pages) if (!num_pages)
return 0; return 0;
current_print_settings_ = print_settings; current_print_settings_ = print_settings;
#if defined(OS_LINUX) || defined(OS_WIN) #if defined(USE_SKIA)
canvas_ = NULL; canvas_ = NULL;
ranges_.clear(); ranges_.clear();
#endif // OS_LINUX || OS_WIN #endif // USE_SKIA
return num_pages; return num_pages;
} }
@ -862,14 +862,19 @@ bool PluginInstance::PrintPage(int page_number, WebKit::WebCanvas* canvas) {
DCHECK(plugin_print_interface_); DCHECK(plugin_print_interface_);
PP_PrintPageNumberRange_Dev page_range; PP_PrintPageNumberRange_Dev page_range;
page_range.first_page_number = page_range.last_page_number = page_number; page_range.first_page_number = page_range.last_page_number = page_number;
#if defined(OS_LINUX) || defined(OS_WIN) #if defined(USE_SKIA)
// The canvas only has a metafile on it for print preview. // The canvas only has a metafile on it for print preview.
if (printing::MetafileSkiaWrapper::GetMetafileFromCanvas(canvas)) { bool save_for_later =
(printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas) != NULL);
#if defined(OS_MACOSX) || defined(OS_WIN)
save_for_later = save_for_later && skia::IsPreviewMetafile(*canvas);
#endif
if (save_for_later) {
ranges_.push_back(page_range); ranges_.push_back(page_range);
canvas_ = canvas; canvas_ = canvas;
return true; return true;
} else } else
#endif // OS_LINUX || OS_WIN #endif // USE_SKIA
{ {
return PrintPageHelper(&page_range, 1, canvas); return PrintPageHelper(&page_range, 1, canvas);
} }
@ -901,12 +906,12 @@ bool PluginInstance::PrintPageHelper(PP_PrintPageNumberRange_Dev* page_ranges,
void PluginInstance::PrintEnd() { void PluginInstance::PrintEnd() {
// Keep a reference on the stack. See NOTE above. // Keep a reference on the stack. See NOTE above.
scoped_refptr<PluginInstance> ref(this); scoped_refptr<PluginInstance> ref(this);
#if defined(OS_LINUX) || defined(OS_WIN) #if defined(USE_SKIA)
if (!ranges_.empty()) if (!ranges_.empty())
PrintPageHelper(&(ranges_.front()), ranges_.size(), canvas_.get()); PrintPageHelper(&(ranges_.front()), ranges_.size(), canvas_.get());
canvas_ = NULL; canvas_ = NULL;
ranges_.clear(); ranges_.clear();
#endif // OS_LINUX || OS_WIN #endif // USE_SKIA
DCHECK(plugin_print_interface_); DCHECK(plugin_print_interface_);
if (plugin_print_interface_) if (plugin_print_interface_)
@ -1061,7 +1066,7 @@ bool PluginInstance::PrintPDFOutput(PP_Resource print_output,
// (NativeMetafile and PreviewMetafile must have compatible formats, // (NativeMetafile and PreviewMetafile must have compatible formats,
// i.e. both PDF for this to work). // i.e. both PDF for this to work).
printing::Metafile* metafile = printing::Metafile* metafile =
printing::MetafileSkiaWrapper::GetMetafileFromCanvas(canvas); printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas);
DCHECK(metafile != NULL); DCHECK(metafile != NULL);
if (metafile) if (metafile)
ret = metafile->InitFromData(mapper.data(), mapper.size()); ret = metafile->InitFromData(mapper.data(), mapper.size());
@ -1086,7 +1091,7 @@ bool PluginInstance::PrintPDFOutput(PP_Resource print_output,
} }
#elif defined(OS_WIN) #elif defined(OS_WIN)
printing::Metafile* metafile = printing::Metafile* metafile =
printing::MetafileSkiaWrapper::GetMetafileFromCanvas(canvas); printing::MetafileSkiaWrapper::GetMetafileFromCanvas(*canvas);
if (metafile) { if (metafile) {
// We only have a metafile when doing print preview, so we just want to // We only have a metafile when doing print preview, so we just want to
// pass the PDF off to preview. // pass the PDF off to preview.

@ -466,14 +466,14 @@ class PluginInstance : public base::RefCounted<PluginInstance>,
// variable to hold on to the pixels. // variable to hold on to the pixels.
scoped_refptr<PPB_ImageData_Impl> last_printed_page_; scoped_refptr<PPB_ImageData_Impl> last_printed_page_;
#endif // defined(OS_MACOSX) #endif // defined(OS_MACOSX)
#if defined(OS_LINUX) || defined(OS_WIN) #if defined(USE_SKIA)
// When printing to PDF (print preview, Linux) the entire document goes into // Always when printing to PDF on Linux and when printing for preview on Mac
// one metafile. However, when users print only a subset of all the pages, // and Win, the entire document goes into one metafile. However, when users
// it is impossible to know if a call to PrintPage() is the last call. // print only a subset of all the pages, it is impossible to know if a call
// Thus in PrintPage(), just store the page number in |ranges_|. // to PrintPage() is the last call. Thus in PrintPage(), just store the page
// The hack is in PrintEnd(), where a valid |canvas_| is preserved in // number in |ranges_|. The hack is in PrintEnd(), where a valid |canvas_|
// PrintWebViewHelper::PrintPages. This makes it possible to generate the // is preserved in PrintWebViewHelper::PrintPages. This makes it possible
// entire PDF given the variables below: // to generate the entire PDF given the variables below:
// //
// The most recently used WebCanvas, guaranteed to be valid. // The most recently used WebCanvas, guaranteed to be valid.
SkRefPtr<WebKit::WebCanvas> canvas_; SkRefPtr<WebKit::WebCanvas> canvas_;