SkDevice virtual changed from onCreateCompatibleDevice to onCreateDevice
[chromium-blink-merge.git] / skia / ext / bitmap_platform_device_cairo.cc
blobf9366493ee1fdd9a93594f4b2e26186ae281a276
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)
9 #include <cairo.h>
10 #else
11 #include <cairo/cairo.h>
12 #endif
14 namespace skia {
16 namespace {
18 void CairoSurfaceReleaseProc(void*, void* context) {
19 SkASSERT(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,
32 bool is_opaque) {
33 SkASSERT(dst);
34 if (!surface) {
35 return false;
37 SkImageInfo info
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);
67 cairo_clip(context);
70 } // namespace
72 void BitmapPlatformDevice::SetMatrixClip(
73 const SkMatrix& transform,
74 const SkRegion& region) {
75 transform_ = transform;
76 clip_region_ = region;
77 config_dirty_ = true;
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
97 // data.
98 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
99 bool is_opaque,
100 cairo_surface_t* surface) {
101 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
102 cairo_surface_destroy(surface);
103 return NULL;
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);
110 SkBitmap bitmap;
111 if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) {
112 cairo_destroy(cairo);
113 return NULL;
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,
121 bool is_opaque) {
122 // This initializes the bitmap to all zeros.
123 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
124 width, height);
126 BitmapPlatformDevice* device = Create(width, height, is_opaque, surface);
128 #ifndef NDEBUG
129 if (device && is_opaque) // Fill with bright bluish green
130 device->eraseColor(SkColorSetARGB(255, 0, 255, 128));
131 #endif
133 return device;
136 BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
137 int height,
138 bool is_opaque) {
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,
145 bool is_opaque,
146 uint8_t* data) {
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,
157 cairo_t* cairo)
158 : SkBitmapDevice(bitmap),
159 cairo_(cairo),
160 config_dirty_(true),
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,
170 Usage /*usage*/) {
171 SkASSERT(info.colorType() == kPMColor_SkColorType);
172 return BitmapPlatformDevice::Create(info.width(), info.height(),
173 info.isOpaque());
176 cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
177 LoadConfig();
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
182 // buffer directly.
183 cairo_surface_mark_dirty(surface);
184 return cairo_;
187 void BitmapPlatformDevice::DrawToNativeContext(
188 PlatformSurface surface, int x, int y, const PlatformRect* src_rect) {
189 // Should never be called on Linux.
190 SkASSERT(false);
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(
220 CAIRO_FORMAT_ARGB32,
221 width,
222 height);
223 if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
224 cairo_surface_destroy(surf);
225 return false;
227 return InstallCairoSurfacePixels(&bitmap_, surf, is_opaque);
230 } // namespace skia