Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / skia / ext / bitmap_platform_device_cairo.cc
blob246984a8a41ee171c1ff1db2465acf220dacc709
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 NULL,
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);
68 cairo_clip(context);
71 } // namespace
73 void BitmapPlatformDevice::SetMatrixClip(
74 const SkMatrix& transform,
75 const SkRegion& region) {
76 transform_ = transform;
77 clip_region_ = region;
78 config_dirty_ = true;
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
98 // data.
99 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
100 bool is_opaque,
101 cairo_surface_t* surface) {
102 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
103 cairo_surface_destroy(surface);
104 return NULL;
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);
111 SkBitmap bitmap;
112 if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) {
113 cairo_destroy(cairo);
114 return NULL;
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,
122 bool is_opaque) {
123 // This initializes the bitmap to all zeros.
124 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
125 width, height);
127 BitmapPlatformDevice* device = Create(width, height, is_opaque, surface);
129 #ifndef NDEBUG
130 if (device && is_opaque) // Fill with bright bluish green
131 SkCanvas(device).drawColor(0xFF00FF80);
132 #endif
134 return device;
137 BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
138 int height,
139 bool is_opaque) {
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,
146 bool is_opaque,
147 uint8_t* data) {
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,
158 cairo_t* cairo)
159 : SkBitmapDevice(bitmap),
160 cairo_(cairo),
161 config_dirty_(true),
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,
171 const SkPaint*) {
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() {
178 LoadConfig();
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
183 // buffer directly.
184 cairo_surface_mark_dirty(surface);
185 return cairo_;
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(
215 CAIRO_FORMAT_ARGB32,
216 width,
217 height);
218 if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
219 cairo_surface_destroy(surf);
220 return false;
222 return InstallCairoSurfacePixels(&bitmap_, surf, is_opaque);
225 } // namespace skia