Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef MOZILLA_GFX_HELPERSCAIRO_H_
7 : #define MOZILLA_GFX_HELPERSCAIRO_H_
8 :
9 : #include "2D.h"
10 : #include "cairo.h"
11 : #include "Logging.h"
12 :
13 : namespace mozilla {
14 : namespace gfx {
15 :
16 : static inline cairo_operator_t
17 0 : GfxOpToCairoOp(CompositionOp op)
18 : {
19 0 : switch (op)
20 : {
21 : case CompositionOp::OP_OVER:
22 0 : return CAIRO_OPERATOR_OVER;
23 : case CompositionOp::OP_ADD:
24 0 : return CAIRO_OPERATOR_ADD;
25 : case CompositionOp::OP_ATOP:
26 0 : return CAIRO_OPERATOR_ATOP;
27 : case CompositionOp::OP_OUT:
28 0 : return CAIRO_OPERATOR_OUT;
29 : case CompositionOp::OP_IN:
30 0 : return CAIRO_OPERATOR_IN;
31 : case CompositionOp::OP_SOURCE:
32 0 : return CAIRO_OPERATOR_SOURCE;
33 : case CompositionOp::OP_DEST_IN:
34 0 : return CAIRO_OPERATOR_DEST_IN;
35 : case CompositionOp::OP_DEST_OUT:
36 0 : return CAIRO_OPERATOR_DEST_OUT;
37 : case CompositionOp::OP_DEST_OVER:
38 0 : return CAIRO_OPERATOR_DEST_OVER;
39 : case CompositionOp::OP_DEST_ATOP:
40 0 : return CAIRO_OPERATOR_DEST_ATOP;
41 : case CompositionOp::OP_XOR:
42 0 : return CAIRO_OPERATOR_XOR;
43 : case CompositionOp::OP_MULTIPLY:
44 0 : return CAIRO_OPERATOR_MULTIPLY;
45 : case CompositionOp::OP_SCREEN:
46 0 : return CAIRO_OPERATOR_SCREEN;
47 : case CompositionOp::OP_OVERLAY:
48 0 : return CAIRO_OPERATOR_OVERLAY;
49 : case CompositionOp::OP_DARKEN:
50 0 : return CAIRO_OPERATOR_DARKEN;
51 : case CompositionOp::OP_LIGHTEN:
52 0 : return CAIRO_OPERATOR_LIGHTEN;
53 : case CompositionOp::OP_COLOR_DODGE:
54 0 : return CAIRO_OPERATOR_COLOR_DODGE;
55 : case CompositionOp::OP_COLOR_BURN:
56 0 : return CAIRO_OPERATOR_COLOR_BURN;
57 : case CompositionOp::OP_HARD_LIGHT:
58 0 : return CAIRO_OPERATOR_HARD_LIGHT;
59 : case CompositionOp::OP_SOFT_LIGHT:
60 0 : return CAIRO_OPERATOR_SOFT_LIGHT;
61 : case CompositionOp::OP_DIFFERENCE:
62 0 : return CAIRO_OPERATOR_DIFFERENCE;
63 : case CompositionOp::OP_EXCLUSION:
64 0 : return CAIRO_OPERATOR_EXCLUSION;
65 : case CompositionOp::OP_HUE:
66 0 : return CAIRO_OPERATOR_HSL_HUE;
67 : case CompositionOp::OP_SATURATION:
68 0 : return CAIRO_OPERATOR_HSL_SATURATION;
69 : case CompositionOp::OP_COLOR:
70 0 : return CAIRO_OPERATOR_HSL_COLOR;
71 : case CompositionOp::OP_LUMINOSITY:
72 0 : return CAIRO_OPERATOR_HSL_LUMINOSITY;
73 : case CompositionOp::OP_COUNT:
74 0 : break;
75 : }
76 :
77 0 : return CAIRO_OPERATOR_OVER;
78 : }
79 :
80 : static inline cairo_antialias_t
81 0 : GfxAntialiasToCairoAntialias(AntialiasMode antialias)
82 : {
83 0 : switch (antialias)
84 : {
85 : case AntialiasMode::NONE:
86 0 : return CAIRO_ANTIALIAS_NONE;
87 : case AntialiasMode::GRAY:
88 0 : return CAIRO_ANTIALIAS_GRAY;
89 : case AntialiasMode::SUBPIXEL:
90 0 : return CAIRO_ANTIALIAS_SUBPIXEL;
91 : default:
92 0 : return CAIRO_ANTIALIAS_DEFAULT;
93 : }
94 : }
95 :
96 : static inline AntialiasMode
97 : CairoAntialiasToGfxAntialias(cairo_antialias_t aAntialias)
98 : {
99 : switch(aAntialias) {
100 : case CAIRO_ANTIALIAS_NONE:
101 : return AntialiasMode::NONE;
102 : case CAIRO_ANTIALIAS_GRAY:
103 : return AntialiasMode::GRAY;
104 : case CAIRO_ANTIALIAS_SUBPIXEL:
105 : return AntialiasMode::SUBPIXEL;
106 : default:
107 : return AntialiasMode::DEFAULT;
108 : }
109 : }
110 :
111 : static inline cairo_filter_t
112 0 : GfxSamplingFilterToCairoFilter(SamplingFilter filter)
113 : {
114 0 : switch (filter)
115 : {
116 : case SamplingFilter::GOOD:
117 0 : return CAIRO_FILTER_GOOD;
118 : case SamplingFilter::LINEAR:
119 0 : return CAIRO_FILTER_BILINEAR;
120 : case SamplingFilter::POINT:
121 0 : return CAIRO_FILTER_NEAREST;
122 : default:
123 0 : MOZ_CRASH("GFX: bad Cairo filter");
124 : }
125 :
126 : return CAIRO_FILTER_BILINEAR;
127 : }
128 :
129 : static inline cairo_extend_t
130 0 : GfxExtendToCairoExtend(ExtendMode extend)
131 : {
132 0 : switch (extend)
133 : {
134 : case ExtendMode::CLAMP:
135 0 : return CAIRO_EXTEND_PAD;
136 : // Cairo doesn't support tiling in only 1 direction,
137 : // So we have to fallback and tile in both.
138 : case ExtendMode::REPEAT_X:
139 : case ExtendMode::REPEAT_Y:
140 : case ExtendMode::REPEAT:
141 0 : return CAIRO_EXTEND_REPEAT;
142 : case ExtendMode::REFLECT:
143 0 : return CAIRO_EXTEND_REFLECT;
144 : }
145 :
146 0 : return CAIRO_EXTEND_PAD;
147 : }
148 :
149 : static inline cairo_format_t
150 21 : GfxFormatToCairoFormat(SurfaceFormat format)
151 : {
152 21 : switch (format)
153 : {
154 : case SurfaceFormat::A8R8G8B8_UINT32:
155 3 : return CAIRO_FORMAT_ARGB32;
156 : case SurfaceFormat::X8R8G8B8_UINT32:
157 18 : return CAIRO_FORMAT_RGB24;
158 : case SurfaceFormat::A8:
159 0 : return CAIRO_FORMAT_A8;
160 : case SurfaceFormat::R5G6B5_UINT16:
161 0 : return CAIRO_FORMAT_RGB16_565;
162 : default:
163 0 : gfxCriticalError() << "Unknown image format " << (int)format;
164 0 : return CAIRO_FORMAT_ARGB32;
165 : }
166 : }
167 :
168 : static inline cairo_format_t
169 : CairoContentToCairoFormat(cairo_content_t content)
170 : {
171 : switch (content)
172 : {
173 : case CAIRO_CONTENT_COLOR:
174 : return CAIRO_FORMAT_RGB24;
175 : case CAIRO_CONTENT_ALPHA:
176 : return CAIRO_FORMAT_A8;
177 : case CAIRO_CONTENT_COLOR_ALPHA:
178 : return CAIRO_FORMAT_ARGB32;
179 : default:
180 : gfxCriticalError() << "Unknown cairo content type " << (int)content;
181 : return CAIRO_FORMAT_A8; // least likely to cause OOB reads
182 : }
183 : }
184 :
185 : static inline cairo_content_t
186 0 : GfxFormatToCairoContent(SurfaceFormat format)
187 : {
188 0 : switch (format)
189 : {
190 : case SurfaceFormat::A8R8G8B8_UINT32:
191 0 : return CAIRO_CONTENT_COLOR_ALPHA;
192 : case SurfaceFormat::X8R8G8B8_UINT32:
193 : case SurfaceFormat::R5G6B5_UINT16: //fall through
194 0 : return CAIRO_CONTENT_COLOR;
195 : case SurfaceFormat::A8:
196 0 : return CAIRO_CONTENT_ALPHA;
197 : default:
198 0 : gfxCriticalError() << "Unknown image content format " << (int)format;
199 0 : return CAIRO_CONTENT_COLOR_ALPHA;
200 : }
201 : }
202 :
203 : static inline cairo_line_join_t
204 0 : GfxLineJoinToCairoLineJoin(JoinStyle style)
205 : {
206 0 : switch (style)
207 : {
208 : case JoinStyle::BEVEL:
209 0 : return CAIRO_LINE_JOIN_BEVEL;
210 : case JoinStyle::ROUND:
211 0 : return CAIRO_LINE_JOIN_ROUND;
212 : case JoinStyle::MITER:
213 0 : return CAIRO_LINE_JOIN_MITER;
214 : case JoinStyle::MITER_OR_BEVEL:
215 0 : return CAIRO_LINE_JOIN_MITER;
216 : }
217 :
218 0 : return CAIRO_LINE_JOIN_MITER;
219 : }
220 :
221 : static inline cairo_line_cap_t
222 0 : GfxLineCapToCairoLineCap(CapStyle style)
223 : {
224 0 : switch (style)
225 : {
226 : case CapStyle::BUTT:
227 0 : return CAIRO_LINE_CAP_BUTT;
228 : case CapStyle::ROUND:
229 0 : return CAIRO_LINE_CAP_ROUND;
230 : case CapStyle::SQUARE:
231 0 : return CAIRO_LINE_CAP_SQUARE;
232 : }
233 :
234 0 : return CAIRO_LINE_CAP_BUTT;
235 : }
236 :
237 : static inline SurfaceFormat
238 0 : CairoContentToGfxFormat(cairo_content_t content)
239 : {
240 0 : switch (content)
241 : {
242 : case CAIRO_CONTENT_COLOR_ALPHA:
243 0 : return SurfaceFormat::A8R8G8B8_UINT32;
244 : case CAIRO_CONTENT_COLOR:
245 : // BEWARE! format may be 565
246 0 : return SurfaceFormat::X8R8G8B8_UINT32;
247 : case CAIRO_CONTENT_ALPHA:
248 0 : return SurfaceFormat::A8;
249 : }
250 :
251 0 : return SurfaceFormat::B8G8R8A8;
252 : }
253 :
254 : static inline SurfaceFormat
255 0 : CairoFormatToGfxFormat(cairo_format_t format)
256 : {
257 0 : switch (format) {
258 : case CAIRO_FORMAT_ARGB32:
259 0 : return SurfaceFormat::A8R8G8B8_UINT32;
260 : case CAIRO_FORMAT_RGB24:
261 0 : return SurfaceFormat::X8R8G8B8_UINT32;
262 : case CAIRO_FORMAT_A8:
263 0 : return SurfaceFormat::A8;
264 : case CAIRO_FORMAT_RGB16_565:
265 0 : return SurfaceFormat::R5G6B5_UINT16;
266 : default:
267 0 : gfxCriticalError() << "Unknown cairo format " << format;
268 0 : return SurfaceFormat::UNKNOWN;
269 : }
270 : }
271 :
272 : static inline FontHinting
273 : CairoHintingToGfxHinting(cairo_hint_style_t aHintStyle)
274 : {
275 : switch (aHintStyle) {
276 : case CAIRO_HINT_STYLE_NONE:
277 : return FontHinting::NONE;
278 : case CAIRO_HINT_STYLE_SLIGHT:
279 : return FontHinting::LIGHT;
280 : case CAIRO_HINT_STYLE_MEDIUM:
281 : return FontHinting::NORMAL;
282 : case CAIRO_HINT_STYLE_FULL:
283 : return FontHinting::FULL;
284 : default:
285 : return FontHinting::NORMAL;
286 : }
287 : }
288 :
289 : SurfaceFormat GfxFormatForCairoSurface(cairo_surface_t* surface);
290 :
291 : static inline void
292 45 : GfxMatrixToCairoMatrix(const Matrix& mat, cairo_matrix_t& retval)
293 : {
294 45 : cairo_matrix_init(&retval, mat._11, mat._12, mat._21, mat._22, mat._31, mat._32);
295 45 : }
296 :
297 : static inline void
298 0 : SetCairoStrokeOptions(cairo_t* aCtx, const StrokeOptions& aStrokeOptions)
299 : {
300 0 : cairo_set_line_width(aCtx, aStrokeOptions.mLineWidth);
301 :
302 0 : cairo_set_miter_limit(aCtx, aStrokeOptions.mMiterLimit);
303 :
304 0 : if (aStrokeOptions.mDashPattern) {
305 : // Convert array of floats to array of doubles
306 0 : std::vector<double> dashes(aStrokeOptions.mDashLength);
307 0 : bool nonZero = false;
308 0 : for (size_t i = 0; i < aStrokeOptions.mDashLength; ++i) {
309 0 : if (aStrokeOptions.mDashPattern[i] != 0) {
310 0 : nonZero = true;
311 : }
312 0 : dashes[i] = aStrokeOptions.mDashPattern[i];
313 : }
314 : // Avoid all-zero patterns that would trigger the CAIRO_STATUS_INVALID_DASH context error state.
315 0 : if (nonZero) {
316 0 : cairo_set_dash(aCtx, &dashes[0], aStrokeOptions.mDashLength,
317 0 : aStrokeOptions.mDashOffset);
318 : }
319 : }
320 :
321 0 : cairo_set_line_join(aCtx, GfxLineJoinToCairoLineJoin(aStrokeOptions.mLineJoin));
322 :
323 0 : cairo_set_line_cap(aCtx, GfxLineCapToCairoLineCap(aStrokeOptions.mLineCap));
324 0 : }
325 :
326 : static inline cairo_fill_rule_t
327 0 : GfxFillRuleToCairoFillRule(FillRule rule)
328 : {
329 0 : switch (rule)
330 : {
331 : case FillRule::FILL_WINDING:
332 0 : return CAIRO_FILL_RULE_WINDING;
333 : case FillRule::FILL_EVEN_ODD:
334 0 : return CAIRO_FILL_RULE_EVEN_ODD;
335 : }
336 :
337 0 : return CAIRO_FILL_RULE_WINDING;
338 : }
339 :
340 : // RAII class for temporarily changing the cairo matrix transform. It will use
341 : // the given matrix transform while it is in scope. When it goes out of scope
342 : // it will put the cairo context back the way it was.
343 :
344 : class CairoTempMatrix
345 : {
346 : public:
347 : CairoTempMatrix(cairo_t* aCtx, const Matrix& aMatrix)
348 : : mCtx(aCtx)
349 : {
350 : cairo_get_matrix(aCtx, &mSaveMatrix);
351 : cairo_matrix_t matrix;
352 : GfxMatrixToCairoMatrix(aMatrix, matrix);
353 : cairo_set_matrix(aCtx, &matrix);
354 : }
355 :
356 : ~CairoTempMatrix()
357 : {
358 : cairo_set_matrix(mCtx, &mSaveMatrix);
359 : }
360 :
361 : private:
362 : cairo_t* mCtx;
363 : cairo_matrix_t mSaveMatrix;
364 : };
365 :
366 : } // namespace gfx
367 : } // namespace mozilla
368 :
369 : #endif /* MOZILLA_GFX_HELPERSCAIRO_H_ */
|