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 Interpolates between Path with Point array of equal size.
406      *
407      * @param ending Point array averaged with this Point array
408      * @param weight contribution of this Point array, and one minus contribution of ending Point array
409      * @param out Path replaced by interpolated averages
410      * @return true if Path contain same number of Point
411      */
412     bool Interpolate(const Path& ending, scalar weight, Path& out);
413 
414     /**
415      * @brief Two equal number of point set path objects are weighted interpolated, and the sets Path.
416      * @param src    The number of point sets of the src Path.
417      * @param ending The number of point sets of the ending Path.
418      * @param weight The weight value is between 0 and 1.
419      * @return true if build succeeded, otherwise false.
420      */
421     virtual bool BuildFromInterpolate(const Path& src, const Path& ending, scalar weight);
422 
423     /**
424      * @brief Transforms Point array, and weight by matrix. Path is replaced by transformed data.
425      *
426      * @param matrix Matrix to apply to Path
427      */
428     virtual void Transform(const Matrix& matrix);
429 
430     /**
431      * @brief Transforms verb array, Point array, and weight by matrix.
432      * Transform may change verbs and increase their number.
433      * Transformed Path replaces dst; if dst is nullptr, original data is replaced.
434      *
435      * @param matrix  Matrix to apply to Path
436      * @param dst     Overwritten, transformed copy of Path; may be nullptr
437      * @param applyPerspectiveClip    Whether to apply perspective clipping
438      */
439     virtual void TransformWithPerspectiveClip(const Matrix& matrix, Path* dst, bool applyPerspectiveClip);
440 
441     /**
442      * @brief Offsets Point array by (dx, dy). Path is replaced by offset data.
443      *
444      * @param dx offset added to Point array x-axis coordinates
445      * @param dy offset added to Point array y-axis coordinates
446      */
447     virtual void Offset(scalar dx, scalar dy);
448 
449     /**
450      * @brief Offsets Point array by (dx, dy). Path is replaced by offset data.
451      *
452      * @param dst The pointer of point sets of the dst Path
453      * @param dx offset added to Point array x-axis coordinates
454      * @param dy offset added to Point array y-axis coordinates
455      */
456     virtual void Offset(Path* dst, scalar dx, scalar dy);
457 
458     virtual bool Op(const Path& path1, Path& path2, PathOp op);
459 
460     /**
461      * @brief Checks whether the Path is valid.
462      */
463     bool IsValid() const;
464 
465     /**
466      * @brief Sets Path to its initial state. Removes Point array, and weights, and sets PathFillType to
467      * PathFillType::Winding. Internal storage associated with Path is released.
468      */
469     virtual void Reset();
470 
471     /**
472      * @brief A closed contour connects the first and last Point with line, forming a continuous loop.
473      */
474     virtual void Close();
475 
476     /**
477      * @brief Gets the length of the current path object.
478      * @param forceClosed   Whether to close the Path.
479      * @return Returns the length of the current path object.
480      */
481     scalar GetLength(bool forceClosed) const;
482 
483     /**
484      * @brief Gets the position and tangent of the distance from the starting position of the Path.
485      * @param distance     The distance from the start of the Path, should be greater than 0 and less than 'GetLength()'
486      * @param position     Sets to the position of distance from the starting position of the Path.
487      * @param tangent      Sets to the tangent of distance from the starting position of the Path.
488      * @param forceClosed  Whether to close the Path.
489      * @return Returns true if succeeded, otherwise false.
490      */
491     bool GetPositionAndTangent(scalar distance, Point& position, Point& tangent, bool forceClosed) const;
492 
493     /**
494      * @brief Determines whether the current contour is closed.
495      * @param forceClosed  Whether to close the Path.
496      * @return Returns true if the current contour is closed, otherwise false.
497      */
498     bool IsClosed(bool forceClosed) const;
499 
500     bool GetMatrix(bool forceClosed, float distance, Matrix* matrix,
501         PathMeasureMatrixFlags flags = PathMeasureMatrixFlags::GET_POS_AND_TAN_MATRIX);
502 
503     std::shared_ptr<Data> Serialize() const;
504     bool Deserialize(std::shared_ptr<Data> data);
505 
506     template<typename T>
GetImpl()507     T* GetImpl() const
508     {
509         return impl_->DowncastingTo<T>();
510     }
511 
512 private:
513     std::shared_ptr<PathImpl> impl_;
514 };
515 } // namespace Drawing
516 } // namespace Rosen
517 } // namespace OHOS
518 #endif
519