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.
26 bool InstallCairoSurfacePixels(SkBitmap* dst,
27 cairo_surface_t* surface,
34 = SkImageInfo::MakeN32Premul(cairo_image_surface_get_width(surface),
35 cairo_image_surface_get_height(surface));
36 return dst->installPixels(info,
37 cairo_image_surface_get_data(surface),
38 cairo_image_surface_get_stride(surface),
39 &CairoSurfaceReleaseProc,
40 static_cast<void*>(surface));
43 void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) {
44 cairo_matrix_t cairo_matrix;
45 cairo_matrix_init(&cairo_matrix,
46 SkScalarToFloat(matrix.getScaleX()),
47 SkScalarToFloat(matrix.getSkewY()),
48 SkScalarToFloat(matrix.getSkewX()),
49 SkScalarToFloat(matrix.getScaleY()),
50 SkScalarToFloat(matrix.getTranslateX()),
51 SkScalarToFloat(matrix.getTranslateY()));
52 cairo_set_matrix(context, &cairo_matrix);
55 void LoadClipToContext(cairo_t* context, const SkRegion& clip) {
56 cairo_reset_clip(context);
58 // TODO(brettw) support non-rect clips.
59 SkIRect bounding = clip.getBounds();
60 cairo_rectangle(context, bounding.fLeft, bounding.fTop,
61 bounding.fRight - bounding.fLeft,
62 bounding.fBottom - bounding.fTop);
68 void BitmapPlatformDevice::SetMatrixClip(
69 const SkMatrix& transform,
70 const SkRegion& region) {
71 transform_ = transform;
72 clip_region_ = region;
76 void BitmapPlatformDevice::LoadConfig() {
77 if (!config_dirty_ || !cairo_)
78 return; // Nothing to do.
79 config_dirty_ = false;
81 // Load the identity matrix since this is what our clip is relative to.
82 cairo_matrix_t cairo_matrix;
83 cairo_matrix_init_identity(&cairo_matrix);
84 cairo_set_matrix(cairo_, &cairo_matrix);
86 LoadClipToContext(cairo_, clip_region_);
87 LoadMatrixToContext(cairo_, transform_);
90 // We use this static factory function instead of the regular constructor so
91 // that we can create the pixel data before calling the constructor. This is
92 // required so that we can call the base class' constructor with the pixel
94 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
96 cairo_surface_t* surface) {
97 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
98 cairo_surface_destroy(surface);
103 if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) {
107 // The device object will take ownership of the graphics context.
108 return new BitmapPlatformDevice(bitmap, surface);
111 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
113 // This initializes the bitmap to all zeros.
114 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
117 BitmapPlatformDevice* device = Create(width, height, is_opaque, surface);
120 if (device && is_opaque) // Fill with bright bluish green
121 device->eraseColor(SkColorSetARGB(255, 0, 255, 128));
127 BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
130 // The Linux port always constructs initialized bitmaps, so there is no extra
131 // work to perform here.
132 return Create(width, height, is_opaque);
135 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
138 cairo_surface_t* surface = cairo_image_surface_create_for_data(
139 data, CAIRO_FORMAT_ARGB32, width, height,
140 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
142 return Create(width, height, is_opaque, surface);
145 // The device will own the bitmap, which corresponds to also owning the pixel
146 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap.
147 BitmapPlatformDevice::BitmapPlatformDevice(
148 const SkBitmap& bitmap,
149 cairo_surface_t* surface)
150 : SkBitmapDevice(bitmap),
151 cairo_(cairo_create(surface)),
153 transform_(SkMatrix::I()) { // Want to load the config next time.
154 SetPlatformDevice(this, this);
157 BitmapPlatformDevice::~BitmapPlatformDevice() {
158 cairo_destroy(cairo_);
161 SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
162 SkBitmap::Config config, int width, int height, bool isOpaque,
164 SkASSERT(config == SkBitmap::kARGB_8888_Config);
165 return BitmapPlatformDevice::Create(width, height, isOpaque);
168 cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
170 cairo_surface_t* surface = cairo_get_target(cairo_);
171 // Tell cairo to flush anything it has pending.
172 cairo_surface_flush(surface);
173 // Tell Cairo that we (probably) modified (actually, will modify) its pixel
175 cairo_surface_mark_dirty(surface);
179 void BitmapPlatformDevice::DrawToNativeContext(
180 PlatformSurface surface, int x, int y, const PlatformRect* src_rect) {
181 // Should never be called on Linux.
185 void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
186 const SkRegion& region,
187 const SkClipStack&) {
188 SetMatrixClip(transform, region);
191 // PlatformCanvas impl
193 SkCanvas* CreatePlatformCanvas(int width, int height, bool is_opaque,
194 uint8_t* data, OnFailureType failureType) {
195 skia::RefPtr<SkBaseDevice> dev = skia::AdoptRef(
196 BitmapPlatformDevice::Create(width, height, is_opaque, data));
197 return CreateCanvas(dev, failureType);
200 // Port of PlatformBitmap to linux
201 PlatformBitmap::~PlatformBitmap() {
202 cairo_destroy(surface_);
205 bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) {
206 // The SkBitmap allocates and owns the bitmap memory; PlatformBitmap owns the
207 // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
208 // outlive the PlatformBitmap if additional copies are made.
209 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
211 cairo_surface_t* surf = cairo_image_surface_create(
215 if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
216 cairo_surface_destroy(surf);
219 return InstallCairoSurfacePixels(&bitmap_, surf, is_opaque);