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