|
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 GfxOpToCairoOp(CompositionOp op) |
|
18 { |
|
19 switch (op) |
|
20 { |
|
21 case CompositionOp::OP_OVER: |
|
22 return CAIRO_OPERATOR_OVER; |
|
23 case CompositionOp::OP_ADD: |
|
24 return CAIRO_OPERATOR_ADD; |
|
25 case CompositionOp::OP_ATOP: |
|
26 return CAIRO_OPERATOR_ATOP; |
|
27 case CompositionOp::OP_OUT: |
|
28 return CAIRO_OPERATOR_OUT; |
|
29 case CompositionOp::OP_IN: |
|
30 return CAIRO_OPERATOR_IN; |
|
31 case CompositionOp::OP_SOURCE: |
|
32 return CAIRO_OPERATOR_SOURCE; |
|
33 case CompositionOp::OP_DEST_IN: |
|
34 return CAIRO_OPERATOR_DEST_IN; |
|
35 case CompositionOp::OP_DEST_OUT: |
|
36 return CAIRO_OPERATOR_DEST_OUT; |
|
37 case CompositionOp::OP_DEST_OVER: |
|
38 return CAIRO_OPERATOR_DEST_OVER; |
|
39 case CompositionOp::OP_DEST_ATOP: |
|
40 return CAIRO_OPERATOR_DEST_ATOP; |
|
41 case CompositionOp::OP_XOR: |
|
42 return CAIRO_OPERATOR_XOR; |
|
43 case CompositionOp::OP_MULTIPLY: |
|
44 return CAIRO_OPERATOR_MULTIPLY; |
|
45 case CompositionOp::OP_SCREEN: |
|
46 return CAIRO_OPERATOR_SCREEN; |
|
47 case CompositionOp::OP_OVERLAY: |
|
48 return CAIRO_OPERATOR_OVERLAY; |
|
49 case CompositionOp::OP_DARKEN: |
|
50 return CAIRO_OPERATOR_DARKEN; |
|
51 case CompositionOp::OP_LIGHTEN: |
|
52 return CAIRO_OPERATOR_LIGHTEN; |
|
53 case CompositionOp::OP_COLOR_DODGE: |
|
54 return CAIRO_OPERATOR_COLOR_DODGE; |
|
55 case CompositionOp::OP_COLOR_BURN: |
|
56 return CAIRO_OPERATOR_COLOR_BURN; |
|
57 case CompositionOp::OP_HARD_LIGHT: |
|
58 return CAIRO_OPERATOR_HARD_LIGHT; |
|
59 case CompositionOp::OP_SOFT_LIGHT: |
|
60 return CAIRO_OPERATOR_SOFT_LIGHT; |
|
61 case CompositionOp::OP_DIFFERENCE: |
|
62 return CAIRO_OPERATOR_DIFFERENCE; |
|
63 case CompositionOp::OP_EXCLUSION: |
|
64 return CAIRO_OPERATOR_EXCLUSION; |
|
65 case CompositionOp::OP_HUE: |
|
66 return CAIRO_OPERATOR_HSL_HUE; |
|
67 case CompositionOp::OP_SATURATION: |
|
68 return CAIRO_OPERATOR_HSL_SATURATION; |
|
69 case CompositionOp::OP_COLOR: |
|
70 return CAIRO_OPERATOR_HSL_COLOR; |
|
71 case CompositionOp::OP_LUMINOSITY: |
|
72 return CAIRO_OPERATOR_HSL_LUMINOSITY; |
|
73 case CompositionOp::OP_COUNT: |
|
74 break; |
|
75 } |
|
76 |
|
77 return CAIRO_OPERATOR_OVER; |
|
78 } |
|
79 |
|
80 static inline cairo_antialias_t |
|
81 GfxAntialiasToCairoAntialias(AntialiasMode antialias) |
|
82 { |
|
83 switch (antialias) |
|
84 { |
|
85 case AntialiasMode::NONE: |
|
86 return CAIRO_ANTIALIAS_NONE; |
|
87 case AntialiasMode::GRAY: |
|
88 return CAIRO_ANTIALIAS_GRAY; |
|
89 case AntialiasMode::SUBPIXEL: |
|
90 return CAIRO_ANTIALIAS_SUBPIXEL; |
|
91 case AntialiasMode::DEFAULT: |
|
92 return CAIRO_ANTIALIAS_DEFAULT; |
|
93 } |
|
94 return CAIRO_ANTIALIAS_DEFAULT; |
|
95 } |
|
96 |
|
97 static inline cairo_filter_t |
|
98 GfxFilterToCairoFilter(Filter filter) |
|
99 { |
|
100 switch (filter) |
|
101 { |
|
102 case Filter::GOOD: |
|
103 return CAIRO_FILTER_GOOD; |
|
104 case Filter::LINEAR: |
|
105 return CAIRO_FILTER_BILINEAR; |
|
106 case Filter::POINT: |
|
107 return CAIRO_FILTER_NEAREST; |
|
108 } |
|
109 |
|
110 return CAIRO_FILTER_BILINEAR; |
|
111 } |
|
112 |
|
113 static inline cairo_extend_t |
|
114 GfxExtendToCairoExtend(ExtendMode extend) |
|
115 { |
|
116 switch (extend) |
|
117 { |
|
118 case ExtendMode::CLAMP: |
|
119 return CAIRO_EXTEND_PAD; |
|
120 case ExtendMode::REPEAT: |
|
121 return CAIRO_EXTEND_REPEAT; |
|
122 case ExtendMode::REFLECT: |
|
123 return CAIRO_EXTEND_REFLECT; |
|
124 } |
|
125 |
|
126 return CAIRO_EXTEND_PAD; |
|
127 } |
|
128 |
|
129 static inline cairo_format_t |
|
130 GfxFormatToCairoFormat(SurfaceFormat format) |
|
131 { |
|
132 switch (format) |
|
133 { |
|
134 case SurfaceFormat::B8G8R8A8: |
|
135 return CAIRO_FORMAT_ARGB32; |
|
136 case SurfaceFormat::B8G8R8X8: |
|
137 return CAIRO_FORMAT_RGB24; |
|
138 case SurfaceFormat::A8: |
|
139 return CAIRO_FORMAT_A8; |
|
140 case SurfaceFormat::R5G6B5: |
|
141 return CAIRO_FORMAT_RGB16_565; |
|
142 default: |
|
143 gfxWarning() << "Unknown image format"; |
|
144 return CAIRO_FORMAT_ARGB32; |
|
145 } |
|
146 } |
|
147 |
|
148 static inline cairo_content_t |
|
149 GfxFormatToCairoContent(SurfaceFormat format) |
|
150 { |
|
151 switch (format) |
|
152 { |
|
153 case SurfaceFormat::B8G8R8A8: |
|
154 return CAIRO_CONTENT_COLOR_ALPHA; |
|
155 case SurfaceFormat::B8G8R8X8: |
|
156 case SurfaceFormat::R5G6B5: //fall through |
|
157 return CAIRO_CONTENT_COLOR; |
|
158 case SurfaceFormat::A8: |
|
159 return CAIRO_CONTENT_ALPHA; |
|
160 default: |
|
161 gfxWarning() << "Unknown image format"; |
|
162 return CAIRO_CONTENT_COLOR_ALPHA; |
|
163 } |
|
164 } |
|
165 |
|
166 static inline cairo_line_join_t |
|
167 GfxLineJoinToCairoLineJoin(JoinStyle style) |
|
168 { |
|
169 switch (style) |
|
170 { |
|
171 case JoinStyle::BEVEL: |
|
172 return CAIRO_LINE_JOIN_BEVEL; |
|
173 case JoinStyle::ROUND: |
|
174 return CAIRO_LINE_JOIN_ROUND; |
|
175 case JoinStyle::MITER: |
|
176 return CAIRO_LINE_JOIN_MITER; |
|
177 case JoinStyle::MITER_OR_BEVEL: |
|
178 return CAIRO_LINE_JOIN_MITER; |
|
179 } |
|
180 |
|
181 return CAIRO_LINE_JOIN_MITER; |
|
182 } |
|
183 |
|
184 static inline cairo_line_cap_t |
|
185 GfxLineCapToCairoLineCap(CapStyle style) |
|
186 { |
|
187 switch (style) |
|
188 { |
|
189 case CapStyle::BUTT: |
|
190 return CAIRO_LINE_CAP_BUTT; |
|
191 case CapStyle::ROUND: |
|
192 return CAIRO_LINE_CAP_ROUND; |
|
193 case CapStyle::SQUARE: |
|
194 return CAIRO_LINE_CAP_SQUARE; |
|
195 } |
|
196 |
|
197 return CAIRO_LINE_CAP_BUTT; |
|
198 } |
|
199 |
|
200 static inline SurfaceFormat |
|
201 CairoContentToGfxFormat(cairo_content_t content) |
|
202 { |
|
203 switch (content) |
|
204 { |
|
205 case CAIRO_CONTENT_COLOR_ALPHA: |
|
206 return SurfaceFormat::B8G8R8A8; |
|
207 case CAIRO_CONTENT_COLOR: |
|
208 // BEWARE! format may be 565 |
|
209 return SurfaceFormat::B8G8R8X8; |
|
210 case CAIRO_CONTENT_ALPHA: |
|
211 return SurfaceFormat::A8; |
|
212 } |
|
213 |
|
214 return SurfaceFormat::B8G8R8A8; |
|
215 } |
|
216 |
|
217 static inline void |
|
218 GfxMatrixToCairoMatrix(const Matrix& mat, cairo_matrix_t& retval) |
|
219 { |
|
220 cairo_matrix_init(&retval, mat._11, mat._12, mat._21, mat._22, mat._31, mat._32); |
|
221 } |
|
222 |
|
223 static inline void |
|
224 SetCairoStrokeOptions(cairo_t* aCtx, const StrokeOptions& aStrokeOptions) |
|
225 { |
|
226 cairo_set_line_width(aCtx, aStrokeOptions.mLineWidth); |
|
227 |
|
228 cairo_set_miter_limit(aCtx, aStrokeOptions.mMiterLimit); |
|
229 |
|
230 if (aStrokeOptions.mDashPattern) { |
|
231 // Convert array of floats to array of doubles |
|
232 std::vector<double> dashes(aStrokeOptions.mDashLength); |
|
233 for (size_t i = 0; i < aStrokeOptions.mDashLength; ++i) { |
|
234 dashes[i] = aStrokeOptions.mDashPattern[i]; |
|
235 } |
|
236 cairo_set_dash(aCtx, &dashes[0], aStrokeOptions.mDashLength, |
|
237 aStrokeOptions.mDashOffset); |
|
238 } |
|
239 |
|
240 cairo_set_line_join(aCtx, GfxLineJoinToCairoLineJoin(aStrokeOptions.mLineJoin)); |
|
241 |
|
242 cairo_set_line_cap(aCtx, GfxLineCapToCairoLineCap(aStrokeOptions.mLineCap)); |
|
243 } |
|
244 |
|
245 static inline cairo_fill_rule_t |
|
246 GfxFillRuleToCairoFillRule(FillRule rule) |
|
247 { |
|
248 switch (rule) |
|
249 { |
|
250 case FillRule::FILL_WINDING: |
|
251 return CAIRO_FILL_RULE_WINDING; |
|
252 case FillRule::FILL_EVEN_ODD: |
|
253 return CAIRO_FILL_RULE_EVEN_ODD; |
|
254 } |
|
255 |
|
256 return CAIRO_FILL_RULE_WINDING; |
|
257 } |
|
258 |
|
259 // RAII class for temporarily changing the cairo matrix transform. It will use |
|
260 // the given matrix transform while it is in scope. When it goes out of scope |
|
261 // it will put the cairo context back the way it was. |
|
262 |
|
263 class CairoTempMatrix |
|
264 { |
|
265 public: |
|
266 CairoTempMatrix(cairo_t* aCtx, const Matrix& aMatrix) |
|
267 : mCtx(aCtx) |
|
268 { |
|
269 cairo_get_matrix(aCtx, &mSaveMatrix); |
|
270 cairo_matrix_t matrix; |
|
271 GfxMatrixToCairoMatrix(aMatrix, matrix); |
|
272 cairo_set_matrix(aCtx, &matrix); |
|
273 } |
|
274 |
|
275 ~CairoTempMatrix() |
|
276 { |
|
277 cairo_set_matrix(mCtx, &mSaveMatrix); |
|
278 } |
|
279 |
|
280 private: |
|
281 cairo_t* mCtx; |
|
282 cairo_matrix_t mSaveMatrix; |
|
283 }; |
|
284 |
|
285 } |
|
286 } |
|
287 |
|
288 #endif /* MOZILLA_GFX_HELPERSCAIRO_H_ */ |