Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / skia / ext / bitmap_platform_device_cairo.cc
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.
4
5 #include "skia/ext/bitmap_platform_device_cairo.h"
6 #include "skia/ext/platform_canvas.h"
7
8 #if defined(OS_OPENBSD)
9 #include <cairo.h>
10 #else
11 #include <cairo/cairo.h>
12 #endif
13
14 namespace skia {
15
16 namespace {
17
18 void CairoSurfaceReleaseProc(void*, void* context) {
19   SkASSERT(context);
20   cairo_surface_destroy(static_cast<cairo_surface_t*>(context));
21 }
22
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,
28                                bool is_opaque) {
29   SkASSERT(dst);
30   if (!surface) {
31     return false;
32   }
33   SkImageInfo info
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));
41 }
42
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);
53 }
54
55 void LoadClipToContext(cairo_t* context, const SkRegion& clip) {
56   cairo_reset_clip(context);
57
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);
63   cairo_clip(context);
64 }
65
66 }  // namespace
67
68 void BitmapPlatformDevice::SetMatrixClip(
69     const SkMatrix& transform,
70     const SkRegion& region) {
71   transform_ = transform;
72   clip_region_ = region;
73   config_dirty_ = true;
74 }
75
76 void BitmapPlatformDevice::LoadConfig() {
77   if (!config_dirty_ || !cairo_)
78     return;  // Nothing to do.
79   config_dirty_ = false;
80
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);
85
86   LoadClipToContext(cairo_, clip_region_);
87   LoadMatrixToContext(cairo_, transform_);
88 }
89
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
93 // data.
94 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
95                                                    bool is_opaque,
96                                                    cairo_surface_t* surface) {
97   if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
98     cairo_surface_destroy(surface);
99     return NULL;
100   }
101
102   SkBitmap bitmap;
103   if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) {
104     return NULL;
105   }
106
107   // The device object will take ownership of the graphics context.
108   return new BitmapPlatformDevice(bitmap, surface);
109 }
110
111 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
112                                                    bool is_opaque) {
113   // This initializes the bitmap to all zeros.
114   cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
115                                                         width, height);
116
117   BitmapPlatformDevice* device = Create(width, height, is_opaque, surface);
118
119 #ifndef NDEBUG
120   if (device && is_opaque)  // Fill with bright bluish green
121     device->eraseColor(SkColorSetARGB(255, 0, 255, 128));
122 #endif
123
124   return device;
125 }
126
127 BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
128                                                            int height,
129                                                            bool is_opaque) {
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);
133 }
134
135 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
136                                                    bool is_opaque,
137                                                    uint8_t* data) {
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));
141
142   return Create(width, height, is_opaque, surface);
143 }
144
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)),
152       config_dirty_(true),
153       transform_(SkMatrix::I()) {  // Want to load the config next time.
154   SetPlatformDevice(this, this);
155 }
156
157 BitmapPlatformDevice::~BitmapPlatformDevice() {
158   cairo_destroy(cairo_);
159 }
160
161 SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
162     SkBitmap::Config config, int width, int height, bool isOpaque,
163     Usage /*usage*/) {
164   SkASSERT(config == SkBitmap::kARGB_8888_Config);
165   return BitmapPlatformDevice::Create(width, height, isOpaque);
166 }
167
168 cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
169   LoadConfig();
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
174   // buffer directly.
175   cairo_surface_mark_dirty(surface);
176   return cairo_;
177 }
178
179 void BitmapPlatformDevice::DrawToNativeContext(
180     PlatformSurface surface, int x, int y, const PlatformRect* src_rect) {
181   // Should never be called on Linux.
182   SkASSERT(false);
183 }
184
185 void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
186                                          const SkRegion& region,
187                                          const SkClipStack&) {
188   SetMatrixClip(transform, region);
189 }
190
191 // PlatformCanvas impl
192
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);
198 }
199
200 // Port of PlatformBitmap to linux
201 PlatformBitmap::~PlatformBitmap() {
202   cairo_destroy(surface_);
203 }
204
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);
210
211   cairo_surface_t* surf = cairo_image_surface_create(
212       CAIRO_FORMAT_ARGB32,
213       width,
214       height);
215   if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
216     cairo_surface_destroy(surf);
217     return false;
218   }
219   return InstallCairoSurfacePixels(&bitmap_, surf, is_opaque);
220 }
221
222 }  // namespace skia