|
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 #include "PathSkia.h" |
|
7 #include <math.h> |
|
8 #include "DrawTargetSkia.h" |
|
9 #include "Logging.h" |
|
10 #include "HelpersSkia.h" |
|
11 #include "PathHelpers.h" |
|
12 |
|
13 namespace mozilla { |
|
14 namespace gfx { |
|
15 |
|
16 PathBuilderSkia::PathBuilderSkia(const Matrix& aTransform, const SkPath& aPath, FillRule aFillRule) |
|
17 : mPath(aPath) |
|
18 { |
|
19 SkMatrix matrix; |
|
20 GfxMatrixToSkiaMatrix(aTransform, matrix); |
|
21 mPath.transform(matrix); |
|
22 SetFillRule(aFillRule); |
|
23 } |
|
24 |
|
25 PathBuilderSkia::PathBuilderSkia(FillRule aFillRule) |
|
26 { |
|
27 SetFillRule(aFillRule); |
|
28 } |
|
29 |
|
30 void |
|
31 PathBuilderSkia::SetFillRule(FillRule aFillRule) |
|
32 { |
|
33 mFillRule = aFillRule; |
|
34 if (mFillRule == FillRule::FILL_WINDING) { |
|
35 mPath.setFillType(SkPath::kWinding_FillType); |
|
36 } else { |
|
37 mPath.setFillType(SkPath::kEvenOdd_FillType); |
|
38 } |
|
39 } |
|
40 |
|
41 void |
|
42 PathBuilderSkia::MoveTo(const Point &aPoint) |
|
43 { |
|
44 mPath.moveTo(SkFloatToScalar(aPoint.x), SkFloatToScalar(aPoint.y)); |
|
45 } |
|
46 |
|
47 void |
|
48 PathBuilderSkia::LineTo(const Point &aPoint) |
|
49 { |
|
50 if (!mPath.countPoints()) { |
|
51 MoveTo(aPoint); |
|
52 } else { |
|
53 mPath.lineTo(SkFloatToScalar(aPoint.x), SkFloatToScalar(aPoint.y)); |
|
54 } |
|
55 } |
|
56 |
|
57 void |
|
58 PathBuilderSkia::BezierTo(const Point &aCP1, |
|
59 const Point &aCP2, |
|
60 const Point &aCP3) |
|
61 { |
|
62 if (!mPath.countPoints()) { |
|
63 MoveTo(aCP1); |
|
64 } |
|
65 mPath.cubicTo(SkFloatToScalar(aCP1.x), SkFloatToScalar(aCP1.y), |
|
66 SkFloatToScalar(aCP2.x), SkFloatToScalar(aCP2.y), |
|
67 SkFloatToScalar(aCP3.x), SkFloatToScalar(aCP3.y)); |
|
68 } |
|
69 |
|
70 void |
|
71 PathBuilderSkia::QuadraticBezierTo(const Point &aCP1, |
|
72 const Point &aCP2) |
|
73 { |
|
74 if (!mPath.countPoints()) { |
|
75 MoveTo(aCP1); |
|
76 } |
|
77 mPath.quadTo(SkFloatToScalar(aCP1.x), SkFloatToScalar(aCP1.y), |
|
78 SkFloatToScalar(aCP2.x), SkFloatToScalar(aCP2.y)); |
|
79 } |
|
80 |
|
81 void |
|
82 PathBuilderSkia::Close() |
|
83 { |
|
84 mPath.close(); |
|
85 } |
|
86 |
|
87 void |
|
88 PathBuilderSkia::Arc(const Point &aOrigin, float aRadius, float aStartAngle, |
|
89 float aEndAngle, bool aAntiClockwise) |
|
90 { |
|
91 ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise); |
|
92 } |
|
93 |
|
94 Point |
|
95 PathBuilderSkia::CurrentPoint() const |
|
96 { |
|
97 int pointCount = mPath.countPoints(); |
|
98 if (!pointCount) { |
|
99 return Point(0, 0); |
|
100 } |
|
101 SkPoint point = mPath.getPoint(pointCount - 1); |
|
102 return Point(SkScalarToFloat(point.fX), SkScalarToFloat(point.fY)); |
|
103 } |
|
104 |
|
105 TemporaryRef<Path> |
|
106 PathBuilderSkia::Finish() |
|
107 { |
|
108 RefPtr<PathSkia> path = new PathSkia(mPath, mFillRule); |
|
109 return path; |
|
110 } |
|
111 |
|
112 void |
|
113 PathBuilderSkia::AppendPath(const SkPath &aPath) |
|
114 { |
|
115 mPath.addPath(aPath); |
|
116 } |
|
117 |
|
118 TemporaryRef<PathBuilder> |
|
119 PathSkia::CopyToBuilder(FillRule aFillRule) const |
|
120 { |
|
121 return TransformedCopyToBuilder(Matrix(), aFillRule); |
|
122 } |
|
123 |
|
124 TemporaryRef<PathBuilder> |
|
125 PathSkia::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const |
|
126 { |
|
127 RefPtr<PathBuilderSkia> builder = new PathBuilderSkia(aTransform, mPath, aFillRule); |
|
128 return builder; |
|
129 } |
|
130 |
|
131 bool |
|
132 PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const |
|
133 { |
|
134 Matrix inverse = aTransform; |
|
135 inverse.Invert(); |
|
136 Point transformed = inverse * aPoint; |
|
137 |
|
138 Rect bounds = GetBounds(aTransform); |
|
139 |
|
140 if (aPoint.x < bounds.x || aPoint.y < bounds.y || |
|
141 aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) { |
|
142 return false; |
|
143 } |
|
144 |
|
145 SkRegion pointRect; |
|
146 pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)), |
|
147 int32_t(SkFloatToScalar(transformed.y - 1)), |
|
148 int32_t(SkFloatToScalar(transformed.x + 1)), |
|
149 int32_t(SkFloatToScalar(transformed.y + 1))); |
|
150 |
|
151 SkRegion pathRegion; |
|
152 |
|
153 return pathRegion.setPath(mPath, pointRect); |
|
154 } |
|
155 |
|
156 bool |
|
157 PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, |
|
158 const Point &aPoint, |
|
159 const Matrix &aTransform) const |
|
160 { |
|
161 Matrix inverse = aTransform; |
|
162 inverse.Invert(); |
|
163 Point transformed = inverse * aPoint; |
|
164 |
|
165 SkPaint paint; |
|
166 StrokeOptionsToPaint(paint, aStrokeOptions); |
|
167 |
|
168 SkPath strokePath; |
|
169 paint.getFillPath(mPath, &strokePath); |
|
170 |
|
171 Rect bounds = aTransform.TransformBounds(SkRectToRect(strokePath.getBounds())); |
|
172 |
|
173 if (aPoint.x < bounds.x || aPoint.y < bounds.y || |
|
174 aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) { |
|
175 return false; |
|
176 } |
|
177 |
|
178 SkRegion pointRect; |
|
179 pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)), |
|
180 int32_t(SkFloatToScalar(transformed.y - 1)), |
|
181 int32_t(SkFloatToScalar(transformed.x + 1)), |
|
182 int32_t(SkFloatToScalar(transformed.y + 1))); |
|
183 |
|
184 SkRegion pathRegion; |
|
185 |
|
186 return pathRegion.setPath(strokePath, pointRect); |
|
187 } |
|
188 |
|
189 Rect |
|
190 PathSkia::GetBounds(const Matrix &aTransform) const |
|
191 { |
|
192 Rect bounds = SkRectToRect(mPath.getBounds()); |
|
193 return aTransform.TransformBounds(bounds); |
|
194 } |
|
195 |
|
196 Rect |
|
197 PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions, |
|
198 const Matrix &aTransform) const |
|
199 { |
|
200 SkPaint paint; |
|
201 StrokeOptionsToPaint(paint, aStrokeOptions); |
|
202 |
|
203 SkPath result; |
|
204 paint.getFillPath(mPath, &result); |
|
205 |
|
206 Rect bounds = SkRectToRect(result.getBounds()); |
|
207 return aTransform.TransformBounds(bounds); |
|
208 } |
|
209 |
|
210 void |
|
211 PathSkia::StreamToSink(PathSink *aSink) const |
|
212 { |
|
213 SkPath::RawIter iter(mPath); |
|
214 |
|
215 SkPoint points[4]; |
|
216 SkPath::Verb currentVerb; |
|
217 while ((currentVerb = iter.next(points)) != SkPath::kDone_Verb) { |
|
218 switch (currentVerb) { |
|
219 case SkPath::kMove_Verb: |
|
220 aSink->MoveTo(SkPointToPoint(points[0])); |
|
221 break; |
|
222 case SkPath::kLine_Verb: |
|
223 aSink->LineTo(SkPointToPoint(points[1])); |
|
224 break; |
|
225 case SkPath::kCubic_Verb: |
|
226 aSink->BezierTo(SkPointToPoint(points[1]), |
|
227 SkPointToPoint(points[2]), |
|
228 SkPointToPoint(points[3])); |
|
229 break; |
|
230 case SkPath::kQuad_Verb: |
|
231 aSink->QuadraticBezierTo(SkPointToPoint(points[1]), |
|
232 SkPointToPoint(points[2])); |
|
233 break; |
|
234 case SkPath::kClose_Verb: |
|
235 aSink->Close(); |
|
236 break; |
|
237 default: |
|
238 MOZ_ASSERT(false); |
|
239 // Unexpected verb found in path! |
|
240 } |
|
241 } |
|
242 } |
|
243 |
|
244 } |
|
245 } |