OLD | NEW |
| (Empty) |
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 "build/build_config.h" | |
6 #include "skia/ext/bitmap_platform_device_cairo.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 CairoSurfaceReleaseProc(void*, void* context) { | |
20 SkASSERT(context); | |
21 cairo_surface_destroy(static_cast<cairo_surface_t*>(context)); | |
22 } | |
23 | |
24 // Back the destination bitmap by a Cairo surface. The bitmap's | |
25 // pixelRef takes ownership of the passed-in surface and will call | |
26 // cairo_surface_destroy() upon destruction. | |
27 // | |
28 // Note: it may immediately destroy the surface, if it fails to create a bitmap | |
29 // with pixels, thus the caller must either ref() the surface before hand, or | |
30 // it must not refer to the surface after this call. | |
31 bool InstallCairoSurfacePixels(SkBitmap* dst, | |
32 cairo_surface_t* surface, | |
33 bool is_opaque) { | |
34 SkASSERT(dst); | |
35 if (!surface) { | |
36 return false; | |
37 } | |
38 SkImageInfo info | |
39 = SkImageInfo::MakeN32(cairo_image_surface_get_width(surface), | |
40 cairo_image_surface_get_height(surface), | |
41 is_opaque ? kOpaque_SkAlphaType | |
42 : kPremul_SkAlphaType); | |
43 return dst->installPixels(info, | |
44 cairo_image_surface_get_data(surface), | |
45 cairo_image_surface_get_stride(surface), | |
46 NULL, | |
47 &CairoSurfaceReleaseProc, | |
48 static_cast<void*>(surface)); | |
49 } | |
50 | |
51 void LoadMatrixToContext(cairo_t* context, const SkMatrix& matrix) { | |
52 cairo_matrix_t cairo_matrix; | |
53 cairo_matrix_init(&cairo_matrix, | |
54 SkScalarToFloat(matrix.getScaleX()), | |
55 SkScalarToFloat(matrix.getSkewY()), | |
56 SkScalarToFloat(matrix.getSkewX()), | |
57 SkScalarToFloat(matrix.getScaleY()), | |
58 SkScalarToFloat(matrix.getTranslateX()), | |
59 SkScalarToFloat(matrix.getTranslateY())); | |
60 cairo_set_matrix(context, &cairo_matrix); | |
61 } | |
62 | |
63 void LoadClipToContext(cairo_t* context, const SkIRect& clip_bounds) { | |
64 cairo_reset_clip(context); | |
65 | |
66 cairo_rectangle(context, clip_bounds.fLeft, clip_bounds.fTop, | |
67 clip_bounds.width(), clip_bounds.height()); | |
68 cairo_clip(context); | |
69 } | |
70 | |
71 } // namespace | |
72 | |
73 void BitmapPlatformDevice::LoadConfig(const SkMatrix& transform, | |
74 const SkIRect& clip_bounds) { | |
75 if (!cairo_) | |
76 return; // Nothing to do. | |
77 | |
78 LoadClipToContext(cairo_, clip_bounds); | |
79 LoadMatrixToContext(cairo_, transform); | |
80 } | |
81 | |
82 // We use this static factory function instead of the regular constructor so | |
83 // that we can create the pixel data before calling the constructor. This is | |
84 // required so that we can call the base class' constructor with the pixel | |
85 // data. | |
86 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, | |
87 bool is_opaque, | |
88 cairo_surface_t* surface) { | |
89 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { | |
90 cairo_surface_destroy(surface); | |
91 return NULL; | |
92 } | |
93 | |
94 // must call this before trying to install the surface, since that may result | |
95 // in the surface being destroyed. | |
96 cairo_t* cairo = cairo_create(surface); | |
97 | |
98 SkBitmap bitmap; | |
99 if (!InstallCairoSurfacePixels(&bitmap, surface, is_opaque)) { | |
100 cairo_destroy(cairo); | |
101 return NULL; | |
102 } | |
103 | |
104 // The device object will take ownership of the graphics context. | |
105 return new BitmapPlatformDevice(bitmap, cairo); | |
106 } | |
107 | |
108 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, | |
109 bool is_opaque) { | |
110 // This initializes the bitmap to all zeros. | |
111 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, | |
112 width, height); | |
113 | |
114 BitmapPlatformDevice* device = Create(width, height, is_opaque, surface); | |
115 | |
116 #ifndef NDEBUG | |
117 if (device && is_opaque) // Fill with bright bluish green | |
118 SkCanvas(device).drawColor(0xFF00FF80); | |
119 #endif | |
120 | |
121 return device; | |
122 } | |
123 | |
124 BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height, | |
125 bool is_opaque, | |
126 uint8_t* data) { | |
127 cairo_surface_t* surface = cairo_image_surface_create_for_data( | |
128 data, CAIRO_FORMAT_ARGB32, width, height, | |
129 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); | |
130 | |
131 return Create(width, height, is_opaque, surface); | |
132 } | |
133 | |
134 // Ownership of the cairo object is transferred. | |
135 BitmapPlatformDevice::BitmapPlatformDevice( | |
136 const SkBitmap& bitmap, | |
137 cairo_t* cairo) | |
138 : SkBitmapDevice(bitmap), | |
139 cairo_(cairo) { | |
140 SetPlatformDevice(this, this); | |
141 } | |
142 | |
143 BitmapPlatformDevice::~BitmapPlatformDevice() { | |
144 cairo_destroy(cairo_); | |
145 } | |
146 | |
147 SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& info, | |
148 const SkPaint*) { | |
149 SkASSERT(info.fInfo.colorType() == kN32_SkColorType); | |
150 return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(), | |
151 info.fInfo.isOpaque()); | |
152 } | |
153 | |
154 cairo_t* BitmapPlatformDevice::BeginPlatformPaint( | |
155 const SkMatrix& transform, | |
156 const SkIRect& clip_bounds) { | |
157 LoadConfig(transform, clip_bounds); | |
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 // PlatformCanvas impl | |
168 | |
169 SkCanvas* CreatePlatformCanvas(int width, int height, bool is_opaque, | |
170 uint8_t* data, OnFailureType failureType) { | |
171 sk_sp<SkBaseDevice> dev( | |
172 BitmapPlatformDevice::Create(width, height, is_opaque, data)); | |
173 return CreateCanvas(dev, failureType); | |
174 } | |
175 | |
176 } // namespace skia | |
OLD | NEW |