• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "skia_path.h"
17 
18 #include "include/core/SkMatrix.h"
19 #include "include/pathops/SkPathOps.h"
20 #include "include/utils/SkParsePath.h"
21 #include "include/core/SkString.h"
22 #include "skia_matrix.h"
23 
24 #include "src/core/SkReadBuffer.h"
25 #include "src/core/SkWriteBuffer.h"
26 
27 #include "draw/path.h"
28 #include "utils/data.h"
29 #include "utils/log.h"
30 
31 namespace OHOS {
32 namespace Rosen {
33 namespace Drawing {
34 
SkiaPath(const SkiaPath & other)35 SkiaPath::SkiaPath(const SkiaPath& other) noexcept : path_(other.path_) {}
36 
operator =(const SkiaPath & other)37 SkiaPath& SkiaPath::operator=(const SkiaPath& other) noexcept
38 {
39     path_ = other.path_;
40     return *this;
41 }
42 
Clone()43 PathImpl* SkiaPath::Clone()
44 {
45     return new SkiaPath(*this);
46 }
47 
InitWithSVGString(const std::string & str)48 bool SkiaPath::InitWithSVGString(const std::string& str)
49 {
50     return SkParsePath::FromSVGString(str.c_str(), &path_);
51 }
52 
ConvertToSVGString() const53 std::string SkiaPath::ConvertToSVGString() const
54 {
55     SkString skString;
56     SkParsePath::ToSVGString(path_, &skString);
57 
58     return skString.c_str();
59 }
60 
MoveTo(scalar x,scalar y)61 void SkiaPath::MoveTo(scalar x, scalar y)
62 {
63     path_.moveTo(x, y);
64     isChanged_ = true;
65 }
66 
LineTo(scalar x,scalar y)67 void SkiaPath::LineTo(scalar x, scalar y)
68 {
69     path_.lineTo(x, y);
70     isChanged_ = true;
71 }
72 
ArcTo(scalar pt1X,scalar pt1Y,scalar pt2X,scalar pt2Y,scalar startAngle,scalar sweepAngle)73 void SkiaPath::ArcTo(scalar pt1X, scalar pt1Y, scalar pt2X, scalar pt2Y, scalar startAngle, scalar sweepAngle)
74 {
75     path_.arcTo(SkRect::MakeLTRB(pt1X, pt1Y, pt2X, pt2Y), startAngle, sweepAngle, false);
76     isChanged_ = true;
77 }
78 
ArcTo(scalar rx,scalar ry,scalar angle,PathDirection direction,scalar endX,scalar endY)79 void SkiaPath::ArcTo(scalar rx, scalar ry, scalar angle, PathDirection direction, scalar endX, scalar endY)
80 {
81     SkPathDirection pathDir = static_cast<SkPathDirection>(direction);
82     SkPath::ArcSize arcLarge = SkPath::ArcSize::kSmall_ArcSize;
83     path_.arcTo(rx, ry, angle, arcLarge, pathDir, endX, endY);
84     isChanged_ = true;
85 }
86 
ArcTo(scalar x1,scalar y1,scalar x2,scalar y2,scalar radius)87 void SkiaPath::ArcTo(scalar x1, scalar y1, scalar x2, scalar y2, scalar radius)
88 {
89     path_.arcTo(x1, y1, x2, y2, radius);
90     isChanged_ = true;
91 }
92 
CubicTo(scalar ctrlPt1X,scalar ctrlPt1Y,scalar ctrlPt2X,scalar ctrlPt2Y,scalar endPtX,scalar endPtY)93 void SkiaPath::CubicTo(scalar ctrlPt1X, scalar ctrlPt1Y, scalar ctrlPt2X, scalar ctrlPt2Y, scalar endPtX, scalar endPtY)
94 {
95     path_.cubicTo(ctrlPt1X, ctrlPt1Y, ctrlPt2X, ctrlPt2Y, endPtX, endPtY);
96     isChanged_ = true;
97 }
98 
QuadTo(scalar ctrlPtX,scalar ctrlPtY,scalar endPtX,scalar endPtY)99 void SkiaPath::QuadTo(scalar ctrlPtX, scalar ctrlPtY, scalar endPtX, scalar endPtY)
100 {
101     path_.quadTo(ctrlPtX, ctrlPtY, endPtX, endPtY);
102     isChanged_ = true;
103 }
104 
ConicTo(scalar ctrlX,scalar ctrlY,scalar endX,scalar endY,scalar weight)105 void SkiaPath::ConicTo(scalar ctrlX, scalar ctrlY, scalar endX, scalar endY, scalar weight)
106 {
107     path_.conicTo(ctrlX, ctrlY, endX, endY, weight);
108     isChanged_ = true;
109 }
110 
RMoveTo(scalar dx,scalar dy)111 void SkiaPath::RMoveTo(scalar dx, scalar dy)
112 {
113     path_.rMoveTo(dx, dy);
114     isChanged_ = true;
115 }
116 
RLineTo(scalar dx,scalar dy)117 void SkiaPath::RLineTo(scalar dx, scalar dy)
118 {
119     path_.rLineTo(dx, dy);
120     isChanged_ = true;
121 }
122 
RArcTo(scalar rx,scalar ry,scalar angle,PathDirection direction,scalar dx,scalar dy)123 void SkiaPath::RArcTo(scalar rx, scalar ry, scalar angle, PathDirection direction, scalar dx, scalar dy)
124 {
125     SkPathDirection pathDir = static_cast<SkPathDirection>(direction);
126     SkPath::ArcSize arcLarge = SkPath::ArcSize::kSmall_ArcSize;
127     path_.arcTo(rx, ry, angle, arcLarge, pathDir, dx, dy);
128     isChanged_ = true;
129 }
130 
RCubicTo(scalar dx1,scalar dy1,scalar dx2,scalar dy2,scalar dx3,scalar dy3)131 void SkiaPath::RCubicTo(scalar dx1, scalar dy1, scalar dx2, scalar dy2, scalar dx3, scalar dy3)
132 {
133     path_.rCubicTo(dx1, dy1, dx2, dy2, dx3, dy3);
134     isChanged_ = true;
135 }
136 
RConicTo(scalar ctrlPtX,scalar ctrlPtY,scalar endPtX,scalar endPtY,scalar weight)137 void SkiaPath::RConicTo(scalar ctrlPtX, scalar ctrlPtY, scalar endPtX, scalar endPtY, scalar weight)
138 {
139     path_.rConicTo(ctrlPtX, ctrlPtY, endPtX, endPtY, weight);
140     isChanged_ = true;
141 }
142 
RQuadTo(scalar dx1,scalar dy1,scalar dx2,scalar dy2)143 void SkiaPath::RQuadTo(scalar dx1, scalar dy1, scalar dx2, scalar dy2)
144 {
145     path_.rQuadTo(dx1, dy1, dx2, dy2);
146     isChanged_ = true;
147 }
148 
AddRect(scalar left,scalar top,scalar right,scalar bottom,PathDirection dir)149 void SkiaPath::AddRect(scalar left, scalar top, scalar right, scalar bottom, PathDirection dir)
150 {
151     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
152     path_.addRect(SkRect::MakeLTRB(left, top, right, bottom), pathDir);
153     isChanged_ = true;
154 }
155 
AddRect(const Rect & rect,unsigned start,PathDirection dir)156 void SkiaPath::AddRect(const Rect& rect, unsigned start, PathDirection dir)
157 {
158     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
159     path_.addRect(SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom()), pathDir, start);
160     isChanged_ = true;
161 }
162 
AddOval(scalar left,scalar top,scalar right,scalar bottom,PathDirection dir)163 void SkiaPath::AddOval(scalar left, scalar top, scalar right, scalar bottom, PathDirection dir)
164 {
165     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
166     path_.addOval(SkRect::MakeLTRB(left, top, right, bottom), pathDir);
167     isChanged_ = true;
168 }
169 
AddOval(scalar left,scalar top,scalar right,scalar bottom,unsigned start,PathDirection dir)170 void SkiaPath::AddOval(scalar left, scalar top, scalar right, scalar bottom, unsigned start, PathDirection dir)
171 {
172     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
173     path_.addOval(SkRect::MakeLTRB(left, top, right, bottom), pathDir, start);
174     isChanged_ = true;
175 }
176 
AddArc(scalar left,scalar top,scalar right,scalar bottom,scalar startAngle,scalar sweepAngle)177 void SkiaPath::AddArc(scalar left, scalar top, scalar right, scalar bottom, scalar startAngle, scalar sweepAngle)
178 {
179     path_.addArc(SkRect::MakeLTRB(left, top, right, bottom), startAngle, sweepAngle);
180     isChanged_ = true;
181 }
182 
AddPoly(const std::vector<Point> & points,int count,bool close)183 void SkiaPath::AddPoly(const std::vector<Point>& points, int count, bool close)
184 {
185     std::vector<SkPoint> pt;
186     for (auto i = 0; i < count; ++i) {
187         pt.emplace_back(SkPoint::Make(points[i].GetX(), points[i].GetY()));
188     }
189     path_.addPoly(&pt[0], count, close);
190     isChanged_ = true;
191 }
192 
AddCircle(scalar x,scalar y,scalar radius,PathDirection dir)193 void SkiaPath::AddCircle(scalar x, scalar y, scalar radius, PathDirection dir)
194 {
195     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
196     path_.addCircle(x, y, radius, pathDir);
197     isChanged_ = true;
198 }
199 
AddRoundRect(scalar left,scalar top,scalar right,scalar bottom,scalar xRadius,scalar yRadius,PathDirection dir)200 void SkiaPath::AddRoundRect(
201     scalar left, scalar top, scalar right, scalar bottom, scalar xRadius, scalar yRadius, PathDirection dir)
202 {
203     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
204     path_.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), xRadius, yRadius, pathDir);
205     isChanged_ = true;
206 }
207 
AddRoundRect(const RoundRect & rrect,PathDirection dir)208 void SkiaPath::AddRoundRect(const RoundRect& rrect, PathDirection dir)
209 {
210     SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
211 
212     Rect rect = rrect.GetRect();
213     SkRect outer = SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
214 
215     SkVector radii[4];
216     Point p;
217     p = rrect.GetCornerRadius(RoundRect::TOP_LEFT_POS);
218     radii[SkRRect::kUpperLeft_Corner] = { p.GetX(), p.GetY() };
219     p = rrect.GetCornerRadius(RoundRect::TOP_RIGHT_POS);
220     radii[SkRRect::kUpperRight_Corner] = { p.GetX(), p.GetY() };
221     p = rrect.GetCornerRadius(RoundRect::BOTTOM_RIGHT_POS);
222     radii[SkRRect::kLowerRight_Corner] = { p.GetX(), p.GetY() };
223     p = rrect.GetCornerRadius(RoundRect::BOTTOM_LEFT_POS);
224     radii[SkRRect::kLowerLeft_Corner] = { p.GetX(), p.GetY() };
225 
226     SkRRect skRRect;
227     skRRect.setRectRadii(outer, radii);
228     path_.addRRect(skRRect, pathDir);
229     isChanged_ = true;
230 }
231 
AddPath(const Path & src,scalar dx,scalar dy,PathAddMode mode)232 void SkiaPath::AddPath(const Path& src, scalar dx, scalar dy, PathAddMode mode)
233 {
234     auto skPathImpl = src.GetImpl<SkiaPath>();
235     if (skPathImpl != nullptr) {
236         path_.addPath(skPathImpl->GetPath(), dx, dy, static_cast<SkPath::AddPathMode>(mode));
237         isChanged_ = true;
238     }
239 }
240 
AddPath(const Path & src,PathAddMode mode)241 void SkiaPath::AddPath(const Path& src, PathAddMode mode)
242 {
243     auto skPathImpl = src.GetImpl<SkiaPath>();
244     if (skPathImpl != nullptr) {
245         path_.addPath(skPathImpl->GetPath(), static_cast<SkPath::AddPathMode>(mode));
246         isChanged_ = true;
247     }
248 }
249 
Contains(scalar x,scalar y) const250 bool SkiaPath::Contains(scalar x, scalar y) const
251 {
252     return path_.contains(x, y);
253 }
254 
ReverseAddPath(const Path & src)255 void SkiaPath::ReverseAddPath(const Path& src)
256 {
257     path_.reverseAddPath(src.GetImpl<SkiaPath>()->GetPath());
258     isChanged_ = true;
259 }
260 
AddPath(const Path & src,const Matrix & matrix,PathAddMode mode)261 void SkiaPath::AddPath(const Path& src, const Matrix& matrix, PathAddMode mode)
262 {
263     auto skPathImpl = src.GetImpl<SkiaPath>();
264     auto skMatrixImpl = matrix.GetImpl<SkiaMatrix>();
265     if (skPathImpl != nullptr && skMatrixImpl != nullptr) {
266         path_.addPath(skPathImpl->GetPath(), skMatrixImpl->ExportSkiaMatrix(), static_cast<SkPath::AddPathMode>(mode));
267         isChanged_ = true;
268     }
269 }
270 
GetBounds() const271 Rect SkiaPath::GetBounds() const
272 {
273     SkRect rect = path_.getBounds();
274     return Rect(rect.left(), rect.top(), rect.right(), rect.bottom());
275 }
276 
SetFillStyle(PathFillType fillstyle)277 void SkiaPath::SetFillStyle(PathFillType fillstyle)
278 {
279     SkPathFillType ft = static_cast<SkPathFillType>(fillstyle);
280     path_.setFillType(ft);
281     isChanged_ = true;
282 }
283 
GetFillStyle() const284 PathFillType SkiaPath::GetFillStyle() const
285 {
286     PathFillType fillType = static_cast<PathFillType>(path_.getFillType());
287     return fillType;
288 }
289 
Interpolate(const Path & ending,scalar weight,Path & out)290 bool SkiaPath::Interpolate(const Path& ending, scalar weight, Path& out)
291 {
292     bool isSuccess = false;
293     auto skPathImpl1 = ending.GetImpl<SkiaPath>();
294     auto skPathImpl2 = out.GetImpl<SkiaPath>();
295     if (skPathImpl1 != nullptr && skPathImpl2 != nullptr) {
296         SkPath interp;
297         isSuccess = path_.interpolate(skPathImpl1->GetPath(), weight, &interp);
298         skPathImpl2->SetPath(interp);
299         isChanged_ = true;
300     }
301     return isSuccess;
302 }
303 
InitWithInterpolate(const Path & srcPath,const Path & endingPath,scalar weight)304 bool SkiaPath::InitWithInterpolate(const Path& srcPath, const Path& endingPath, scalar weight)
305 {
306     const SkPath& srcSkPath = srcPath.GetImpl<SkiaPath>()->GetPath();
307     isChanged_ = true;
308     return srcSkPath.interpolate(endingPath.GetImpl<SkiaPath>()->GetPath(), weight, &path_);
309 }
310 
Transform(const Matrix & matrix)311 void SkiaPath::Transform(const Matrix& matrix)
312 {
313     auto skMatrixImpl = matrix.GetImpl<SkiaMatrix>();
314     if (skMatrixImpl != nullptr) {
315         path_.transform(skMatrixImpl->ExportSkiaMatrix());
316         isChanged_ = true;
317     }
318 }
319 
TransformWithPerspectiveClip(const Matrix & matrix,Path * dst,bool applyPerspectiveClip)320 void SkiaPath::TransformWithPerspectiveClip(const Matrix& matrix, Path* dst, bool applyPerspectiveClip)
321 {
322     auto skMatrixImpl = matrix.GetImpl<SkiaMatrix>();
323     if (skMatrixImpl == nullptr) {
324         LOGE("SkiaPath::TransformWithPerspectiveClip, skMatrixImpl is nullptr!");
325         return;
326     }
327     if (dst == nullptr) {
328         path_.transform(skMatrixImpl->ExportSkiaMatrix(), nullptr,
329             static_cast<SkApplyPerspectiveClip>(applyPerspectiveClip));
330         return;
331     }
332     auto dstPathImpl = dst->GetImpl<SkiaPath>();
333     if (dstPathImpl == nullptr) {
334         LOGE("SkiaPath::TransformWithPerspectiveClip, dstPathImpl is nullptr!");
335         return;
336     }
337     path_.transform(skMatrixImpl->ExportSkiaMatrix(), &dstPathImpl->path_,
338         static_cast<SkApplyPerspectiveClip>(applyPerspectiveClip));
339     isChanged_ = true;
340 }
341 
Offset(scalar dx,scalar dy)342 void SkiaPath::Offset(scalar dx, scalar dy)
343 {
344     path_.offset(dx, dy);
345     isChanged_ = true;
346 }
347 
Offset(Path * dst,scalar dx,scalar dy)348 void SkiaPath::Offset(Path* dst, scalar dx, scalar dy)
349 {
350     if (dst == nullptr) {
351         path_.offset(dx, dy, nullptr);
352         return;
353     }
354     auto dstPathImpl = dst->GetImpl<SkiaPath>();
355     if (dstPathImpl == nullptr) {
356         LOGE("SkiaPath::Offset, data is invalid!");
357         return;
358     }
359     path_.offset(dx, dy, &dstPathImpl->path_);
360     isChanged_ = true;
361 }
362 
OpWith(const Path & path1,const Path & path2,PathOp op)363 bool SkiaPath::OpWith(const Path& path1, const Path& path2, PathOp op)
364 {
365     SkPathOp pathOp = static_cast<SkPathOp>(op);
366     bool isOpSuccess = false;
367 
368     auto skPathImpl1 = path1.GetImpl<SkiaPath>();
369     auto skPathImpl2 = path2.GetImpl<SkiaPath>();
370     if (skPathImpl1 != nullptr && skPathImpl2 != nullptr) {
371         isOpSuccess = Op(skPathImpl1->GetPath(), skPathImpl2->GetPath(), pathOp, &path_);
372     }
373 
374     isChanged_ = true;
375     if (isOpSuccess) {
376         return true;
377     }
378     return false;
379 }
380 
IsValid() const381 bool SkiaPath::IsValid() const
382 {
383     return !path_.isEmpty();
384 }
385 
Reset()386 void SkiaPath::Reset()
387 {
388     path_.reset();
389     isChanged_ = true;
390 }
391 
Close()392 void SkiaPath::Close()
393 {
394     path_.close();
395     isChanged_ = true;
396 }
397 
SetPath(const SkPath & path)398 void SkiaPath::SetPath(const SkPath& path)
399 {
400     path_ = path;
401     isChanged_ = true;
402 }
403 
GetPath() const404 const SkPath& SkiaPath::GetPath() const
405 {
406     return path_;
407 }
408 
GetMutablePath()409 SkPath& SkiaPath::GetMutablePath()
410 {
411     isChanged_ = true;
412     return path_;
413 }
414 
PathMeasureUpdate(bool forceClosed)415 void SkiaPath::PathMeasureUpdate(bool forceClosed)
416 {
417     if (pathMeasure_ == nullptr) {
418         pathMeasure_ = std::make_unique<SkPathMeasure>(path_, forceClosed);
419         isChanged_ = false;
420         forceClosed_ = forceClosed;
421         return;
422     }
423 
424     if (isChanged_ || forceClosed != forceClosed_) {
425         pathMeasure_->setPath(&path_, forceClosed);
426         isChanged_ = false;
427         forceClosed_ = forceClosed;
428     }
429 }
430 
GetLength(bool forceClosed)431 scalar SkiaPath::GetLength(bool forceClosed)
432 {
433     PathMeasureUpdate(forceClosed);
434     return pathMeasure_->getLength();
435 }
436 
GetPositionAndTangent(scalar distance,Point & position,Point & tangent,bool forceClosed)437 bool SkiaPath::GetPositionAndTangent(scalar distance, Point& position, Point& tangent, bool forceClosed)
438 {
439     PathMeasureUpdate(forceClosed);
440     bool ret = false;
441     SkPoint skPosition;
442     SkVector skTangent;
443     ret = pathMeasure_->getPosTan(distance, &skPosition, &skTangent);
444     if (ret) {
445         position.SetX(skPosition.x());
446         position.SetY(skPosition.y());
447         tangent.SetX(skTangent.x());
448         tangent.SetY(skTangent.y());
449     }
450 
451     return ret;
452 }
453 
GetSegment(scalar start,scalar stop,Path * dst,bool startWithMoveTo,bool forceClosed)454 bool SkiaPath::GetSegment(scalar start, scalar stop, Path* dst, bool startWithMoveTo, bool forceClosed)
455 {
456     if (dst == nullptr) {
457         return false;
458     }
459     auto skiaPath = dst->GetImpl<SkiaPath>();
460     if (skiaPath == nullptr) {
461         return false;
462     }
463     PathMeasureUpdate(forceClosed);
464     return pathMeasure_->getSegment(start, stop, &skiaPath->GetMutablePath(), startWithMoveTo);
465 }
466 
IsClosed(bool forceClosed)467 bool SkiaPath::IsClosed(bool forceClosed)
468 {
469     PathMeasureUpdate(forceClosed);
470     return pathMeasure_->isClosed();
471 }
472 
GetMatrix(bool forceClosed,float distance,Matrix * matrix,PathMeasureMatrixFlags flag)473 bool SkiaPath::GetMatrix(bool forceClosed, float distance, Matrix* matrix, PathMeasureMatrixFlags flag)
474 {
475     if (matrix == nullptr) {
476         return false;
477     }
478     PathMeasureUpdate(forceClosed);
479     SkPathMeasure::MatrixFlags skFlag = SkPathMeasure::kGetPosAndTan_MatrixFlag;
480     if (flag == PathMeasureMatrixFlags::GET_POSITION_MATRIX) {
481         skFlag = SkPathMeasure::kGetPosition_MatrixFlag;
482     } else if (flag == PathMeasureMatrixFlags::GET_TANGENT_MATRIX) {
483         skFlag = SkPathMeasure::kGetTangent_MatrixFlag;
484     }
485     return pathMeasure_->getMatrix(distance,
486         &matrix->GetImpl<SkiaMatrix>()->ExportMatrix(), skFlag);
487 }
488 
Serialize() const489 std::shared_ptr<Data> SkiaPath::Serialize() const
490 {
491     if (path_.isEmpty()) {
492         LOGE("SkiaPath::Serialize, path is empty!");
493     }
494     SkBinaryWriteBuffer writer;
495     writer.writePath(path_);
496     size_t length = writer.bytesWritten();
497     std::shared_ptr<Data> data = std::make_shared<Data>();
498     data->BuildUninitialized(length);
499     writer.writeToMemory(data->WritableData());
500     return data;
501 }
502 
Deserialize(std::shared_ptr<Data> data)503 bool SkiaPath::Deserialize(std::shared_ptr<Data> data)
504 {
505     if (data == nullptr) {
506         LOGE("SkiaPath::Deserialize, data is invalid!");
507         return false;
508     }
509 
510     SkReadBuffer reader(data->GetData(), data->GetSize());
511     reader.readPath(&path_);
512     return true;
513 }
514 
515 } // namespace Drawing
516 } // namespace Rosen
517 } // namespace OHOS
518