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