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