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
),
44 &CairoSurfaceReleaseProc
,
45 static_cast<void*>(surface
));
48 void LoadMatrixToContext(cairo_t
* context
, const SkMatrix
& matrix
) {
49 cairo_matrix_t cairo_matrix
;
50 cairo_matrix_init(&cairo_matrix
,
51 SkScalarToFloat(matrix
.getScaleX()),
52 SkScalarToFloat(matrix
.getSkewY()),
53 SkScalarToFloat(matrix
.getSkewX()),
54 SkScalarToFloat(matrix
.getScaleY()),
55 SkScalarToFloat(matrix
.getTranslateX()),
56 SkScalarToFloat(matrix
.getTranslateY()));
57 cairo_set_matrix(context
, &cairo_matrix
);
60 void LoadClipToContext(cairo_t
* context
, const SkRegion
& clip
) {
61 cairo_reset_clip(context
);
63 // TODO(brettw) support non-rect clips.
64 SkIRect bounding
= clip
.getBounds();
65 cairo_rectangle(context
, bounding
.fLeft
, bounding
.fTop
,
66 bounding
.fRight
- bounding
.fLeft
,
67 bounding
.fBottom
- bounding
.fTop
);
73 void BitmapPlatformDevice::SetMatrixClip(
74 const SkMatrix
& transform
,
75 const SkRegion
& region
) {
76 transform_
= transform
;
77 clip_region_
= region
;
81 void BitmapPlatformDevice::LoadConfig() {
82 if (!config_dirty_
|| !cairo_
)
83 return; // Nothing to do.
84 config_dirty_
= false;
86 // Load the identity matrix since this is what our clip is relative to.
87 cairo_matrix_t cairo_matrix
;
88 cairo_matrix_init_identity(&cairo_matrix
);
89 cairo_set_matrix(cairo_
, &cairo_matrix
);
91 LoadClipToContext(cairo_
, clip_region_
);
92 LoadMatrixToContext(cairo_
, transform_
);
95 // We use this static factory function instead of the regular constructor so
96 // that we can create the pixel data before calling the constructor. This is
97 // required so that we can call the base class' constructor with the pixel
99 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
101 cairo_surface_t
* surface
) {
102 if (cairo_surface_status(surface
) != CAIRO_STATUS_SUCCESS
) {
103 cairo_surface_destroy(surface
);
107 // must call this before trying to install the surface, since that may result
108 // in the surface being destroyed.
109 cairo_t
* cairo
= cairo_create(surface
);
112 if (!InstallCairoSurfacePixels(&bitmap
, surface
, is_opaque
)) {
113 cairo_destroy(cairo
);
117 // The device object will take ownership of the graphics context.
118 return new BitmapPlatformDevice(bitmap
, cairo
);
121 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
123 // This initializes the bitmap to all zeros.
124 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
127 BitmapPlatformDevice
* device
= Create(width
, height
, is_opaque
, surface
);
130 if (device
&& is_opaque
) // Fill with bright bluish green
131 SkCanvas(device
).drawColor(0xFF00FF80);
137 BitmapPlatformDevice
* BitmapPlatformDevice::CreateAndClear(int width
,
140 // The Linux port always constructs initialized bitmaps, so there is no extra
141 // work to perform here.
142 return Create(width
, height
, is_opaque
);
145 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
148 cairo_surface_t
* surface
= cairo_image_surface_create_for_data(
149 data
, CAIRO_FORMAT_ARGB32
, width
, height
,
150 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, width
));
152 return Create(width
, height
, is_opaque
, surface
);
155 // Ownership of the cairo object is transferred.
156 BitmapPlatformDevice::BitmapPlatformDevice(
157 const SkBitmap
& bitmap
,
159 : SkBitmapDevice(bitmap
),
162 transform_(SkMatrix::I()) { // Want to load the config next time.
163 SetPlatformDevice(this, this);
166 BitmapPlatformDevice::~BitmapPlatformDevice() {
167 cairo_destroy(cairo_
);
170 SkBaseDevice
* BitmapPlatformDevice::onCreateDevice(const CreateInfo
& info
,
172 SkASSERT(info
.fInfo
.colorType() == kN32_SkColorType
);
173 return BitmapPlatformDevice::Create(info
.fInfo
.width(), info
.fInfo
.height(),
174 info
.fInfo
.isOpaque());
177 cairo_t
* BitmapPlatformDevice::BeginPlatformPaint() {
179 cairo_surface_t
* surface
= cairo_get_target(cairo_
);
180 // Tell cairo to flush anything it has pending.
181 cairo_surface_flush(surface
);
182 // Tell Cairo that we (probably) modified (actually, will modify) its pixel
184 cairo_surface_mark_dirty(surface
);
188 void BitmapPlatformDevice::setMatrixClip(const SkMatrix
& transform
,
189 const SkRegion
& region
,
190 const SkClipStack
&) {
191 SetMatrixClip(transform
, region
);
194 // PlatformCanvas impl
196 SkCanvas
* CreatePlatformCanvas(int width
, int height
, bool is_opaque
,
197 uint8_t* data
, OnFailureType failureType
) {
198 skia::RefPtr
<SkBaseDevice
> dev
= skia::AdoptRef(
199 BitmapPlatformDevice::Create(width
, height
, is_opaque
, data
));
200 return CreateCanvas(dev
, failureType
);
203 // Port of PlatformBitmap to linux
204 PlatformBitmap::~PlatformBitmap() {
205 cairo_destroy(surface_
);
208 bool PlatformBitmap::Allocate(int width
, int height
, bool is_opaque
) {
209 // The SkBitmap allocates and owns the bitmap memory; PlatformBitmap owns the
210 // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
211 // outlive the PlatformBitmap if additional copies are made.
212 int stride
= cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32
, width
);
214 cairo_surface_t
* surf
= cairo_image_surface_create(
218 if (cairo_surface_status(surf
) != CAIRO_STATUS_SUCCESS
) {
219 cairo_surface_destroy(surf
);
222 return InstallCairoSurfacePixels(&bitmap_
, surf
, is_opaque
);