1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef PATH_H
17 #define PATH_H
18
19 #include <memory>
20 #include <vector>
21
22 #include "common/rs_macros.h"
23 #include "drawing/engine_adapter/impl_interface/path_impl.h"
24 #include "utils/drawing_macros.h"
25 #include "utils/matrix.h"
26 #include "utils/point.h"
27 #include "utils/rect.h"
28
29 #ifdef WINDOWS_PLATFORM
30 #ifdef DIFFERENCE
31 #undef DIFFERENCE
32 #endif
33 #ifdef WINDING
34 #undef WINDING
35 #endif
36 #endif
37
38 namespace OHOS {
39 namespace Rosen {
40 namespace Drawing {
41 enum class PathDirection {
42 CW_DIRECTION,
43 CCW_DIRECTION,
44 };
45
46 enum class PathFillType {
47 WINDING,
48 EVENTODD,
49 INVERSE_WINDING,
50 INVERSE_EVENTODD,
51 };
52
53 enum class PathOp {
54 DIFFERENCE,
55 INTERSECT,
56 UNION,
57 XOR,
58 REVERSE_DIFFERENCE,
59 };
60
61 enum class PathAddMode {
62 APPEND_PATH_ADD_MODE,
63 EXTEND_PATH_ADD_MODE,
64 };
65
66 enum class PathMeasureMatrixFlags {
67 GET_POSITION_MATRIX,
68 GET_TANGENT_MATRIX,
69 GET_POS_AND_TAN_MATRIX,
70 };
71
72 class DRAWING_API Path {
73 public:
74 Path() noexcept;
75 Path(const Path& p) noexcept;
76 Path &operator=(const Path& p) noexcept;
77 virtual ~Path();
78
GetDrawingType()79 virtual DrawingType GetDrawingType() const
80 {
81 return DrawingType::COMMON;
82 }
83
84 /**
85 * @brief Parses the SVG format string that describes the drawing path, and sets the Path.
86 *
87 * @param str A string in SVG format that describes the drawing path.
88 * @return true if build succeeded, otherwise false.
89 */
90 virtual bool BuildFromSVGString(const std::string& str);
91
92 /**
93 * @brief Parses into a string in SVG format that describes the Path.
94 * @return Returns a string in SVG format.
95 */
96 std::string ConvertToSVGString() const;
97
98 /**
99 * @brief Adds beginning of contour at (x, y).
100 *
101 * @param x contour start x-axis
102 * @param y contour start y-axis
103 */
104 virtual void MoveTo(scalar x, scalar y);
105
106 /**
107 * @brief Adds line from last point to Point(x, y).
108 *
109 * @param x x-axis of end point of added line
110 * @param y y-axis of end point of added line
111 */
112 virtual void LineTo(scalar x, scalar y);
113
114 /**
115 * @brief Appends arc to Path. Arc added is part of ellipse bounded by oval, from startAngle through sweepAngle.
116 * Both startAngle and sweepAngle are measured in degrees, where zero degrees is aligned with the positive x-axis,
117 * and positive sweeps extends arc clockwise. ArcTo() adds line connecting Path last Point to initial arc Point if
118 * forceMoveTo is false and Path is not empty. Otherwise, added contour begins with first point of arc.
119 * Angles greater than -360 and less than 360 are treated modulo 360.
120 *
121 * @param pt1X left of bounds of ellipse containing arc
122 * @param pt1Y top of bounds of ellipse containing arc
123 * @param pt2X right of bounds of ellipse containing arc
124 * @param pt2Y bottom of bounds of ellipse containing arc
125 * @param startAngle starting angle of arc in degrees
126 * @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
127 */
128 virtual void ArcTo(scalar pt1X, scalar pt1Y, scalar pt2X, scalar pt2Y, scalar startAngle, scalar sweepAngle);
129 virtual void ArcTo(const Point& pt1, const Point& pt2, scalar startAngle, scalar sweepAngle);
130 /**
131 * @brief Appends arc to Path. Arc is implemented by one or more conics weighted to describe part of oval
132 * with radii (rx, ry) rotated by xAxisRotate degrees. Arc curves from last Path Point to (endX, endY), choosing
133 * one of four possible routes: clockwise or counterclockwise, and smaller or larger. Arc sweep is always
134 * less than 360 degrees. ArcTo() appends line to (endX, endY) if either radii are zero, or if last Path Point
135 * equals (endX, endY). ArcTo() scales radii (rx, ry) to fit last Path Point and (endX, endY) if both are greater
136 * than zero but too small.
137 *
138 * @param rx radius on x-axis before x-axis rotation
139 * @param ry radius on y-axis before x-axis rotation
140 * @param angle x-axis rotation in degrees; positive values are clockwise
141 * @param direction chooses clockwise or counterclockwise arc
142 * @param endX x-axis end of arc
143 * @param endY y-axis end of arc
144 */
145 virtual void ArcTo(scalar rx, scalar ry, scalar angle, PathDirection direction, scalar endX, scalar endY);
146
147 /**
148 * @brief Appends arc to Path, after appending line if needed. Arc is implemented by conic weighted
149 * to describe part of circle. Arc is contained by tangent from last Path point to (x1, y1), and tangent
150 * from (x1, y1) to (x2, y2). Arc is part of circle sized to radius, positioned so it touches both tangent lines.
151 * If last Path Point does not start Arc, ArcTo appends connecting Line to Path. The length of Vector from
152 * (x1, y1) to (x2, y2) does not affect Arc. Arc sweep is always less than 180 degrees. If radius is zero,
153 * or if tangents are nearly parallel, ArcTo appends Line from last Path Point to (x1, y1).
154 *
155 * @param x1 x-axis value common to pair of tangents
156 * @param y1 y-axis value common to pair of tangents
157 * @param x2 x-axis value end of second tangent
158 * @param y2 y-axis value end of second tangent
159 * @param radius distance from arc to circle center
160 */
161 virtual void ArcTo(scalar x1, scalar y1, scalar x2, scalar y2, scalar radius);
162
163 /**
164 * @brief Adds cubic from last point towards (ctrlPt1X, ctrlPt1Y), then towards (ctrlPt2X, ctrlPt2Y),
165 * ending at (endPtX, endPtY).
166 *
167 * @param ctrlPt1X x-axis of first control Point of cubic
168 * @param ctrlPt1Y y-axis of first control Point of cubic
169 * @param ctrlPt2X x-axis of second control Point of cubic
170 * @param ctrlPt2Y y-axis of second control Point of cubic
171 * @param endPtX x-axis of end Point of cubic
172 * @param endPtY y-axis of end Point of cubic
173 */
174 virtual void CubicTo(
175 scalar ctrlPt1X, scalar ctrlPt1Y, scalar ctrlPt2X, scalar ctrlPt2Y, scalar endPtX, scalar endPtY);
176
177 /**
178 * @brief Adds cubic from last point towards Point ctrlPt1, then towards Point ctrlPt2, ending at Point endPt.
179 *
180 * @param ctrlPt1 first control Point of cubic
181 * @param ctrlPt2 second control Point of cubic
182 * @param endPt end Point of cubic
183 */
184 virtual void CubicTo(const Point& ctrlPt1, const Point& ctrlPt2, const Point& endPt);
185
186 /**
187 * @brief Adds quad from last point towards (ctrlPtX, ctrlPtY), to (endPtX, endPtY).
188 *
189 * @param ctrlPtX control Point of quad on x-axis
190 * @param ctrlPtY control Point of quad on y-axis
191 * @param endPtX end Point of quad on x-axis
192 * @param endPtY end Point of quad on y-axis
193 */
194 virtual void QuadTo(scalar ctrlPtX, scalar ctrlPtY, scalar endPtX, scalar endPtY);
195
196 /**
197 * @brief Adds quad from last point towards control Point, to end Point.
198 *
199 * @param ctrlPt control Point of added quad
200 * @param endPt end Point of added quad
201 */
202 virtual void QuadTo(const Point& ctrlPt, const Point endPt);
203 /**
204 * @brief Draws a conic from the last point of a path to the target point.
205 *
206 * @param ctrlX Indicates the x coordinate of the control point
207 * @param ctrlY Indicates the y coordinate of the control point
208 * @param endX Indicates the x coordinate of the target point
209 * @param endY Indicates the y coordinate of the target point
210 * @param weight Indicates the weight of added conic.
211 */
212 virtual void ConicTo(scalar ctrlX, scalar ctrlY, scalar endX, scalar endY, scalar weight);
213
214 /**
215 * @brief Adds beginning of contour relative to last point. If Path is empty,
216 * starts contour at (dx, dy). Otherwise, start contour at last point offset by (dx, dy).
217 * Function name stands for "relative move to".
218 *
219 * @param dx offset from last point to contour start on x-axis
220 * @param dy offset from last point to contour start on y-axis
221 */
222 virtual void RMoveTo(scalar dx, scalar dy);
223
224 /**
225 * @brief Adds line from last point to vector (dx, dy).
226 *
227 * @param dx offset from last point to line end on x-axis
228 * @param dy offset from last point to line end on y-axis
229 */
230 virtual void RLineTo(scalar dx, scalar dy);
231
232 /**
233 * @brief Appends arc to Path, relative to last Path Point.
234 *
235 * @param rx radius before x-axis rotation
236 * @param ry radius before y-axis rotation
237 * @param angle x-axis rotation in degrees; positive values are clockwise
238 * @param direction chooses clockwise or counterclockwise arc
239 * @param dx x-axis offset end of arc from last Path Point
240 * @param dy y-axis offset end of arc from last Path Point
241 */
242 virtual void RArcTo(scalar rx, scalar ry, scalar angle, PathDirection direction, scalar dx, scalar dy);
243
244 /**
245 * @brief Adds cubic from last point towards vector (dx1, dy1), then towards vector (dx2, dy2),
246 * to vector (dx3, dy3).
247 *
248 * @param dx1 offset from last point to first cubic control on x-axis
249 * @param dy1 offset from last point to first cubic control on y-axis
250 * @param dx2 offset from last point to second cubic control on x-axis
251 * @param dy2 offset from last point to second cubic control on y-axis
252 * @param dx3 offset from last point to cubic end on x-axis
253 * @param dy3 offset from last point to cubic end on y-axis
254 */
255 virtual void RCubicTo(scalar dx1, scalar dy1, scalar dx2, scalar dy2, scalar dx3, scalar dy3);
256
257 /**
258 * @brief Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2).
259 *
260 * @param dx1 offset from last point to quad control on x-axis
261 * @param dy1 offset from last point to quad control on y-axis
262 * @param dx2 offset from last point to quad end on x-axis
263 * @param dy2 offset from last point to quad end on y-axis
264 */
265 virtual void RQuadTo(scalar dx1, scalar dy1, scalar dx2, scalar dy2);
266
267 /**
268 * @brief Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2),
269 * weighted by w. If Path is empty, or last Path::Verb is kClose_Verb,
270 * last point is set to (0, 0) before adding conic.
271 *
272 * @param ctrlPtX offset from last point to conic control on x-axis
273 * @param ctrlPtY offset from last point to conic control on y-axis
274 * @param endPtX offset from last point to conic end on x-axis
275 * @param endPtY offset from last point to conic end on y-axis
276 * @param weight weight of added conic
277 */
278 virtual void RConicTo(scalar ctrlPtX, scalar ctrlPtY, scalar endPtX, scalar endPtY, scalar weight);
279
280 /**
281 * @brief Adds a new contour to the path, defined by the rect, and wound in the specified direction.
282 *
283 * @param rect Rect to add as a closed contour
284 * @param dir Path::PathDirection to orient the new contour
285 */
286 virtual void AddRect(const Rect& rect, PathDirection dir = PathDirection::CW_DIRECTION);
287
288 /**
289 * @brief Adds a new contour to the path, defined by the rect, and wound in the specified direction.
290 *
291 * @param rect Rect to add as a closed contour
292 * @param dir Path::PathDirection to orient the new contour
293 * @param start Initial corner of Rect to add
294 */
295 virtual void AddRect(const Rect& rect, unsigned start, PathDirection dir = PathDirection::CW_DIRECTION);
296 virtual void AddRect(
297 scalar left, scalar top, scalar right, scalar bottom, PathDirection dir = PathDirection::CW_DIRECTION);
298
299 /**
300 * @brief Adds oval to Path. Oval is upright ellipse bounded by Rect oval with radii equal to
301 * half oval width and half oval height. Oval begins at start and continues clockwise if dir is
302 * PathDirection::CW_DIRECTION, counterclockwise if dir is PathDirection::CCW_DIRECTION.
303 *
304 * @param oval bounds of ellipse added
305 * @param dir Path::PathDirection to wind ellipse
306 */
307 virtual void AddOval(const Rect& oval, PathDirection dir = PathDirection::CW_DIRECTION);
308
309 /**
310 * @brief Adds oval to Path. Oval is upright ellipse bounded by Rect oval with radii equal to
311 * half oval width and half oval height. Oval begins at start and continues clockwise if dir is
312 * PathDirection::CW_DIRECTION, counterclockwise if dir is PathDirection::CCW_DIRECTION.
313 *
314 * @param oval bounds of ellipse added
315 * @param start Index of initial point of ellipse
316 * @param dir Path::PathDirection to wind ellipse
317 */
318 virtual void AddOval(const Rect& oval, unsigned start, PathDirection dir = PathDirection::CCW_DIRECTION);
319
320 /**
321 * @brief Appends arc to Path, as the start of new contour. Arc added is part of ellipse bounded by oval,
322 * from startAngle through sweepAngle. Both startAngle and sweepAngle are measured in degrees, where zero
323 * degrees is aligned with the positive x-axis, and positive sweeps extends arc clockwise. If sweepAngle <= -360,
324 * or sweepAngle >= 360; and startAngle modulo 90 is nearly zero, append oval instead of arc. Otherwise, sweepAngle
325 * values are treated modulo 360, and arc may or may not draw depending on numeric rounding.
326 *
327 * @param oval bounds of ellipse containing arc
328 * @param startAngle starting angle of arc in degrees
329 * @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
330 */
331 virtual void AddArc(const Rect& oval, scalar startAngle, scalar sweepAngle);
332
333 /**
334 * @brief Adds contour created from line array, adding (count - 1) line segments.
335 *
336 * @param points array of line sharing end and start Point
337 * @param count length of Point array
338 * @param close true to add line connecting contour end and start
339 */
340 virtual void AddPoly(const std::vector<Point>& points, int count, bool close);
341 virtual void AddCircle(scalar x, scalar y, scalar radius, PathDirection dir = PathDirection::CW_DIRECTION);
342 virtual void AddRoundRect(
343 const Rect& rect, scalar xRadius, scalar yRadius, PathDirection dir = PathDirection::CW_DIRECTION);
344
345 /**
346 * @brief Adds the circle rectangle to the Path.
347 * @param roundRect The boundary and radius of a roundRect.
348 * @param dir Direction of rotation.
349 */
350 virtual void AddRoundRect(const RoundRect& roundRect, PathDirection dir = PathDirection::CW_DIRECTION);
351
352 /**
353 * @brief Appends src to Path, offset by (dx, dy).
354 *
355 * @param src Path Point, and conic weights to add
356 * @param dx offset added to src Point array x-axis coordinates
357 * @param dy offset added to src Point array y-axis coordinates
358 * @param mode the add path's add mode
359 */
360 virtual void AddPath(const Path& src, scalar dx, scalar dy, PathAddMode mode = PathAddMode::APPEND_PATH_ADD_MODE);
361
362 /**
363 * @brief Appends src to Path.
364 *
365 * @param src Path Point, and conic weights to add
366 * @param mode the add path's add mode
367 */
368 virtual void AddPath(const Path& src, PathAddMode mode = PathAddMode::APPEND_PATH_ADD_MODE);
369
370 /**
371 * @brief Appends src to Path, transformed by matrix.
372 * Transformed curves may have different verbs, Point, and conic weights.
373 *
374 * @param src Path Point, and conic weights to add
375 * @param matrix transform applied to src
376 * @param mode the add path's add mode
377 */
378 virtual void AddPath(const Path& src, const Matrix& matrix, PathAddMode mode = PathAddMode::APPEND_PATH_ADD_MODE);
379 virtual bool Contains(scalar x, scalar y) const;
380
381 /**
382 * @brief Adds the src from back forward to the Path.
383 * @param src To add Path.
384 */
385 virtual void ReverseAddPath(const Path& src);
386
387 /**
388 * @brief Returns minimum and maximum axes values of Point array. Returns (0, 0, 0, 0)
389 * if Path contains no points. Returned bounds width and height may be larger or smaller
390 * than area affected when Path is drawn.
391 *
392 * @return Rect bounds of all Point in Point array
393 */
394 Rect GetBounds() const;
395
396 /**
397 * @brief Sets PathFillType, the rule used to fill Path. While there is no check that ft is legal,
398 * values outside of PathFillType are not supported.
399 *
400 * @param fillstyle enum PathFillType
401 */
402 virtual void SetFillStyle(PathFillType fillstyle);
403
404 /**
405 * @brief Gets PathFillType, the rule used to fill Path.
406 *
407 * @return current PathFillType setting
408 */
409 PathFillType GetFillStyle() const;
410
411 /**
412 * @brief Interpolates between Path with Point array of equal size.
413 *
414 * @param ending Point array averaged with this Point array
415 * @param weight contribution of this Point array, and one minus contribution of ending Point array
416 * @param out Path replaced by interpolated averages
417 * @return true if Path contain same number of Point
418 */
419 bool Interpolate(const Path& ending, scalar weight, Path& out);
420
421 /**
422 * @brief Two equal number of point set path objects are weighted interpolated, and the sets Path.
423 * @param src The number of point sets of the src Path.
424 * @param ending The number of point sets of the ending Path.
425 * @param weight The weight value is between 0 and 1.
426 * @return true if build succeeded, otherwise false.
427 */
428 virtual bool BuildFromInterpolate(const Path& src, const Path& ending, scalar weight);
429
430 /**
431 * @brief Transforms Point array, and weight by matrix. Path is replaced by transformed data.
432 *
433 * @param matrix Matrix to apply to Path
434 */
435 virtual void Transform(const Matrix& matrix);
436
437 /**
438 * @brief Transforms verb array, Point array, and weight by matrix.
439 * Transform may change verbs and increase their number.
440 * Transformed Path replaces dst; if dst is nullptr, original data is replaced.
441 *
442 * @param matrix Matrix to apply to Path
443 * @param dst Overwritten, transformed copy of Path; may be nullptr
444 * @param applyPerspectiveClip Whether to apply perspective clipping
445 */
446 virtual void TransformWithPerspectiveClip(const Matrix& matrix, Path* dst, bool applyPerspectiveClip);
447
448 /**
449 * @brief Offsets Point array by (dx, dy). Path is replaced by offset data.
450 *
451 * @param dx offset added to Point array x-axis coordinates
452 * @param dy offset added to Point array y-axis coordinates
453 */
454 virtual void Offset(scalar dx, scalar dy);
455
456 /**
457 * @brief Offsets Point array by (dx, dy). Path is replaced by offset data.
458 *
459 * @param dst The pointer of point sets of the dst Path
460 * @param dx offset added to Point array x-axis coordinates
461 * @param dy offset added to Point array y-axis coordinates
462 */
463 virtual void Offset(Path* dst, scalar dx, scalar dy);
464
465 virtual bool Op(const Path& path1, Path& path2, PathOp op);
466
467 /**
468 * @brief Checks whether the Path is valid.
469 */
470 bool IsValid() const;
471
472 /**
473 * @brief Sets Path to its initial state. Removes Point array, and weights, and sets PathFillType to
474 * PathFillType::Winding. Internal storage associated with Path is released.
475 */
476 virtual void Reset();
477
478 /**
479 * @brief A closed contour connects the first and last Point with line, forming a continuous loop.
480 */
481 virtual void Close();
482
483 /**
484 * @brief Gets the length of the current path object.
485 * @param forceClosed Whether to close the Path.
486 * @return Returns the length of the current path object.
487 */
488 scalar GetLength(bool forceClosed) const;
489
490 /**
491 * @brief Gets the position and tangent of the distance from the starting position of the Path.
492 * @param distance The distance from the start of the Path, should be greater than 0 and less than 'GetLength()'
493 * @param position Sets to the position of distance from the starting position of the Path.
494 * @param tangent Sets to the tangent of distance from the starting position of the Path.
495 * @param forceClosed Whether to close the Path.
496 * @return Returns true if succeeded, otherwise false.
497 */
498 bool GetPositionAndTangent(scalar distance, Point& position, Point& tangent, bool forceClosed) const;
499
500 /**
501 * @brief Gets the path between the start and end points.
502 * @param start The distance from the starting point of the segment to the starting point of the path.
503 * @param stop The distance from the end point of the segment to the starting point of the path.
504 * @param dst The path obtained.
505 * @param startWithMoveTo Whether the path obtained moveTo to the starting segment.
506 * @param forceClosed Whether to close the path.
507 * @return Returns false if the segment is zero-length or start > stop, else return true.
508 */
509 bool GetSegment(scalar start, scalar stop, Path* dst, bool startWithMoveTo, bool forceClosed) const;
510
511 /**
512 * @brief Determines whether the current contour is closed.
513 * @param forceClosed Whether to close the Path.
514 * @return Returns true if the current contour is closed, otherwise false.
515 */
516 bool IsClosed(bool forceClosed) const;
517
518 bool GetMatrix(bool forceClosed, float distance, Matrix* matrix,
519 PathMeasureMatrixFlags flags = PathMeasureMatrixFlags::GET_POS_AND_TAN_MATRIX);
520
521 inline void Dump(std::string& out) const;
522
523 std::shared_ptr<Data> Serialize() const;
524 bool Deserialize(std::shared_ptr<Data> data);
525
526 template<typename T>
GetImpl()527 T* GetImpl() const
528 {
529 return impl_->DowncastingTo<T>();
530 }
531
532 private:
533 std::shared_ptr<PathImpl> impl_;
534 };
535
Dump(std::string & out)536 inline void Path::Dump(std::string& out) const
537 {
538 out += '[';
539 if (impl_ != nullptr) {
540 auto bounds = impl_->GetBounds();
541 out += "length:" + std::to_string(impl_->GetLength(false));
542 out += " Bounds";
543 bounds.Dump(out);
544 out += " valid:" + std::string(impl_->IsValid() ? "true" : "false");
545 }
546 out += ']';
547 }
548 } // namespace Drawing
549 } // namespace Rosen
550 } // namespace OHOS
551 #endif
552