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_HELPERSSKIA_H_
7 : #define MOZILLA_GFX_HELPERSSKIA_H_
8 :
9 : #include "2D.h"
10 : #include "skia/include/core/SkCanvas.h"
11 : #include "skia/include/effects/SkDashPathEffect.h"
12 : #include "skia/include/core/SkShader.h"
13 : #ifdef USE_SKIA_GPU
14 : #include "skia/include/gpu/GrTypes.h"
15 : #endif
16 : #include "mozilla/Assertions.h"
17 : #include <vector>
18 : #include "nsDebug.h"
19 :
20 : namespace mozilla {
21 : namespace gfx {
22 :
23 : static inline SkColorType
24 154 : GfxFormatToSkiaColorType(SurfaceFormat format)
25 : {
26 154 : switch (format)
27 : {
28 : case SurfaceFormat::B8G8R8A8:
29 117 : return kBGRA_8888_SkColorType;
30 : case SurfaceFormat::B8G8R8X8:
31 : // We probably need to do something here.
32 33 : return kBGRA_8888_SkColorType;
33 : case SurfaceFormat::R5G6B5_UINT16:
34 0 : return kRGB_565_SkColorType;
35 : case SurfaceFormat::A8:
36 4 : return kAlpha_8_SkColorType;
37 : default:
38 0 : return kRGBA_8888_SkColorType;
39 : }
40 : }
41 :
42 : static inline SurfaceFormat
43 18 : SkiaColorTypeToGfxFormat(SkColorType aColorType, SkAlphaType aAlphaType = kPremul_SkAlphaType)
44 : {
45 18 : switch (aColorType)
46 : {
47 : case kBGRA_8888_SkColorType:
48 18 : return aAlphaType == kOpaque_SkAlphaType ?
49 18 : SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
50 : case kRGB_565_SkColorType:
51 0 : return SurfaceFormat::R5G6B5_UINT16;
52 : case kAlpha_8_SkColorType:
53 0 : return SurfaceFormat::A8;
54 : default:
55 0 : return SurfaceFormat::B8G8R8A8;
56 : }
57 : }
58 :
59 : static inline SkAlphaType
60 390 : GfxFormatToSkiaAlphaType(SurfaceFormat format)
61 : {
62 390 : switch (format)
63 : {
64 : case SurfaceFormat::B8G8R8X8:
65 : case SurfaceFormat::R5G6B5_UINT16:
66 61 : return kOpaque_SkAlphaType;
67 : default:
68 329 : return kPremul_SkAlphaType;
69 : }
70 : }
71 :
72 : static inline SkImageInfo
73 154 : MakeSkiaImageInfo(const IntSize& aSize, SurfaceFormat aFormat)
74 : {
75 154 : return SkImageInfo::Make(aSize.width, aSize.height,
76 : GfxFormatToSkiaColorType(aFormat),
77 308 : GfxFormatToSkiaAlphaType(aFormat));
78 : }
79 :
80 : #ifdef USE_SKIA_GPU
81 : static inline GrPixelConfig
82 0 : GfxFormatToGrConfig(SurfaceFormat format)
83 : {
84 0 : switch (format)
85 : {
86 : case SurfaceFormat::B8G8R8A8:
87 0 : return kBGRA_8888_GrPixelConfig;
88 : case SurfaceFormat::B8G8R8X8:
89 : // We probably need to do something here.
90 0 : return kBGRA_8888_GrPixelConfig;
91 : case SurfaceFormat::R5G6B5_UINT16:
92 0 : return kRGB_565_GrPixelConfig;
93 : case SurfaceFormat::A8:
94 0 : return kAlpha_8_GrPixelConfig;
95 : default:
96 0 : return kRGBA_8888_GrPixelConfig;
97 : }
98 :
99 : }
100 : #endif
101 : static inline void
102 2160 : GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval)
103 : {
104 2160 : retval.setAll(SkFloatToScalar(mat._11), SkFloatToScalar(mat._21), SkFloatToScalar(mat._31),
105 2160 : SkFloatToScalar(mat._12), SkFloatToScalar(mat._22), SkFloatToScalar(mat._32),
106 2160 : 0, 0, SK_Scalar1);
107 2160 : }
108 :
109 : static inline void
110 0 : GfxMatrixToSkiaMatrix(const Matrix4x4& aMatrix, SkMatrix& aResult)
111 : {
112 0 : aResult.setAll(SkFloatToScalar(aMatrix._11), SkFloatToScalar(aMatrix._21), SkFloatToScalar(aMatrix._41),
113 0 : SkFloatToScalar(aMatrix._12), SkFloatToScalar(aMatrix._22), SkFloatToScalar(aMatrix._42),
114 0 : SkFloatToScalar(aMatrix._14), SkFloatToScalar(aMatrix._24), SkFloatToScalar(aMatrix._44));
115 0 : }
116 :
117 : static inline SkPaint::Cap
118 15 : CapStyleToSkiaCap(CapStyle aCap)
119 : {
120 15 : switch (aCap)
121 : {
122 : case CapStyle::BUTT:
123 15 : return SkPaint::kButt_Cap;
124 : case CapStyle::ROUND:
125 0 : return SkPaint::kRound_Cap;
126 : case CapStyle::SQUARE:
127 0 : return SkPaint::kSquare_Cap;
128 : }
129 0 : return SkPaint::kDefault_Cap;
130 : }
131 :
132 : static inline SkPaint::Join
133 15 : JoinStyleToSkiaJoin(JoinStyle aJoin)
134 : {
135 15 : switch (aJoin)
136 : {
137 : case JoinStyle::BEVEL:
138 0 : return SkPaint::kBevel_Join;
139 : case JoinStyle::ROUND:
140 0 : return SkPaint::kRound_Join;
141 : case JoinStyle::MITER:
142 : case JoinStyle::MITER_OR_BEVEL:
143 15 : return SkPaint::kMiter_Join;
144 : }
145 0 : return SkPaint::kDefault_Join;
146 : }
147 :
148 : static inline bool
149 15 : StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions)
150 : {
151 : // Skia renders 0 width strokes with a width of 1 (and in black),
152 : // so we should just skip the draw call entirely.
153 : // Skia does not handle non-finite line widths.
154 15 : if (!aOptions.mLineWidth || !IsFinite(aOptions.mLineWidth)) {
155 0 : return false;
156 : }
157 15 : aPaint.setStrokeWidth(SkFloatToScalar(aOptions.mLineWidth));
158 15 : aPaint.setStrokeMiter(SkFloatToScalar(aOptions.mMiterLimit));
159 15 : aPaint.setStrokeCap(CapStyleToSkiaCap(aOptions.mLineCap));
160 15 : aPaint.setStrokeJoin(JoinStyleToSkiaJoin(aOptions.mLineJoin));
161 :
162 15 : if (aOptions.mDashLength > 0) {
163 : // Skia only supports dash arrays that are multiples of 2.
164 : uint32_t dashCount;
165 :
166 0 : if (aOptions.mDashLength % 2 == 0) {
167 0 : dashCount = aOptions.mDashLength;
168 : } else {
169 0 : dashCount = aOptions.mDashLength * 2;
170 : }
171 :
172 0 : std::vector<SkScalar> pattern;
173 0 : pattern.resize(dashCount);
174 :
175 0 : for (uint32_t i = 0; i < dashCount; i++) {
176 0 : pattern[i] = SkFloatToScalar(aOptions.mDashPattern[i % aOptions.mDashLength]);
177 : }
178 :
179 0 : sk_sp<SkPathEffect> dash = SkDashPathEffect::Make(&pattern.front(),
180 : dashCount,
181 0 : SkFloatToScalar(aOptions.mDashOffset));
182 0 : aPaint.setPathEffect(dash);
183 : }
184 :
185 15 : aPaint.setStyle(SkPaint::kStroke_Style);
186 15 : return true;
187 : }
188 :
189 : static inline SkBlendMode
190 424 : GfxOpToSkiaOp(CompositionOp op)
191 : {
192 424 : switch (op)
193 : {
194 : case CompositionOp::OP_OVER:
195 410 : return SkBlendMode::kSrcOver;
196 : case CompositionOp::OP_ADD:
197 0 : return SkBlendMode::kPlus;
198 : case CompositionOp::OP_ATOP:
199 0 : return SkBlendMode::kSrcATop;
200 : case CompositionOp::OP_OUT:
201 0 : return SkBlendMode::kSrcOut;
202 : case CompositionOp::OP_IN:
203 0 : return SkBlendMode::kSrcIn;
204 : case CompositionOp::OP_SOURCE:
205 14 : return SkBlendMode::kSrc;
206 : case CompositionOp::OP_DEST_IN:
207 0 : return SkBlendMode::kDstIn;
208 : case CompositionOp::OP_DEST_OUT:
209 0 : return SkBlendMode::kDstOut;
210 : case CompositionOp::OP_DEST_OVER:
211 0 : return SkBlendMode::kDstOver;
212 : case CompositionOp::OP_DEST_ATOP:
213 0 : return SkBlendMode::kDstATop;
214 : case CompositionOp::OP_XOR:
215 0 : return SkBlendMode::kXor;
216 : case CompositionOp::OP_MULTIPLY:
217 0 : return SkBlendMode::kMultiply;
218 : case CompositionOp::OP_SCREEN:
219 0 : return SkBlendMode::kScreen;
220 : case CompositionOp::OP_OVERLAY:
221 0 : return SkBlendMode::kOverlay;
222 : case CompositionOp::OP_DARKEN:
223 0 : return SkBlendMode::kDarken;
224 : case CompositionOp::OP_LIGHTEN:
225 0 : return SkBlendMode::kLighten;
226 : case CompositionOp::OP_COLOR_DODGE:
227 0 : return SkBlendMode::kColorDodge;
228 : case CompositionOp::OP_COLOR_BURN:
229 0 : return SkBlendMode::kColorBurn;
230 : case CompositionOp::OP_HARD_LIGHT:
231 0 : return SkBlendMode::kHardLight;
232 : case CompositionOp::OP_SOFT_LIGHT:
233 0 : return SkBlendMode::kSoftLight;
234 : case CompositionOp::OP_DIFFERENCE:
235 0 : return SkBlendMode::kDifference;
236 : case CompositionOp::OP_EXCLUSION:
237 0 : return SkBlendMode::kExclusion;
238 : case CompositionOp::OP_HUE:
239 0 : return SkBlendMode::kHue;
240 : case CompositionOp::OP_SATURATION:
241 0 : return SkBlendMode::kSaturation;
242 : case CompositionOp::OP_COLOR:
243 0 : return SkBlendMode::kColor;
244 : case CompositionOp::OP_LUMINOSITY:
245 0 : return SkBlendMode::kLuminosity;
246 : default:
247 0 : return SkBlendMode::kSrcOver;
248 : }
249 : }
250 :
251 : /* There's quite a bit of inconsistency about
252 : * whether float colors should be rounded with .5f.
253 : * We choose to do it to match cairo which also
254 : * happens to match the Direct3D specs */
255 1126 : static inline U8CPU ColorFloatToByte(Float color)
256 : {
257 : //XXX: do a better job converting to int
258 1126 : return U8CPU(color*255.f + .5f);
259 : };
260 :
261 170 : static inline SkColor ColorToSkColor(const Color &color, Float aAlpha)
262 : {
263 170 : return SkColorSetARGB(ColorFloatToByte(color.a*aAlpha), ColorFloatToByte(color.r),
264 : ColorFloatToByte(color.g), ColorFloatToByte(color.b));
265 : }
266 :
267 : static inline SkPoint
268 0 : PointToSkPoint(const Point &aPoint)
269 : {
270 0 : return SkPoint::Make(SkFloatToScalar(aPoint.x), SkFloatToScalar(aPoint.y));
271 : }
272 :
273 : static inline SkRect
274 1008 : RectToSkRect(const Rect& aRect)
275 : {
276 1008 : return SkRect::MakeXYWH(SkFloatToScalar(aRect.x), SkFloatToScalar(aRect.y),
277 2016 : SkFloatToScalar(aRect.width), SkFloatToScalar(aRect.height));
278 : }
279 :
280 : static inline SkRect
281 22 : IntRectToSkRect(const IntRect& aRect)
282 : {
283 44 : return SkRect::MakeXYWH(SkIntToScalar(aRect.x), SkIntToScalar(aRect.y),
284 66 : SkIntToScalar(aRect.width), SkIntToScalar(aRect.height));
285 : }
286 :
287 : static inline SkIRect
288 : RectToSkIRect(const Rect& aRect)
289 : {
290 : return SkIRect::MakeXYWH(int32_t(aRect.x), int32_t(aRect.y),
291 : int32_t(aRect.width), int32_t(aRect.height));
292 : }
293 :
294 : static inline SkIRect
295 124 : IntRectToSkIRect(const IntRect& aRect)
296 : {
297 124 : return SkIRect::MakeXYWH(aRect.x, aRect.y, aRect.width, aRect.height);
298 : }
299 :
300 : static inline IntRect
301 0 : SkIRectToIntRect(const SkIRect& aRect)
302 : {
303 0 : return IntRect(aRect.x(), aRect.y(), aRect.width(), aRect.height());
304 : }
305 :
306 : static inline Point
307 112 : SkPointToPoint(const SkPoint &aPoint)
308 : {
309 112 : return Point(SkScalarToFloat(aPoint.x()), SkScalarToFloat(aPoint.y()));
310 : }
311 :
312 : static inline Rect
313 112 : SkRectToRect(const SkRect &aRect)
314 : {
315 224 : return Rect(SkScalarToFloat(aRect.x()), SkScalarToFloat(aRect.y()),
316 336 : SkScalarToFloat(aRect.width()), SkScalarToFloat(aRect.height()));
317 : }
318 :
319 : static inline SkShader::TileMode
320 223 : ExtendModeToTileMode(ExtendMode aMode, Axis aAxis)
321 : {
322 223 : switch (aMode)
323 : {
324 : case ExtendMode::CLAMP:
325 117 : return SkShader::kClamp_TileMode;
326 : case ExtendMode::REPEAT:
327 90 : return SkShader::kRepeat_TileMode;
328 : case ExtendMode::REFLECT:
329 0 : return SkShader::kMirror_TileMode;
330 : case ExtendMode::REPEAT_X:
331 : {
332 : return aAxis == Axis::X_AXIS
333 16 : ? SkShader::kRepeat_TileMode
334 16 : : SkShader::kClamp_TileMode;
335 : }
336 : case ExtendMode::REPEAT_Y:
337 : {
338 : return aAxis == Axis::Y_AXIS
339 0 : ? SkShader::kRepeat_TileMode
340 0 : : SkShader::kClamp_TileMode;
341 : }
342 : }
343 0 : return SkShader::kClamp_TileMode;
344 : }
345 :
346 : static inline SkPaint::Hinting
347 : GfxHintingToSkiaHinting(FontHinting aHinting)
348 : {
349 : switch (aHinting) {
350 : case FontHinting::NONE:
351 : return SkPaint::kNo_Hinting;
352 : case FontHinting::LIGHT:
353 : return SkPaint::kSlight_Hinting;
354 : case FontHinting::NORMAL:
355 : return SkPaint::kNormal_Hinting;
356 : case FontHinting::FULL:
357 : return SkPaint::kFull_Hinting;
358 : }
359 : return SkPaint::kNormal_Hinting;
360 : }
361 :
362 : static inline FillRule GetFillRule(SkPath::FillType aFillType)
363 : {
364 : switch (aFillType)
365 : {
366 : case SkPath::kWinding_FillType:
367 : return FillRule::FILL_WINDING;
368 : case SkPath::kEvenOdd_FillType:
369 : return FillRule::FILL_EVEN_ODD;
370 : case SkPath::kInverseWinding_FillType:
371 : case SkPath::kInverseEvenOdd_FillType:
372 : default:
373 : NS_WARNING("Unsupported fill type\n");
374 : break;
375 : }
376 :
377 : return FillRule::FILL_EVEN_ODD;
378 : }
379 :
380 : /**
381 : * Returns true if the canvas is backed by pixels. Returns false if the canvas
382 : * wraps an SkPDFDocument, for example.
383 : *
384 : * Note: It is not clear whether the test used to implement this function may
385 : * result in it returning false in some circumstances even when the canvas
386 : * _is_ pixel backed. In other words maybe it is possible for such a canvas to
387 : * have kUnknown_SkPixelGeometry?
388 : */
389 3 : static inline bool IsBackedByPixels(const SkCanvas* aCanvas)
390 : {
391 3 : SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
392 6 : if (!aCanvas->getProps(&props) ||
393 3 : props.pixelGeometry() == kUnknown_SkPixelGeometry) {
394 0 : return false;
395 : }
396 3 : return true;
397 : }
398 :
399 : } // namespace gfx
400 : } // namespace mozilla
401 :
402 : #endif /* MOZILLA_GFX_HELPERSSKIA_H_ */
|