Bug 1885602 - Part 4: Implement navigating to the settings from the menu header for...
[gecko.git] / gfx / 2d / HelpersSkia.h
blob7f7bf6fbc1e9a63729173315e7cf0672c1668512
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_
10 #include "2D.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"
17 #include <cmath>
18 #include <vector>
19 #include "nsDebug.h"
21 namespace mozilla {
22 namespace gfx {
24 static inline SkColorType GfxFormatToSkiaColorType(SurfaceFormat format) {
25 switch (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;
40 default:
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) {
48 switch (aColorType) {
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;
56 default:
57 return SurfaceFormat::B8G8R8A8;
61 static inline SkAlphaType GfxFormatToSkiaAlphaType(SurfaceFormat format) {
62 switch (format) {
63 case SurfaceFormat::B8G8R8X8:
64 case SurfaceFormat::R5G6B5_UINT16:
65 return kOpaque_SkAlphaType;
66 default:
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,
82 SK_Scalar1);
85 static inline void GfxMatrixToSkiaMatrix(const Matrix4x4& aMatrix,
86 SkMatrix& aResult) {
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) {
95 switch (aCap) {
96 case CapStyle::BUTT:
97 return SkPaint::kButt_Cap;
98 case CapStyle::ROUND:
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) {
107 switch (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)) {
126 return false;
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.
135 uint32_t dashCount;
137 if (aOptions.mDashLength % 2 == 0) {
138 dashCount = aOptions.mDashLength;
139 } else {
140 dashCount = aOptions.mDashLength * 2;
143 std::vector<SkScalar> pattern;
144 pattern.resize(dashCount);
146 for (uint32_t i = 0; i < dashCount; i++) {
147 pattern[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);
157 return true;
160 static inline SkBlendMode GfxOpToSkiaOp(CompositionOp op) {
161 switch (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:
217 break;
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) {
277 switch (aMode) {
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) {
295 switch (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) {
309 switch (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:
316 default:
317 NS_WARNING("Unsupported fill type\n");
318 break;
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) {
337 return false;
339 return true;
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);
357 } // namespace gfx
358 } // namespace mozilla
360 #endif /* MOZILLA_GFX_HELPERSSKIA_H_ */