Skip to content

Commit

Permalink
Keep the cairo clipping region in sync with the Skia one.
Browse files Browse the repository at this point in the history
The PlatformCanvas now tracks this, so we don't need to have the similar code
in gfx::Canvas. I moved most references of cairo_surface_t to cairo_t since the
cairo_t has a transform and clip but the surface does not.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20499 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
brettw@chromium.org committed Jul 13, 2009
1 parent 44df752 commit 7f1fe3f
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 68 deletions.
21 changes: 1 addition & 20 deletions app/gfx/canvas_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,29 +95,11 @@ void Canvas::SizeStringInt(const std::wstring& text,
cairo_surface_destroy(surface);
}

void Canvas::ApplySkiaMatrixToCairoContext(cairo_t* cr) {
const SkMatrix& skia_matrix = getTotalMatrix();
cairo_matrix_t cairo_matrix;
cairo_matrix_init(&cairo_matrix,
SkScalarToFloat(skia_matrix.getScaleX()),
SkScalarToFloat(skia_matrix.getSkewY()),
SkScalarToFloat(skia_matrix.getSkewX()),
SkScalarToFloat(skia_matrix.getScaleY()),
SkScalarToFloat(skia_matrix.getTranslateX()),
SkScalarToFloat(skia_matrix.getTranslateY()));
cairo_set_matrix(cr, &cairo_matrix);
}

void Canvas::DrawStringInt(const std::wstring& text,
const gfx::Font& font,
const SkColor& color, int x, int y, int w, int h,
int flags) {
cairo_surface_t* surface = beginPlatformPaint();
cairo_t* cr = cairo_create(surface);
// We're going to draw onto the surface directly. This circumvents the matrix
// installed by Skia. Apply the matrix from skia to cairo so they align and
// we draw at the right place.
ApplySkiaMatrixToCairoContext(cr);
cairo_t* cr = beginPlatformPaint();
PangoLayout* layout = pango_cairo_create_layout(cr);

cairo_set_source_rgb(cr,
Expand Down Expand Up @@ -169,7 +151,6 @@ void Canvas::DrawStringInt(const std::wstring& text,
pango_cairo_show_layout(cr, layout);

g_object_unref(layout);
cairo_destroy(cr);
// NOTE: beginPlatformPaint returned its surface, we shouldn't destroy it.
}

Expand Down
4 changes: 2 additions & 2 deletions base/gfx/native_widget_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class NSTextField;
typedef struct _GdkCursor GdkCursor;
typedef struct _GtkWidget GtkWidget;
typedef struct _GtkWindow GtkWindow;
typedef struct _cairo_surface cairo_surface_t;
typedef struct _cairo cairo_t;
#endif

namespace gfx {
Expand All @@ -73,7 +73,7 @@ typedef void* NativeMenu;
typedef GtkWidget* NativeView;
typedef GtkWindow* NativeWindow;
typedef GtkWidget* NativeEditView;
typedef cairo_surface_t* NativeDrawingContext;
typedef cairo_t* NativeDrawingContext;
typedef GdkCursor* NativeCursor;
typedef GtkWidget* NativeMenu;
#endif
Expand Down
13 changes: 3 additions & 10 deletions chrome/renderer/webplugin_delegate_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -932,16 +932,9 @@ void WebPluginDelegateProxy::PaintSadPlugin(gfx::NativeDrawingContext context,
skia::PlatformDevice& device = canvas.getTopPlatformDevice();
device.drawToHDC(context, plugin_rect_.x(), plugin_rect_.y(), NULL);
#elif defined(OS_LINUX)
// Though conceptually we've been handed a cairo_surface_t* and we
// could've just hooked up the canvas to draw directly onto it, our
// canvas implementation currently uses cairo as a dumb pixel buffer
// and would have done the following copy anyway.
// TODO(evanm): revisit when we have printing hooked up, as that might
// change our usage of cairo.
skia::PlatformDevice& device = canvas.getTopPlatformDevice();
cairo_t* cairo = cairo_create(context);
cairo_surface_t* source_surface = device.beginPlatformPaint();
cairo_set_source_surface(cairo, source_surface, plugin_rect_.x(), plugin_rect_.y());
cairo_t* cairo = canvas.getTopPlatformDevice().beginPlatformPaint();
cairo_set_source_surface(cairo, cairo_get_target(context),
plugin_rect_.x(), plugin_rect_.y());
cairo_paint(cairo);
cairo_destroy(cairo);
// We have no endPlatformPaint() on the Linux PlatformDevice.
Expand Down
119 changes: 109 additions & 10 deletions skia/ext/bitmap_platform_device_linux.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// 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.

Expand All @@ -8,6 +8,33 @@

namespace skia {

namespace {

void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) {
cairo_matrix_t cairo_matrix;
cairo_matrix_init(&cairo_matrix,
SkScalarToFloat(matrix.getScaleX()),
SkScalarToFloat(matrix.getSkewY()),
SkScalarToFloat(matrix.getSkewX()),
SkScalarToFloat(matrix.getScaleY()),
SkScalarToFloat(matrix.getTranslateX()),
SkScalarToFloat(matrix.getTranslateY()));
cairo_set_matrix(context, &cairo_matrix);
}

void LoadClipToContext(cairo_t* context, const SkRegion& clip) {
cairo_reset_clip(context);

// TODO(brettw) 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);
}

} // namespace

// -----------------------------------------------------------------------------
// These objects are reference counted and own a Cairo surface. The surface is
// the backing store for a Skia bitmap and we reference count it so that we can
Expand All @@ -17,25 +44,92 @@ namespace skia {
class BitmapPlatformDevice::BitmapPlatformDeviceData
: public base::RefCounted<BitmapPlatformDeviceData> {
public:
explicit BitmapPlatformDeviceData(cairo_surface_t* surface)
: surface_(surface) { }
explicit BitmapPlatformDeviceData(cairo_surface_t* surface);

cairo_surface_t* surface() const { return surface_; }
cairo_t* GetContext();
cairo_surface_t* GetSurface();

// Sets the transform and clip operations. This will not update the Cairo
// surface, but will mark the config as dirty. The next call of LoadConfig
// will pick up these changes.
void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);

protected:
friend class base::RefCounted<BitmapPlatformDeviceData>;

~BitmapPlatformDeviceData();

void LoadConfig();

// The Cairo surface inside this DC.
cairo_t* context_;
cairo_surface_t *const surface_;

friend class base::RefCounted<BitmapPlatformDeviceData>;
~BitmapPlatformDeviceData() {
cairo_surface_destroy(surface_);
}
// True when there is a transform or clip that has not been set to the
// surface. The surface is retrieved for every text operation, and the
// transform and clip do not change as much. We can save time by not loading
// the clip and transform for every one.
bool config_dirty_;

// Translation assigned to the DC: we need to keep track of this separately
// so it can be updated even if the DC isn't created yet.
SkMatrix transform_;

// The current clipping
SkRegion clip_region_;

// Disallow copy & assign.
BitmapPlatformDeviceData(const BitmapPlatformDeviceData&);
BitmapPlatformDeviceData& operator=(
const BitmapPlatformDeviceData&);
};

BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData(
cairo_surface_t* surface)
: surface_(surface),
config_dirty_(true) { // Want to load the config next time.
context_ = cairo_create(surface);
}

BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() {
cairo_destroy(context_);
cairo_surface_destroy(surface_);
}

cairo_t* BitmapPlatformDevice::BitmapPlatformDeviceData::GetContext() {
LoadConfig();
return context_;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip(
const SkMatrix& transform,
const SkRegion& region) {
transform_ = transform;
clip_region_ = region;
config_dirty_ = true;
}

cairo_surface_t*
BitmapPlatformDevice::BitmapPlatformDeviceData::GetSurface() {
// TODO(brettw) this function should be removed.
LoadConfig();
return surface_;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() {
if (!config_dirty_ || !context_)
return; // Nothing to do.
config_dirty_ = false;

// Load the identity matrix since this is what our clip is relative to.
cairo_matrix_t cairo_matrix;
cairo_matrix_init_identity(&cairo_matrix);
cairo_set_matrix(context_, &cairo_matrix);

LoadClipToContext(context_, clip_region_);
LoadMatrixToContext(context_, transform_);
}

// We use this static factory function instead of the regular constructor so
// that we can create the pixel data before calling the constructor. This is
// required so that we can call the base class' constructor with the pixel
Expand Down Expand Up @@ -98,8 +192,13 @@ BitmapPlatformDevice::BitmapPlatformDevice(
BitmapPlatformDevice::~BitmapPlatformDevice() {
}

cairo_surface_t* BitmapPlatformDevice::surface() const {
return data_->surface();
cairo_t* BitmapPlatformDevice::beginPlatformPaint() {
return data_->GetContext();
}

void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
const SkRegion& region) {
data_->SetMatrixClip(transform, region);
}

BitmapPlatformDevice& BitmapPlatformDevice::operator=(
Expand Down
8 changes: 5 additions & 3 deletions skia/ext/bitmap_platform_device_linux.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// 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.

Expand Down Expand Up @@ -85,9 +85,11 @@ class BitmapPlatformDevice : public PlatformDevice {

// If someone wants to paint on a Cairo surface version of our
// buffer, then give them the surface we're already using.
virtual cairo_surface_t* beginPlatformPaint() { return surface(); }
virtual cairo_t* beginPlatformPaint();

cairo_surface_t* surface() const;
// Loads the given transform and clipping region into the HDC. This is
// overridden from SkDevice.
virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region);

private:
scoped_refptr<BitmapPlatformDeviceData> data_;
Expand Down
3 changes: 3 additions & 0 deletions skia/ext/bitmap_platform_device_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class BitmapPlatformDevice : public PlatformDevice {
// Retrieves the bitmap DC, which is the memory DC for our bitmap data. The
// bitmap DC is lazy created.
virtual HDC getBitmapDC();

// Loads the given transform and clipping region into the HDC. This is
// overridden from SkDevice.
virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region);

virtual void drawToHDC(HDC dc, int x, int y, const RECT* src_rect);
Expand Down
11 changes: 6 additions & 5 deletions skia/ext/canvas_paint_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ class CanvasPaintT : public T {
public:
// This constructor assumes the result is opaque.
explicit CanvasPaintT(GdkEventExpose* event)
: surface_(NULL),
: context_(NULL),
window_(event->window),
rectangle_(event->area),
composite_alpha_(false) {
init(true);
}

CanvasPaintT(GdkEventExpose* event, bool opaque)
: surface_(NULL),
: context_(NULL),
window_(event->window),
rectangle_(event->area),
composite_alpha_(false) {
Expand All @@ -44,7 +44,8 @@ class CanvasPaintT : public T {
cairo_t* cr = gdk_cairo_create(window_);
if (composite_alpha_)
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface(cr, surface_, rectangle_.x, rectangle_.y);
cairo_surface_t* source_surface = cairo_get_target(context_);
cairo_set_source_surface(cr, source_surface, rectangle_.x, rectangle_.y);
cairo_rectangle(cr, rectangle_.x, rectangle_.y,
rectangle_.width, rectangle_.height);
cairo_fill(cr);
Expand Down Expand Up @@ -80,10 +81,10 @@ class CanvasPaintT : public T {
// surface.
T::translate(-SkIntToScalar(rectangle_.x), -SkIntToScalar(rectangle_.y));

surface_ = T::getTopPlatformDevice().beginPlatformPaint();
context_ = T::getTopPlatformDevice().beginPlatformPaint();
}

cairo_surface_t* surface_;
cairo_t* context_;
GdkWindow* window_;
GdkRectangle rectangle_;
// See description above setter.
Expand Down
2 changes: 1 addition & 1 deletion skia/ext/platform_canvas_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ bool PlatformCanvas::initialize(int width, int height, bool is_opaque,
return true;
}

cairo_surface_t* PlatformCanvas::beginPlatformPaint() {
cairo_t* PlatformCanvas::beginPlatformPaint() {
return getTopPlatformDevice().beginPlatformPaint();
}

Expand Down
6 changes: 3 additions & 3 deletions skia/ext/platform_device_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@

#include "third_party/skia/include/core/SkDevice.h"

typedef struct _cairo_surface cairo_surface_t;
typedef struct _cairo cairo_t;

namespace skia {

// Blindly copying the mac hierarchy.
class PlatformDevice : public SkDevice {
public:
typedef cairo_surface_t* PlatformSurface;
typedef cairo_t* PlatformSurface;

// Returns if the preferred rendering engine is vectorial or bitmap based.
virtual bool IsVectorial() = 0;

virtual cairo_surface_t* beginPlatformPaint() = 0;
virtual PlatformSurface beginPlatformPaint() = 0;

protected:
// Forwards |bitmap| to SkDevice's constructor.
Expand Down
20 changes: 10 additions & 10 deletions webkit/glue/plugins/webplugin_delegate_impl_gtk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,13 @@ void WebPluginDelegateImpl::UpdateGeometry(
}
}

void WebPluginDelegateImpl::Paint(cairo_surface_t* context,
void WebPluginDelegateImpl::Paint(cairo_t* context,
const gfx::Rect& rect) {
if (windowless_)
WindowlessPaint(context, rect);
}

void WebPluginDelegateImpl::Print(cairo_surface_t* context) {
void WebPluginDelegateImpl::Print(cairo_t* context) {
NOTIMPLEMENTED();
}

Expand Down Expand Up @@ -399,7 +399,7 @@ void DrawDebugRectangle(cairo_surface_t* surface,
} // namespace
#endif

void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
void WebPluginDelegateImpl::WindowlessPaint(cairo_t* context,
const gfx::Rect& damage_rect) {
// Compare to:
// http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp:
Expand Down Expand Up @@ -526,7 +526,8 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
// Copy the current image into the pixmap, so the plugin can draw over
// this background.
cairo_t* cairo = gdk_cairo_create(pixmap_);
cairo_set_source_surface(cairo, context, offset_x, offset_y);
cairo_set_source_surface(cairo, cairo_get_target(context),
offset_x, offset_y);
cairo_rectangle(cairo, draw_rect.x() + offset_x, draw_rect.y() + offset_y,
draw_rect.width(), draw_rect.height());
cairo_clip(cairo);
Expand All @@ -551,13 +552,12 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
DCHECK_EQ(err, NPERR_NO_ERROR);

// Now copy the rendered image pixmap back into the drawing buffer.
cairo = cairo_create(context);
gdk_cairo_set_source_pixmap(cairo, pixmap_, -offset_x, -offset_y);
cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(),
gdk_cairo_set_source_pixmap(context, pixmap_, -offset_x, -offset_y);
cairo_rectangle(context, draw_rect.x(), draw_rect.y(),
draw_rect.width(), draw_rect.height());
cairo_clip(cairo);
cairo_paint(cairo);
cairo_destroy(cairo);
cairo_clip(context);
cairo_paint(context);
cairo_destroy(context);

#ifdef DEBUG_RECTANGLES
// Draw some debugging rectangles.
Expand Down
Loading

0 comments on commit 7f1fe3f

Please sign in to comment.