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_HELPERSSKIA_H_
8 #define MOZILLA_GFX_HELPERSSKIA_H_
11 #include "skia/include/core/SkCanvas.h"
12 #include "skia/include/core/SkPathEffect.h"
13 #include "skia/include/core/SkPathTypes.h"
14 #include "skia/include/core/SkShader.h"
15 #include "skia/include/effects/SkDashPathEffect.h"
16 #include "mozilla/Assertions.h"
24 static inline SkColorType
GfxFormatToSkiaColorType(SurfaceFormat format
) {
26 case SurfaceFormat::B8G8R8A8
:
27 return kBGRA_8888_SkColorType
;
28 case SurfaceFormat::B8G8R8X8
:
29 // We probably need to do something here.
30 return kBGRA_8888_SkColorType
;
31 case SurfaceFormat::R5G6B5_UINT16
:
32 return kRGB_565_SkColorType
;
33 case SurfaceFormat::A8
:
34 return kAlpha_8_SkColorType
;
35 case SurfaceFormat::R8G8B8A8
:
36 return kRGBA_8888_SkColorType
;
37 case SurfaceFormat::A8R8G8B8
:
38 MOZ_DIAGNOSTIC_ASSERT(false, "A8R8G8B8 unsupported by Skia");
39 return kRGBA_8888_SkColorType
;
41 MOZ_DIAGNOSTIC_ASSERT(false, "Unknown surface format");
42 return kRGBA_8888_SkColorType
;
46 static inline SurfaceFormat
SkiaColorTypeToGfxFormat(
47 SkColorType aColorType
, SkAlphaType aAlphaType
= kPremul_SkAlphaType
) {
49 case kBGRA_8888_SkColorType
:
50 return aAlphaType
== kOpaque_SkAlphaType
? SurfaceFormat::B8G8R8X8
51 : SurfaceFormat::B8G8R8A8
;
52 case kRGB_565_SkColorType
:
53 return SurfaceFormat::R5G6B5_UINT16
;
54 case kAlpha_8_SkColorType
:
55 return SurfaceFormat::A8
;
57 return SurfaceFormat::B8G8R8A8
;
61 static inline SkAlphaType
GfxFormatToSkiaAlphaType(SurfaceFormat format
) {
63 case SurfaceFormat::B8G8R8X8
:
64 case SurfaceFormat::R5G6B5_UINT16
:
65 return kOpaque_SkAlphaType
;
67 return kPremul_SkAlphaType
;
71 static inline SkImageInfo
MakeSkiaImageInfo(const IntSize
& aSize
,
72 SurfaceFormat aFormat
) {
73 return SkImageInfo::Make(aSize
.width
, aSize
.height
,
74 GfxFormatToSkiaColorType(aFormat
),
75 GfxFormatToSkiaAlphaType(aFormat
));
78 static inline void GfxMatrixToSkiaMatrix(const Matrix
& mat
, SkMatrix
& retval
) {
79 retval
.setAll(SkFloatToScalar(mat
._11
), SkFloatToScalar(mat
._21
),
80 SkFloatToScalar(mat
._31
), SkFloatToScalar(mat
._12
),
81 SkFloatToScalar(mat
._22
), SkFloatToScalar(mat
._32
), 0, 0,
85 static inline void GfxMatrixToSkiaMatrix(const Matrix4x4
& aMatrix
,
87 aResult
.setAll(SkFloatToScalar(aMatrix
._11
), SkFloatToScalar(aMatrix
._21
),
88 SkFloatToScalar(aMatrix
._41
), SkFloatToScalar(aMatrix
._12
),
89 SkFloatToScalar(aMatrix
._22
), SkFloatToScalar(aMatrix
._42
),
90 SkFloatToScalar(aMatrix
._14
), SkFloatToScalar(aMatrix
._24
),
91 SkFloatToScalar(aMatrix
._44
));
94 static inline SkPaint::Cap
CapStyleToSkiaCap(CapStyle aCap
) {
97 return SkPaint::kButt_Cap
;
99 return SkPaint::kRound_Cap
;
100 case CapStyle::SQUARE
:
101 return SkPaint::kSquare_Cap
;
103 return SkPaint::kDefault_Cap
;
106 static inline SkPaint::Join
JoinStyleToSkiaJoin(JoinStyle aJoin
) {
108 case JoinStyle::BEVEL
:
109 return SkPaint::kBevel_Join
;
110 case JoinStyle::ROUND
:
111 return SkPaint::kRound_Join
;
112 case JoinStyle::MITER
:
113 case JoinStyle::MITER_OR_BEVEL
:
114 return SkPaint::kMiter_Join
;
116 return SkPaint::kDefault_Join
;
119 static inline bool StrokeOptionsToPaint(SkPaint
& aPaint
,
120 const StrokeOptions
& aOptions
,
121 bool aUsePathEffects
= true) {
122 // Skia renders 0 width strokes with a width of 1 (and in black),
123 // so we should just skip the draw call entirely.
124 // Skia does not handle non-finite line widths.
125 if (!aOptions
.mLineWidth
|| !std::isfinite(aOptions
.mLineWidth
)) {
128 aPaint
.setStrokeWidth(SkFloatToScalar(aOptions
.mLineWidth
));
129 aPaint
.setStrokeMiter(SkFloatToScalar(aOptions
.mMiterLimit
));
130 aPaint
.setStrokeCap(CapStyleToSkiaCap(aOptions
.mLineCap
));
131 aPaint
.setStrokeJoin(JoinStyleToSkiaJoin(aOptions
.mLineJoin
));
133 if (aOptions
.mDashLength
> 0 && aUsePathEffects
) {
134 // Skia only supports dash arrays that are multiples of 2.
137 if (aOptions
.mDashLength
% 2 == 0) {
138 dashCount
= aOptions
.mDashLength
;
140 dashCount
= aOptions
.mDashLength
* 2;
143 std::vector
<SkScalar
> pattern
;
144 pattern
.resize(dashCount
);
146 for (uint32_t i
= 0; i
< dashCount
; i
++) {
148 SkFloatToScalar(aOptions
.mDashPattern
[i
% aOptions
.mDashLength
]);
151 auto dash
= SkDashPathEffect::Make(&pattern
.front(), dashCount
,
152 SkFloatToScalar(aOptions
.mDashOffset
));
153 aPaint
.setPathEffect(dash
);
156 aPaint
.setStyle(SkPaint::kStroke_Style
);
160 static inline SkBlendMode
GfxOpToSkiaOp(CompositionOp op
) {
162 case CompositionOp::OP_CLEAR
:
163 return SkBlendMode::kClear
;
164 case CompositionOp::OP_OVER
:
165 return SkBlendMode::kSrcOver
;
166 case CompositionOp::OP_ADD
:
167 return SkBlendMode::kPlus
;
168 case CompositionOp::OP_ATOP
:
169 return SkBlendMode::kSrcATop
;
170 case CompositionOp::OP_OUT
:
171 return SkBlendMode::kSrcOut
;
172 case CompositionOp::OP_IN
:
173 return SkBlendMode::kSrcIn
;
174 case CompositionOp::OP_SOURCE
:
175 return SkBlendMode::kSrc
;
176 case CompositionOp::OP_DEST_IN
:
177 return SkBlendMode::kDstIn
;
178 case CompositionOp::OP_DEST_OUT
:
179 return SkBlendMode::kDstOut
;
180 case CompositionOp::OP_DEST_OVER
:
181 return SkBlendMode::kDstOver
;
182 case CompositionOp::OP_DEST_ATOP
:
183 return SkBlendMode::kDstATop
;
184 case CompositionOp::OP_XOR
:
185 return SkBlendMode::kXor
;
186 case CompositionOp::OP_MULTIPLY
:
187 return SkBlendMode::kMultiply
;
188 case CompositionOp::OP_SCREEN
:
189 return SkBlendMode::kScreen
;
190 case CompositionOp::OP_OVERLAY
:
191 return SkBlendMode::kOverlay
;
192 case CompositionOp::OP_DARKEN
:
193 return SkBlendMode::kDarken
;
194 case CompositionOp::OP_LIGHTEN
:
195 return SkBlendMode::kLighten
;
196 case CompositionOp::OP_COLOR_DODGE
:
197 return SkBlendMode::kColorDodge
;
198 case CompositionOp::OP_COLOR_BURN
:
199 return SkBlendMode::kColorBurn
;
200 case CompositionOp::OP_HARD_LIGHT
:
201 return SkBlendMode::kHardLight
;
202 case CompositionOp::OP_SOFT_LIGHT
:
203 return SkBlendMode::kSoftLight
;
204 case CompositionOp::OP_DIFFERENCE
:
205 return SkBlendMode::kDifference
;
206 case CompositionOp::OP_EXCLUSION
:
207 return SkBlendMode::kExclusion
;
208 case CompositionOp::OP_HUE
:
209 return SkBlendMode::kHue
;
210 case CompositionOp::OP_SATURATION
:
211 return SkBlendMode::kSaturation
;
212 case CompositionOp::OP_COLOR
:
213 return SkBlendMode::kColor
;
214 case CompositionOp::OP_LUMINOSITY
:
215 return SkBlendMode::kLuminosity
;
216 case CompositionOp::OP_COUNT
:
220 return SkBlendMode::kSrcOver
;
223 /* There's quite a bit of inconsistency about
224 * whether float colors should be rounded with .5f.
225 * We choose to do it to match cairo which also
226 * happens to match the Direct3D specs */
227 static inline U8CPU
ColorFloatToByte(Float color
) {
228 // XXX: do a better job converting to int
229 return U8CPU(color
* 255.f
+ .5f
);
232 static inline SkColor
ColorToSkColor(const DeviceColor
& color
, Float aAlpha
) {
233 return SkColorSetARGB(ColorFloatToByte(color
.a
* aAlpha
),
234 ColorFloatToByte(color
.r
), ColorFloatToByte(color
.g
),
235 ColorFloatToByte(color
.b
));
238 static inline SkPoint
PointToSkPoint(const Point
& aPoint
) {
239 return SkPoint::Make(SkFloatToScalar(aPoint
.x
), SkFloatToScalar(aPoint
.y
));
242 static inline SkRect
RectToSkRect(const Rect
& aRect
) {
243 return SkRect::MakeXYWH(
244 SkFloatToScalar(aRect
.X()), SkFloatToScalar(aRect
.Y()),
245 SkFloatToScalar(aRect
.Width()), SkFloatToScalar(aRect
.Height()));
248 static inline SkRect
IntRectToSkRect(const IntRect
& aRect
) {
249 return SkRect::MakeXYWH(SkIntToScalar(aRect
.X()), SkIntToScalar(aRect
.Y()),
250 SkIntToScalar(aRect
.Width()),
251 SkIntToScalar(aRect
.Height()));
254 static inline SkIRect
RectToSkIRect(const Rect
& aRect
) {
255 return SkIRect::MakeXYWH(int32_t(aRect
.X()), int32_t(aRect
.Y()),
256 int32_t(aRect
.Width()), int32_t(aRect
.Height()));
259 static inline SkIRect
IntRectToSkIRect(const IntRect
& aRect
) {
260 return SkIRect::MakeXYWH(aRect
.X(), aRect
.Y(), aRect
.Width(), aRect
.Height());
263 static inline IntRect
SkIRectToIntRect(const SkIRect
& aRect
) {
264 return IntRect(aRect
.x(), aRect
.y(), aRect
.width(), aRect
.height());
267 static inline Point
SkPointToPoint(const SkPoint
& aPoint
) {
268 return Point(SkScalarToFloat(aPoint
.x()), SkScalarToFloat(aPoint
.y()));
271 static inline Rect
SkRectToRect(const SkRect
& aRect
) {
272 return Rect(SkScalarToFloat(aRect
.x()), SkScalarToFloat(aRect
.y()),
273 SkScalarToFloat(aRect
.width()), SkScalarToFloat(aRect
.height()));
276 static inline SkTileMode
ExtendModeToTileMode(ExtendMode aMode
, Axis aAxis
) {
278 case ExtendMode::CLAMP
:
279 return SkTileMode::kClamp
;
280 case ExtendMode::REPEAT
:
281 return SkTileMode::kRepeat
;
282 case ExtendMode::REFLECT
:
283 return SkTileMode::kMirror
;
284 case ExtendMode::REPEAT_X
: {
285 return aAxis
== Axis::X_AXIS
? SkTileMode::kRepeat
: SkTileMode::kClamp
;
287 case ExtendMode::REPEAT_Y
: {
288 return aAxis
== Axis::Y_AXIS
? SkTileMode::kRepeat
: SkTileMode::kClamp
;
291 return SkTileMode::kClamp
;
294 static inline SkFontHinting
GfxHintingToSkiaHinting(FontHinting aHinting
) {
296 case FontHinting::NONE
:
297 return SkFontHinting::kNone
;
298 case FontHinting::LIGHT
:
299 return SkFontHinting::kSlight
;
300 case FontHinting::NORMAL
:
301 return SkFontHinting::kNormal
;
302 case FontHinting::FULL
:
303 return SkFontHinting::kFull
;
305 return SkFontHinting::kNormal
;
308 static inline FillRule
GetFillRule(SkPathFillType aFillType
) {
310 case SkPathFillType::kWinding
:
311 return FillRule::FILL_WINDING
;
312 case SkPathFillType::kEvenOdd
:
313 return FillRule::FILL_EVEN_ODD
;
314 case SkPathFillType::kInverseWinding
:
315 case SkPathFillType::kInverseEvenOdd
:
317 NS_WARNING("Unsupported fill type\n");
321 return FillRule::FILL_EVEN_ODD
;
325 * Returns true if the canvas is backed by pixels. Returns false if the canvas
326 * wraps an SkPDFDocument, for example.
328 * Note: It is not clear whether the test used to implement this function may
329 * result in it returning false in some circumstances even when the canvas
330 * _is_ pixel backed. In other words maybe it is possible for such a canvas to
331 * have kUnknown_SkPixelGeometry?
333 static inline bool IsBackedByPixels(const SkCanvas
* aCanvas
) {
334 SkSurfaceProps
props(0, kUnknown_SkPixelGeometry
);
335 if (!aCanvas
->getProps(&props
) ||
336 props
.pixelGeometry() == kUnknown_SkPixelGeometry
) {
343 * Computes appropriate resolution scale to be used with SkPath::getFillPath
344 * based on the scaling of the supplied transform.
346 float ComputeResScaleForStroking(const Matrix
& aTransform
);
349 * This is a wrapper around SkGeometry's SkConic that can be used to convert
350 * conic sections in an SkPath to a sequence of quadratic curves. The quads
351 * vector is organized such that for the Nth quad, it's control points are
352 * 2*N, 2*N+1, 2*N+2. This function returns the resulting number of quads.
354 int ConvertConicToQuads(const Point
& aP0
, const Point
& aP1
, const Point
& aP2
,
355 float aWeight
, std::vector
<Point
>& aQuads
);
358 } // namespace mozilla
360 #endif /* MOZILLA_GFX_HELPERSSKIA_H_ */