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 void CairoSurfaceReleaseProc(void*, void* context
) {
20 cairo_surface_destroy(static_cast<cairo_surface_t
*>(context
));
23 // Back the destination bitmap by a Cairo surface. The bitmap's
24 // pixelRef takes ownership of the passed-in surface and will call
25 // cairo_surface_destroy() upon destruction.
27 // Note: it may immediately destroy the surface, if it fails to create a bitmap
28 // with pixels, thus the caller must either ref() the surface before hand, or
29 // it must not refer to the surface after this call.
30 bool InstallCairoSurfacePixels(SkBitmap
* dst
,
31 cairo_surface_t
* surface
,
38 = SkImageInfo::MakeN32Premul(cairo_image_surface_get_width(surface
),
39 cairo_image_surface_get_height(surface
));
40 return dst
->installPixels(info
,
41 cairo_image_surface_get_data(surface
),
42 cairo_image_surface_get_stride(surface
),
43 &CairoSurfaceReleaseProc
,
44 static_cast<void*>(surface
));
47 void LoadMatrixToContext(cairo_t
* context
, const SkMatrix
& matrix
) {
48 cairo_matrix_t cairo_matrix
;
49 cairo_matrix_init(&cairo_matrix
,
50 SkScalarToFloat(matrix
.getScaleX()),
51 SkScalarToFloat(matrix
.getSkewY()),
52 SkScalarToFloat(matrix
.getSkewX()),
53 SkScalarToFloat(matrix
.getScaleY()),
54 SkScalarToFloat(matrix
.getTranslateX()),
55 SkScalarToFloat(matrix
.getTranslateY()));
56 cairo_set_matrix(context
, &cairo_matrix
);
59 void LoadClipToContext(cairo_t
* context
, const SkRegion
& clip
) {
60 cairo_reset_clip(context
);
62 // TODO(brettw) support non-rect clips.
63 SkIRect bounding
= clip
.getBounds();
64 cairo_rectangle(context
, bounding
.fLeft
, bounding
.fTop
,
65 bounding
.fRight
- bounding
.fLeft
,
66 bounding
.fBottom
- bounding
.fTop
);
72 void BitmapPlatformDevice::SetMatrixClip(
73 const SkMatrix
& transform
,
74 const SkRegion
& region
) {
75 transform_
= transform
;
76 clip_region_
= region
;
80 void BitmapPlatformDevice::LoadConfig() {
81 if (!config_dirty_
|| !cairo_
)
82 return; // Nothing to do.
83 config_dirty_
= false;
85 // Load the identity matrix since this is what our clip is relative to.
86 cairo_matrix_t cairo_matrix
;
87 cairo_matrix_init_identity(&cairo_matrix
);
88 cairo_set_matrix(cairo_
, &cairo_matrix
);
90 LoadClipToContext(cairo_
, clip_region_
);
91 LoadMatrixToContext(cairo_
, transform_
);
94 // We use this static factory function instead of the regular constructor so
95 // that we can create the pixel data before calling the constructor. This is
96 // required so that we can call the base class' constructor with the pixel
98 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
100 cairo_surface_t
* surface
) {
101 if (cairo_surface_status(surface
) != CAIRO_STATUS_SUCCESS
) {
102 cairo_surface_destroy(surface
);
106 // must call this before trying to install the surface, since that may result
107 // in the surface being destroyed.
108 cairo_t
* cairo
= cairo_create(surface
);
111 if (!InstallCairoSurfacePixels(&bitmap
, surface
, is_opaque
)) {
112 cairo_destroy(cairo
);
116 // The device object will take ownership of the graphics context.
117 return new BitmapPlatformDevice(bitmap
, cairo
);
120 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
122 // This initializes the bitmap to all zeros.
123 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
126 BitmapPlatformDevice
* device
= Create(width
, height
, is_opaque
, surface
);
129 if (device
&& is_opaque
) // Fill with bright bluish green
130 device
->eraseColor(SkColorSetARGB(255, 0, 255, 128));
136 BitmapPlatformDevice
* BitmapPlatformDevice::CreateAndClear(int width
,
139 // The Linux port always constructs initialized bitmaps, so there is no extra
140 // work to perform here.
141 return Create(width
, height
, is_opaque
);
144 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
147 cairo_surface_t
* surface
= cairo_image_surface_create_for_data(
148 data
, CAIRO_FORMAT_ARGB32
, width
, height
,
149 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, width
));
151 return Create(width
, height
, is_opaque
, surface
);
154 // Ownership of the cairo object is transferred.
155 BitmapPlatformDevice::BitmapPlatformDevice(
156 const SkBitmap
& bitmap
,
158 : SkBitmapDevice(bitmap
),
161 transform_(SkMatrix::I()) { // Want to load the config next time.
162 SetPlatformDevice(this, this);
165 BitmapPlatformDevice::~BitmapPlatformDevice() {
166 cairo_destroy(cairo_
);
169 SkBaseDevice
* BitmapPlatformDevice::onCreateDevice(const SkImageInfo
& info
,
171 SkASSERT(info
.colorType() == kPMColor_SkColorType
);
172 return BitmapPlatformDevice::Create(info
.width(), info
.height(),
176 cairo_t
* BitmapPlatformDevice::BeginPlatformPaint() {
178 cairo_surface_t
* surface
= cairo_get_target(cairo_
);
179 // Tell cairo to flush anything it has pending.
180 cairo_surface_flush(surface
);
181 // Tell Cairo that we (probably) modified (actually, will modify) its pixel
183 cairo_surface_mark_dirty(surface
);
187 void BitmapPlatformDevice::DrawToNativeContext(
188 PlatformSurface surface
, int x
, int y
, const PlatformRect
* src_rect
) {
189 // Should never be called on Linux.
193 void BitmapPlatformDevice::setMatrixClip(const SkMatrix
& transform
,
194 const SkRegion
& region
,
195 const SkClipStack
&) {
196 SetMatrixClip(transform
, region
);
199 // PlatformCanvas impl
201 SkCanvas
* CreatePlatformCanvas(int width
, int height
, bool is_opaque
,
202 uint8_t* data
, OnFailureType failureType
) {
203 skia::RefPtr
<SkBaseDevice
> dev
= skia::AdoptRef(
204 BitmapPlatformDevice::Create(width
, height
, is_opaque
, data
));
205 return CreateCanvas(dev
, failureType
);
208 // Port of PlatformBitmap to linux
209 PlatformBitmap::~PlatformBitmap() {
210 cairo_destroy(surface_
);
213 bool PlatformBitmap::Allocate(int width
, int height
, bool is_opaque
) {
214 // The SkBitmap allocates and owns the bitmap memory; PlatformBitmap owns the
215 // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
216 // outlive the PlatformBitmap if additional copies are made.
217 int stride
= cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, width
);
219 cairo_surface_t
* surf
= cairo_image_surface_create(
223 if (cairo_surface_status(surf
) != CAIRO_STATUS_SUCCESS
) {
224 cairo_surface_destroy(surf
);
227 return InstallCairoSurfacePixels(&bitmap_
, surf
, is_opaque
);