OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |