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