@react-native-ohos/react-native-clippathview 1.1.9-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/harmony/clipPath/BuildProfile.ets +6 -0
- package/harmony/clipPath/LICENSE +21 -0
- package/harmony/clipPath/OAT.xml +39 -0
- package/harmony/clipPath/README.OpenSource +11 -0
- package/harmony/clipPath/ResourceTable.txt +0 -0
- package/harmony/clipPath/build-profile.json5 +11 -0
- package/harmony/clipPath/consumer-rules.txt +0 -0
- package/harmony/clipPath/hvigorfile.ts +6 -0
- package/harmony/clipPath/index.ets +15 -0
- package/harmony/clipPath/obfuscation-rules.txt +18 -0
- package/harmony/clipPath/oh-package.json5 +14 -0
- package/harmony/clipPath/src/main/cpp/CMakeLists.txt +7 -0
- package/harmony/clipPath/src/main/cpp/ClipPathProps.h +127 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewComponentInstance.cpp +102 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewComponentInstance.h +33 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewJSIBinder.h +60 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNapiBinder.h +79 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNoneComponentInstance.cpp +102 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNoneComponentInstance.h +38 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNoneJSIBinder.h +61 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNoneNapiBinder.h +80 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNoneNode.cpp +381 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewNoneNode.h +98 -0
- package/harmony/clipPath/src/main/cpp/ClipPathViewPackage.h +85 -0
- package/harmony/clipPath/src/main/cpp/ComponentDescriptors.h +30 -0
- package/harmony/clipPath/src/main/cpp/ModUtil.cpp +47 -0
- package/harmony/clipPath/src/main/cpp/ModUtil.h +36 -0
- package/harmony/clipPath/src/main/cpp/Props.cpp +95 -0
- package/harmony/clipPath/src/main/cpp/Props.h +108 -0
- package/harmony/clipPath/src/main/cpp/RNCClipPathTurboModule.cpp +38 -0
- package/harmony/clipPath/src/main/cpp/RNCClipPathTurboModule.h +37 -0
- package/harmony/clipPath/src/main/cpp/SVGPathParser.cpp +617 -0
- package/harmony/clipPath/src/main/cpp/SVGPathParser.h +71 -0
- package/harmony/clipPath/src/main/cpp/SVGViewBox.cpp +94 -0
- package/harmony/clipPath/src/main/cpp/SVGViewBox.h +32 -0
- package/harmony/clipPath/src/main/cpp/ShadowNodes.cpp +22 -0
- package/harmony/clipPath/src/main/cpp/ShadowNodes.h +41 -0
- package/harmony/clipPath/src/main/cpp/pen_style_node.h +10 -0
- package/harmony/clipPath/src/main/ets/ClipPathPackage.ts +46 -0
- package/harmony/clipPath/src/main/ets/ClipPathTurboModule.ts +32 -0
- package/harmony/clipPath/src/main/module.json5 +7 -0
- package/harmony/clipPath/src/main/resources/base/element/string.json +8 -0
- package/harmony/clipPath/src/main/resources/en_US/element/string.json +8 -0
- package/harmony/clipPath/src/main/resources/zh_CN/element/string.json +8 -0
- package/harmony/clipPath/ts.ts +26 -0
- package/harmony/clipPath.har +0 -0
- package/index.d.ts +58 -0
- package/index.js +5 -0
- package/package.json +64 -0
- package/react-native-clippath.podspec +30 -0
- package/src/ClipPath.android.js +7 -0
- package/src/ClipPath.ios.js +5 -0
- package/src/ClipPath.web.js +5 -0
- package/src/ClipPathH.android.js +6 -0
- package/src/ClipPathH.ios.js +5 -0
- package/src/ClipPathH.web.js +5 -0
- package/src/ClipPathMobile.js +6 -0
- package/src/ClipPathMobileN.js +6 -0
- package/src/ClipPathNativeComponent.ts +48 -0
- package/src/ClipPathWeb.js +345 -0
- package/src/demo.jpg +0 -0
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2022 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 "SVGPathParser.h"
|
|
17
|
+
#include <native_drawing/drawing_path.h>
|
|
18
|
+
#include <stdexcept>
|
|
19
|
+
#include <sstream>
|
|
20
|
+
#include "math.h"
|
|
21
|
+
#include <cctype>
|
|
22
|
+
#include "cmath"
|
|
23
|
+
#include "vector"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
namespace rnoh {
|
|
27
|
+
float SVGPathParser::mScale = 0.0f;
|
|
28
|
+
int SVGPathParser::i = 0;
|
|
29
|
+
int SVGPathParser::l = 0;
|
|
30
|
+
std::string SVGPathParser::s = "";
|
|
31
|
+
float SVGPathParser::mPenX = 0.0f;
|
|
32
|
+
float SVGPathParser::mPenY = 0.0f;
|
|
33
|
+
float SVGPathParser::mPivotX = 0.0f;
|
|
34
|
+
float SVGPathParser::mPivotY = 0.0f;
|
|
35
|
+
float SVGPathParser::mPenDownX = 0.0f;
|
|
36
|
+
float SVGPathParser::mPenDownY = 0.0f;
|
|
37
|
+
bool SVGPathParser::mPenDown = false;
|
|
38
|
+
|
|
39
|
+
OH_Drawing_Path *SVGPathParser::parse(const std::string d) {
|
|
40
|
+
if (d.empty()) {
|
|
41
|
+
return nullptr;
|
|
42
|
+
}
|
|
43
|
+
OH_Drawing_Path *cPath_ = OH_Drawing_PathCreate();
|
|
44
|
+
char prev_cmd = ' ';
|
|
45
|
+
l = d.length();
|
|
46
|
+
s = d;
|
|
47
|
+
i = 0;
|
|
48
|
+
|
|
49
|
+
mPenX = 0.f;
|
|
50
|
+
mPenY = 0.f;
|
|
51
|
+
mPivotX = 0.f;
|
|
52
|
+
mPivotY = 0.f;
|
|
53
|
+
mPenDownX = 0.f;
|
|
54
|
+
mPenDownY = 0.f;
|
|
55
|
+
mPenDown = false;
|
|
56
|
+
|
|
57
|
+
while (i < l) {
|
|
58
|
+
skip_spaces();
|
|
59
|
+
|
|
60
|
+
if (i >= l) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
bool has_prev_cmd = prev_cmd != ' ';
|
|
65
|
+
char first_char = s.at(i);
|
|
66
|
+
|
|
67
|
+
if (!has_prev_cmd && first_char != 'M' && first_char != 'm') {
|
|
68
|
+
// The first segment must be a MoveTo.
|
|
69
|
+
std::ostringstream oss;
|
|
70
|
+
oss << "Unexpected character" << first_char << ",i=" << i << ",s=" << s;
|
|
71
|
+
throw std::logic_error(oss.str());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// TODO: simplify
|
|
75
|
+
bool is_implicit_move_to;
|
|
76
|
+
char cmd;
|
|
77
|
+
if (is_cmd(first_char)) {
|
|
78
|
+
is_implicit_move_to = false;
|
|
79
|
+
cmd = first_char;
|
|
80
|
+
i += 1;
|
|
81
|
+
} else if (is_number_start(first_char) && has_prev_cmd) {
|
|
82
|
+
if (prev_cmd == 'Z' || prev_cmd == 'z') {
|
|
83
|
+
// ClosePath cannot be followed by a number.
|
|
84
|
+
std::ostringstream oss;
|
|
85
|
+
oss << "Unexpected number after 'z' (s=" << s << ")";
|
|
86
|
+
throw std::logic_error(oss.str());
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (prev_cmd == 'M' || prev_cmd == 'm') {
|
|
90
|
+
// 'If a moveto is followed by multiple pairs of coordinates,
|
|
91
|
+
// the subsequent pairs are treated as implicit lineto commands.'
|
|
92
|
+
// So we parse them as LineTo.
|
|
93
|
+
is_implicit_move_to = true;
|
|
94
|
+
if (is_absolute(prev_cmd)) {
|
|
95
|
+
cmd = 'L';
|
|
96
|
+
} else {
|
|
97
|
+
cmd = 'l';
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
is_implicit_move_to = false;
|
|
101
|
+
cmd = prev_cmd;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
std::ostringstream oss;
|
|
105
|
+
oss << "Unexpected character" << first_char << ",i=" << i << ",s=" << s;
|
|
106
|
+
throw std::logic_error(oss.str());
|
|
107
|
+
}
|
|
108
|
+
bool absolute = is_absolute(cmd);
|
|
109
|
+
switch (cmd) {
|
|
110
|
+
case 'm': {
|
|
111
|
+
rnoh:
|
|
112
|
+
move(parse_list_number(), parse_list_number(), cPath_);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case 'M': {
|
|
116
|
+
moveTo(parse_list_number(), parse_list_number(), cPath_);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case 'l': {
|
|
120
|
+
line(parse_list_number(), parse_list_number(), cPath_);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case 'L': {
|
|
124
|
+
lineTo(parse_list_number(), parse_list_number(), cPath_);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
case 'h': {
|
|
128
|
+
line(parse_list_number(), 0, cPath_);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'H': {
|
|
132
|
+
lineTo(parse_list_number(), mPenY, cPath_);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'v': {
|
|
136
|
+
line(0, parse_list_number(), cPath_);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case 'V': {
|
|
140
|
+
lineTo(mPenX, parse_list_number(), cPath_);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case 'c': {
|
|
144
|
+
curve(parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(),
|
|
145
|
+
parse_list_number(), parse_list_number(), cPath_);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'C': {
|
|
149
|
+
curveTo(parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(),
|
|
150
|
+
parse_list_number(), parse_list_number(), cPath_);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
case 's': {
|
|
154
|
+
smoothCurve(parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(), cPath_);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case 'S': {
|
|
158
|
+
smoothCurveTo(parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(), cPath_);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
case 'q': {
|
|
162
|
+
quadraticBezierCurve(parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(),
|
|
163
|
+
cPath_);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'Q': {
|
|
167
|
+
quadraticBezierCurveTo(parse_list_number(), parse_list_number(), parse_list_number(), parse_list_number(),
|
|
168
|
+
cPath_);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 't': {
|
|
172
|
+
smoothQuadraticBezierCurve(parse_list_number(), parse_list_number(), cPath_);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case 'T': {
|
|
176
|
+
smoothQuadraticBezierCurveTo(parse_list_number(), parse_list_number(), cPath_);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case 'a': {
|
|
180
|
+
arc(parse_list_number(), parse_list_number(), parse_list_number(), parse_flag(), parse_flag(),
|
|
181
|
+
parse_list_number(), parse_list_number(), cPath_);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case 'A': {
|
|
185
|
+
arcTo(parse_list_number(), parse_list_number(), parse_list_number(), parse_flag(), parse_flag(),
|
|
186
|
+
parse_list_number(), parse_list_number(), cPath_);
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'z':
|
|
190
|
+
case 'Z': {
|
|
191
|
+
close(cPath_);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
default: {
|
|
195
|
+
std::ostringstream oss;
|
|
196
|
+
oss << "Unexpected comand " << cmd << ",s=" << s << ")";
|
|
197
|
+
throw std::logic_error(oss.str());
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (is_implicit_move_to) {
|
|
202
|
+
if (absolute) {
|
|
203
|
+
prev_cmd = 'M';
|
|
204
|
+
} else {
|
|
205
|
+
prev_cmd = 'm';
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
prev_cmd = cmd;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return cPath_;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
void SVGPathParser::move(float x, float y, OH_Drawing_Path *cPath_) { moveTo(x + mPenX, y + mPenY, cPath_); }
|
|
215
|
+
|
|
216
|
+
void SVGPathParser::moveTo(float x, float y, OH_Drawing_Path *cPath_) {
|
|
217
|
+
mPenDownX = mPivotX = mPenX = x;
|
|
218
|
+
mPenDownY = mPivotY = mPenY = y;
|
|
219
|
+
OH_Drawing_PathMoveTo(cPath_, x * mScale, y * mScale);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
void SVGPathParser::line(float x, float y, OH_Drawing_Path *cPath_) { lineTo(x + mPenX, y + mPenY, cPath_); }
|
|
223
|
+
void SVGPathParser::lineTo(float x, float y, OH_Drawing_Path *cPath_) {
|
|
224
|
+
// FLog.w(ReactConstants.TAG, "line x: " + x + " y: " + y);
|
|
225
|
+
setPenDown();
|
|
226
|
+
mPivotX = mPenX = x;
|
|
227
|
+
mPivotY = mPenY = y;
|
|
228
|
+
OH_Drawing_PathLineTo(cPath_, x * mScale, y * mScale);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void SVGPathParser::curve(float c1x, float c1y, float c2x, float c2y, float ex, float ey, OH_Drawing_Path *cPath_) {
|
|
232
|
+
curveTo(c1x + mPenX, c1y + mPenY, c2x + mPenX, c2y + mPenY, ex + mPenX, ey + mPenY, cPath_);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
void SVGPathParser::curveTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey, OH_Drawing_Path *cPath_) {
|
|
236
|
+
mPivotX = c2x;
|
|
237
|
+
mPivotY = c2y;
|
|
238
|
+
cubicTo(c1x, c1y, c2x, c2y, ex, ey, cPath_);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
void SVGPathParser::cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey, OH_Drawing_Path *cPath_) {
|
|
242
|
+
setPenDown();
|
|
243
|
+
mPenX = ex;
|
|
244
|
+
mPenY = ey;
|
|
245
|
+
OH_Drawing_PathCubicTo(cPath_, c1x * mScale, c1y * mScale, c2x * mScale, c2y * mScale, ex * mScale, ey * mScale);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
void SVGPathParser::smoothCurve(float c1x, float c1y, float ex, float ey, OH_Drawing_Path *cPath_) {
|
|
250
|
+
smoothCurveTo(c1x + mPenX, c1y + mPenY, ex + mPenX, ey + mPenY, cPath_);
|
|
251
|
+
}
|
|
252
|
+
void SVGPathParser::smoothCurveTo(float c1x, float c1y, float ex, float ey, OH_Drawing_Path *cPath_) {
|
|
253
|
+
// FLog.w(ReactConstants.TAG, "smoothcurve c1x: " + c1x + " c1y: " + c1y + "ex: " + ex + " ey: " + ey);
|
|
254
|
+
float c2x = c1x;
|
|
255
|
+
float c2y = c1y;
|
|
256
|
+
c1x = (mPenX * 2) - mPivotX;
|
|
257
|
+
c1y = (mPenY * 2) - mPivotY;
|
|
258
|
+
mPivotX = c2x;
|
|
259
|
+
mPivotY = c2y;
|
|
260
|
+
cubicTo(c1x, c1y, c2x, c2y, ex, ey, cPath_);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
void SVGPathParser::quadraticBezierCurve(float c1x, float c1y, float c2x, float c2y, OH_Drawing_Path *cPath_) {
|
|
264
|
+
quadraticBezierCurveTo(c1x + mPenX, c1y + mPenY, c2x + mPenX, c2y + mPenY, cPath_);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
void SVGPathParser::quadraticBezierCurveTo(float c1x, float c1y, float c2x, float c2y, OH_Drawing_Path *cPath_) {
|
|
268
|
+
// FLog.w(ReactConstants.TAG, "quad c1x: " + c1x + " c1y: " + c1y + "c2x: " + c2x + " c2y: " + c2y);
|
|
269
|
+
mPivotX = c1x;
|
|
270
|
+
mPivotY = c1y;
|
|
271
|
+
float ex = c2x;
|
|
272
|
+
float ey = c2y;
|
|
273
|
+
c2x = (ex + c1x * 2) / 3;
|
|
274
|
+
c2y = (ey + c1y * 2) / 3;
|
|
275
|
+
c1x = (mPenX + c1x * 2) / 3;
|
|
276
|
+
c1y = (mPenY + c1y * 2) / 3;
|
|
277
|
+
cubicTo(c1x, c1y, c2x, c2y, ex, ey, cPath_);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
void SVGPathParser::smoothQuadraticBezierCurve(float c1x, float c1y, OH_Drawing_Path *cPath_) {
|
|
281
|
+
smoothQuadraticBezierCurveTo(c1x + mPenX, c1y + mPenY, cPath_);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
void SVGPathParser::smoothQuadraticBezierCurveTo(float c1x, float c1y, OH_Drawing_Path *cPath_) {
|
|
285
|
+
// FLog.w(ReactConstants.TAG, "smoothquad c1x: " + c1x + " c1y: " + c1y);
|
|
286
|
+
float c2x = c1x;
|
|
287
|
+
float c2y = c1y;
|
|
288
|
+
c1x = (mPenX * 2) - mPivotX;
|
|
289
|
+
c1y = (mPenY * 2) - mPivotY;
|
|
290
|
+
quadraticBezierCurveTo(c1x, c1y, c2x, c2y, cPath_);
|
|
291
|
+
}
|
|
292
|
+
void SVGPathParser::arc(float rx, float ry, float rotation, bool outer, bool clockwise, float x, float y,
|
|
293
|
+
OH_Drawing_Path *cPath_) {
|
|
294
|
+
arcTo(rx, ry, rotation, outer, clockwise, x + mPenX, y + mPenY, cPath_);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
void SVGPathParser::arcTo(float rx, float ry, float rotation, bool outer, bool clockwise, float x, float y,
|
|
298
|
+
OH_Drawing_Path *cPath_) {
|
|
299
|
+
// FLog.w(ReactConstants.TAG, "arc rx: " + rx + " ry: " + ry + " rotation: " + rotation + " outer: " + outer + "
|
|
300
|
+
// clockwise: " + clockwise + " x: " + x + " y: " + y);
|
|
301
|
+
float tX = mPenX;
|
|
302
|
+
float tY = mPenY;
|
|
303
|
+
|
|
304
|
+
ry = abs(ry == 0 ? (rx == 0 ? (y - tY) : rx) : ry);
|
|
305
|
+
rx = abs(rx == 0 ? (x - tX) : rx);
|
|
306
|
+
|
|
307
|
+
if (rx == 0 || ry == 0 || (x == tX && y == tY)) {
|
|
308
|
+
lineTo(x, y, cPath_);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
float rad = static_cast<float>(rotation * (M_PI / 180.0));
|
|
313
|
+
float cos = std::cos(rad);
|
|
314
|
+
float sin = std::sin(rad);
|
|
315
|
+
x -= tX;
|
|
316
|
+
y -= tY;
|
|
317
|
+
|
|
318
|
+
// Ellipse Center
|
|
319
|
+
float cx = cos * x / 2 + sin * y / 2;
|
|
320
|
+
float cy = -sin * x / 2 + cos * y / 2;
|
|
321
|
+
float rxry = rx * rx * ry * ry;
|
|
322
|
+
float rycx = ry * ry * cx * cx;
|
|
323
|
+
float rxcy = rx * rx * cy * cy;
|
|
324
|
+
float a = rxry - rxcy - rycx;
|
|
325
|
+
|
|
326
|
+
if (a < 0) {
|
|
327
|
+
a = std::sqrt(1 - a / rxry);
|
|
328
|
+
rx *= a;
|
|
329
|
+
ry *= a;
|
|
330
|
+
cx = x / 2;
|
|
331
|
+
cy = y / 2;
|
|
332
|
+
} else {
|
|
333
|
+
a = std::sqrt(a / (rxcy + rycx));
|
|
334
|
+
|
|
335
|
+
if (outer == clockwise) {
|
|
336
|
+
a = -a;
|
|
337
|
+
}
|
|
338
|
+
float cxd = -a * cy * rx / ry;
|
|
339
|
+
float cyd = a * cx * ry / rx;
|
|
340
|
+
cx = cos * cxd - sin * cyd + x / 2;
|
|
341
|
+
cy = sin * cxd + cos * cyd + y / 2;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Rotation + Scale Transform
|
|
345
|
+
float xx = cos / rx;
|
|
346
|
+
float yx = sin / rx;
|
|
347
|
+
float xy = -sin / ry;
|
|
348
|
+
float yy = cos / ry;
|
|
349
|
+
|
|
350
|
+
// Start and End Angle
|
|
351
|
+
float sa = std::atan2(xy * -cx + yy * -cy, xx * -cx + yx * -cy);
|
|
352
|
+
float ea = std::atan2(xy * (x - cx) + yy * (y - cy), xx * (x - cx) + yx * (y - cy));
|
|
353
|
+
|
|
354
|
+
cx += tX;
|
|
355
|
+
cy += tY;
|
|
356
|
+
x += tX;
|
|
357
|
+
y += tY;
|
|
358
|
+
|
|
359
|
+
setPenDown();
|
|
360
|
+
|
|
361
|
+
mPenX = mPivotX = x;
|
|
362
|
+
mPenY = mPivotY = y;
|
|
363
|
+
|
|
364
|
+
if (rx != ry || rad != 0.f) {
|
|
365
|
+
arcToBezier(cx, cy, rx, ry, sa, ea, clockwise, rad, cPath_);
|
|
366
|
+
} else {
|
|
367
|
+
|
|
368
|
+
float start = static_cast<float>(sa * 180.0 / M_PI);
|
|
369
|
+
float end = static_cast<float>(ea * 180.0 / M_PI);
|
|
370
|
+
float sweep = abs((start - end) - std::floor((start - end) / 360) * 360);
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
if (outer) {
|
|
374
|
+
if (sweep < 180) {
|
|
375
|
+
sweep = 360 - sweep;
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
if (sweep > 180) {
|
|
379
|
+
sweep = 360 - sweep;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (!clockwise) {
|
|
384
|
+
sweep = -sweep;
|
|
385
|
+
}
|
|
386
|
+
OH_Drawing_PathArcTo(cPath_, (cx - rx) * mScale, (cy - rx) * mScale, (cx + rx) * mScale, (cy + rx) * mScale,
|
|
387
|
+
start, sweep);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
void SVGPathParser::setPenDown() {
|
|
391
|
+
if (!mPenDown) {
|
|
392
|
+
mPenDownX = mPenX;
|
|
393
|
+
mPenDownY = mPenY;
|
|
394
|
+
mPenDown = true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
void SVGPathParser::close(OH_Drawing_Path *cPath_) {
|
|
398
|
+
if (mPenDown) {
|
|
399
|
+
mPenX = mPenDownX;
|
|
400
|
+
mPenY = mPenDownY;
|
|
401
|
+
mPenDown = false;
|
|
402
|
+
OH_Drawing_PathClose(cPath_);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
void SVGPathParser::arcToBezier(float cx, float cy, float rx, float ry, float sa, float ea, bool clockwise, float rad,
|
|
406
|
+
OH_Drawing_Path *cPath_) {
|
|
407
|
+
// Inverse Rotation + Scale Transform
|
|
408
|
+
float cos = std::cos(rad);
|
|
409
|
+
float sin = std::sin(rad);
|
|
410
|
+
float xx = cos * rx;
|
|
411
|
+
float yx = -sin * ry;
|
|
412
|
+
float xy = sin * rx;
|
|
413
|
+
float yy = cos * ry;
|
|
414
|
+
|
|
415
|
+
// Bezier Curve Approximation
|
|
416
|
+
float arc = ea - sa;
|
|
417
|
+
if (arc < 0 && clockwise) {
|
|
418
|
+
arc += M_PI * 2;
|
|
419
|
+
} else if (arc > 0 && !clockwise) {
|
|
420
|
+
arc -= M_PI * 2;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
int n = (int)std::ceil(std::abs(round(arc / (M_PI / 2))));
|
|
424
|
+
|
|
425
|
+
float step = arc / n;
|
|
426
|
+
float k = (float)((4 / 3.0) * std::tan(step / 4));
|
|
427
|
+
float x = std::cos(sa);
|
|
428
|
+
float y = std::sin(sa);
|
|
429
|
+
|
|
430
|
+
for (int i = 0; i < n; i++) {
|
|
431
|
+
float cp1x = x - k * y;
|
|
432
|
+
float cp1y = y + k * x;
|
|
433
|
+
|
|
434
|
+
sa += step;
|
|
435
|
+
x = std::cos(sa);
|
|
436
|
+
y = std::sin(sa);
|
|
437
|
+
|
|
438
|
+
float cp2x = x + k * y;
|
|
439
|
+
float cp2y = y - k * x;
|
|
440
|
+
|
|
441
|
+
float c1x = (cx + xx * cp1x + yx * cp1y);
|
|
442
|
+
float c1y = (cy + xy * cp1x + yy * cp1y);
|
|
443
|
+
float c2x = (cx + xx * cp2x + yx * cp2y);
|
|
444
|
+
float c2y = (cy + xy * cp2x + yy * cp2y);
|
|
445
|
+
float ex = (cx + xx * x + yx * y);
|
|
446
|
+
float ey = (cy + xy * x + yy * y);
|
|
447
|
+
OH_Drawing_PathCubicTo(cPath_, c1x * mScale, c1y * mScale, c2x * mScale, c2y * mScale, ex * mScale,
|
|
448
|
+
ey * mScale);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
double SVGPathParser::_round(double val) {
|
|
453
|
+
double multiplier = pow(10, 4);
|
|
454
|
+
return round(val * multiplier) / multiplier;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
void SVGPathParser::skip_spaces() {
|
|
458
|
+
while (i < l && std::isspace(s.at(i)))
|
|
459
|
+
i++;
|
|
460
|
+
}
|
|
461
|
+
bool SVGPathParser::is_cmd(char c) {
|
|
462
|
+
switch (c) {
|
|
463
|
+
case 'M':
|
|
464
|
+
case 'm':
|
|
465
|
+
case 'Z':
|
|
466
|
+
case 'z':
|
|
467
|
+
case 'L':
|
|
468
|
+
case 'l':
|
|
469
|
+
case 'H':
|
|
470
|
+
case 'h':
|
|
471
|
+
case 'V':
|
|
472
|
+
case 'v':
|
|
473
|
+
case 'C':
|
|
474
|
+
case 'c':
|
|
475
|
+
case 'S':
|
|
476
|
+
case 's':
|
|
477
|
+
case 'Q':
|
|
478
|
+
case 'q':
|
|
479
|
+
case 'T':
|
|
480
|
+
case 't':
|
|
481
|
+
case 'A':
|
|
482
|
+
case 'a':
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
bool SVGPathParser::is_number_start(char c) { return (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+'; }
|
|
490
|
+
|
|
491
|
+
bool SVGPathParser::is_absolute(char c) { return std::isupper(c); }
|
|
492
|
+
// By the SVG spec 'large-arc' and 'sweep' must contain only one char
|
|
493
|
+
// and can be written without any separators, e.g.: 10 20 30 01 10 20.
|
|
494
|
+
|
|
495
|
+
bool SVGPathParser::parse_flag() {
|
|
496
|
+
skip_spaces();
|
|
497
|
+
|
|
498
|
+
char c = s.at(i);
|
|
499
|
+
switch (c) {
|
|
500
|
+
case '0':
|
|
501
|
+
case '1': {
|
|
502
|
+
i += 1;
|
|
503
|
+
if (i < l && s.at(i) == ',') {
|
|
504
|
+
i += 1;
|
|
505
|
+
}
|
|
506
|
+
skip_spaces();
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
default:
|
|
510
|
+
std::ostringstream oss;
|
|
511
|
+
oss << "Unexpected flag" << c << ",i=" << i << ",s=" << s;
|
|
512
|
+
throw std::logic_error(oss.str());
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return c == '1';
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
float SVGPathParser::parse_list_number() {
|
|
520
|
+
if (i == l) {
|
|
521
|
+
std::ostringstream oss;
|
|
522
|
+
oss << "Unexpected end (s=" << s << ")";
|
|
523
|
+
throw std::logic_error(oss.str());
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
float n = parse_number();
|
|
527
|
+
skip_spaces();
|
|
528
|
+
parse_list_separator();
|
|
529
|
+
|
|
530
|
+
return n;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
float SVGPathParser::parse_number() {
|
|
534
|
+
// Strip off leading whitespaces.
|
|
535
|
+
skip_spaces();
|
|
536
|
+
|
|
537
|
+
if (i == l) {
|
|
538
|
+
std::ostringstream oss;
|
|
539
|
+
oss << "Unexpected end (s=" << s << ")";
|
|
540
|
+
throw std::logic_error(oss.str());
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
int start = i;
|
|
544
|
+
|
|
545
|
+
char c = s.at(i);
|
|
546
|
+
|
|
547
|
+
// Consume sign.
|
|
548
|
+
if (c == '-' || c == '+') {
|
|
549
|
+
i += 1;
|
|
550
|
+
c = s.at(i);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Consume integer.
|
|
554
|
+
if (c >= '0' && c <= '9') {
|
|
555
|
+
skip_digits();
|
|
556
|
+
if (i < l) {
|
|
557
|
+
c = s.at(i);
|
|
558
|
+
}
|
|
559
|
+
} else if (c != '.') {
|
|
560
|
+
std::ostringstream oss;
|
|
561
|
+
oss << "Invalid number formating character " << c << ",i=" << i << ",s=" << s;
|
|
562
|
+
throw std::logic_error(oss.str());
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Consume fraction.
|
|
566
|
+
if (c == '.') {
|
|
567
|
+
i += 1;
|
|
568
|
+
skip_digits();
|
|
569
|
+
if (i < l) {
|
|
570
|
+
c = s.at(i);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if ((c == 'e' || c == 'E') && i + 1 < l) {
|
|
575
|
+
char c2 = s.at(i + 1);
|
|
576
|
+
// Check for `em`/`ex`.
|
|
577
|
+
if (c2 != 'm' && c2 != 'x') {
|
|
578
|
+
i += 1;
|
|
579
|
+
c = s.at(i);
|
|
580
|
+
|
|
581
|
+
if (c == '+' || c == '-') {
|
|
582
|
+
i += 1;
|
|
583
|
+
skip_digits();
|
|
584
|
+
} else if (c >= '0' && c <= '9') {
|
|
585
|
+
skip_digits();
|
|
586
|
+
} else {
|
|
587
|
+
std::ostringstream oss;
|
|
588
|
+
oss << "Invalid number formating character " << c << ",i=" << i << ",s=" << s;
|
|
589
|
+
throw std::logic_error(oss.str());
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
std::string num = s.substr(start, i);
|
|
595
|
+
float n = std::stof(num);
|
|
596
|
+
|
|
597
|
+
// inf, nan, etc. are an error.
|
|
598
|
+
if (std::isinf(n) || std::isnan(n)) {
|
|
599
|
+
std::ostringstream oss;
|
|
600
|
+
oss << "Invalid number" << num << ",start=" << start << ",i=" << i << ",s=" << s;
|
|
601
|
+
throw std::logic_error(oss.str());
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return n;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
void SVGPathParser::parse_list_separator() {
|
|
608
|
+
if (i < l && s.at(i) == ',') {
|
|
609
|
+
i += 1;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
void SVGPathParser::skip_digits() {
|
|
614
|
+
while (i < l && std::isdigit(s.at(i)))
|
|
615
|
+
i++;
|
|
616
|
+
}
|
|
617
|
+
}; // namespace rnoh
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2022 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 HARMONY_SVGPATHPARSER_H
|
|
17
|
+
#define HARMONY_SVGPATHPARSER_H
|
|
18
|
+
#include <native_drawing/drawing_types.h>
|
|
19
|
+
#include <string>
|
|
20
|
+
|
|
21
|
+
namespace rnoh {
|
|
22
|
+
class SVGPathParser {
|
|
23
|
+
public:
|
|
24
|
+
static float mScale;
|
|
25
|
+
static OH_Drawing_Path *parse(const std::string d);
|
|
26
|
+
|
|
27
|
+
private:
|
|
28
|
+
static int i;
|
|
29
|
+
static int l;
|
|
30
|
+
static std::string s;
|
|
31
|
+
static float mPenX;
|
|
32
|
+
static float mPenY;
|
|
33
|
+
static float mPivotX;
|
|
34
|
+
static float mPivotY;
|
|
35
|
+
static float mPenDownX;
|
|
36
|
+
static float mPenDownY;
|
|
37
|
+
static bool mPenDown;
|
|
38
|
+
static void move(float x, float y, OH_Drawing_Path *cPath_);
|
|
39
|
+
static void moveTo(float x, float y, OH_Drawing_Path *cPath_);
|
|
40
|
+
static void line(float x, float y, OH_Drawing_Path *cPath_);
|
|
41
|
+
static void lineTo(float x, float y, OH_Drawing_Path *cPath_);
|
|
42
|
+
static void curve(float c1x, float c1y, float c2x, float c2y, float ex, float ey, OH_Drawing_Path *cPath_);
|
|
43
|
+
static void curveTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey, OH_Drawing_Path *cPath_);
|
|
44
|
+
static void cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey, OH_Drawing_Path *cPath_);
|
|
45
|
+
static void smoothCurve(float c1x, float c1y, float ex, float ey, OH_Drawing_Path *cPath_);
|
|
46
|
+
static void smoothCurveTo(float c1x, float c1y, float ex, float ey, OH_Drawing_Path *cPath_);
|
|
47
|
+
static void quadraticBezierCurve(float c1x, float c1y, float c2x, float c2y, OH_Drawing_Path *cPath_);
|
|
48
|
+
static void quadraticBezierCurveTo(float c1x, float c1y, float c2x, float c2y, OH_Drawing_Path *cPath_);
|
|
49
|
+
static void smoothQuadraticBezierCurve(float c1x, float c1y, OH_Drawing_Path *cPath_);
|
|
50
|
+
static void smoothQuadraticBezierCurveTo(float c1x, float c1y, OH_Drawing_Path *cPath_);
|
|
51
|
+
static void arc(float rx, float ry, float rotation, bool outer, bool clockwise, float x, float y,
|
|
52
|
+
OH_Drawing_Path *cPath_);
|
|
53
|
+
static void arcTo(float rx, float ry, float rotation, bool outer, bool clockwise, float x, float y,
|
|
54
|
+
OH_Drawing_Path *cPath_);
|
|
55
|
+
static void close(OH_Drawing_Path *cPath_);
|
|
56
|
+
static void arcToBezier(float cx, float cy, float rx, float ry, float sa, float ea, bool clockwise, float rad,
|
|
57
|
+
OH_Drawing_Path *cPath_);
|
|
58
|
+
static void setPenDown();
|
|
59
|
+
static double _round(double val);
|
|
60
|
+
static void skip_spaces();
|
|
61
|
+
static bool is_cmd(char c);
|
|
62
|
+
static bool is_number_start(char c);
|
|
63
|
+
static bool is_absolute(char c);
|
|
64
|
+
static bool parse_flag();
|
|
65
|
+
static float parse_list_number();
|
|
66
|
+
static float parse_number();
|
|
67
|
+
static void parse_list_separator();
|
|
68
|
+
static void skip_digits();
|
|
69
|
+
};
|
|
70
|
+
} // namespace rnoh
|
|
71
|
+
#endif // HARMONY_SVGPATHPARSER_H
|