1 /*
2 * Copyright (c) 2021-2023 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/SkPathMeasure.h"
22 #include "include/core/SkString.h"
23 #include "skia_matrix.h"
24
25 #include "src/core/SkReadBuffer.h"
26 #include "src/core/SkWriteBuffer.h"
27
28 #include "draw/path.h"
29 #include "utils/data.h"
30 #include "utils/log.h"
31
32 namespace OHOS {
33 namespace Rosen {
34 namespace Drawing {
35
SkiaPath(const SkiaPath & other)36 SkiaPath::SkiaPath(const SkiaPath& other) noexcept
37 {
38 path_ = other.path_;
39 }
40
operator =(const SkiaPath & other)41 SkiaPath& SkiaPath::operator=(const SkiaPath& other) noexcept
42 {
43 path_ = other.path_;
44 return *this;
45 }
46
Clone()47 PathImpl* SkiaPath::Clone()
48 {
49 return new SkiaPath(*this);
50 }
51
InitWithSVGString(const std::string & str)52 bool SkiaPath::InitWithSVGString(const std::string& str)
53 {
54 return SkParsePath::FromSVGString(str.c_str(), &path_);
55 }
56
ConvertToSVGString() const57 std::string SkiaPath::ConvertToSVGString() const
58 {
59 SkString skString;
60 SkParsePath::ToSVGString(path_, &skString);
61
62 return skString.c_str();
63 }
64
MoveTo(scalar x,scalar y)65 void SkiaPath::MoveTo(scalar x, scalar y)
66 {
67 path_.moveTo(x, y);
68 }
69
LineTo(scalar x,scalar y)70 void SkiaPath::LineTo(scalar x, scalar y)
71 {
72 path_.lineTo(x, y);
73 }
74
ArcTo(scalar pt1X,scalar pt1Y,scalar pt2X,scalar pt2Y,scalar startAngle,scalar sweepAngle)75 void SkiaPath::ArcTo(scalar pt1X, scalar pt1Y, scalar pt2X, scalar pt2Y, scalar startAngle, scalar sweepAngle)
76 {
77 path_.arcTo(SkRect::MakeLTRB(pt1X, pt1Y, pt2X, pt2Y), startAngle, sweepAngle, false);
78 }
79
ArcTo(scalar rx,scalar ry,scalar angle,PathDirection direction,scalar endX,scalar endY)80 void SkiaPath::ArcTo(scalar rx, scalar ry, scalar angle, PathDirection direction, scalar endX, scalar endY)
81 {
82 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
83 SkPathDirection pathDir = static_cast<SkPathDirection>(direction);
84 #else
85 SkPath::Direction pathDir = static_cast<SkPath::Direction>(direction);
86 #endif
87 SkPath::ArcSize arcLarge = SkPath::ArcSize::kSmall_ArcSize;
88 path_.arcTo(rx, ry, angle, arcLarge, pathDir, endX, endY);
89 }
90
ArcTo(scalar x1,scalar y1,scalar x2,scalar y2,scalar radius)91 void SkiaPath::ArcTo(scalar x1, scalar y1, scalar x2, scalar y2, scalar radius)
92 {
93 path_.arcTo(x1, y1, x2, y2, radius);
94 }
95
CubicTo(scalar ctrlPt1X,scalar ctrlPt1Y,scalar ctrlPt2X,scalar ctrlPt2Y,scalar endPtX,scalar endPtY)96 void SkiaPath::CubicTo(scalar ctrlPt1X, scalar ctrlPt1Y, scalar ctrlPt2X, scalar ctrlPt2Y, scalar endPtX, scalar endPtY)
97 {
98 path_.cubicTo(ctrlPt1X, ctrlPt1Y, ctrlPt2X, ctrlPt2Y, endPtX, endPtY);
99 }
100
QuadTo(scalar ctrlPtX,scalar ctrlPtY,scalar endPtX,scalar endPtY)101 void SkiaPath::QuadTo(scalar ctrlPtX, scalar ctrlPtY, scalar endPtX, scalar endPtY)
102 {
103 path_.quadTo(ctrlPtX, ctrlPtY, endPtX, endPtY);
104 }
105
RMoveTo(scalar dx,scalar dy)106 void SkiaPath::RMoveTo(scalar dx, scalar dy)
107 {
108 path_.rMoveTo(dx, dy);
109 }
110
RLineTo(scalar dx,scalar dy)111 void SkiaPath::RLineTo(scalar dx, scalar dy)
112 {
113 path_.rLineTo(dx, dy);
114 }
115
RArcTo(scalar rx,scalar ry,scalar angle,PathDirection direction,scalar dx,scalar dy)116 void SkiaPath::RArcTo(scalar rx, scalar ry, scalar angle, PathDirection direction, scalar dx, scalar dy)
117 {
118 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
119 SkPathDirection pathDir = static_cast<SkPathDirection>(direction);
120 #else
121 SkPath::Direction pathDir = static_cast<SkPath::Direction>(direction);
122 #endif
123 SkPath::ArcSize arcLarge = SkPath::ArcSize::kSmall_ArcSize;
124 path_.arcTo(rx, ry, angle, arcLarge, pathDir, dx, dy);
125 }
126
RCubicTo(scalar dx1,scalar dy1,scalar dx2,scalar dy2,scalar dx3,scalar dy3)127 void SkiaPath::RCubicTo(scalar dx1, scalar dy1, scalar dx2, scalar dy2, scalar dx3, scalar dy3)
128 {
129 path_.rCubicTo(dx1, dy1, dx2, dy2, dx3, dy3);
130 }
131
RQuadTo(scalar dx1,scalar dy1,scalar dx2,scalar dy2)132 void SkiaPath::RQuadTo(scalar dx1, scalar dy1, scalar dx2, scalar dy2)
133 {
134 path_.rQuadTo(dx1, dy1, dx2, dy2);
135 }
136
AddRect(scalar left,scalar top,scalar right,scalar bottom,PathDirection dir)137 void SkiaPath::AddRect(scalar left, scalar top, scalar right, scalar bottom, PathDirection dir)
138 {
139 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
140 SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
141 #else
142 SkPath::Direction pathDir = static_cast<SkPath::Direction>(dir);
143 #endif
144 path_.addRect(SkRect::MakeLTRB(left, top, right, bottom), pathDir);
145 }
146
AddOval(scalar left,scalar top,scalar right,scalar bottom,PathDirection dir)147 void SkiaPath::AddOval(scalar left, scalar top, scalar right, scalar bottom, PathDirection dir)
148 {
149 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
150 SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
151 #else
152 SkPath::Direction pathDir = static_cast<SkPath::Direction>(dir);
153 #endif
154 path_.addOval(SkRect::MakeLTRB(left, top, right, bottom), pathDir);
155 }
156
AddArc(scalar left,scalar top,scalar right,scalar bottom,scalar startAngle,scalar sweepAngle)157 void SkiaPath::AddArc(scalar left, scalar top, scalar right, scalar bottom, scalar startAngle, scalar sweepAngle)
158 {
159 path_.addArc(SkRect::MakeLTRB(left, top, right, bottom), startAngle, sweepAngle);
160 }
161
AddPoly(const std::vector<Point> & points,int count,bool close)162 void SkiaPath::AddPoly(const std::vector<Point>& points, int count, bool close)
163 {
164 std::vector<SkPoint> pt;
165 for (auto i = 0; i < count; ++i) {
166 pt.emplace_back(SkPoint::Make(points[i].GetX(), points[i].GetY()));
167 }
168 path_.addPoly(&pt[0], count, close);
169 }
170
AddCircle(scalar x,scalar y,scalar radius,PathDirection dir)171 void SkiaPath::AddCircle(scalar x, scalar y, scalar radius, PathDirection dir)
172 {
173 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
174 SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
175 #else
176 SkPath::Direction pathDir = static_cast<SkPath::Direction>(dir);
177 #endif
178 path_.addCircle(x, y, radius, pathDir);
179 }
180
AddRoundRect(scalar left,scalar top,scalar right,scalar bottom,scalar xRadius,scalar yRadius,PathDirection dir)181 void SkiaPath::AddRoundRect(
182 scalar left, scalar top, scalar right, scalar bottom, scalar xRadius, scalar yRadius, PathDirection dir)
183 {
184 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
185 SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
186 #else
187 SkPath::Direction pathDir = static_cast<SkPath::Direction>(dir);
188 #endif
189 path_.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), xRadius, yRadius, pathDir);
190 }
191
AddRoundRect(const RoundRect & rrect,PathDirection dir)192 void SkiaPath::AddRoundRect(const RoundRect& rrect, PathDirection dir)
193 {
194 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
195 SkPathDirection pathDir = static_cast<SkPathDirection>(dir);
196 #else
197 SkPath::Direction pathDir = static_cast<SkPath::Direction>(dir);
198 #endif
199
200 Rect rect = rrect.GetRect();
201 SkRect outer = SkRect::MakeLTRB(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
202
203 SkVector radii[4];
204 Point p;
205 p = rrect.GetCornerRadius(RoundRect::TOP_LEFT_POS);
206 radii[SkRRect::kUpperLeft_Corner] = { p.GetX(), p.GetY() };
207 p = rrect.GetCornerRadius(RoundRect::TOP_RIGHT_POS);
208 radii[SkRRect::kUpperRight_Corner] = { p.GetX(), p.GetY() };
209 p = rrect.GetCornerRadius(RoundRect::BOTTOM_RIGHT_POS);
210 radii[SkRRect::kLowerRight_Corner] = { p.GetX(), p.GetY() };
211 p = rrect.GetCornerRadius(RoundRect::BOTTOM_LEFT_POS);
212 radii[SkRRect::kLowerLeft_Corner] = { p.GetX(), p.GetY() };
213
214 SkRRect skRRect;
215 skRRect.setRectRadii(outer, radii);
216 path_.addRRect(skRRect, pathDir);
217 }
218
AddPath(const Path & src,scalar dx,scalar dy)219 void SkiaPath::AddPath(const Path& src, scalar dx, scalar dy)
220 {
221 auto skPathImpl = src.GetImpl<SkiaPath>();
222 if (skPathImpl != nullptr) {
223 path_.addPath(skPathImpl->GetPath(), dx, dy);
224 }
225 }
226
AddPath(const Path & src)227 void SkiaPath::AddPath(const Path& src)
228 {
229 auto skPathImpl = src.GetImpl<SkiaPath>();
230 if (skPathImpl != nullptr) {
231 path_.addPath(skPathImpl->GetPath());
232 }
233 }
234
Contains(scalar x,scalar y) const235 bool SkiaPath::Contains(scalar x, scalar y) const
236 {
237 return path_.contains(x, y);
238 }
239
ReverseAddPath(const Path & src)240 void SkiaPath::ReverseAddPath(const Path& src)
241 {
242 path_.reverseAddPath(src.GetImpl<SkiaPath>()->GetPath());
243 }
244
AddPathWithMatrix(const Path & src,const Matrix & matrix)245 void SkiaPath::AddPathWithMatrix(const Path& src, const Matrix& matrix)
246 {
247 auto skPathImpl = src.GetImpl<SkiaPath>();
248 auto skMatrixImpl = matrix.GetImpl<SkiaMatrix>();
249 if (skPathImpl != nullptr && skMatrixImpl != nullptr) {
250 path_.addPath(skPathImpl->GetPath(), skMatrixImpl->ExportSkiaMatrix());
251 }
252 }
253
GetBounds() const254 Rect SkiaPath::GetBounds() const
255 {
256 SkRect rect = path_.getBounds();
257 return Rect(rect.left(), rect.top(), rect.right(), rect.bottom());
258 }
259
SetFillStyle(PathFillType fillstyle)260 void SkiaPath::SetFillStyle(PathFillType fillstyle)
261 {
262 #if defined(USE_CANVASKIT0310_SKIA) || defined(NEW_SKIA)
263 SkPathFillType ft = static_cast<SkPathFillType>(fillstyle);
264 #else
265 SkPath::FillType ft = static_cast<SkPath::FillType>(fillstyle);
266 #endif
267 path_.setFillType(ft);
268 }
269
Interpolate(const Path & ending,scalar weight,Path & out)270 bool SkiaPath::Interpolate(const Path& ending, scalar weight, Path& out)
271 {
272 bool isSuccess = false;
273 auto skPathImpl1 = ending.GetImpl<SkiaPath>();
274 auto skPathImpl2 = out.GetImpl<SkiaPath>();
275 if (skPathImpl1 != nullptr && skPathImpl2 != nullptr) {
276 SkPath interp;
277 isSuccess = path_.interpolate(skPathImpl1->GetPath(), weight, &interp);
278 skPathImpl2->SetPath(interp);
279 }
280 return isSuccess;
281 }
282
InitWithInterpolate(const Path & srcPath,const Path & endingPath,scalar weight)283 bool SkiaPath::InitWithInterpolate(const Path& srcPath, const Path& endingPath, scalar weight)
284 {
285 const SkPath& srcSkPath = srcPath.GetImpl<SkiaPath>()->GetPath();
286 return srcSkPath.interpolate(endingPath.GetImpl<SkiaPath>()->GetPath(), weight, &path_);
287 }
288
Transform(const Matrix & matrix)289 void SkiaPath::Transform(const Matrix& matrix)
290 {
291 auto skMatrixImpl = matrix.GetImpl<SkiaMatrix>();
292 if (skMatrixImpl != nullptr) {
293 path_.transform(skMatrixImpl->ExportSkiaMatrix());
294 }
295 }
296
Offset(scalar dx,scalar dy)297 void SkiaPath::Offset(scalar dx, scalar dy)
298 {
299 path_.offset(dx, dy);
300 }
301
OpWith(const Path & path1,const Path & path2,PathOp op)302 bool SkiaPath::OpWith(const Path& path1, const Path& path2, PathOp op)
303 {
304 SkPathOp pathOp = static_cast<SkPathOp>(op);
305 bool isOpSuccess = false;
306
307 auto skPathImpl1 = path1.GetImpl<SkiaPath>();
308 auto skPathImpl2 = path2.GetImpl<SkiaPath>();
309 if (skPathImpl1 != nullptr && skPathImpl2 != nullptr) {
310 isOpSuccess = Op(skPathImpl1->GetPath(), skPathImpl2->GetPath(), pathOp, &path_);
311 }
312
313 if (isOpSuccess) {
314 return true;
315 }
316 return false;
317 }
318
IsValid() const319 bool SkiaPath::IsValid() const
320 {
321 return !path_.isEmpty();
322 }
323
Reset()324 void SkiaPath::Reset()
325 {
326 path_.reset();
327 }
328
Close()329 void SkiaPath::Close()
330 {
331 path_.close();
332 }
333
SetPath(const SkPath & path)334 void SkiaPath::SetPath(const SkPath& path)
335 {
336 path_ = path;
337 }
338
GetPath() const339 const SkPath& SkiaPath::GetPath() const
340 {
341 return path_;
342 }
343
GetLength(bool forceClosed) const344 scalar SkiaPath::GetLength(bool forceClosed) const
345 {
346 SkPathMeasure pathMeasure(path_, forceClosed);
347 return pathMeasure.getLength();
348 }
349
GetPositionAndTangent(scalar distance,Point & position,Point & tangent,bool forceClosed) const350 bool SkiaPath::GetPositionAndTangent(scalar distance, Point& position, Point& tangent, bool forceClosed) const
351 {
352 bool ret = false;
353 SkPoint skPosition;
354 SkVector skTangent;
355 SkPathMeasure pathMeasure(path_, forceClosed);
356 ret = pathMeasure.getPosTan(distance, &skPosition, &skTangent);
357 if (ret) {
358 position.SetX(skPosition.x());
359 position.SetY(skPosition.y());
360 tangent.SetX(skTangent.x());
361 tangent.SetY(skTangent.y());
362 }
363
364 return ret;
365 }
366
Serialize() const367 std::shared_ptr<Data> SkiaPath::Serialize() const
368 {
369 SkBinaryWriteBuffer writer;
370 writer.writePath(path_);
371 size_t length = writer.bytesWritten();
372 std::shared_ptr<Data> data = std::make_shared<Data>();
373 data->BuildUninitialized(length);
374 writer.writeToMemory(data->WritableData());
375 return data;
376 }
377
Deserialize(std::shared_ptr<Data> data)378 bool SkiaPath::Deserialize(std::shared_ptr<Data> data)
379 {
380 if (data == nullptr) {
381 LOGD("SkiaPath::Deserialize, data is invalid!");
382 return false;
383 }
384
385 SkReadBuffer reader(data->GetData(), data->GetSize());
386 reader.readPath(&path_);
387 return true;
388 }
389
390 } // namespace Drawing
391 } // namespace Rosen
392 } // namespace OHOS
393