- add sources.
[platform/framework/web/crosswalk.git] / src / skia / ext / bitmap_platform_device_linux.cc
1 // Copyright (c) 2012 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_linux.h"
6 #include "skia/ext/bitmap_platform_device_data.h"
7 #include "skia/ext/platform_canvas.h"
8
9 #if defined(OS_OPENBSD)
10 #include <cairo.h>
11 #else
12 #include <cairo/cairo.h>
13 #endif
14
15 namespace skia {
16
17 namespace {
18
19 void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) {
20   cairo_matrix_t cairo_matrix;
21   cairo_matrix_init(&cairo_matrix,
22                     SkScalarToFloat(matrix.getScaleX()),
23                     SkScalarToFloat(matrix.getSkewY()),
24                     SkScalarToFloat(matrix.getSkewX()),
25                     SkScalarToFloat(matrix.getScaleY()),
26                     SkScalarToFloat(matrix.getTranslateX()),
27                     SkScalarToFloat(matrix.getTranslateY()));
28   cairo_set_matrix(context, &cairo_matrix);
29 }
30
31 void LoadClipToContext(cairo_t* context, const SkRegion& clip) {
32   cairo_reset_clip(context);
33
34   // TODO(brettw) support non-rect clips.
35   SkIRect bounding = clip.getBounds();
36   cairo_rectangle(context, bounding.fLeft, bounding.fTop,
37                   bounding.fRight - bounding.fLeft,
38                   bounding.fBottom - bounding.fTop);
39   cairo_clip(context);
40 }
41
42 }  // namespace
43
44 BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData(
45     cairo_surface_t* surface)
46     : surface_(surface),
47       config_dirty_(true),
48       transform_(SkMatrix::I()) {  // Want to load the config next time.
49   bitmap_context_ = cairo_create(surface);
50 }
51
52 BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() {
53   cairo_destroy(bitmap_context_);
54   cairo_surface_destroy(surface_);
55 }
56
57 void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip(
58     const SkMatrix& transform,
59     const SkRegion& region) {
60   transform_ = transform;
61   clip_region_ = region;
62   config_dirty_ = true;
63 }
64
65 void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() {
66   if (!config_dirty_ || !bitmap_context_)
67     return;  // Nothing to do.
68   config_dirty_ = false;
69
70   // Load the identity matrix since this is what our clip is relative to.
71   cairo_matrix_t cairo_matrix;
72   cairo_matrix_init_identity(&cairo_matrix);
73   cairo_set_matrix(bitmap_context_, &cairo_matrix);
74
75   LoadClipToContext(bitmap_context_, clip_region_);
76   LoadMatrixToContext(bitmap_context_, transform_);
77 }
78
79 // We use this static factory function instead of the regular constructor so
80 // that we can create the pixel data before calling the constructor. This is
81 // required so that we can call the base class' constructor with the pixel
82 // data.
83 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
84                                                    bool is_opaque,
85                                                    cairo_surface_t* surface) {
86   if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
87     cairo_surface_destroy(surface);
88     return NULL;
89   }
90   SkBitmap bitmap;
91   bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height,
92                    cairo_image_surface_get_stride(surface),
93                    is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
94   bitmap.setPixels(cairo_image_surface_get_data(surface));
95
96   // The device object will take ownership of the graphics context.
97   return new BitmapPlatformDevice
98       (bitmap, new BitmapPlatformDeviceData(surface));
99 }
100
101 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
102                                                    bool is_opaque) {
103   // This initializes the bitmap to all zeros.
104   cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
105                                                         width, height);
106
107   BitmapPlatformDevice* device = Create(width, height, is_opaque, surface);
108
109 #ifndef NDEBUG
110   if (device && is_opaque)  // Fill with bright bluish green
111     device->eraseColor(SkColorSetARGB(255, 0, 255, 128));
112 #endif
113
114   return device;
115 }
116
117 BitmapPlatformDevice* BitmapPlatformDevice::CreateAndClear(int width,
118                                                            int height,
119                                                            bool is_opaque) {
120   // The Linux port always constructs initialized bitmaps, so there is no extra
121   // work to perform here.
122   return Create(width, height, is_opaque);
123 }
124
125 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
126                                                    bool is_opaque,
127                                                    uint8_t* data) {
128   cairo_surface_t* surface = cairo_image_surface_create_for_data(
129       data, CAIRO_FORMAT_ARGB32, width, height,
130       cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
131
132   return Create(width, height, is_opaque, surface);
133 }
134
135 // The device will own the bitmap, which corresponds to also owning the pixel
136 // data. Therefore, we do not transfer ownership to the SkBitmapDevice's bitmap.
137 BitmapPlatformDevice::BitmapPlatformDevice(
138     const SkBitmap& bitmap,
139     BitmapPlatformDeviceData* data)
140     : SkBitmapDevice(bitmap),
141       data_(data) {
142   SetPlatformDevice(this, this);
143 }
144
145 BitmapPlatformDevice::~BitmapPlatformDevice() {
146 }
147
148 SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
149     SkBitmap::Config config, int width, int height, bool isOpaque,
150     Usage /*usage*/) {
151   SkASSERT(config == SkBitmap::kARGB_8888_Config);
152   return BitmapPlatformDevice::Create(width, height, isOpaque);
153 }
154
155 cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
156   data_->LoadConfig();
157   cairo_t* cairo = data_->bitmap_context();
158   cairo_surface_t* surface = cairo_get_target(cairo);
159   // Tell cairo to flush anything it has pending.
160   cairo_surface_flush(surface);
161   // Tell Cairo that we (probably) modified (actually, will modify) its pixel
162   // buffer directly.
163   cairo_surface_mark_dirty(surface);
164   return cairo;
165 }
166
167 void BitmapPlatformDevice::DrawToNativeContext(
168     PlatformSurface surface, int x, int y, const PlatformRect* src_rect) {
169   // Should never be called on Linux.
170   SkASSERT(false);
171 }
172
173 void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
174                                          const SkRegion& region,
175                                          const SkClipStack&) {
176   data_->SetMatrixClip(transform, region);
177 }
178
179 // PlatformCanvas impl
180
181 SkCanvas* CreatePlatformCanvas(int width, int height, bool is_opaque,
182                                uint8_t* data, OnFailureType failureType) {
183   skia::RefPtr<SkBaseDevice> dev = skia::AdoptRef(
184       BitmapPlatformDevice::Create(width, height, is_opaque, data));
185   return CreateCanvas(dev, failureType);
186 }
187
188 // Port of PlatformBitmap to linux
189 PlatformBitmap::~PlatformBitmap() {
190   cairo_destroy(surface_);
191 }
192
193 bool PlatformBitmap::Allocate(int width, int height, bool is_opaque) {
194   // The SkBitmap allocates and owns the bitmap memory; PlatformBitmap owns the
195   // cairo drawing context tied to the bitmap. The SkBitmap's pixelRef can
196   // outlive the PlatformBitmap if additional copies are made.
197   int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
198   bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width, height, stride,
199                     is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
200   if (!bitmap_.allocPixels())  // Using the default allocator.
201     return false;
202
203   cairo_surface_t* surf = cairo_image_surface_create_for_data(
204       reinterpret_cast<unsigned char*>(bitmap_.getPixels()),
205       CAIRO_FORMAT_ARGB32,
206       width,
207       height,
208       stride);
209   if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
210     cairo_surface_destroy(surf);
211     return false;
212   }
213
214   surface_ = cairo_create(surf);
215   cairo_surface_destroy(surf);
216   return true;
217 }
218
219 }  // namespace skia