1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "flutter/lib/ui/painting/path.h" |
6 | |
7 | #define _USE_MATH_DEFINES |
8 | #include <math.h> |
9 | |
10 | #include "flutter/lib/ui/painting/matrix.h" |
11 | #include "flutter/lib/ui/ui_dart_state.h" |
12 | #include "third_party/tonic/converter/dart_converter.h" |
13 | #include "third_party/tonic/dart_args.h" |
14 | #include "third_party/tonic/dart_binding_macros.h" |
15 | #include "third_party/tonic/dart_library_natives.h" |
16 | |
17 | using tonic::ToDart; |
18 | |
19 | namespace flutter { |
20 | |
21 | typedef CanvasPath Path; |
22 | |
23 | static void Path_constructor(Dart_NativeArguments args) { |
24 | UIDartState::ThrowIfUIOperationsProhibited(); |
25 | DartCallConstructor(&CanvasPath::CreateNew, args); |
26 | } |
27 | |
28 | IMPLEMENT_WRAPPERTYPEINFO(ui, Path); |
29 | |
30 | #define FOR_EACH_BINDING(V) \ |
31 | V(Path, addArc) \ |
32 | V(Path, addOval) \ |
33 | V(Path, addPath) \ |
34 | V(Path, addPolygon) \ |
35 | V(Path, addRect) \ |
36 | V(Path, addRRect) \ |
37 | V(Path, arcTo) \ |
38 | V(Path, arcToPoint) \ |
39 | V(Path, close) \ |
40 | V(Path, conicTo) \ |
41 | V(Path, contains) \ |
42 | V(Path, cubicTo) \ |
43 | V(Path, extendWithPath) \ |
44 | V(Path, extendWithPathAndMatrix) \ |
45 | V(Path, getFillType) \ |
46 | V(Path, lineTo) \ |
47 | V(Path, moveTo) \ |
48 | V(Path, quadraticBezierTo) \ |
49 | V(Path, relativeArcToPoint) \ |
50 | V(Path, relativeConicTo) \ |
51 | V(Path, relativeCubicTo) \ |
52 | V(Path, relativeLineTo) \ |
53 | V(Path, relativeMoveTo) \ |
54 | V(Path, relativeQuadraticBezierTo) \ |
55 | V(Path, reset) \ |
56 | V(Path, setFillType) \ |
57 | V(Path, shift) \ |
58 | V(Path, transform) \ |
59 | V(Path, getBounds) \ |
60 | V(Path, addPathWithMatrix) \ |
61 | V(Path, op) \ |
62 | V(Path, clone) |
63 | |
64 | FOR_EACH_BINDING(DART_NATIVE_CALLBACK) |
65 | |
66 | void CanvasPath::RegisterNatives(tonic::DartLibraryNatives* natives) { |
67 | natives->Register({{"Path_constructor" , Path_constructor, 1, true}, |
68 | FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); |
69 | } |
70 | |
71 | CanvasPath::CanvasPath() {} |
72 | |
73 | CanvasPath::~CanvasPath() {} |
74 | |
75 | int CanvasPath::getFillType() { |
76 | return static_cast<int>(path_.getFillType()); |
77 | } |
78 | |
79 | void CanvasPath::setFillType(int fill_type) { |
80 | path_.setFillType(static_cast<SkPathFillType>(fill_type)); |
81 | } |
82 | |
83 | void CanvasPath::moveTo(float x, float y) { |
84 | path_.moveTo(x, y); |
85 | } |
86 | |
87 | void CanvasPath::relativeMoveTo(float x, float y) { |
88 | path_.rMoveTo(x, y); |
89 | } |
90 | |
91 | void CanvasPath::lineTo(float x, float y) { |
92 | path_.lineTo(x, y); |
93 | } |
94 | |
95 | void CanvasPath::relativeLineTo(float x, float y) { |
96 | path_.rLineTo(x, y); |
97 | } |
98 | |
99 | void CanvasPath::quadraticBezierTo(float x1, float y1, float x2, float y2) { |
100 | path_.quadTo(x1, y1, x2, y2); |
101 | } |
102 | |
103 | void CanvasPath::relativeQuadraticBezierTo(float x1, |
104 | float y1, |
105 | float x2, |
106 | float y2) { |
107 | path_.rQuadTo(x1, y1, x2, y2); |
108 | } |
109 | |
110 | void CanvasPath::cubicTo(float x1, |
111 | float y1, |
112 | float x2, |
113 | float y2, |
114 | float x3, |
115 | float y3) { |
116 | path_.cubicTo(x1, y1, x2, y2, x3, y3); |
117 | } |
118 | |
119 | void CanvasPath::relativeCubicTo(float x1, |
120 | float y1, |
121 | float x2, |
122 | float y2, |
123 | float x3, |
124 | float y3) { |
125 | path_.rCubicTo(x1, y1, x2, y2, x3, y3); |
126 | } |
127 | |
128 | void CanvasPath::conicTo(float x1, float y1, float x2, float y2, float w) { |
129 | path_.conicTo(x1, y1, x2, y2, w); |
130 | } |
131 | |
132 | void CanvasPath::relativeConicTo(float x1, |
133 | float y1, |
134 | float x2, |
135 | float y2, |
136 | float w) { |
137 | path_.rConicTo(x1, y1, x2, y2, w); |
138 | } |
139 | |
140 | void CanvasPath::arcTo(float left, |
141 | float top, |
142 | float right, |
143 | float bottom, |
144 | float startAngle, |
145 | float sweepAngle, |
146 | bool forceMoveTo) { |
147 | path_.arcTo(SkRect::MakeLTRB(left, top, right, bottom), |
148 | startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, |
149 | forceMoveTo); |
150 | } |
151 | |
152 | void CanvasPath::arcToPoint(float arcEndX, |
153 | float arcEndY, |
154 | float radiusX, |
155 | float radiusY, |
156 | float xAxisRotation, |
157 | bool isLargeArc, |
158 | bool isClockwiseDirection) { |
159 | const auto arcSize = isLargeArc ? SkPath::ArcSize::kLarge_ArcSize |
160 | : SkPath::ArcSize::kSmall_ArcSize; |
161 | const auto direction = |
162 | isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW; |
163 | |
164 | path_.arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, arcEndX, |
165 | arcEndY); |
166 | } |
167 | |
168 | void CanvasPath::relativeArcToPoint(float arcEndDeltaX, |
169 | float arcEndDeltaY, |
170 | float radiusX, |
171 | float radiusY, |
172 | float xAxisRotation, |
173 | bool isLargeArc, |
174 | bool isClockwiseDirection) { |
175 | const auto arcSize = isLargeArc ? SkPath::ArcSize::kLarge_ArcSize |
176 | : SkPath::ArcSize::kSmall_ArcSize; |
177 | const auto direction = |
178 | isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW; |
179 | path_.rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, |
180 | arcEndDeltaX, arcEndDeltaY); |
181 | } |
182 | |
183 | void CanvasPath::addRect(float left, float top, float right, float bottom) { |
184 | path_.addRect(SkRect::MakeLTRB(left, top, right, bottom)); |
185 | } |
186 | |
187 | void CanvasPath::addOval(float left, float top, float right, float bottom) { |
188 | path_.addOval(SkRect::MakeLTRB(left, top, right, bottom)); |
189 | } |
190 | |
191 | void CanvasPath::addArc(float left, |
192 | float top, |
193 | float right, |
194 | float bottom, |
195 | float startAngle, |
196 | float sweepAngle) { |
197 | path_.addArc(SkRect::MakeLTRB(left, top, right, bottom), |
198 | startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI); |
199 | } |
200 | |
201 | void CanvasPath::addPolygon(const tonic::Float32List& points, bool close) { |
202 | path_.addPoly(reinterpret_cast<const SkPoint*>(points.data()), |
203 | points.num_elements() / 2, close); |
204 | } |
205 | |
206 | void CanvasPath::addRRect(const RRect& rrect) { |
207 | path_.addRRect(rrect.sk_rrect); |
208 | } |
209 | |
210 | void CanvasPath::addPath(CanvasPath* path, double dx, double dy) { |
211 | if (!path) { |
212 | Dart_ThrowException(ToDart("Path.addPath called with non-genuine Path." )); |
213 | return; |
214 | } |
215 | path_.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode); |
216 | } |
217 | |
218 | void CanvasPath::addPathWithMatrix(CanvasPath* path, |
219 | double dx, |
220 | double dy, |
221 | tonic::Float64List& matrix4) { |
222 | if (!path) { |
223 | Dart_ThrowException( |
224 | ToDart("Path.addPathWithMatrix called with non-genuine Path." )); |
225 | return; |
226 | } |
227 | |
228 | SkMatrix matrix = ToSkMatrix(matrix4); |
229 | matrix.setTranslateX(matrix.getTranslateX() + dx); |
230 | matrix.setTranslateY(matrix.getTranslateY() + dy); |
231 | path_.addPath(path->path(), matrix, SkPath::kAppend_AddPathMode); |
232 | matrix4.Release(); |
233 | } |
234 | |
235 | void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) { |
236 | if (!path) { |
237 | Dart_ThrowException( |
238 | ToDart("Path.extendWithPath called with non-genuine Path." )); |
239 | return; |
240 | } |
241 | path_.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode); |
242 | } |
243 | |
244 | void CanvasPath::extendWithPathAndMatrix(CanvasPath* path, |
245 | double dx, |
246 | double dy, |
247 | tonic::Float64List& matrix4) { |
248 | if (!path) { |
249 | Dart_ThrowException( |
250 | ToDart("Path.addPathWithMatrix called with non-genuine Path." )); |
251 | return; |
252 | } |
253 | |
254 | SkMatrix matrix = ToSkMatrix(matrix4); |
255 | matrix.setTranslateX(matrix.getTranslateX() + dx); |
256 | matrix.setTranslateY(matrix.getTranslateY() + dy); |
257 | path_.addPath(path->path(), matrix, SkPath::kExtend_AddPathMode); |
258 | matrix4.Release(); |
259 | } |
260 | |
261 | void CanvasPath::close() { |
262 | path_.close(); |
263 | } |
264 | |
265 | void CanvasPath::reset() { |
266 | path_.reset(); |
267 | } |
268 | |
269 | bool CanvasPath::contains(double x, double y) { |
270 | return path_.contains(x, y); |
271 | } |
272 | |
273 | void CanvasPath::shift(Dart_Handle path_handle, double dx, double dy) { |
274 | fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle); |
275 | path_.offset(dx, dy, &path->path_); |
276 | } |
277 | |
278 | void CanvasPath::transform(Dart_Handle path_handle, |
279 | tonic::Float64List& matrix4) { |
280 | fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle); |
281 | path_.transform(ToSkMatrix(matrix4), &path->path_); |
282 | matrix4.Release(); |
283 | } |
284 | |
285 | tonic::Float32List CanvasPath::getBounds() { |
286 | tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4)); |
287 | const SkRect& bounds = path_.getBounds(); |
288 | rect[0] = bounds.left(); |
289 | rect[1] = bounds.top(); |
290 | rect[2] = bounds.right(); |
291 | rect[3] = bounds.bottom(); |
292 | return rect; |
293 | } |
294 | |
295 | bool CanvasPath::op(CanvasPath* path1, CanvasPath* path2, int operation) { |
296 | return Op(path1->path(), path2->path(), static_cast<SkPathOp>(operation), |
297 | &path_); |
298 | } |
299 | |
300 | void CanvasPath::clone(Dart_Handle path_handle) { |
301 | fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle); |
302 | // per Skia docs, this will create a fast copy |
303 | // data is shared until the source path or dest path are mutated |
304 | path->path_ = path_; |
305 | } |
306 | |
307 | // This is doomed to be called too early, since Paths are mutable. |
308 | // However, it can help for some of the clone/shift/transform type methods |
309 | // where the resultant path will initially have a meaningful size. |
310 | size_t CanvasPath::GetAllocationSize() const { |
311 | return sizeof(CanvasPath) + path_.approximateBytesUsed(); |
312 | } |
313 | |
314 | } // namespace flutter |
315 | |