diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-05 20:26:41 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-05 20:26:41 +0000 |
commit | 6862ac6cbec1c9a3d7e332b3e8c696c9a3d172d6 (patch) | |
tree | 7b810a3eb33cb63e404c8f4d67e6f3676168b13b /skia | |
parent | e7ef7150c893a1ff2fe4197ce9d76ccb21001caa (diff) | |
download | chromium_src-6862ac6cbec1c9a3d7e332b3e8c696c9a3d172d6.zip chromium_src-6862ac6cbec1c9a3d7e332b3e8c696c9a3d172d6.tar.gz chromium_src-6862ac6cbec1c9a3d7e332b3e8c696c9a3d172d6.tar.bz2 |
Original change by Min-Yu Huang <minyu.huang@gmail.com> in
http://codereview.chromium.org/160347
This is the very preliminary implementation to support printing on Linux and it
has not been finished yet. For each page to be printed, we convert rendering
actions on canvas into cairo APIs and generate a PS/PDF file.
chrome/chrome.gyp:
Include our newly added and renamed files.
chrome/browser/browser.h:
chrome/browser/browser.cc:
Allow the user print the web page by hitting ctrl-p.
chrome/browser/gtk/standard_menus.cc:
Show "Print" in the menu.
chrome/renderer/print_web_view_helper.cc:
chrome/renderer/print_web_view_helper.h:
chrome/renderer/print_web_view_helper_mac.cc
chrome/renderer/print_web_view_helper_win.cc
Move the class PrepareFrameAndViewForPrint to the header file and move
platform dependent parts to their corresponding files.
chrome/renderer/print_web_view_helper_linux.cc:
Hard-coded parameters for printing. Only print the first page now.
skia/ext/vector_canvas.cc:
skia/ext/vector_canvas.h:
skia/ext/vector_canvas_linux.cc:
skia/ext/vector_canvas_win.cc:
Move platform dependent parts to their corresponding files.
skia/ext/vector_platform_device.h:
skia/ext/vector_platform_device_linux.cc:
skia/ext/vector_platform_device_linux.h
We translate skia APIs into Cairo APIs here. A PDF file is also created and
saved to the disk at this moment for testing purpose (you have to run chrome
without the sandbox to save the file). There are still lots of bugs.
skia/skia.gyp:
Include our newly added files when compiling skia package on Linux.
BUG=9847
Review URL: http://codereview.chromium.org/160673
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22522 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r-- | skia/ext/vector_canvas.cc | 58 | ||||
-rw-r--r-- | skia/ext/vector_canvas.h | 18 | ||||
-rw-r--r-- | skia/ext/vector_canvas_linux.cc | 49 | ||||
-rw-r--r-- | skia/ext/vector_canvas_win.cc | 49 | ||||
-rw-r--r-- | skia/ext/vector_platform_device.h | 17 | ||||
-rw-r--r-- | skia/ext/vector_platform_device_linux.cc | 498 | ||||
-rw-r--r-- | skia/ext/vector_platform_device_linux.h | 112 | ||||
-rw-r--r-- | skia/skia.gyp | 9 |
8 files changed, 710 insertions, 100 deletions
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': [ |