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/. */
9 #include "DrawTargetSkia.h"
11 #include "HelpersSkia.h"
12 #include "PathHelpers.h"
13 #include "skia/src/core/SkDraw.h"
15 namespace mozilla::gfx
{
17 PathBuilderSkia::PathBuilderSkia(const Matrix
& aTransform
, const SkPath
& aPath
,
21 GfxMatrixToSkiaMatrix(aTransform
, matrix
);
22 mPath
.transform(matrix
);
23 SetFillRule(aFillRule
);
26 PathBuilderSkia::PathBuilderSkia(FillRule aFillRule
) { SetFillRule(aFillRule
); }
28 void PathBuilderSkia::SetFillRule(FillRule aFillRule
) {
29 mFillRule
= aFillRule
;
30 if (mFillRule
== FillRule::FILL_WINDING
) {
31 mPath
.setFillType(SkPath::kWinding_FillType
);
33 mPath
.setFillType(SkPath::kEvenOdd_FillType
);
37 void PathBuilderSkia::MoveTo(const Point
& aPoint
) {
38 mPath
.moveTo(SkFloatToScalar(aPoint
.x
), SkFloatToScalar(aPoint
.y
));
39 mCurrentPoint
= aPoint
;
43 void PathBuilderSkia::LineTo(const Point
& aPoint
) {
44 if (!mPath
.countPoints()) {
47 mPath
.lineTo(SkFloatToScalar(aPoint
.x
), SkFloatToScalar(aPoint
.y
));
49 mCurrentPoint
= aPoint
;
52 void PathBuilderSkia::BezierTo(const Point
& aCP1
, const Point
& aCP2
,
54 if (!mPath
.countPoints()) {
57 mPath
.cubicTo(SkFloatToScalar(aCP1
.x
), SkFloatToScalar(aCP1
.y
),
58 SkFloatToScalar(aCP2
.x
), SkFloatToScalar(aCP2
.y
),
59 SkFloatToScalar(aCP3
.x
), SkFloatToScalar(aCP3
.y
));
63 void PathBuilderSkia::QuadraticBezierTo(const Point
& aCP1
, const Point
& aCP2
) {
64 if (!mPath
.countPoints()) {
67 mPath
.quadTo(SkFloatToScalar(aCP1
.x
), SkFloatToScalar(aCP1
.y
),
68 SkFloatToScalar(aCP2
.x
), SkFloatToScalar(aCP2
.y
));
72 void PathBuilderSkia::Close() {
74 mCurrentPoint
= mBeginPoint
;
77 void PathBuilderSkia::Arc(const Point
& aOrigin
, float aRadius
,
78 float aStartAngle
, float aEndAngle
,
79 bool aAntiClockwise
) {
80 ArcToBezier(this, aOrigin
, Size(aRadius
, aRadius
), aStartAngle
, aEndAngle
,
84 already_AddRefed
<Path
> PathBuilderSkia::Finish() {
86 MakeAndAddRef
<PathSkia
>(mPath
, mFillRule
, mCurrentPoint
, mBeginPoint
);
87 mCurrentPoint
= Point(0.0, 0.0);
88 mBeginPoint
= Point(0.0, 0.0);
92 void PathBuilderSkia::AppendPath(const SkPath
& aPath
) { mPath
.addPath(aPath
); }
94 already_AddRefed
<PathBuilder
> PathSkia::CopyToBuilder(
95 FillRule aFillRule
) const {
96 return TransformedCopyToBuilder(Matrix(), aFillRule
);
99 already_AddRefed
<PathBuilder
> PathSkia::TransformedCopyToBuilder(
100 const Matrix
& aTransform
, FillRule aFillRule
) const {
101 RefPtr
<PathBuilderSkia
> builder
=
102 MakeAndAddRef
<PathBuilderSkia
>(aTransform
, mPath
, aFillRule
);
104 builder
->mCurrentPoint
= aTransform
.TransformPoint(mCurrentPoint
);
105 builder
->mBeginPoint
= aTransform
.TransformPoint(mBeginPoint
);
107 return builder
.forget();
110 static bool SkPathContainsPoint(const SkPath
& aPath
, const Point
& aPoint
,
111 const Matrix
& aTransform
) {
112 Matrix inverse
= aTransform
;
113 if (!inverse
.Invert()) {
117 SkPoint point
= PointToSkPoint(inverse
.TransformPoint(aPoint
));
118 return aPath
.contains(point
.fX
, point
.fY
);
121 bool PathSkia::ContainsPoint(const Point
& aPoint
,
122 const Matrix
& aTransform
) const {
123 if (!mPath
.isFinite()) {
127 return SkPathContainsPoint(mPath
, aPoint
, aTransform
);
130 bool PathSkia::StrokeContainsPoint(const StrokeOptions
& aStrokeOptions
,
132 const Matrix
& aTransform
) const {
133 if (!mPath
.isFinite()) {
138 if (!StrokeOptionsToPaint(paint
, aStrokeOptions
)) {
143 GfxMatrixToSkiaMatrix(aTransform
, skiaMatrix
);
145 paint
.getFillPath(mPath
, &strokePath
, nullptr,
146 SkDraw::ComputeResScaleForStroking(skiaMatrix
));
148 return SkPathContainsPoint(strokePath
, aPoint
, aTransform
);
151 Rect
PathSkia::GetBounds(const Matrix
& aTransform
) const {
152 if (!mPath
.isFinite()) {
156 Rect bounds
= SkRectToRect(mPath
.computeTightBounds());
157 return aTransform
.TransformBounds(bounds
);
160 Rect
PathSkia::GetStrokedBounds(const StrokeOptions
& aStrokeOptions
,
161 const Matrix
& aTransform
) const {
162 if (!mPath
.isFinite()) {
167 if (!StrokeOptionsToPaint(paint
, aStrokeOptions
)) {
172 paint
.getFillPath(mPath
, &result
);
174 Rect bounds
= SkRectToRect(result
.computeTightBounds());
175 return aTransform
.TransformBounds(bounds
);
178 Rect
PathSkia::GetFastBounds(const Matrix
& aTransform
,
179 const StrokeOptions
* aStrokeOptions
) const {
180 if (!mPath
.isFinite()) {
183 SkRect bounds
= mPath
.getBounds();
184 if (aStrokeOptions
) {
185 // If the path is stroked, ensure that the bounds are inflated by any
186 // relevant options such as line width. Avoid using dash path effects
187 // for performance and to ensure computeFastStrokeBounds succeeds.
189 if (!StrokeOptionsToPaint(paint
, *aStrokeOptions
, false)) {
192 SkRect outBounds
= SkRect::MakeEmpty();
193 bounds
= paint
.computeFastStrokeBounds(bounds
, &outBounds
);
195 return aTransform
.TransformBounds(SkRectToRect(bounds
));
198 void PathSkia::StreamToSink(PathSink
* aSink
) const {
199 SkPath::RawIter
iter(mPath
);
202 SkPath::Verb currentVerb
;
203 while ((currentVerb
= iter
.next(points
)) != SkPath::kDone_Verb
) {
204 switch (currentVerb
) {
205 case SkPath::kMove_Verb
:
206 aSink
->MoveTo(SkPointToPoint(points
[0]));
208 case SkPath::kLine_Verb
:
209 aSink
->LineTo(SkPointToPoint(points
[1]));
211 case SkPath::kCubic_Verb
:
212 aSink
->BezierTo(SkPointToPoint(points
[1]), SkPointToPoint(points
[2]),
213 SkPointToPoint(points
[3]));
215 case SkPath::kQuad_Verb
:
216 aSink
->QuadraticBezierTo(SkPointToPoint(points
[1]),
217 SkPointToPoint(points
[2]));
219 case SkPath::kClose_Verb
:
224 // Unexpected verb found in path!
229 } // namespace mozilla::gfx