1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "skia/ext/bitmap_platform_device_cairo.h"
6 #include "skia/ext/platform_canvas.h"
8 #if defined(OS_OPENBSD)
11 #include <cairo/cairo.h>
18 // CairoSurfacePixelRef is an SkPixelRef that is backed by a cairo surface.
19 class SK_API CairoSurfacePixelRef
: public SkPixelRef
{
21 // The constructor takes ownership of the passed-in surface.
22 explicit CairoSurfacePixelRef(const SkImageInfo
& info
,
23 cairo_surface_t
* surface
);
24 virtual ~CairoSurfacePixelRef();
26 SK_DECLARE_UNFLATTENABLE_OBJECT();
29 virtual void* onLockPixels(SkColorTable
**) SK_OVERRIDE
;
30 virtual void onUnlockPixels() SK_OVERRIDE
;
33 cairo_surface_t
* surface_
;
36 CairoSurfacePixelRef::CairoSurfacePixelRef(const SkImageInfo
& info
,
37 cairo_surface_t
* surface
)
38 : SkPixelRef(info
), surface_(surface
) {
41 CairoSurfacePixelRef::~CairoSurfacePixelRef() {
43 cairo_surface_destroy(surface_
);
46 void* CairoSurfacePixelRef::onLockPixels(SkColorTable
** color_table
) {
48 return cairo_image_surface_get_data(surface_
);
51 void CairoSurfacePixelRef::onUnlockPixels() {
56 void LoadMatrixToContext(cairo_t
* context
, const SkMatrix
& matrix
) {
57 cairo_matrix_t cairo_matrix
;
58 cairo_matrix_init(&cairo_matrix
,
59 SkScalarToFloat(matrix
.getScaleX()),
60 SkScalarToFloat(matrix
.getSkewY()),
61 SkScalarToFloat(matrix
.getSkewX()),
62 SkScalarToFloat(matrix
.getScaleY()),
63 SkScalarToFloat(matrix
.getTranslateX()),
64 SkScalarToFloat(matrix
.getTranslateY()));
65 cairo_set_matrix(context
, &cairo_matrix
);
68 void LoadClipToContext(cairo_t
* context
, const SkRegion
& clip
) {
69 cairo_reset_clip(context
);
71 // TODO(brettw) support non-rect clips.
72 SkIRect bounding
= clip
.getBounds();
73 cairo_rectangle(context
, bounding
.fLeft
, bounding
.fTop
,
74 bounding
.fRight
- bounding
.fLeft
,
75 bounding
.fBottom
- bounding
.fTop
);
81 void BitmapPlatformDevice::SetMatrixClip(
82 const SkMatrix
& transform
,
83 const SkRegion
& region
) {
84 transform_
= transform
;
85 clip_region_
= region
;
89 void BitmapPlatformDevice::LoadConfig() {
90 if (!config_dirty_
|| !cairo_
)
91 return; // Nothing to do.
92 config_dirty_
= false;
94 // Load the identity matrix since this is what our clip is relative to.
95 cairo_matrix_t cairo_matrix
;
96 cairo_matrix_init_identity(&cairo_matrix
);
97 cairo_set_matrix(cairo_
, &cairo_matrix
);
99 LoadClipToContext(cairo_
, clip_region_
);
100 LoadMatrixToContext(cairo_
, transform_
);
103 // We use this static factory function instead of the regular constructor so
104 // that we can create the pixel data before calling the constructor. This is
105 // required so that we can call the base class' constructor with the pixel
107 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
109 cairo_surface_t
* surface
) {
110 if (cairo_surface_status(surface
) != CAIRO_STATUS_SUCCESS
) {
111 cairo_surface_destroy(surface
);
118 kPMColor_SkColorType
,
119 is_opaque
? kOpaque_SkAlphaType
: kPremul_SkAlphaType
123 bitmap
.setConfig(info
, cairo_image_surface_get_stride(surface
));
124 RefPtr
<SkPixelRef
> pixel_ref
= AdoptRef(new CairoSurfacePixelRef(info
,
126 bitmap
.setPixelRef(pixel_ref
.get());
128 // The device object will take ownership of the graphics context.
129 return new BitmapPlatformDevice(bitmap
, surface
);
132 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
134 // This initializes the bitmap to all zeros.
135 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
138 BitmapPlatformDevice
* device
= Create(width
, height
, is_opaque
, surface
);
141 if (device
&& is_opaque
) // Fill with bright bluish green
142 device
->eraseColor(SkColorSetARGB(255, 0, 255, 128));
148 BitmapPlatformDevice
* BitmapPlatformDevice::CreateAndClear(int width
,
151 // The Linux port always constructs initialized bitmaps, so there is no extra
152 // work to perform here.
153 return Create(width
, height
, is_opaque
);
156 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
159 cairo_surface_t
* surface
= cairo_image_surface_create_for_data(
160 data
, CAIRO_FORMAT_ARGB32
, width
, height
,
161 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, width
));
163 return Create(width
, height
, is_opaque
, surface
);
166 // The device will own the bitmap, which corresponds to also owning the pixel
167 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap.
168 BitmapPlatformDevice::BitmapPlatformDevice(
169 const SkBitmap
& bitmap
,
170 cairo_surface_t
* surface
)
171 : SkBitmapDevice(bitmap
),
172 cairo_(cairo_create(surface
)),
174 transform_(SkMatrix::I()) { // Want to load the config next time.
175 SetPlatformDevice(this, this);
178 BitmapPlatformDevice::~BitmapPlatformDevice() {
179 cairo_destroy(cairo_
);
182 SkBaseDevice
* BitmapPlatformDevice::onCreateCompatibleDevice(
183 SkBitmap::Config config
, int width
, int height
, bool isOpaque
,
185 SkASSERT(config
== SkBitmap::kARGB_8888_Config
);
186 return BitmapPlatformDevice::Create(width
, height
, isOpaque
);
189 cairo_t
* BitmapPlatformDevice::BeginPlatformPaint() {
191 cairo_surface_t
* surface
= cairo_get_target(cairo_
);
192 // Tell cairo to flush anything it has pending.
193 cairo_surface_flush(surface
);
194 // Tell Cairo that we (probably) modified (actually, will modify) its pixel
196 cairo_surface_mark_dirty(surface
);
200 void BitmapPlatformDevice::DrawToNativeContext(
201 PlatformSurface surface
, int x
, int y
, const PlatformRect
* src_rect
) {
202 // Should never be called on Linux.
206 void BitmapPlatformDevice::setMatrixClip(const SkMatrix
& transform
,
207 const SkRegion
& region
,
208 const SkClipStack
&) {
209 SetMatrixClip(transform
, region
);
212 // PlatformCanvas impl
214 SkCanvas
* CreatePlatformCanvas(int width
, int height
, bool is_opaque
,
215 uint8_t* data
, OnFailureType failureType
) {
216 skia::RefPtr
<SkBaseDevice
> dev
= skia::AdoptRef(
217 BitmapPlatformDevice::Create(width
, height
, is_opaque
, data
));
218 return CreateCanvas(dev
, failureType
);
221 // Port of PlatformBitmap to linux
222 PlatformBitmap::~PlatformBitmap() {
223 cairo_destroy(surface_
);
226 bool PlatformBitmap::Allocate(int width
, int height
, bool is_opaque
) {
230 kPMColor_SkColorType
,
231 is_opaque
? kOpaque_SkAlphaType
: kPremul_SkAlphaType
234 // The SkBitmap allocates and owns the bitmap memory; PlatformBitmap owns the
235 // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
236 // outlive the PlatformBitmap if additional copies are made.
237 int stride
= cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, width
);
238 bitmap_
.setConfig(info
, stride
);
240 cairo_surface_t
* surf
= cairo_image_surface_create(
244 if (cairo_surface_status(surf
) != CAIRO_STATUS_SUCCESS
) {
245 cairo_surface_destroy(surf
);
248 RefPtr
<SkPixelRef
> pixel_ref
= AdoptRef(new CairoSurfacePixelRef(info
, surf
));
249 bitmap_
.setPixelRef(pixel_ref
.get());