1 /*
2 * Copyright (c) 2021 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 "frameworks/bridge/declarative_frontend/jsview/js_shape_abstract.h"
17
18 #include "base/utils/utils.h"
19 #include "bridge/declarative_frontend/jsview/models/shape_abstract_model_impl.h"
20 #include "core/common/container.h"
21 #include "core/components_ng/pattern/shape/shape_abstract_model.h"
22 #include "core/components_ng/pattern/shape/shape_abstract_model_ng.h"
23 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
24
25 namespace OHOS::Ace {
26
27 std::unique_ptr<ShapeAbstractModel> ShapeAbstractModel::instance_ = nullptr;
28
GetInstance()29 ShapeAbstractModel* ShapeAbstractModel::GetInstance()
30 {
31 if (!instance_) {
32 #ifdef NG_BUILD
33 instance_.reset(new NG::ShapeAbstractModelNG());
34 #else
35 if (Container::IsCurrentUseNewPipeline()) {
36 instance_.reset(new NG::ShapeAbstractModelNG());
37 } else {
38 instance_.reset(new Framework::ShapeAbstractModelImpl());
39 }
40 #endif
41 }
42 return instance_.get();
43 }
44
45 } // namespace OHOS::Ace
46
47 namespace OHOS::Ace::Framework {
48 namespace {
49 constexpr double DEFAULT_OPACITY = 1.0;
50 constexpr double MIN_OPACITY = 0.0;
51 } // namespace
52
SetStrokeDashArray(const JSCallbackInfo & info)53 void JSShapeAbstract::SetStrokeDashArray(const JSCallbackInfo& info)
54 {
55 if (info.Length() < 1 || !info[0]->IsArray()) {
56 LOGE("info is not array");
57 return;
58 }
59 JSRef<JSArray> array = JSRef<JSArray>::Cast(info[0]);
60 int32_t length = static_cast<int32_t>(array->Length());
61 std::vector<Dimension> dashArray;
62 for (int32_t i = 0; i < length; i++) {
63 JSRef<JSVal> value = array->GetValueAt(i);
64 Dimension dim;
65 if (ParseJsDimensionVp(value, dim)) {
66 dashArray.emplace_back(dim);
67 }
68 }
69 if (length != static_cast<int32_t>(dashArray.size())) {
70 LOGE("ParseJsDimensionVp failed");
71 return;
72 }
73 // if odd,add twice
74 if ((static_cast<uint32_t>(length) & 1)) {
75 for (int32_t i = 0; i < length; i++) {
76 dashArray.emplace_back(dashArray[i]);
77 }
78 }
79 ShapeAbstractModel::GetInstance()->SetStrokeDashArray(dashArray);
80 }
81
SetStroke(const JSCallbackInfo & info)82 void JSShapeAbstract::SetStroke(const JSCallbackInfo& info)
83 {
84 if (info.Length() < 1) {
85 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
86 return;
87 }
88 Color strokeColor;
89 if (!ParseJsColor(info[0], strokeColor)) {
90 ShapeAbstractModel::GetInstance()->SetStroke(Color::TRANSPARENT);
91 return;
92 }
93 ShapeAbstractModel::GetInstance()->SetStroke(strokeColor);
94 }
95
SetFill(const JSCallbackInfo & info)96 void JSShapeAbstract::SetFill(const JSCallbackInfo& info)
97 {
98 if (info.Length() < 1) {
99 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
100 return;
101 }
102 if (info[0]->IsString() && info[0]->ToString() == "none") {
103 ShapeAbstractModel::GetInstance()->SetFill(Color::TRANSPARENT);
104 } else {
105 Color fillColor = Color::BLACK;
106 if (ParseJsColor(info[0], fillColor)) {
107 ShapeAbstractModel::GetInstance()->SetFill(fillColor);
108 } else {
109 ShapeAbstractModel::GetInstance()->SetFill(fillColor);
110 }
111 }
112 }
113
SetStrokeDashOffset(const JSCallbackInfo & info)114 void JSShapeAbstract::SetStrokeDashOffset(const JSCallbackInfo& info)
115 {
116 if (info.Length() < 1) {
117 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
118 return;
119 }
120 Dimension offset;
121 if (!ParseJsDimensionVp(info[0], offset)) {
122 return;
123 }
124 ShapeAbstractModel::GetInstance()->SetStrokeDashOffset(offset);
125 }
126
SetStrokeLineCap(int lineCap)127 void JSShapeAbstract::SetStrokeLineCap(int lineCap)
128 {
129 ShapeAbstractModel::GetInstance()->SetStrokeLineCap(lineCap);
130 }
131
SetStrokeLineJoin(int lineJoin)132 void JSShapeAbstract::SetStrokeLineJoin(int lineJoin)
133 {
134 ShapeAbstractModel::GetInstance()->SetStrokeLineJoin(lineJoin);
135 }
136
SetStrokeMiterLimit(const JSCallbackInfo & info)137 void JSShapeAbstract::SetStrokeMiterLimit(const JSCallbackInfo& info)
138 {
139 if (info.Length() < 1) {
140 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
141 return;
142 }
143 double miterLimit;
144 if (!ParseJsDouble(info[0], miterLimit)) {
145 return;
146 }
147 if (GreatOrEqual(miterLimit, 1.0)) {
148 ShapeAbstractModel::GetInstance()->SetStrokeMiterLimit(miterLimit);
149 }
150 }
151
SetStrokeOpacity(const JSCallbackInfo & info)152 void JSShapeAbstract::SetStrokeOpacity(const JSCallbackInfo& info)
153 {
154 if (info.Length() < 1) {
155 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
156 return;
157 }
158 double strokeOpacity = DEFAULT_OPACITY;
159 ParseJsDouble(info[0], strokeOpacity);
160 if (GreatOrEqual(strokeOpacity, 1.0)) {
161 strokeOpacity = DEFAULT_OPACITY;
162 }
163 if (LessOrEqual(strokeOpacity, 0.0)) {
164 strokeOpacity = MIN_OPACITY;
165 }
166 ShapeAbstractModel::GetInstance()->SetStrokeOpacity(strokeOpacity);
167 }
168
SetFillOpacity(const JSCallbackInfo & info)169 void JSShapeAbstract::SetFillOpacity(const JSCallbackInfo& info)
170 {
171 if (info.Length() < 1) {
172 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
173 return;
174 }
175 double fillOpacity = DEFAULT_OPACITY;
176 ParseJsDouble(info[0], fillOpacity);
177 ShapeAbstractModel::GetInstance()->SetFillOpacity(fillOpacity);
178 }
179
SetStrokeWidth(const JSCallbackInfo & info)180 void JSShapeAbstract::SetStrokeWidth(const JSCallbackInfo& info)
181 {
182 if (info.Length() < 1) {
183 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
184 return;
185 }
186 // the default value is 1.0_vp
187 Dimension lineWidth = 1.0_vp;
188 if (info[0]->IsString()) {
189 const std::string& value = info[0]->ToString();
190 lineWidth = StringUtils::StringToDimensionWithUnit(value, DimensionUnit::VP, 1.0);
191 } else {
192 ParseJsDimensionVp(info[0], lineWidth);
193 }
194 if (lineWidth.IsNegative()) {
195 lineWidth = 1.0_vp;
196 }
197 ShapeAbstractModel::GetInstance()->SetStrokeWidth(lineWidth);
198 }
199
SetAntiAlias(bool antiAlias)200 void JSShapeAbstract::SetAntiAlias(bool antiAlias)
201 {
202 ShapeAbstractModel::GetInstance()->SetAntiAlias(antiAlias);
203 }
204
JsWidth(const JSCallbackInfo & info)205 void JSShapeAbstract::JsWidth(const JSCallbackInfo& info)
206 {
207 if (info.Length() < 1) {
208 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
209 return;
210 }
211
212 SetWidth(info[0]);
213 }
214
SetWidth(const JSRef<JSVal> & jsValue)215 void JSShapeAbstract::SetWidth(const JSRef<JSVal>& jsValue)
216 {
217 Dimension dimWidth;
218 if (!ParseJsDimensionVp(jsValue, dimWidth)) {
219 return;
220 }
221 ShapeAbstractModel::GetInstance()->SetWidth(dimWidth);
222 }
223
JsHeight(const JSCallbackInfo & info)224 void JSShapeAbstract::JsHeight(const JSCallbackInfo& info)
225 {
226 if (info.Length() < 1) {
227 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
228 return;
229 }
230
231 SetHeight(info[0]);
232 }
233
SetHeight(const JSRef<JSVal> & jsValue)234 void JSShapeAbstract::SetHeight(const JSRef<JSVal>& jsValue)
235 {
236 Dimension dimHeight;
237 if (!ParseJsDimensionVp(jsValue, dimHeight)) {
238 return;
239 }
240 ShapeAbstractModel::GetInstance()->SetHeight(dimHeight);
241 }
242
JsSize(const JSCallbackInfo & info)243 void JSShapeAbstract::JsSize(const JSCallbackInfo& info)
244 {
245 if (info.Length() < 1) {
246 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
247 return;
248 }
249
250 if (!info[0]->IsObject()) {
251 LOGE("arg is not Object or String.");
252 return;
253 }
254
255 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
256 SetWidth(sizeObj->GetProperty("width"));
257 SetHeight(sizeObj->GetProperty("height"));
258 }
259
ObjectWidth(const JSCallbackInfo & info)260 void JSShapeAbstract::ObjectWidth(const JSCallbackInfo& info)
261 {
262 info.ReturnSelf();
263 if (info.Length() < 1) {
264 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
265 return;
266 }
267
268 ObjectWidth(info[0]);
269 }
270
ObjectWidth(const JSRef<JSVal> & jsValue)271 void JSShapeAbstract::ObjectWidth(const JSRef<JSVal>& jsValue)
272 {
273 Dimension value;
274 if (!ParseJsDimensionVp(jsValue, value)) {
275 return;
276 }
277 if (LessNotEqual(value.Value(), 0.0)) {
278 LOGE("Value is less than zero");
279 return;
280 }
281 if (basicShape_) {
282 basicShape_->SetWidth(value);
283 }
284 }
285
ObjectHeight(const JSCallbackInfo & info)286 void JSShapeAbstract::ObjectHeight(const JSCallbackInfo& info)
287 {
288 info.ReturnSelf();
289 if (info.Length() < 1) {
290 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
291 return;
292 }
293
294 ObjectHeight(info[0]);
295 }
296
ObjectHeight(const JSRef<JSVal> & jsValue)297 void JSShapeAbstract::ObjectHeight(const JSRef<JSVal>& jsValue)
298 {
299 Dimension value;
300 if (!ParseJsDimensionVp(jsValue, value)) {
301 return;
302 }
303 if (LessNotEqual(value.Value(), 0.0)) {
304 LOGE("Value is less than zero");
305 return;
306 }
307 if (basicShape_) {
308 basicShape_->SetHeight(value);
309 }
310 }
311
ObjectSize(const JSCallbackInfo & info)312 void JSShapeAbstract::ObjectSize(const JSCallbackInfo& info)
313 {
314 if (info.Length() < 1) {
315 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
316 return;
317 }
318
319 if (!info[0]->IsObject()) {
320 LOGE("arg is not Object or String.");
321 return;
322 }
323
324 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
325 ObjectWidth(sizeObj->GetProperty("width"));
326 ObjectHeight(sizeObj->GetProperty("height"));
327 }
328
ObjectOffset(const JSCallbackInfo & info)329 void JSShapeAbstract::ObjectOffset(const JSCallbackInfo& info)
330 {
331 info.ReturnSelf();
332 if (info.Length() > 0 && info[0]->IsObject()) {
333 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
334 JSRef<JSVal> xVal = sizeObj->GetProperty("x");
335 JSRef<JSVal> yVal = sizeObj->GetProperty("y");
336 Dimension x;
337 Dimension y;
338 if (basicShape_ && ParseJsDimensionVp(xVal, x) && ParseJsDimensionVp(yVal, y)) {
339 basicShape_->SetOffset(DimensionOffset(x, y));
340 }
341 }
342 }
343
ObjectFill(const JSCallbackInfo & info)344 void JSShapeAbstract::ObjectFill(const JSCallbackInfo& info)
345 {
346 info.ReturnSelf();
347 if (info.Length() < 1) {
348 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
349 return;
350 }
351
352 Color color;
353 if (ParseJsColor(info[0], color) && basicShape_) {
354 basicShape_->SetColor(color);
355 }
356 }
357
JSBind()358 void JSShapeAbstract::JSBind()
359 {
360 JSClass<JSShapeAbstract>::Declare("JSShapeAbstract");
361 MethodOptions opt = MethodOptions::NONE;
362 JSClass<JSShapeAbstract>::StaticMethod("stroke", &JSShapeAbstract::SetStroke, opt);
363 JSClass<JSShapeAbstract>::StaticMethod("fill", &JSShapeAbstract::SetFill, opt);
364 JSClass<JSShapeAbstract>::StaticMethod("strokeDashOffset", &JSShapeAbstract::SetStrokeDashOffset, opt);
365 JSClass<JSShapeAbstract>::StaticMethod("strokeDashArray", &JSShapeAbstract::SetStrokeDashArray);
366 JSClass<JSShapeAbstract>::StaticMethod("strokeLineCap", &JSShapeAbstract::SetStrokeLineCap, opt);
367 JSClass<JSShapeAbstract>::StaticMethod("strokeLineJoin", &JSShapeAbstract::SetStrokeLineJoin, opt);
368 JSClass<JSShapeAbstract>::StaticMethod("strokeMiterLimit", &JSShapeAbstract::SetStrokeMiterLimit, opt);
369 JSClass<JSShapeAbstract>::StaticMethod("strokeOpacity", &JSShapeAbstract::SetStrokeOpacity, opt);
370 JSClass<JSShapeAbstract>::StaticMethod("fillOpacity", &JSShapeAbstract::SetFillOpacity, opt);
371 JSClass<JSShapeAbstract>::StaticMethod("strokeWidth", &JSShapeAbstract::SetStrokeWidth, opt);
372 JSClass<JSShapeAbstract>::StaticMethod("antiAlias", &JSShapeAbstract::SetAntiAlias, opt);
373 JSClass<JSShapeAbstract>::StaticMethod("width", &JSShapeAbstract::JsWidth, opt);
374 JSClass<JSShapeAbstract>::StaticMethod("height", &JSShapeAbstract::JsHeight, opt);
375 JSClass<JSShapeAbstract>::StaticMethod("size", &JSShapeAbstract::JsSize, opt);
376 JSClass<JSShapeAbstract>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
377 JSClass<JSShapeAbstract>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
378 JSClass<JSShapeAbstract>::Inherit<JSViewAbstract>();
379 }
380
SetSize(const JSCallbackInfo & info)381 void JSShapeAbstract::SetSize(const JSCallbackInfo& info)
382 {
383 if (info.Length() > 0 && info[0]->IsObject()) {
384 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
385 JSRef<JSVal> width = obj->GetProperty("width");
386 JSRef<JSVal> height = obj->GetProperty("height");
387 Dimension dimWidth;
388 if (ParseJsDimensionVp(width, dimWidth)) {
389 ShapeAbstractModel::GetInstance()->SetWidth(dimWidth);
390 }
391 Dimension dimHeight;
392 if (ParseJsDimensionVp(height, dimHeight)) {
393 ShapeAbstractModel::GetInstance()->SetHeight(dimHeight);
394 }
395 }
396 }
397
398 } // namespace OHOS::Ace::Framework
399