summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser.cc9
-rw-r--r--chrome/browser/browser.h6
-rw-r--r--chrome/browser/gtk/standard_menus.cc7
-rw-r--r--chrome/chrome.gyp3
-rw-r--r--chrome/renderer/print_web_view_helper.cc337
-rw-r--r--chrome/renderer/print_web_view_helper.h38
-rw-r--r--chrome/renderer/print_web_view_helper_linux.cc85
-rw-r--r--chrome/renderer/print_web_view_helper_mac.cc20
-rw-r--r--chrome/renderer/print_web_view_helper_win.cc199
-rw-r--r--skia/ext/vector_canvas.cc58
-rw-r--r--skia/ext/vector_canvas.h18
-rw-r--r--skia/ext/vector_canvas_linux.cc49
-rw-r--r--skia/ext/vector_canvas_win.cc49
-rw-r--r--skia/ext/vector_platform_device.h17
-rw-r--r--skia/ext/vector_platform_device_linux.cc498
-rw-r--r--skia/ext/vector_platform_device_linux.h112
-rw-r--r--skia/skia.gyp9
17 files changed, 900 insertions, 614 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index 712ef35..562f3b0 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -964,17 +964,20 @@ bool Browser::SupportsWindowFeature(WindowFeature feature) const {
}
#if defined(OS_WIN)
-
void Browser::ClosePopups() {
UserMetrics::RecordAction(L"CloseAllSuppressedPopups", profile_);
GetSelectedTabContents()->CloseAllSuppressedPopups();
}
+#endif
void Browser::Print() {
UserMetrics::RecordAction(L"PrintPreview", profile_);
+#if defined(OS_WIN) || defined(OS_LINUX)
GetSelectedTabContents()->PrintPreview();
+#else
+ NOTIMPLEMENTED();
+#endif
}
-#endif // #if defined(OS_WIN)
void Browser::ToggleEncodingAutoDetect() {
UserMetrics::RecordAction(L"AutoDetectChange", profile_);
@@ -1334,8 +1337,8 @@ void Browser::ExecuteCommandWithDisposition(
case IDC_VIEW_SOURCE: ViewSource(); break;
#if defined(OS_WIN)
case IDC_CLOSE_POPUPS: ClosePopups(); break;
- case IDC_PRINT: Print(); break;
#endif
+ case IDC_PRINT: Print(); break;
case IDC_ENCODING_AUTO_DETECT: ToggleEncodingAutoDetect(); break;
case IDC_ENCODING_UTF8:
case IDC_ENCODING_UTF16LE:
diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h
index 5044810..fe309e0 100644
--- a/chrome/browser/browser.h
+++ b/chrome/browser/browser.h
@@ -134,8 +134,8 @@ class Browser : public TabStripModelDelegate,
const SessionID& session_id() const { return session_id_; }
CommandUpdater* command_updater() { return &command_updater_; }
FindBarController* find_bar() { return find_bar_controller_.get(); }
- ExtensionShelfModel* extension_shelf_model() {
- return extension_shelf_model_.get();
+ ExtensionShelfModel* extension_shelf_model() {
+ return extension_shelf_model_.get();
}
// Setters /////////////////////////////////////////////////////////////////
@@ -336,8 +336,8 @@ class Browser : public TabStripModelDelegate,
#if defined(OS_WIN)
// Page-related commands.
void ClosePopups();
- void Print();
#endif
+ void Print();
void ToggleEncodingAutoDetect();
void OverrideEncoding(int encoding_id);
diff --git a/chrome/browser/gtk/standard_menus.cc b/chrome/browser/gtk/standard_menus.cc
index be4355b..72a66ac 100644
--- a/chrome/browser/gtk/standard_menus.cc
+++ b/chrome/browser/gtk/standard_menus.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -50,10 +50,7 @@ struct MenuCreateMaterial standard_page_menu_materials[] = {
{ MENU_NORMAL, IDC_FIND, IDS_FIND, 0, NULL, GDK_f, GDK_CONTROL_MASK },
{ MENU_NORMAL, IDC_SAVE_PAGE, IDS_SAVE_PAGE, 0, NULL, GDK_s,
GDK_CONTROL_MASK },
- // Printing hasn't been implemented yet. Remove it from the menu until
- // someone implements it.
- // http://code.google.com/p/chromium/issues/detail?id=9847
- //{ MENU_NORMAL, IDC_PRINT, IDS_PRINT, 0, NULL, GDK_p, GDK_CONTROL_MASK },
+ { MENU_NORMAL, IDC_PRINT, IDS_PRINT, 0, NULL, GDK_p, GDK_CONTROL_MASK },
{ MENU_SEPARATOR },
{ MENU_NORMAL, IDC_ZOOM_MENU, IDS_ZOOM_MENU, 0, zoom_menu_materials },
// The encoding menu submenu is filled in by code below.
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index d535d8b..c2eb3ea 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -2600,6 +2600,9 @@
'renderer/plugin_channel_host.h',
'renderer/print_web_view_helper.cc',
'renderer/print_web_view_helper.h',
+ 'renderer/print_web_view_helper_linux.cc',
+ 'renderer/print_web_view_helper_mac.cc',
+ 'renderer/print_web_view_helper_win.cc',
'renderer/render_process.cc',
'renderer/render_process.h',
'renderer/render_thread.cc',
diff --git a/chrome/renderer/print_web_view_helper.cc b/chrome/renderer/print_web_view_helper.cc
index 1e9a0fe..a0803ba 100644
--- a/chrome/renderer/print_web_view_helper.cc
+++ b/chrome/renderer/print_web_view_helper.cc
@@ -6,220 +6,64 @@
#include "app/l10n_util.h"
#include "base/logging.h"
-#include "base/gfx/size.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/render_view.h"
#include "grit/generated_resources.h"
-#include "printing/native_metafile.h"
#include "printing/units.h"
-#include "webkit/api/public/WebConsoleMessage.h"
#include "webkit/api/public/WebRect.h"
#include "webkit/api/public/WebScreenInfo.h"
#include "webkit/api/public/WebSize.h"
-#include "webkit/api/public/WebURL.h"
#include "webkit/api/public/WebURLRequest.h"
#include "webkit/glue/webframe.h"
-#if defined(OS_WIN)
-#include "skia/ext/vector_canvas.h"
-#endif
-
-using WebKit::WebConsoleMessage;
using WebKit::WebRect;
using WebKit::WebScreenInfo;
using WebKit::WebString;
using WebKit::WebURLRequest;
-namespace {
-
-const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
-const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 2 * 60; // 2 Minutes.
-
-// Class that calls the Begin and End print functions on the frame and changes
-// the size of the view temporarily to support full page printing..
-// Do not serve any events in the time between construction and destruction of
-// this class because it will cause flicker.
-class PrepareFrameAndViewForPrint {
- public:
- PrepareFrameAndViewForPrint(const ViewMsg_Print_Params& print_params,
- WebFrame* frame,
- WebView* web_view)
- : frame_(frame),
- web_view_(web_view),
- expected_pages_count_(0) {
- print_canvas_size_.set_width(
- printing::ConvertUnit(print_params.printable_size.width(),
- static_cast<int>(print_params.dpi),
- print_params.desired_dpi));
- print_canvas_size_.set_height(
- printing::ConvertUnit(print_params.printable_size.height(),
- static_cast<int>(print_params.dpi),
- print_params.desired_dpi));
-
- // Layout page according to printer page size. Since WebKit shrinks the
- // size of the page automatically (from 125% to 200%) we trick it to
- // think the page is 125% larger so the size of the page is correct for
- // minimum (default) scaling.
- // This is important for sites that try to fill the page.
- gfx::Size print_layout_size(print_canvas_size_);
- print_layout_size.set_height(static_cast<int>(
- static_cast<double>(print_layout_size.height()) * 1.25));
+PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
+ const ViewMsg_Print_Params& print_params,
+ WebFrame* frame,
+ WebView* web_view)
+ : frame_(frame), web_view_(web_view), expected_pages_count_(0) {
- prev_view_size_ = web_view->size();
-
- web_view->resize(print_layout_size);
-
- expected_pages_count_ = frame->PrintBegin(print_canvas_size_);
- }
-
- int GetExpectedPageCount() const {
- return expected_pages_count_;
- }
-
- gfx::Size GetPrintCanvasSize() const {
- return print_canvas_size_;
- }
-
- ~PrepareFrameAndViewForPrint() {
- frame_->PrintEnd();
- web_view_->resize(prev_view_size_);
- }
+ print_canvas_size_.set_width(
+ printing::ConvertUnit(print_params.printable_size.width(),
+ static_cast<int>(print_params.dpi),
+ print_params.desired_dpi));
- private:
- WebFrame* frame_;
- WebView* web_view_;
- gfx::Size print_canvas_size_;
- gfx::Size prev_view_size_;
- int expected_pages_count_;
+ print_canvas_size_.set_height(
+ printing::ConvertUnit(print_params.printable_size.height(),
+ static_cast<int>(print_params.dpi),
+ print_params.desired_dpi));
- DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint);
-};
-
-} // namespace
-
-void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) {
-#if defined(OS_WIN)
-
- // If still not finished with earlier print request simply ignore.
- if (IsPrinting())
- return;
-
- // Check if there is script repeatedly trying to print and ignore it if too
- // frequent. We use exponential wait time so for a page that calls print() in
- // a loop the user will need to cancel the print dialog after 2 seconds, 4
- // seconds, 8, ... up to the maximum of 2 minutes.
- // This gives the user time to navigate from the page.
- if (script_initiated && (user_cancelled_scripted_print_count_ > 0)) {
- base::TimeDelta diff = base::Time::Now() - last_cancelled_script_print_;
- int min_wait_seconds = std::min(
- kMinSecondsToIgnoreJavascriptInitiatedPrint <<
- (user_cancelled_scripted_print_count_ - 1),
- kMaxSecondsToIgnoreJavascriptInitiatedPrint);
- if (diff.InSeconds() < min_wait_seconds) {
- WebString message(WebString::fromUTF8(
- "Ignoring too frequent calls to print()."));
- frame->AddMessageToConsole(WebConsoleMessage(
- WebConsoleMessage::LevelWarning,
- message));
- return;
- }
- }
-
- // Retrieve the default print settings to calculate the expected number of
- // pages.
- ViewMsg_Print_Params default_settings;
- bool user_cancelled_print = false;
-
- IPC::SyncMessage* msg =
- new ViewHostMsg_GetDefaultPrintSettings(routing_id(), &default_settings);
- if (Send(msg)) {
- msg = NULL;
- // Check if the printer returned any settings, if the settings is empty, we
- // can safely assume there are no printer drivers configured. So we safely
- // terminate.
- if (default_settings.IsEmpty()) {
- // TODO: Create an async alert (http://crbug.com/14918).
- render_view_->RunJavaScriptAlert(frame,
- l10n_util::GetString(IDS_DEFAULT_PRINTER_NOT_FOUND_WARNING));
- return;
- }
-
- // Continue only if the settings are valid.
- if (default_settings.dpi && default_settings.document_cookie) {
- int expected_pages_count = 0;
-
- // Prepare once to calculate the estimated page count. This must be in
- // a scope for itself (see comments on PrepareFrameAndViewForPrint).
- {
- PrepareFrameAndViewForPrint prep_frame_view(default_settings,
- frame,
- frame->GetView());
- expected_pages_count = prep_frame_view.GetExpectedPageCount();
- DCHECK(expected_pages_count);
- }
+ // Layout page according to printer page size. Since WebKit shrinks the
+ // size of the page automatically (from 125% to 200%) we trick it to
+ // think the page is 125% larger so the size of the page is correct for
+ // minimum (default) scaling.
+ // This is important for sites that try to fill the page.
+ gfx::Size print_layout_size(print_canvas_size_);
+ print_layout_size.set_height(static_cast<int>(
+ static_cast<double>(print_layout_size.height()) * 1.25));
- // Ask the browser to show UI to retrieve the final print settings.
- ViewMsg_PrintPages_Params print_settings;
+ prev_view_size_ = web_view->size();
- ViewHostMsg_ScriptedPrint_Params params;
+ web_view->resize(print_layout_size);
- // The routing id is sent across as it is needed to look up the
- // corresponding RenderViewHost instance to signal and reset the
- // pump messages event.
- params.routing_id = routing_id();
- // host_window_ may be NULL at this point if the current window is a popup
- // and the print() command has been issued from the parent. The receiver
- // of this message has to deal with this.
- params.host_window_id = render_view_->host_window();
- params.cookie = default_settings.document_cookie;
- params.has_selection = frame->HasSelection();
- params.expected_pages_count = expected_pages_count;
+ expected_pages_count_ = frame->PrintBegin(print_canvas_size_);
+}
- msg = new ViewHostMsg_ScriptedPrint(params,
- &print_settings);
- msg->set_pump_messages_event(render_view_->modal_dialog_event());
+PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
+ frame_->PrintEnd();
+ web_view_->resize(prev_view_size_);
+}
- if (Send(msg)) {
- msg = NULL;
- // If the settings are invalid, early quit.
- if (print_settings.params.dpi &&
- print_settings.params.document_cookie) {
- if (print_settings.params.selection_only) {
- CopyAndPrint(print_settings, frame);
- } else {
- // TODO: Always copy before printing.
- PrintPages(print_settings, frame);
- }
+PrintWebViewHelper::PrintWebViewHelper(RenderView* render_view)
+ : render_view_(render_view),
+ user_cancelled_scripted_print_count_(0) {}
- // Reset cancel counter on first successful print.
- user_cancelled_scripted_print_count_ = 0;
- return; // All went well.
- } else {
- user_cancelled_print = true;
- }
- } else {
- // Send() failed.
- NOTREACHED();
- }
- } else {
- // Failed to get default settings.
- NOTREACHED();
- }
- } else {
- // Send() failed.
- NOTREACHED();
- }
- if (script_initiated && user_cancelled_print) {
- ++user_cancelled_scripted_print_count_;
- last_cancelled_script_print_ = base::Time::Now();
- }
- DidFinishPrinting(user_cancelled_print);
-#else // defined(OS_WIN)
- // TODO(port): print not implemented
- NOTIMPLEMENTED();
-#endif
-}
+PrintWebViewHelper::~PrintWebViewHelper() {}
void PrintWebViewHelper::DidFinishPrinting(bool success) {
if (!success) {
@@ -237,7 +81,6 @@ void PrintWebViewHelper::DidFinishPrinting(bool success) {
print_web_view_.release(); // Close deletes object.
print_pages_params_.reset();
}
-
}
bool PrintWebViewHelper::CopyAndPrint(const ViewMsg_PrintPages_Params& params,
@@ -292,120 +135,6 @@ void PrintWebViewHelper::PrintPages(const ViewMsg_PrintPages_Params& params,
}
}
-void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params,
- const gfx::Size& canvas_size,
- WebFrame* frame) {
-#if defined(OS_WIN)
- // Generate a memory-based metafile. It will use the current screen's DPI.
- printing::NativeMetafile metafile;
-
- metafile.CreateDc(NULL, NULL);
- HDC hdc = metafile.hdc();
- DCHECK(hdc);
- skia::PlatformDevice::InitializeDC(hdc);
- // Since WebKit extends the page width depending on the magical shrink
- // factor we make sure the canvas covers the worst case scenario
- // (x2.0 currently). PrintContext will then set the correct clipping region.
- int size_x = static_cast<int>(canvas_size.width() * params.params.max_shrink);
- int size_y = static_cast<int>(canvas_size.height() *
- params.params.max_shrink);
- // Calculate the dpi adjustment.
- float shrink = static_cast<float>(canvas_size.width()) /
- params.params.printable_size.width();
-#if 0
- // TODO(maruel): This code is kept for testing until the 100% GDI drawing
- // code is stable. maruels use this code's output as a reference when the
- // GDI drawing code fails.
-
- // 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);
- if (shrink <= 0) {
- NOTREACHED() << "Printing page " << params.page_number << " failed.";
- } else {
- // Update the dpi adjustment with the "page shrink" calculated in webkit.
- shrink /= webkit_shrink;
- }
-
- // Create a BMP v4 header that we can serialize.
- BITMAPV4HEADER bitmap_header;
- gfx::CreateBitmapV4Header(size_x, size_y, &bitmap_header);
- const SkBitmap& src_bmp = canvas.getDevice()->accessBitmap(true);
- SkAutoLockPixels src_lock(src_bmp);
- int retval = StretchDIBits(hdc,
- 0,
- 0,
- size_x, size_y,
- 0, 0,
- size_x, size_y,
- src_bmp.getPixels(),
- reinterpret_cast<BITMAPINFO*>(&bitmap_header),
- DIB_RGB_COLORS,
- SRCCOPY);
- DCHECK(retval != GDI_ERROR);
-#else
- // 100% GDI based.
- skia::VectorCanvas canvas(hdc, size_x, size_y);
- float webkit_shrink = frame->PrintPage(params.page_number, &canvas);
- if (shrink <= 0) {
- NOTREACHED() << "Printing page " << params.page_number << " failed.";
- } else {
- // Update the dpi adjustment with the "page shrink" calculated in webkit.
- shrink /= webkit_shrink;
- }
-#endif
-
- // Done printing. Close the device context to retrieve the compiled metafile.
- if (!metafile.CloseDc()) {
- NOTREACHED() << "metafile failed";
- }
-
- // Get the size of the compiled metafile.
- unsigned buf_size = metafile.GetDataSize();
- DCHECK_GT(buf_size, 128u);
- ViewHostMsg_DidPrintPage_Params page_params;
- page_params.data_size = 0;
- page_params.metafile_data_handle = NULL;
- page_params.page_number = params.page_number;
- page_params.document_cookie = params.params.document_cookie;
- page_params.actual_shrink = shrink;
- base::SharedMemory shared_buf;
-
- // 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.
- if (buf_size < 350*1024*1024) {
- // Allocate a shared memory buffer to hold the generated metafile data.
- if (shared_buf.Create(L"", false, false, buf_size) &&
- shared_buf.Map(buf_size)) {
- // Copy the bits into shared memory.
- if (metafile.GetData(shared_buf.memory(), buf_size)) {
- page_params.metafile_data_handle = shared_buf.handle();
- page_params.data_size = buf_size;
- } else {
- NOTREACHED() << "GetData() failed";
- }
- shared_buf.Unmap();
- } else {
- NOTREACHED() << "Buffer allocation failed";
- }
- } else {
- NOTREACHED() << "Buffer too large: " << buf_size;
- }
- metafile.CloseEmf();
- if (Send(new ViewHostMsg_DuplicateSection(
- routing_id(),
- page_params.metafile_data_handle,
- &page_params.metafile_data_handle))) {
- Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params));
- }
-#else // defined(OS_WIN)
- // TODO(port) implement printing
- NOTIMPLEMENTED();
-#endif
-}
-
bool PrintWebViewHelper::Send(IPC::Message* msg) {
return render_view_->Send(msg);
}
diff --git a/chrome/renderer/print_web_view_helper.h b/chrome/renderer/print_web_view_helper.h
index 13d0747..efa6ee0 100644
--- a/chrome/renderer/print_web_view_helper.h
+++ b/chrome/renderer/print_web_view_helper.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/gfx/size.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
#include "webkit/glue/webview_delegate.h"
@@ -26,16 +27,43 @@ struct ViewMsg_PrintPage_Params;
struct ViewMsg_PrintPages_Params;
+// Class that calls the Begin and End print functions on the frame and changes
+// the size of the view temporarily to support full page printing..
+// Do not serve any events in the time between construction and destruction of
+// this class because it will cause flicker.
+class PrepareFrameAndViewForPrint {
+ public:
+ PrepareFrameAndViewForPrint(const ViewMsg_Print_Params& print_params,
+ WebFrame* frame,
+ WebView* web_view);
+ ~PrepareFrameAndViewForPrint();
+
+ int GetExpectedPageCount() const {
+ return expected_pages_count_;
+ }
+
+ const gfx::Size& GetPrintCanvasSize() const {
+ return print_canvas_size_;
+ }
+
+ private:
+ WebFrame* frame_;
+ WebView* web_view_;
+ gfx::Size print_canvas_size_;
+ gfx::Size prev_view_size_;
+ int expected_pages_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint);
+};
+
+
// PrintWebViewHelper handles most of the printing grunt work for RenderView.
// We plan on making print asynchronous and that will require copying the DOM
// of the document and creating a new WebView with the contents.
class PrintWebViewHelper : public WebViewDelegate {
public:
- explicit PrintWebViewHelper(RenderView * render_view)
- : render_view_(render_view),
- user_cancelled_scripted_print_count_(0) {}
-
- virtual ~PrintWebViewHelper() {}
+ explicit PrintWebViewHelper(RenderView* render_view);
+ virtual ~PrintWebViewHelper();
void Print(WebFrame* frame, bool script_initiated);
diff --git a/chrome/renderer/print_web_view_helper_linux.cc b/chrome/renderer/print_web_view_helper_linux.cc
new file mode 100644
index 0000000..52b997d
--- /dev/null
+++ b/chrome/renderer/print_web_view_helper_linux.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/print_web_view_helper.h"
+
+#include "base/logging.h"
+#include "chrome/common/render_messages.h"
+#include "skia/ext/vector_canvas.h"
+#include "webkit/glue/webframe.h"
+
+
+void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) {
+ // If still not finished with earlier print request simply ignore.
+ if (IsPrinting())
+ return;
+
+ // TODO(myhuang): Get printing parameters via IPC.
+ // For testing purpose, we hard-coded printing parameters here.
+
+ // The paper size is US Letter (8.5 in. by 11 in.).
+ // Using default margins:
+ // Left = 0.25 in.
+ // Right = 0.25 in.
+ // Top = 0.25 in.
+ // Bottom = 0.56 in.
+ const int kDPI = 72;
+ const int kWidth = (8.5-0.25-0.25) * kDPI;
+ const int kHeight = (11-0.25-0.56) * kDPI;
+ ViewMsg_Print_Params default_settings;
+ default_settings.printable_size = gfx::Size(kWidth, kHeight);
+ default_settings.dpi = kDPI;
+ default_settings.min_shrink = 1.25;
+ default_settings.max_shrink = 2.0;
+ default_settings.desired_dpi = kDPI;
+ default_settings.document_cookie = NULL;
+ default_settings.selection_only = false;
+
+ // Calculate the estimated page count.
+ PrepareFrameAndViewForPrint prep_frame_view(default_settings,
+ frame,
+ frame->GetView());
+ int expected_pages_count = prep_frame_view.GetExpectedPageCount();
+ DCHECK(expected_pages_count);
+
+ ViewMsg_PrintPage_Params page_params;
+ page_params.params = default_settings;
+
+ // TODO(myhuang): Get final printing settings via IPC.
+ // For testing purpose, we hard-coded printing settings here.
+
+ // Print the first page only.
+ expected_pages_count = 1;
+ for (int i = 0; i < expected_pages_count; ++i) {
+ page_params.page_number = i;
+ PrintPage(page_params, prep_frame_view.GetPrintCanvasSize(), frame);
+ }
+}
+
+void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params,
+ const gfx::Size& canvas_size,
+ WebFrame* frame) {
+ // Since WebKit extends the page width depending on the magical shrink
+ // factor we make sure the canvas covers the worst case scenario
+ // (x2.0 currently). PrintContext will then set the correct clipping region.
+ int size_x = static_cast<int>(canvas_size.width() * params.params.max_shrink);
+ int size_y = static_cast<int>(canvas_size.height() *
+ params.params.max_shrink);
+ // Calculate the dpi adjustment.
+ float shrink = static_cast<float>(canvas_size.width()) /
+ params.params.printable_size.width();
+
+ // TODO(myhuang): We now use VectorCanvas to generate a PS/PDF file for
+ // each page in printing. We might also need to create a metafile class
+ // on Linux.
+ skia::VectorCanvas canvas(size_x, size_y);
+ float webkit_shrink = frame->PrintPage(params.page_number, &canvas);
+ if (shrink <= 0) {
+ NOTREACHED() << "Printing page " << params.page_number << " failed.";
+ } else {
+ // Update the dpi adjustment with the "page shrink" calculated in webkit.
+ shrink /= webkit_shrink;
+ }
+}
+
diff --git a/chrome/renderer/print_web_view_helper_mac.cc b/chrome/renderer/print_web_view_helper_mac.cc
new file mode 100644
index 0000000..ce07add
--- /dev/null
+++ b/chrome/renderer/print_web_view_helper_mac.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/print_web_view_helper.h"
+
+#include "base/logging.h"
+
+void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) {
+ // TODO(port): print not implemented
+ NOTIMPLEMENTED();
+}
+
+void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params,
+ const gfx::Size& canvas_size,
+ WebFrame* frame) {
+ // TODO(port) implement printing
+ NOTIMPLEMENTED();
+}
+
diff --git a/chrome/renderer/print_web_view_helper_win.cc b/chrome/renderer/print_web_view_helper_win.cc
index 1e9a0fe..e4e372a 100644
--- a/chrome/renderer/print_web_view_helper_win.cc
+++ b/chrome/renderer/print_web_view_helper_win.cc
@@ -5,105 +5,29 @@
#include "chrome/renderer/print_web_view_helper.h"
#include "app/l10n_util.h"
-#include "base/logging.h"
#include "base/gfx/size.h"
+#include "base/logging.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/render_view.h"
#include "grit/generated_resources.h"
#include "printing/native_metafile.h"
-#include "printing/units.h"
#include "webkit/api/public/WebConsoleMessage.h"
-#include "webkit/api/public/WebRect.h"
-#include "webkit/api/public/WebScreenInfo.h"
-#include "webkit/api/public/WebSize.h"
-#include "webkit/api/public/WebURL.h"
-#include "webkit/api/public/WebURLRequest.h"
#include "webkit/glue/webframe.h"
-#if defined(OS_WIN)
-#include "skia/ext/vector_canvas.h"
-#endif
-
using WebKit::WebConsoleMessage;
-using WebKit::WebRect;
-using WebKit::WebScreenInfo;
using WebKit::WebString;
-using WebKit::WebURLRequest;
-
-namespace {
-
-const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
-const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 2 * 60; // 2 Minutes.
-
-// Class that calls the Begin and End print functions on the frame and changes
-// the size of the view temporarily to support full page printing..
-// Do not serve any events in the time between construction and destruction of
-// this class because it will cause flicker.
-class PrepareFrameAndViewForPrint {
- public:
- PrepareFrameAndViewForPrint(const ViewMsg_Print_Params& print_params,
- WebFrame* frame,
- WebView* web_view)
- : frame_(frame),
- web_view_(web_view),
- expected_pages_count_(0) {
- print_canvas_size_.set_width(
- printing::ConvertUnit(print_params.printable_size.width(),
- static_cast<int>(print_params.dpi),
- print_params.desired_dpi));
- print_canvas_size_.set_height(
- printing::ConvertUnit(print_params.printable_size.height(),
- static_cast<int>(print_params.dpi),
- print_params.desired_dpi));
-
- // Layout page according to printer page size. Since WebKit shrinks the
- // size of the page automatically (from 125% to 200%) we trick it to
- // think the page is 125% larger so the size of the page is correct for
- // minimum (default) scaling.
- // This is important for sites that try to fill the page.
- gfx::Size print_layout_size(print_canvas_size_);
- print_layout_size.set_height(static_cast<int>(
- static_cast<double>(print_layout_size.height()) * 1.25));
-
- prev_view_size_ = web_view->size();
-
- web_view->resize(print_layout_size);
-
- expected_pages_count_ = frame->PrintBegin(print_canvas_size_);
- }
-
- int GetExpectedPageCount() const {
- return expected_pages_count_;
- }
- gfx::Size GetPrintCanvasSize() const {
- return print_canvas_size_;
- }
-
- ~PrepareFrameAndViewForPrint() {
- frame_->PrintEnd();
- web_view_->resize(prev_view_size_);
- }
-
- private:
- WebFrame* frame_;
- WebView* web_view_;
- gfx::Size print_canvas_size_;
- gfx::Size prev_view_size_;
- int expected_pages_count_;
-
- DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint);
-};
-
-} // namespace
+#include "skia/ext/vector_canvas.h"
void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) {
-#if defined(OS_WIN)
+ const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
+ const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 2 * 60; // 2 Minutes.
// If still not finished with earlier print request simply ignore.
if (IsPrinting())
return;
+ // TODO(maruel): Move this out of platform specific code.
// Check if there is script repeatedly trying to print and ignore it if too
// frequent. We use exponential wait time so for a page that calls print() in
// a loop the user will need to cancel the print dialog after 2 seconds, 4
@@ -215,87 +139,11 @@ void PrintWebViewHelper::Print(WebFrame* frame, bool script_initiated) {
last_cancelled_script_print_ = base::Time::Now();
}
DidFinishPrinting(user_cancelled_print);
-#else // defined(OS_WIN)
- // TODO(port): print not implemented
- NOTIMPLEMENTED();
-#endif
-}
-
-void PrintWebViewHelper::DidFinishPrinting(bool success) {
- if (!success) {
- WebView* web_view = print_web_view_.get();
- if (!web_view)
- web_view = render_view_->webview();
-
- // TODO: Create an async alert (http://crbug.com/14918).
- render_view_->RunJavaScriptAlert(web_view->GetMainFrame(),
- l10n_util::GetString(IDS_PRINT_SPOOL_FAILED_ERROR_TEXT));
- }
-
- if (print_web_view_.get()) {
- print_web_view_->close();
- print_web_view_.release(); // Close deletes object.
- print_pages_params_.reset();
- }
-
-}
-
-bool PrintWebViewHelper::CopyAndPrint(const ViewMsg_PrintPages_Params& params,
- WebFrame* web_frame) {
- // Create a new WebView with the same settings as the current display one.
- // Except that we disable javascript (don't want any active content running
- // on the page).
- WebPreferences prefs = web_frame->GetView()->GetPreferences();
- prefs.javascript_enabled = false;
- prefs.java_enabled = false;
- print_web_view_.reset(WebView::Create(this, prefs));
-
- print_pages_params_.reset(new ViewMsg_PrintPages_Params(params));
- print_pages_params_->pages.clear(); // Print all pages of selection.
-
- std::string html = web_frame->GetSelection(true);
- std::string url_str = "data:text/html;charset=utf-8,";
- url_str.append(html);
- GURL url(url_str);
-
- // When loading is done this will call DidStopLoading that will do the
- // actual printing.
- print_web_view_->GetMainFrame()->LoadRequest(WebURLRequest(url));
-
- return true;
-}
-
-void PrintWebViewHelper::PrintPages(const ViewMsg_PrintPages_Params& params,
- WebFrame* frame) {
- PrepareFrameAndViewForPrint prep_frame_view(params.params,
- frame,
- frame->GetView());
- int page_count = prep_frame_view.GetExpectedPageCount();
-
- Send(new ViewHostMsg_DidGetPrintedPagesCount(routing_id(),
- params.params.document_cookie,
- page_count));
- if (page_count) {
- ViewMsg_PrintPage_Params page_params;
- page_params.params = params.params;
- if (params.pages.empty()) {
- for (int i = 0; i < page_count; ++i) {
- page_params.page_number = i;
- PrintPage(page_params, prep_frame_view.GetPrintCanvasSize(), frame);
- }
- } else {
- for (size_t i = 0; i < params.pages.size(); ++i) {
- page_params.page_number = params.pages[i];
- PrintPage(page_params, prep_frame_view.GetPrintCanvasSize(), frame);
- }
- }
- }
}
void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame) {
-#if defined(OS_WIN)
// Generate a memory-based metafile. It will use the current screen's DPI.
printing::NativeMetafile metafile;
@@ -400,42 +248,5 @@ void PrintWebViewHelper::PrintPage(const ViewMsg_PrintPage_Params& params,
&page_params.metafile_data_handle))) {
Send(new ViewHostMsg_DidPrintPage(routing_id(), page_params));
}
-#else // defined(OS_WIN)
- // TODO(port) implement printing
- NOTIMPLEMENTED();
-#endif
-}
-
-bool PrintWebViewHelper::Send(IPC::Message* msg) {
- return render_view_->Send(msg);
-}
-
-int32 PrintWebViewHelper::routing_id() {
- return render_view_->routing_id();
-}
-
-WebRect PrintWebViewHelper::windowRect() {
- NOTREACHED();
- return WebRect();
}
-WebRect PrintWebViewHelper::windowResizerRect() {
- NOTREACHED();
- return WebRect();
-}
-
-WebRect PrintWebViewHelper::rootWindowRect() {
- NOTREACHED();
- return WebRect();
-}
-
-WebScreenInfo PrintWebViewHelper::screenInfo() {
- NOTREACHED();
- return WebScreenInfo();
-}
-
-void PrintWebViewHelper::DidStopLoading(WebView* webview) {
- DCHECK(print_pages_params_.get() != NULL);
- DCHECK_EQ(webview, print_web_view_.get());
- PrintPages(*print_pages_params_.get(), print_web_view_->GetMainFrame());
-}
diff --git a/skia/ext/vector_canvas.cc b/skia/ext/vector_canvas.cc
index 75b7310..c80d0c3 100644
--- a/skia/ext/vector_canvas.cc
+++ b/skia/ext/vector_canvas.cc
@@ -1,36 +1,17 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "skia/ext/vector_canvas.h"
-#include "skia/ext/bitmap_platform_device_win.h"
-#include "skia/ext/vector_platform_device_win.h"
-
namespace skia {
VectorCanvas::VectorCanvas() {
}
-VectorCanvas::VectorCanvas(HDC dc, int width, int height) {
- bool initialized = initialize(dc, width, height);
- if (!initialized)
- __debugbreak();
-}
-
VectorCanvas::~VectorCanvas() {
}
-bool VectorCanvas::initialize(HDC context, int width, int height) {
- SkDevice* device = createPlatformDevice(width, height, true, context);
- if (!device)
- return false;
-
- setDevice(device);
- device->unref(); // was created with refcount 1, and setDevice also refs
- return true;
-}
-
SkBounder* VectorCanvas::setBounder(SkBounder* bounder) {
if (!IsTopDeviceVectorial())
return PlatformCanvas::setBounder(bounder);
@@ -40,49 +21,12 @@ SkBounder* VectorCanvas::setBounder(SkBounder* bounder) {
return NULL;
}
-SkDevice* VectorCanvas::createDevice(SkBitmap::Config config,
- int width, int height,
- bool is_opaque, bool isForLayer) {
- SkASSERT(config == SkBitmap::kARGB_8888_Config);
- return createPlatformDevice(width, height, is_opaque, NULL);
-}
-
SkDrawFilter* VectorCanvas::setDrawFilter(SkDrawFilter* filter) {
// This function isn't used in the code. Verify this assumption.
SkASSERT(false);
return NULL;
}
-SkDevice* VectorCanvas::createPlatformDevice(int width,
- int height, bool is_opaque,
- HANDLE shared_section) {
- if (!is_opaque) {
- // TODO(maruel): http://b/1184002 1184002 When restoring a semi-transparent
- // layer, i.e. merging it, we need to rasterize it because GDI doesn't
- // support transparency except for AlphaBlend(). Right now, a
- // BitmapPlatformDevice is created when VectorCanvas think a saveLayers()
- // call is being done. The way to save a layer would be to create an
- // EMF-based VectorDevice and have this device registers the drawing. When
- // playing back the device into a bitmap, do it at the printer's dpi instead
- // of the layout's dpi (which is much lower).
- return BitmapPlatformDevice::create(width, height,
- is_opaque, shared_section);
- }
-
- // TODO(maruel): http://b/1183870 Look if it would be worth to increase the
- // resolution by ~10x (any worthy factor) to increase the rendering precision
- // (think about printing) while using a relatively low dpi. This happens
- // because we receive float as input but the GDI functions works with
- // integers. The idea is to premultiply the matrix with this factor and
- // multiply each SkScalar that are passed to SkScalarRound(value) as
- // SkScalarRound(value * 10). Safari is already doing the same for text
- // rendering.
- SkASSERT(shared_section);
- PlatformDevice* device = VectorPlatformDevice::create(
- reinterpret_cast<HDC>(shared_section), width, height);
- return device;
-}
-
bool VectorCanvas::IsTopDeviceVectorial() const {
return getTopPlatformDevice().IsVectorial();
}
diff --git a/skia/ext/vector_canvas.h b/skia/ext/vector_canvas.h
index 510e8f3..27f7598 100644
--- a/skia/ext/vector_canvas.h
+++ b/skia/ext/vector_canvas.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,7 @@
#define SKIA_EXT_VECTOR_CANVAS_H_
#include "skia/ext/platform_canvas.h"
-#include "skia/ext/vector_platform_device_win.h"
+#include "skia/ext/vector_platform_device.h"
namespace skia {
@@ -17,22 +17,36 @@ namespace skia {
class VectorCanvas : public PlatformCanvas {
public:
VectorCanvas();
+#if defined(WIN32)
VectorCanvas(HDC dc, int width, int height);
+#elif defined(__linux__)
+ VectorCanvas(int width, int height);
+#endif
virtual ~VectorCanvas();
// For two-part init, call if you use the no-argument constructor above
+#if defined(WIN32)
bool initialize(HDC context, int width, int height);
+#elif defined(__linux__)
+ bool initialize(int width, int height);
+#endif
virtual SkBounder* setBounder(SkBounder*);
+#if defined(WIN32) || defined(__linux__)
virtual SkDevice* createDevice(SkBitmap::Config config,
int width, int height,
bool is_opaque, bool isForLayer);
+#endif
virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter);
private:
// |is_opaque| is unused. |shared_section| is in fact the HDC used for output.
+#if defined(WIN32)
virtual SkDevice* createPlatformDevice(int width, int height, bool is_opaque,
HANDLE shared_section);
+#elif defined(__linux__)
+ virtual SkDevice* createPlatformDevice(int width, int height, bool is_opaque);
+#endif
// Returns true if the top device is vector based and not bitmap based.
bool IsTopDeviceVectorial() const;
diff --git a/skia/ext/vector_canvas_linux.cc b/skia/ext/vector_canvas_linux.cc
new file mode 100644
index 0000000..95722c9
--- /dev/null
+++ b/skia/ext/vector_canvas_linux.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "skia/ext/vector_canvas.h"
+
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/vector_platform_device.h"
+
+namespace skia {
+
+VectorCanvas::VectorCanvas(int width, int height) {
+ bool initialized = initialize(width, height);
+
+ SkASSERT(initialized);
+}
+
+bool VectorCanvas::initialize(int width, int height) {
+ SkDevice* device = createPlatformDevice(width, height, true);
+ if (!device)
+ return false;
+
+ setDevice(device);
+ device->unref(); // was created with refcount 1, and setDevice also refs
+ return true;
+}
+
+SkDevice* VectorCanvas::createDevice(SkBitmap::Config config,
+ int width, int height,
+ bool is_opaque, bool isForLayer) {
+ SkASSERT(config == SkBitmap::kARGB_8888_Config);
+ return createPlatformDevice(width, height, is_opaque);
+}
+
+SkDevice* VectorCanvas::createPlatformDevice(int width,
+ int height, bool is_opaque) {
+ // TODO(myhuang): Here we might also have similar issues as those on Windows
+ // (vector_canvas_win.cc, http://crbug.com/18382 & http://crbug.com/18383).
+ // Please note that is_opaque is true when we use this class for printing.
+ if (!is_opaque) {
+ return BitmapPlatformDevice::Create(width, height, is_opaque);
+ }
+
+ PlatformDevice* device = VectorPlatformDevice::create(width, height);
+ return device;
+}
+
+} // namespace skia
+
diff --git a/skia/ext/vector_canvas_win.cc b/skia/ext/vector_canvas_win.cc
index 75b7310..3fe14b0 100644
--- a/skia/ext/vector_canvas_win.cc
+++ b/skia/ext/vector_canvas_win.cc
@@ -1,26 +1,20 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "skia/ext/vector_canvas.h"
-#include "skia/ext/bitmap_platform_device_win.h"
-#include "skia/ext/vector_platform_device_win.h"
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/vector_platform_device.h"
namespace skia {
-VectorCanvas::VectorCanvas() {
-}
-
VectorCanvas::VectorCanvas(HDC dc, int width, int height) {
bool initialized = initialize(dc, width, height);
if (!initialized)
__debugbreak();
}
-VectorCanvas::~VectorCanvas() {
-}
-
bool VectorCanvas::initialize(HDC context, int width, int height) {
SkDevice* device = createPlatformDevice(width, height, true, context);
if (!device)
@@ -31,15 +25,6 @@ bool VectorCanvas::initialize(HDC context, int width, int height) {
return true;
}
-SkBounder* VectorCanvas::setBounder(SkBounder* bounder) {
- if (!IsTopDeviceVectorial())
- return PlatformCanvas::setBounder(bounder);
-
- // This function isn't used in the code. Verify this assumption.
- SkASSERT(false);
- return NULL;
-}
-
SkDevice* VectorCanvas::createDevice(SkBitmap::Config config,
int width, int height,
bool is_opaque, bool isForLayer) {
@@ -47,17 +32,11 @@ SkDevice* VectorCanvas::createDevice(SkBitmap::Config config,
return createPlatformDevice(width, height, is_opaque, NULL);
}
-SkDrawFilter* VectorCanvas::setDrawFilter(SkDrawFilter* filter) {
- // This function isn't used in the code. Verify this assumption.
- SkASSERT(false);
- return NULL;
-}
-
SkDevice* VectorCanvas::createPlatformDevice(int width,
int height, bool is_opaque,
HANDLE shared_section) {
if (!is_opaque) {
- // TODO(maruel): http://b/1184002 1184002 When restoring a semi-transparent
+ // TODO(maruel): http://crbug.com/18382 When restoring a semi-transparent
// layer, i.e. merging it, we need to rasterize it because GDI doesn't
// support transparency except for AlphaBlend(). Right now, a
// BitmapPlatformDevice is created when VectorCanvas think a saveLayers()
@@ -69,23 +48,19 @@ SkDevice* VectorCanvas::createPlatformDevice(int width,
is_opaque, shared_section);
}
- // TODO(maruel): http://b/1183870 Look if it would be worth to increase the
- // resolution by ~10x (any worthy factor) to increase the rendering precision
- // (think about printing) while using a relatively low dpi. This happens
- // because we receive float as input but the GDI functions works with
- // integers. The idea is to premultiply the matrix with this factor and
- // multiply each SkScalar that are passed to SkScalarRound(value) as
- // SkScalarRound(value * 10). Safari is already doing the same for text
- // rendering.
+ // TODO(maruel): http://crbug.com/18383 Look if it would be worth to
+ // increase the resolution by ~10x (any worthy factor) to increase the
+ // rendering precision (think about printing) while using a relatively
+ // low dpi. This happens because we receive float as input but the GDI
+ // functions works with integers. The idea is to premultiply the matrix
+ // with this factor and multiply each SkScalar that are passed to
+ // SkScalarRound(value) as SkScalarRound(value * 10). Safari is already
+ // doing the same for text rendering.
SkASSERT(shared_section);
PlatformDevice* device = VectorPlatformDevice::create(
reinterpret_cast<HDC>(shared_section), width, height);
return device;
}
-bool VectorCanvas::IsTopDeviceVectorial() const {
- return getTopPlatformDevice().IsVectorial();
-}
-
} // namespace skia
diff --git a/skia/ext/vector_platform_device.h b/skia/ext/vector_platform_device.h
new file mode 100644
index 0000000..d77e565
--- /dev/null
+++ b/skia/ext/vector_platform_device.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SKIA_EXT_VECTOR_PLATFORM_DEVICE_H_
+#define SKIA_EXT_VECTOR_PLATFORM_DEVICE_H_
+
+// This file provides an easy way to include the appropriate
+// VectorPlatformDevice header file for your platform.
+#if defined(WIN32)
+#include "skia/ext/vector_platform_device_win.h"
+#elif defined(__linux__)
+#include "skia/ext/vector_platform_device_linux.h"
+#endif
+
+#endif
+
diff --git a/skia/ext/vector_platform_device_linux.cc b/skia/ext/vector_platform_device_linux.cc
new file mode 100644
index 0000000..8c1b108
--- /dev/null
+++ b/skia/ext/vector_platform_device_linux.cc
@@ -0,0 +1,498 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "skia/ext/vector_platform_device.h"
+
+// TODO(myhuang): We have to decide or allow the user the choose the type
+// of the surface in the future.
+#include <cairo-pdf.h>
+
+#include "third_party/skia/include/core/SkTypeface.h"
+
+namespace skia {
+
+VectorPlatformDevice* VectorPlatformDevice::create(int width, int height) {
+ SkASSERT(width > 0);
+ SkASSERT(height > 0);
+
+ // TODO(myhuang): Can we get rid of the bitmap? In this vetorial device,
+ // the content of this bitmap is meaningless. However, it does occupy
+ // lots of memory space.
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+
+ return new VectorPlatformDevice(bitmap);
+}
+
+VectorPlatformDevice::VectorPlatformDevice(const SkBitmap& bitmap)
+ : PlatformDevice(bitmap) {
+ SkASSERT(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
+
+ // FIXME(myhuang): At this moment, we write the PDF file to the disk
+ // for testing when we run chromium without sanboxing.
+ surface_ = cairo_pdf_surface_create("chrome_printing_test.pdf",
+ width(), height());
+ SkASSERT(surface);
+ context_ = cairo_create(surface_);
+ SkASSERT(context_);
+
+ transform_.reset();
+}
+
+VectorPlatformDevice::~VectorPlatformDevice() {
+ SkASSERT(surface);
+ SkASSERT(context_);
+
+ cairo_destroy(context_);
+ cairo_surface_destroy(surface_);
+}
+
+void VectorPlatformDevice::drawBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkMatrix& matrix,
+ const SkPaint& paint) {
+ SkASSERT(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
+
+ // Load the temporary matrix. This is what will translate, rotate and resize
+ // the bitmap.
+ SkMatrix actual_transform(transform_);
+ actual_transform.preConcat(matrix);
+ LoadTransformToContext(actual_transform);
+
+ InternalDrawBitmap(bitmap, 0, 0, paint);
+
+ // Restore the original matrix.
+ LoadTransformToContext(transform_);
+}
+
+void VectorPlatformDevice::drawDevice(const SkDraw& draw,
+ SkDevice* device,
+ int x,
+ int y,
+ const SkPaint& paint) {
+ SkASSERT(device);
+ SkASSERT(device->accessBitmap(false));
+
+ // TODO(myhuang): We may also have to consider http://b/1183870 .
+ drawSprite(draw, device->accessBitmap(false), x, y, paint);
+}
+
+void VectorPlatformDevice::drawPaint(const SkDraw& draw,
+ const SkPaint& paint) {
+ // Bypass the current transformation matrix.
+ LoadIdentityTransformToContext();
+
+ // FIXME(myhuang): Is there a better way to do this?
+ SkRect rect;
+ rect.fLeft = 0;
+ rect.fTop = 0;
+ rect.fRight = SkIntToScalar(width() + 1);
+ rect.fBottom = SkIntToScalar(height() + 1);
+ drawRect(draw, rect, paint);
+
+ // Restore the original matrix.
+ LoadTransformToContext(transform_);
+}
+
+void VectorPlatformDevice::drawPath(const SkDraw& draw,
+ const SkPath& path,
+ const SkPaint& paint) {
+ if (paint.getPathEffect()) {
+ // Apply the path effect forehand.
+ SkPath path_modified;
+ paint.getFillPath(path, &path_modified);
+
+ // Removes the path effect from the temporary SkPaint object.
+ SkPaint paint_no_effet(paint);
+ paint_no_effet.setPathEffect(NULL)->safeUnref();
+
+ // Draw the calculated path.
+ drawPath(draw, path_modified, paint_no_effet);
+ return;
+ }
+
+ // Setup paint color.
+ ApplyPaintColor(paint);
+
+ SkPaint::Style style = paint.getStyle();
+ // Setup fill style.
+ if (style & SkPaint::kFill_Style) {
+ ApplyFillStyle(path);
+ }
+
+ // Setup stroke style.
+ if (style & SkPaint::kStroke_Style) {
+ ApplyStrokeStyle(paint);
+ }
+
+ // Iterate path verbs.
+ // TODO(myhuang): Is there a better way to do this?
+ SkPoint current_points[4];
+ SkPath::Iter iter(path, false);
+ for (SkPath::Verb verb = iter.next(current_points);
+ verb != SkPath::kDone_Verb;
+ verb = iter.next(current_points)) {
+ switch (verb) {
+ case SkPath::kMove_Verb: { // iter.next returns 1 point
+ cairo_move_to(context_, current_points[0].fX, current_points[0].fY);
+ } break;
+
+ case SkPath::kLine_Verb: { // iter.next returns 2 points
+ cairo_line_to(context_, current_points[1].fX, current_points[1].fY);
+ } break;
+
+ case SkPath::kQuad_Verb: { // iter.next returns 3 points
+ cairo_curve_to(context_,
+ current_points[1].fX, current_points[1].fY,
+ current_points[2].fX, current_points[2].fY,
+ current_points[2].fX, current_points[2].fY);
+ } break;
+
+ case SkPath::kCubic_Verb: { // iter.next returns 4 points
+ cairo_curve_to(context_,
+ current_points[1].fX, current_points[1].fY,
+ current_points[2].fX, current_points[2].fY,
+ current_points[3].fX, current_points[3].fY);
+ } break;
+
+ case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
+ cairo_close_path(context_);
+ } break;
+
+ case SkPath::kDone_Verb: { // iter.next returns 0 points
+ } break;
+
+ default: {
+ // Should not reach here!
+ SkASSERT(false);
+ } break;
+ }
+ }
+
+ DoPaintStyle(paint);
+}
+
+void VectorPlatformDevice::drawPoints(const SkDraw& draw,
+ SkCanvas::PointMode mode,
+ size_t count,
+ const SkPoint pts[],
+ const SkPaint& paint) {
+ SkASSERT(pts);
+
+ if (!count)
+ return;
+
+ // Setup paint color.
+ ApplyPaintColor(paint);
+
+ // Setup stroke style.
+ ApplyStrokeStyle(paint);
+
+ switch (mode) {
+ case SkCanvas::kPoints_PointMode: {
+ // There is a bug in Cairo that it won't draw anything when using some
+ // specific caps, e.g. SkPaint::kSquare_Cap. This is because Cairo does
+ // not have enough/ambiguous direction information. One possible work-
+ // around is to draw a really short line.
+ for (size_t i = 0; i < count; ++i) {
+ double x = pts[i].fX;
+ double y = pts[i].fY;
+ cairo_move_to(context_, x, y);
+ cairo_line_to(context_, x+.01, y);
+ }
+ } break;
+
+ case SkCanvas::kLines_PointMode: {
+ if (count % 2) {
+ SkASSERT(false);
+ return;
+ }
+
+ for (size_t i = 0; i < count >> 1; ++i) {
+ double x1 = pts[i << 1].fX;
+ double y1 = pts[i << 1].fY;
+ double x2 = pts[(i << 1) + 1].fX;
+ double y2 = pts[(i << 1) + 1].fY;
+ cairo_move_to(context_, x1, y1);
+ cairo_line_to(context_, x2, y2);
+ }
+ } break;
+
+ case SkCanvas::kPolygon_PointMode: {
+ double x = pts[0].fX;
+ double y = pts[0].fY;
+ cairo_move_to(context_, x, y);
+ for (size_t i = 1; i < count; ++i) {
+ x = pts[i].fX;
+ y = pts[i].fY;
+ cairo_line_to(context_, x, y);
+ }
+ } break;
+
+ default:
+ SkASSERT(false);
+ return;
+ }
+ cairo_stroke(context_);
+}
+
+// TODO(myhuang): Support font family.
+// TODO(myhuang): Support Stroke/Fill better.
+void VectorPlatformDevice::drawPosText(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ const SkScalar pos[],
+ SkScalar constY,
+ int scalarsPerPos,
+ const SkPaint& paint) {
+ SkASSERT(text);
+ SkASSERT(pos);
+ SkASSERT(paint.gettextEncoding() == SkPaint::kGlyphID_TextEncoding);
+ SkASSERT(scalarsPerPos == 2); // Each pos contains x and y.
+
+ if (!len)
+ return;
+
+ // Text color.
+ ApplyPaintColor(paint);
+
+ cairo_set_font_size(context_, paint.getTextSize());
+
+ SkTypeface* typeface = paint.getTypeface();
+ SkASSERT(typeface);
+
+ cairo_font_slant_t font_slant =
+ typeface->isItalic() ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_NORMAL;
+
+ cairo_font_weight_t font_weight =
+ typeface->isBold() ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL;
+
+ cairo_select_font_face(context_, "", font_slant, font_weight);
+
+ // FIXME(myhuang): We now draw glyphs one by one.
+ // Maybe we should draw them altogether in the future.
+ const uint16_t* glyphIDs = reinterpret_cast<const uint16_t*>(text);
+ // scalarsPerPos should be 2 here in the loop!
+ for (size_t i = 0; i < len / scalarsPerPos; ++i) {
+ uint16_t glyphID = glyphIDs[i];
+
+ cairo_glyph_t glyph;
+ glyph.index = glyphID;
+ glyph.x = pos[i * scalarsPerPos + 0];
+ glyph.y = pos[i * scalarsPerPos + 1];
+ cairo_glyph_path(context_, &glyph, 1);
+ }
+ DoPaintStyle(paint);
+}
+
+void VectorPlatformDevice::drawRect(const SkDraw& draw,
+ const SkRect& rect,
+ const SkPaint& paint) {
+ if (paint.getPathEffect()) {
+ // Draw a path instead.
+ SkPath path_orginal;
+ path_orginal.addRect(rect);
+
+ // Apply the path effect to the rect.
+ SkPath path_modified;
+ paint.getFillPath(path_orginal, &path_modified);
+
+ // Removes the path effect from the temporary SkPaint object.
+ SkPaint paint_no_effet(paint);
+ paint_no_effet.setPathEffect(NULL)->safeUnref();
+
+ // Draw the calculated path.
+ drawPath(draw, path_modified, paint_no_effet);
+ return;
+ }
+
+ // Setup color.
+ ApplyPaintColor(paint);
+
+ // Setup stroke style.
+ ApplyStrokeStyle(paint);
+
+ // Draw rectangle.
+ cairo_rectangle(context_,
+ rect.fLeft, rect.fTop,
+ rect.fRight - rect.fLeft, rect.fBottom - rect.fTop);
+
+ DoPaintStyle(paint);
+}
+
+void VectorPlatformDevice::drawSprite(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ int x, int y,
+ const SkPaint& paint) {
+ SkASSERT(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
+
+ LoadIdentityTransformToContext();
+
+ InternalDrawBitmap(bitmap, x, y, paint);
+
+ // Restore the original matrix.
+ LoadTransformToContext(transform_);
+}
+
+void VectorPlatformDevice::drawText(const SkDraw& draw,
+ const void* text,
+ size_t byteLength,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) {
+ // This function isn't used in the code. Verify this assumption.
+ SkASSERT(false);
+}
+
+
+void VectorPlatformDevice::drawTextOnPath(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ const SkPath& path,
+ const SkMatrix* matrix,
+ const SkPaint& paint) {
+ // This function isn't used in the code. Verify this assumption.
+ SkASSERT(false);
+}
+
+void VectorPlatformDevice::drawVertices(const SkDraw& draw,
+ SkCanvas::VertexMode vmode,
+ int vertexCount,
+ const SkPoint vertices[],
+ const SkPoint texs[],
+ const SkColor colors[],
+ SkXfermode* xmode,
+ const uint16_t indices[],
+ int indexCount,
+ const SkPaint& paint) {
+ // This function isn't used in the code. Verify this assumption.
+ SkASSERT(false);
+}
+
+void VectorPlatformDevice::setMatrixClip(const SkMatrix& transform,
+ const SkRegion& region) {
+ clip_region_ = region;
+ if (!clip_region_.isEmpty())
+ LoadClipRegion(clip_region_);
+
+ transform_ = transform;
+ LoadTransformToContext(transform_);
+}
+
+void VectorPlatformDevice::ApplyPaintColor(const SkPaint& paint) {
+ SkColor color = paint.getColor();
+ double a = static_cast<double>(SkColorGetA(color)) / 255.;
+ double r = static_cast<double>(SkColorGetR(color)) / 255.;
+ double g = static_cast<double>(SkColorGetG(color)) / 255.;
+ double b = static_cast<double>(SkColorGetB(color)) / 255.;
+
+ cairo_set_source_rgba(context_, r, g, b, a);
+}
+
+void VectorPlatformDevice::ApplyFillStyle(const SkPath& path) {
+ // Setup fill style.
+ // TODO(myhuang): Cairo does NOT support all skia fill rules!!
+ cairo_set_fill_rule(context_,
+ static_cast<cairo_fill_rule_t>(path.getFillType()));
+}
+
+void VectorPlatformDevice::ApplyStrokeStyle(const SkPaint& paint) {
+ // Line width.
+ cairo_set_line_width(context_, paint.getStrokeWidth());
+
+ // Line join.
+ cairo_set_line_join(context_,
+ static_cast<cairo_line_join_t>(paint.getStrokeJoin()));
+
+ // Line cap.
+ cairo_set_line_cap(context_,
+ static_cast<cairo_line_cap_t>(paint.getStrokeCap()));
+}
+
+void VectorPlatformDevice::DoPaintStyle(const SkPaint& paint) {
+ SkPaint::Style style = paint.getStyle();
+
+ switch (style) {
+ case SkPaint::kFill_Style: {
+ cairo_fill(context_);
+ } break;
+
+ case SkPaint::kStroke_Style: {
+ cairo_stroke(context_);
+ } break;
+
+ case SkPaint::kStrokeAndFill_Style: {
+ cairo_fill_preserve(context_);
+ cairo_stroke(context_);
+ } break;
+
+ default:
+ SkASSERT(false);
+ }
+}
+
+void VectorPlatformDevice::InternalDrawBitmap(const SkBitmap& bitmap,
+ int x, int y,
+ const SkPaint& paint) {
+ SkASSERT(bitmap.getConfig() == SkBitmap::kARGB_8888_Config);
+
+ unsigned char alpha = paint.getAlpha();
+
+ if (alpha == 0)
+ return;
+
+ int src_size_x = bitmap.width();
+ int src_size_y = bitmap.height();
+
+ if (!src_size_x || !src_size_y)
+ return;
+
+ SkAutoLockPixels image_lock(bitmap);
+
+ cairo_surface_t* bitmap_surface =
+ cairo_image_surface_create_for_data(
+ reinterpret_cast<unsigned char*>(bitmap.getPixels()),
+ CAIRO_FORMAT_ARGB32, src_size_x, src_size_y, bitmap.rowBytes());
+
+ cairo_set_source_surface(context_, bitmap_surface, x, y);
+ cairo_paint_with_alpha(context_, static_cast<double>(alpha) / 255.);
+
+ cairo_surface_destroy(bitmap_surface);
+}
+
+void VectorPlatformDevice::LoadClipRegion(const SkRegion& clip) {
+ cairo_reset_clip(context_);
+
+ LoadIdentityTransformToContext();
+
+ // TODO(myhuang): Support non-rect clips.
+ SkIRect bounding = clip.getBounds();
+ cairo_rectangle(context_, bounding.fLeft, bounding.fTop,
+ bounding.fRight - bounding.fLeft,
+ bounding.fBottom - bounding.fTop);
+ cairo_clip(context_);
+
+ // Restore the original matrix.
+ LoadTransformToContext(transform_);
+}
+
+void VectorPlatformDevice::LoadIdentityTransformToContext() {
+ SkMatrix identity;
+ identity.reset();
+ LoadTransformToContext(identity);
+}
+
+void VectorPlatformDevice::LoadTransformToContext(const SkMatrix& matrix) {
+ cairo_matrix_t m;
+ m.xx = matrix[SkMatrix::kMScaleX];
+ m.xy = matrix[SkMatrix::kMSkewX];
+ m.x0 = matrix[SkMatrix::kMTransX];
+ m.yx = matrix[SkMatrix::kMSkewY];
+ m.yy = matrix[SkMatrix::kMScaleY];
+ m.y0 = matrix[SkMatrix::kMTransY];
+ cairo_set_matrix(context_, &m);
+}
+
+} // namespace skia
+
diff --git a/skia/ext/vector_platform_device_linux.h b/skia/ext/vector_platform_device_linux.h
new file mode 100644
index 0000000..0cd9512
--- /dev/null
+++ b/skia/ext/vector_platform_device_linux.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SKIA_EXT_VECTOR_PLATFORM_DEVICE_LINUX_H_
+#define SKIA_EXT_VECTOR_PLATFORM_DEVICE_LINUX_H_
+
+#include "skia/ext/platform_device.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkRegion.h"
+
+typedef struct _cairo_surface cairo_surface_t;
+
+namespace skia {
+
+// This device is basically a wrapper that provides a surface for SkCanvas
+// to draw into. It is basically an adaptor which converts skia APIs into
+// cooresponding Cairo APIs and outputs to a Cairo PDF surface. Please NOTE
+// that since it is completely vectorial, the bitmap content in it is thus
+// meaningless.
+class VectorPlatformDevice : public PlatformDevice {
+ public:
+ // Factory function.
+ static VectorPlatformDevice* create(int width, int height);
+
+ virtual ~VectorPlatformDevice();
+
+ virtual bool IsVectorial() { return true; }
+ virtual PlatformSurface beginPlatformPaint() { return context_; }
+
+ // We translate following skia APIs into corresponding Cairo APIs.
+ virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
+ const SkMatrix& matrix, const SkPaint& paint);
+ virtual void drawDevice(const SkDraw& draw, SkDevice*, int x, int y,
+ const SkPaint&);
+ virtual void drawPaint(const SkDraw& draw, const SkPaint& paint);
+ virtual void drawPath(const SkDraw& draw, const SkPath& path,
+ const SkPaint& paint);
+ virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
+ size_t count, const SkPoint[], const SkPaint& paint);
+ virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
+ const SkScalar pos[], SkScalar constY,
+ int scalarsPerPos, const SkPaint& paint);
+ virtual void drawRect(const SkDraw& draw, const SkRect& r,
+ const SkPaint& paint);
+ virtual void drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
+ int x, int y, const SkPaint& paint);
+ virtual void drawText(const SkDraw& draw, const void* text, size_t len,
+ SkScalar x, SkScalar y, const SkPaint& paint);
+ virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint);
+ virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode,
+ int vertexCount,
+ const SkPoint verts[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint);
+ virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region);
+
+ protected:
+ explicit VectorPlatformDevice(const SkBitmap& bitmap);
+
+ private:
+ // Apply paint's color in the context.
+ void ApplyPaintColor(const SkPaint& paint);
+
+ // Apply path's fill style in the context.
+ void ApplyFillStyle(const SkPath& path);
+
+ // Apply paint's stroke style in the context.
+ void ApplyStrokeStyle(const SkPaint& paint);
+
+ // Perform painting.
+ void DoPaintStyle(const SkPaint& paint);
+
+ // Draws a bitmap in the the device, using the currently loaded matrix.
+ void InternalDrawBitmap(const SkBitmap& bitmap, int x, int y,
+ const SkPaint& paint);
+
+ // Set up the clipping region for the context. Please note that now we only
+ // use the bounding box of the region for clipping.
+ // TODO(myhuang): Support non-rectangular clipping.
+ void LoadClipRegion(const SkRegion& clip);
+
+ // Use identity matrix to set up context's transformation.
+ void LoadIdentityTransformToContext();
+
+ // Use matrix to set up context's transformation.
+ void LoadTransformToContext(const SkMatrix& matrix);
+
+ // Transformation assigned to the context.
+ SkMatrix transform_;
+
+ // The current clipping region.
+ SkRegion clip_region_;
+
+ // Context's target surface. It is a PS/PDF surface.
+ cairo_surface_t* surface_;
+
+ // Device context.
+ cairo_t* context_;
+
+ // Copy & assign are not supported.
+ VectorPlatformDevice(const VectorPlatformDevice&);
+ const VectorPlatformDevice& operator=(const VectorPlatformDevice&);
+};
+
+} // namespace skia
+
+#endif // SKIA_EXT_VECTOR_PLATFORM_DEVICE_LINUX_H_
+
diff --git a/skia/skia.gyp b/skia/skia.gyp
index 9c33f6a..45e4281 100644
--- a/skia/skia.gyp
+++ b/skia/skia.gyp
@@ -529,6 +529,11 @@
'ext/skia_utils_win.h',
'ext/vector_canvas.cc',
'ext/vector_canvas.h',
+ 'ext/vector_canvas_linux.cc',
+ 'ext/vector_canvas_win.cc',
+ 'ext/vector_platform_device.h',
+ 'ext/vector_platform_device_linux.cc',
+ 'ext/vector_platform_device_linux.h',
'ext/vector_platform_device_win.cc',
'ext/vector_platform_device_win.h',
],
@@ -569,10 +574,6 @@
}],
[ 'OS != "win"', {
'sources/': [ ['exclude', '_win\\.(cc|cpp)$'] ],
- 'sources!': [
- 'ext/vector_canvas.cc',
- 'ext/vector_device.cc',
- ],
}],
[ 'OS == "linux"', {
'dependencies': [