• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 std::mutex ShapeAbstractModel::mutex_;
29 
GetInstance()30 ShapeAbstractModel* ShapeAbstractModel::GetInstance()
31 {
32     if (!instance_) {
33         std::lock_guard<std::mutex> lock(mutex_);
34         if (!instance_) {
35 #ifdef NG_BUILD
36             instance_.reset(new NG::ShapeAbstractModelNG());
37 #else
38             if (Container::IsCurrentUseNewPipeline()) {
39                 instance_.reset(new NG::ShapeAbstractModelNG());
40             } else {
41                 instance_.reset(new Framework::ShapeAbstractModelImpl());
42             }
43 #endif
44         }
45     }
46     return instance_.get();
47 }
48 
49 } // namespace OHOS::Ace
50 
51 namespace OHOS::Ace::Framework {
52 namespace {
53 constexpr double DEFAULT_OPACITY = 1.0;
54 constexpr double MIN_OPACITY = 0.0;
55 constexpr double STROKE_MITERLIMIT_DEFAULT = 4.0f;
56 } // namespace
57 
SetStrokeDashArray(const JSCallbackInfo & info)58 void JSShapeAbstract::SetStrokeDashArray(const JSCallbackInfo& info)
59 {
60     if (info.Length() < 1 || !info[0]->IsArray()) {
61         LOGE("info is not array");
62         return;
63     }
64     JSRef<JSArray> array = JSRef<JSArray>::Cast(info[0]);
65     auto length = static_cast<int32_t>(array->Length());
66     std::vector<Dimension> dashArray;
67     for (int32_t i = 0; i < length; i++) {
68         JSRef<JSVal> value = array->GetValueAt(i);
69         CalcDimension dim;
70         bool paramIsValid = false;
71         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
72             paramIsValid = ParseJsDimensionVp(value, dim);
73         } else {
74             paramIsValid = ParseJsDimensionVpNG(value, dim);
75         }
76         if (paramIsValid) {
77             dashArray.emplace_back(dim);
78         } else {
79             LOGE("ParseJsDimension failed");
80             dashArray.clear();
81             break;
82         }
83     }
84     // if odd,add twice
85     if (static_cast<uint32_t>(length) == dashArray.size() && (static_cast<uint32_t>(length) & 1)) {
86         for (int32_t i = 0; i < length; i++) {
87             dashArray.emplace_back(dashArray[i]);
88         }
89     }
90     ShapeAbstractModel::GetInstance()->SetStrokeDashArray(dashArray);
91 }
92 
SetStroke(const JSCallbackInfo & info)93 void JSShapeAbstract::SetStroke(const JSCallbackInfo& info)
94 {
95     if (info.Length() < 1) {
96         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
97         return;
98     }
99     Color strokeColor;
100     if (!ParseJsColor(info[0], strokeColor)) {
101         ShapeAbstractModel::GetInstance()->SetStroke(Color::TRANSPARENT);
102         return;
103     }
104     ShapeAbstractModel::GetInstance()->SetStroke(strokeColor);
105 }
106 
SetFill(const JSCallbackInfo & info)107 void JSShapeAbstract::SetFill(const JSCallbackInfo& info)
108 {
109     if (info.Length() < 1) {
110         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
111         return;
112     }
113     if (info[0]->IsString() && info[0]->ToString() == "none") {
114         ShapeAbstractModel::GetInstance()->SetFill(Color::TRANSPARENT);
115     } else {
116         Color fillColor = Color::BLACK;
117         static const char shapeComponentName[] = "";
118         static const char attrsShapeAbstractFill[] = "fill";
119         CheckColor(info[0], fillColor, shapeComponentName, attrsShapeAbstractFill);
120         ShapeAbstractModel::GetInstance()->SetFill(fillColor);
121     }
122 }
123 
SetStrokeDashOffset(const JSCallbackInfo & info)124 void JSShapeAbstract::SetStrokeDashOffset(const JSCallbackInfo& info)
125 {
126     if (info.Length() < 1) {
127         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
128         return;
129     }
130     CalcDimension offset(0.0f);
131     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
132         if (!ParseJsDimensionVp(info[0], offset)) {
133             return;
134         }
135     } else {
136         if (!ParseJsDimensionVpNG(info[0], offset)) {
137             // set to default value(0.0f)
138             offset.SetValue(0.0f);
139         }
140     }
141     ShapeAbstractModel::GetInstance()->SetStrokeDashOffset(offset);
142 }
143 
SetStrokeLineCap(int lineCap)144 void JSShapeAbstract::SetStrokeLineCap(int lineCap)
145 {
146     ShapeAbstractModel::GetInstance()->SetStrokeLineCap(lineCap);
147 }
148 
SetStrokeLineJoin(int lineJoin)149 void JSShapeAbstract::SetStrokeLineJoin(int lineJoin)
150 {
151     ShapeAbstractModel::GetInstance()->SetStrokeLineJoin(lineJoin);
152 }
153 
SetStrokeMiterLimit(const JSCallbackInfo & info)154 void JSShapeAbstract::SetStrokeMiterLimit(const JSCallbackInfo& info)
155 {
156     if (info.Length() < 1) {
157         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
158         return;
159     }
160     double miterLimit = STROKE_MITERLIMIT_DEFAULT;
161     if (!ParseJsDouble(info[0], miterLimit)) {
162         LOGI("strokeMiterLimit error. now use default value");
163     }
164     ShapeAbstractModel::GetInstance()->SetStrokeMiterLimit(miterLimit);
165 }
166 
SetStrokeOpacity(const JSCallbackInfo & info)167 void JSShapeAbstract::SetStrokeOpacity(const JSCallbackInfo& info)
168 {
169     if (info.Length() < 1) {
170         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
171         return;
172     }
173     double strokeOpacity = DEFAULT_OPACITY;
174     ParseJsDouble(info[0], strokeOpacity);
175     if (GreatOrEqual(strokeOpacity, 1.0)) {
176         strokeOpacity = DEFAULT_OPACITY;
177     }
178     if (LessOrEqual(strokeOpacity, 0.0)) {
179         strokeOpacity = MIN_OPACITY;
180     }
181     ShapeAbstractModel::GetInstance()->SetStrokeOpacity(strokeOpacity);
182 }
183 
184 // https://svgwg.org/svg2-draft/painting.html#FillOpacity
SetFillOpacity(const JSCallbackInfo & info)185 void JSShapeAbstract::SetFillOpacity(const JSCallbackInfo& info)
186 {
187     if (info.Length() < 1) {
188         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
189         return;
190     }
191     double fillOpacity = DEFAULT_OPACITY;
192     ParseJsDouble(info[0], fillOpacity);
193     if (GreatOrEqual(fillOpacity, DEFAULT_OPACITY)) {
194         fillOpacity = DEFAULT_OPACITY;
195     }
196     if (LessOrEqual(fillOpacity, MIN_OPACITY)) {
197         fillOpacity = MIN_OPACITY;
198     }
199     ShapeAbstractModel::GetInstance()->SetFillOpacity(fillOpacity);
200 }
201 
SetStrokeWidth(const JSCallbackInfo & info)202 void JSShapeAbstract::SetStrokeWidth(const JSCallbackInfo& info)
203 {
204     if (info.Length() < 1) {
205         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
206         return;
207     }
208     // the default value is 1.0_vp
209     CalcDimension lineWidth = 1.0_vp;
210     if (info[0]->IsString()) {
211         const std::string& value = info[0]->ToString();
212         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
213             lineWidth = StringUtils::StringToDimensionWithUnit(value, DimensionUnit::VP, 1.0);
214         } else {
215             if (!StringUtils::StringToDimensionWithUnitNG(value, lineWidth, DimensionUnit::VP, 1.0)) {
216                 // unit is invalid, use default value(1.0vp) instead.
217                 lineWidth = 1.0_vp;
218             }
219         }
220     } else {
221         ParseJsDimensionVp(info[0], lineWidth);
222     }
223     if (lineWidth.IsNegative()) {
224         lineWidth = 1.0_vp;
225     }
226     ShapeAbstractModel::GetInstance()->SetStrokeWidth(lineWidth);
227 }
228 
SetAntiAlias(bool antiAlias)229 void JSShapeAbstract::SetAntiAlias(bool antiAlias)
230 {
231     ShapeAbstractModel::GetInstance()->SetAntiAlias(antiAlias);
232 }
233 
JsWidth(const JSCallbackInfo & info)234 void JSShapeAbstract::JsWidth(const JSCallbackInfo& info)
235 {
236     if (info.Length() < 1) {
237         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
238         return;
239     }
240 
241     SetWidth(info[0]);
242 }
243 
SetWidth(const JSRef<JSVal> & jsValue)244 void JSShapeAbstract::SetWidth(const JSRef<JSVal>& jsValue)
245 {
246     CalcDimension value;
247     if (jsValue->IsUndefined()) {
248         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
249         LOGW("jsValue is undefined");
250         return;
251     }
252     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
253         if (!ParseJsDimensionVp(jsValue, value)) {
254             LOGW("ParseJsDimensionVp failed");
255             return;
256         }
257     } else {
258         if (!ParseJsDimensionVpNG(jsValue, value)) {
259             ViewAbstractModel::GetInstance()->ClearWidthOrHeight(true);
260             LOGW("ParseJsDimensionVp failed");
261             return;
262         }
263     }
264 
265     if (LessNotEqual(value.Value(), 0.0)) {
266         LOGW("value is less than zero");
267         value.SetValue(0.0);
268     }
269     ShapeAbstractModel::GetInstance()->SetWidth(value);
270 }
271 
JsHeight(const JSCallbackInfo & info)272 void JSShapeAbstract::JsHeight(const JSCallbackInfo& info)
273 {
274     if (info.Length() < 1) {
275         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
276         return;
277     }
278 
279     SetHeight(info[0]);
280 }
281 
SetHeight(const JSRef<JSVal> & jsValue)282 void JSShapeAbstract::SetHeight(const JSRef<JSVal>& jsValue)
283 {
284     CalcDimension value;
285     if (jsValue->IsUndefined()) {
286         ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
287         LOGW("jsValue is undefined");
288         return;
289     }
290     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
291         if (!ParseJsDimensionVp(jsValue, value)) {
292             LOGW("ParseJsDimensionVp failed");
293             return;
294         }
295     } else {
296         if (!ParseJsDimensionVpNG(jsValue, value)) {
297             ViewAbstractModel::GetInstance()->ClearWidthOrHeight(false);
298             LOGW("ParseJsDimensionVp failed");
299             return;
300         }
301     }
302 
303     if (LessNotEqual(value.Value(), 0.0)) {
304         LOGW("value is less than zero");
305         value.SetValue(0.0);
306     }
307     ShapeAbstractModel::GetInstance()->SetHeight(value);
308 }
309 
JsSize(const JSCallbackInfo & info)310 void JSShapeAbstract::JsSize(const JSCallbackInfo& info)
311 {
312     if (info.Length() < 1) {
313         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
314         return;
315     }
316 
317     if (!info[0]->IsObject()) {
318         LOGE("arg is not Object or String.");
319         return;
320     }
321 
322     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
323     SetWidth(sizeObj->GetProperty("width"));
324     SetHeight(sizeObj->GetProperty("height"));
325 }
326 
ObjectWidth(const JSCallbackInfo & info)327 void JSShapeAbstract::ObjectWidth(const JSCallbackInfo& info)
328 {
329     info.ReturnSelf();
330     if (info.Length() < 1) {
331         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
332         return;
333     }
334 
335     ObjectWidth(info[0]);
336 }
337 
ObjectWidth(const JSRef<JSVal> & jsValue)338 void JSShapeAbstract::ObjectWidth(const JSRef<JSVal>& jsValue)
339 {
340     CalcDimension value;
341     if (!ParseJsDimensionVp(jsValue, value)) {
342         return;
343     }
344     if (LessNotEqual(value.Value(), 0.0)) {
345         LOGE("Value is less than zero");
346         return;
347     }
348     if (basicShape_) {
349         basicShape_->SetWidth(value);
350     }
351 }
352 
ObjectHeight(const JSCallbackInfo & info)353 void JSShapeAbstract::ObjectHeight(const JSCallbackInfo& info)
354 {
355     info.ReturnSelf();
356     if (info.Length() < 1) {
357         LOGE("The arg is wrong, it is supposed to have at least 1 argument");
358         return;
359     }
360 
361     ObjectHeight(info[0]);
362 }
363 
ObjectHeight(const JSRef<JSVal> & jsValue)364 void JSShapeAbstract::ObjectHeight(const JSRef<JSVal>& jsValue)
365 {
366     CalcDimension value;
367     if (!ParseJsDimensionVp(jsValue, value)) {
368         return;
369     }
370     if (LessNotEqual(value.Value(), 0.0)) {
371         LOGE("Value is less than zero");
372         return;
373     }
374     if (basicShape_) {
375         basicShape_->SetHeight(value);
376     }
377 }
378 
ObjectSize(const JSCallbackInfo & info)379 void JSShapeAbstract::ObjectSize(const JSCallbackInfo& info)
380 {
381     if (info.Length() < 1) {
382         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
383         return;
384     }
385 
386     if (!info[0]->IsObject()) {
387         LOGE("arg is not Object or String.");
388         return;
389     }
390 
391     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
392     ObjectWidth(sizeObj->GetProperty("width"));
393     ObjectHeight(sizeObj->GetProperty("height"));
394 }
395 
ObjectOffset(const JSCallbackInfo & info)396 void JSShapeAbstract::ObjectOffset(const JSCallbackInfo& info)
397 {
398     info.ReturnSelf();
399     if (info.Length() > 0 && info[0]->IsObject()) {
400         JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
401         JSRef<JSVal> xVal = sizeObj->GetProperty("x");
402         JSRef<JSVal> yVal = sizeObj->GetProperty("y");
403         CalcDimension x;
404         CalcDimension y;
405         if (basicShape_ && ParseJsDimensionVp(xVal, x) && ParseJsDimensionVp(yVal, y)) {
406             basicShape_->SetOffset(DimensionOffset(x, y));
407         }
408     }
409 }
410 
ObjectFill(const JSCallbackInfo & info)411 void JSShapeAbstract::ObjectFill(const JSCallbackInfo& info)
412 {
413     info.ReturnSelf();
414     if (info.Length() < 1) {
415         LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
416         return;
417     }
418 
419     Color color;
420     if (ParseJsColor(info[0], color) && basicShape_) {
421         basicShape_->SetColor(color);
422     }
423 }
424 
JSBind(BindingTarget globalObj)425 void JSShapeAbstract::JSBind(BindingTarget globalObj)
426 {
427     JSClass<JSShapeAbstract>::Declare("JSShapeAbstract");
428     MethodOptions opt = MethodOptions::NONE;
429     JSClass<JSShapeAbstract>::StaticMethod("stroke", &JSShapeAbstract::SetStroke, opt);
430     JSClass<JSShapeAbstract>::StaticMethod("fill", &JSShapeAbstract::SetFill, opt);
431     JSClass<JSShapeAbstract>::StaticMethod("foregroundColor", &JSShapeAbstract::SetForegroundColor, opt);
432     JSClass<JSShapeAbstract>::StaticMethod("strokeDashOffset", &JSShapeAbstract::SetStrokeDashOffset, opt);
433     JSClass<JSShapeAbstract>::StaticMethod("strokeDashArray", &JSShapeAbstract::SetStrokeDashArray);
434     JSClass<JSShapeAbstract>::StaticMethod("strokeLineCap", &JSShapeAbstract::SetStrokeLineCap, opt);
435     JSClass<JSShapeAbstract>::StaticMethod("strokeLineJoin", &JSShapeAbstract::SetStrokeLineJoin, opt);
436     JSClass<JSShapeAbstract>::StaticMethod("strokeMiterLimit", &JSShapeAbstract::SetStrokeMiterLimit, opt);
437     JSClass<JSShapeAbstract>::StaticMethod("strokeOpacity", &JSShapeAbstract::SetStrokeOpacity, opt);
438     JSClass<JSShapeAbstract>::StaticMethod("fillOpacity", &JSShapeAbstract::SetFillOpacity, opt);
439     JSClass<JSShapeAbstract>::StaticMethod("strokeWidth", &JSShapeAbstract::SetStrokeWidth, opt);
440     JSClass<JSShapeAbstract>::StaticMethod("antiAlias", &JSShapeAbstract::SetAntiAlias, opt);
441     JSClass<JSShapeAbstract>::StaticMethod("width", &JSShapeAbstract::JsWidth, opt);
442     JSClass<JSShapeAbstract>::StaticMethod("height", &JSShapeAbstract::JsHeight, opt);
443     JSClass<JSShapeAbstract>::StaticMethod("size", &JSShapeAbstract::JsSize, opt);
444     JSClass<JSShapeAbstract>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
445     JSClass<JSShapeAbstract>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
446     JSClass<JSShapeAbstract>::InheritAndBind<JSViewAbstract>(globalObj);
447 }
448 
SetSize(const JSCallbackInfo & info)449 void JSShapeAbstract::SetSize(const JSCallbackInfo& info)
450 {
451     if (info.Length() > 0 && info[0]->IsObject()) {
452         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
453         JSRef<JSVal> width = obj->GetProperty("width");
454         JSRef<JSVal> height = obj->GetProperty("height");
455         SetWidth(width);
456         SetHeight(height);
457     }
458 }
459 
ObjectPosition(const JSCallbackInfo & info)460 void JSShapeAbstract::ObjectPosition(const JSCallbackInfo& info)
461 {
462     info.ReturnSelf();
463     if (info.Length() > 0 && info[0]->IsObject()) {
464         JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
465         JSRef<JSVal> xVal = sizeObj->GetProperty("x");
466         JSRef<JSVal> yVal = sizeObj->GetProperty("y");
467         CalcDimension x;
468         CalcDimension y;
469         DimensionOffset position(x, y);
470         CHECK_NULL_VOID(basicShape_);
471         if (ParseJsDimensionVp(xVal, x)) {
472             position.SetX(x);
473         }
474         if (ParseJsDimensionVp(yVal, y)) {
475             position.SetY(y);
476         }
477         basicShape_->SetPosition(position);
478     }
479 }
480 
SetForegroundColor(const JSCallbackInfo & info)481 void JSShapeAbstract::SetForegroundColor(const JSCallbackInfo& info)
482 {
483     if (info.Length() < 1) {
484         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
485         return;
486     }
487     Color foregroundColor;
488     ForegroundColorStrategy strategy;
489     if (ParseJsColorStrategy(info[0], strategy)) {
490         ShapeAbstractModel::GetInstance()->SetFill(Color::FOREGROUND);
491         ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
492         return;
493     }
494     if (!ParseJsColor(info[0], foregroundColor)) {
495         ShapeAbstractModel::GetInstance()->SetFill(Color::BLACK);
496         ViewAbstractModel::GetInstance()->SetForegroundColor(Color::BLACK);
497         return;
498     }
499     ShapeAbstractModel::GetInstance()->SetFill(foregroundColor);
500     ViewAbstractModel::GetInstance()->SetForegroundColor(foregroundColor);
501 }
502 } // namespace OHOS::Ace::Framework
503