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.
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"
9 #if defined(OS_OPENBSD)
12 #include <cairo/cairo.h>
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
);
31 void LoadClipToContext(cairo_t
* context
, const SkRegion
& clip
) {
32 cairo_reset_clip(context
);
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
);
44 BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData(
45 cairo_surface_t
* surface
)
48 transform_(SkMatrix::I()) { // Want to load the config next time.
49 bitmap_context_
= cairo_create(surface
);
52 BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() {
53 cairo_destroy(bitmap_context_
);
54 cairo_surface_destroy(surface_
);
57 void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip(
58 const SkMatrix
& transform
,
59 const SkRegion
& region
) {
60 transform_
= transform
;
61 clip_region_
= region
;
65 void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() {
66 if (!config_dirty_
|| !bitmap_context_
)
67 return; // Nothing to do.
68 config_dirty_
= false;
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
);
75 LoadClipToContext(bitmap_context_
, clip_region_
);
76 LoadMatrixToContext(bitmap_context_
, transform_
);
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
83 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
85 cairo_surface_t
* surface
) {
86 if (cairo_surface_status(surface
) != CAIRO_STATUS_SUCCESS
) {
87 cairo_surface_destroy(surface
);
91 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, width
, height
,
92 cairo_image_surface_get_stride(surface
));
93 bitmap
.setPixels(cairo_image_surface_get_data(surface
));
94 bitmap
.setIsOpaque(is_opaque
);
96 // The device object will take ownership of the graphics context.
97 return new BitmapPlatformDevice
98 (bitmap
, new BitmapPlatformDeviceData(surface
));
101 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
103 // This initializes the bitmap to all zeros.
104 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
,
107 BitmapPlatformDevice
* device
= Create(width
, height
, is_opaque
, surface
);
110 if (device
&& is_opaque
) // Fill with bright bluish green
111 device
->eraseColor(SkColorSetARGB(255, 0, 255, 128));
117 BitmapPlatformDevice
* BitmapPlatformDevice::CreateAndClear(int width
,
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
);
125 BitmapPlatformDevice
* BitmapPlatformDevice::Create(int width
, int height
,
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
));
132 return Create(width
, height
, is_opaque
, surface
);
135 // The device will own the bitmap, which corresponds to also owning the pixel
136 // data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
137 BitmapPlatformDevice::BitmapPlatformDevice(
138 const SkBitmap
& bitmap
,
139 BitmapPlatformDeviceData
* data
)
142 SetPlatformDevice(this, this);
145 BitmapPlatformDevice::~BitmapPlatformDevice() {
148 SkDevice
* BitmapPlatformDevice::onCreateCompatibleDevice(
149 SkBitmap::Config config
, int width
, int height
, bool isOpaque
,
151 SkASSERT(config
== SkBitmap::kARGB_8888_Config
);
152 return BitmapPlatformDevice::Create(width
, height
, isOpaque
);
155 cairo_t
* BitmapPlatformDevice::BeginPlatformPaint() {
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
163 cairo_surface_mark_dirty(surface
);
167 void BitmapPlatformDevice::DrawToNativeContext(
168 PlatformSurface surface
, int x
, int y
, const PlatformRect
* src_rect
) {
169 // Should never be called on Linux.
173 void BitmapPlatformDevice::setMatrixClip(const SkMatrix
& transform
,
174 const SkRegion
& region
,
175 const SkClipStack
&) {
176 data_
->SetMatrixClip(transform
, region
);
179 // PlatformCanvas impl
181 SkCanvas
* CreatePlatformCanvas(int width
, int height
, bool is_opaque
,
182 uint8_t* data
, OnFailureType failureType
) {
183 skia::RefPtr
<SkDevice
> dev
= skia::AdoptRef(
184 BitmapPlatformDevice::Create(width
, height
, is_opaque
, data
));
185 return CreateCanvas(dev
, failureType
);
188 // Port of PlatformBitmap to linux
189 PlatformBitmap::~PlatformBitmap() {
190 cairo_destroy(surface_
);
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 if (!bitmap_
.allocPixels()) // Using the default allocator.
201 bitmap_
.setIsOpaque(is_opaque
);
203 cairo_surface_t
* surf
= cairo_image_surface_create_for_data(
204 reinterpret_cast<unsigned char*>(bitmap_
.getPixels()),
209 if (cairo_surface_status(surf
) != CAIRO_STATUS_SUCCESS
) {
210 cairo_surface_destroy(surf
);
214 surface_
= cairo_create(surf
);
215 cairo_surface_destroy(surf
);