• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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.h"
17 
18 #include "base/geometry/ng/image_mesh.h"
19 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
20 #include "bridge/declarative_frontend/jsview/models/shape_model_impl.h"
21 #include "core/common/container.h"
22 #include "core/components_ng/pattern/shape/shape_abstract_model.h"
23 #include "core/components_ng/pattern/shape/shape_model_ng.h"
24 #include "frameworks/bridge/declarative_frontend/jsview/js_utils.h"
25 
26 namespace OHOS::Ace {
27 namespace {
28 constexpr double DEFAULT_OPACITY = 1.0;
29 constexpr double STROKE_MITERLIMIT_DEFAULT = 4.0f;
30 } // namespace
GetInstance()31 ShapeModel* ShapeModel::GetInstance()
32 {
33 #ifdef NG_BUILD
34     static NG::ShapeModelNG instance;
35     return &instance;
36 #else
37     if (Container::IsCurrentUseNewPipeline()) {
38         static NG::ShapeModelNG instance;
39         return &instance;
40     } else {
41         static Framework::ShapeModelImpl instance;
42         return &instance;
43     }
44 #endif
45 }
46 } // namespace OHOS::Ace
47 
48 namespace OHOS::Ace::Framework {
49 
Create(const JSCallbackInfo & info)50 void JSShape::Create(const JSCallbackInfo& info)
51 {
52     ShapeModel::GetInstance()->Create();
53     JSInteractableView::SetFocusable(true);
54     InitBox(info);
55 }
56 
InitBox(const JSCallbackInfo & info)57 void JSShape::InitBox(const JSCallbackInfo& info)
58 {
59     RefPtr<PixelMap> pixMap = nullptr;
60     if (info.Length() == 1 && info[0]->IsObject()) {
61 #if !defined(PREVIEW) && defined(PIXEL_MAP_SUPPORTED)
62         pixMap = CreatePixelMapFromNapiValue(info[0]);
63 #endif
64     }
65     ShapeModel::GetInstance()->InitBox(pixMap);
66 }
67 
SetViewPort(const JSCallbackInfo & info)68 void JSShape::SetViewPort(const JSCallbackInfo& info)
69 {
70     if (info.Length() < 1) {
71         return;
72     }
73     if (info[0]->IsObject()) {
74         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
75         JSRef<JSVal> leftValue = obj->GetProperty("x");
76         JSRef<JSVal> topValue = obj->GetProperty("y");
77         JSRef<JSVal> widthValue = obj->GetProperty("width");
78         JSRef<JSVal> heightValue = obj->GetProperty("height");
79         ShapeViewBox viewBox;
80         CalcDimension dimLeft;
81         ParseJsDimensionVp(leftValue, dimLeft);
82         CalcDimension dimTop;
83         ParseJsDimensionVp(topValue, dimTop);
84         CalcDimension dimWidth;
85         ParseJsDimensionVp(widthValue, dimWidth);
86         CalcDimension dimHeight;
87         ParseJsDimensionVp(heightValue, dimHeight);
88         ShapeModel::GetInstance()->SetViewPort(dimLeft, dimTop, dimWidth, dimHeight);
89     }
90     info.SetReturnValue(info.This());
91 }
92 
JsWidth(const JSCallbackInfo & info)93 void JSShape::JsWidth(const JSCallbackInfo& info)
94 {
95     if (info.Length() < 1) {
96         return;
97     }
98 
99     JsWidth(info[0]);
100 }
101 
JsWidth(const JSRef<JSVal> & jsValue)102 void JSShape::JsWidth(const JSRef<JSVal>& jsValue)
103 {
104     JSViewAbstract::JsWidth(jsValue);
105     ShapeModel::GetInstance()->SetWidth();
106 }
107 
JsHeight(const JSCallbackInfo & info)108 void JSShape::JsHeight(const JSCallbackInfo& info)
109 {
110     if (info.Length() < 1) {
111         return;
112     }
113 
114     JsHeight(info[0]);
115 }
116 
JsHeight(const JSRef<JSVal> & jsValue)117 void JSShape::JsHeight(const JSRef<JSVal>& jsValue)
118 {
119     JSViewAbstract::JsHeight(jsValue);
120     ShapeModel::GetInstance()->SetHeight();
121 }
122 
JsSize(const JSCallbackInfo & info)123 void JSShape::JsSize(const JSCallbackInfo& info)
124 {
125     if (info.Length() < 1) {
126         return;
127     }
128 
129     if (!info[0]->IsObject()) {
130         return;
131     }
132 
133     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
134     JsWidth(sizeObj->GetProperty("width"));
135     JsHeight(sizeObj->GetProperty("height"));
136 }
137 
SetStrokeDashArray(const JSCallbackInfo & info)138 void JSShape::SetStrokeDashArray(const JSCallbackInfo& info)
139 {
140     std::vector<Dimension> dashArray;
141     if (info.Length() < 1 || !info[0]->IsArray()) {
142         ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
143         return;
144     }
145     JSRef<JSArray> array = JSRef<JSArray>::Cast(info[0]);
146     int32_t length = static_cast<int32_t>(array->Length());
147     if (length <= 0) {
148         ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
149         return;
150     }
151     for (int32_t i = 0; i < length; i++) {
152         JSRef<JSVal> value = array->GetValueAt(i);
153         CalcDimension dim;
154         bool paramIsValid = false;
155         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
156             paramIsValid = ParseJsDimensionVp(value, dim);
157         } else {
158             paramIsValid = ParseJsDimensionVpNG(value, dim);
159         }
160         if (paramIsValid) {
161             dashArray.emplace_back(dim);
162         } else {
163             dashArray.clear();
164             break;
165         }
166     }
167     // if odd,add twice
168     if (static_cast<uint32_t>(length) == dashArray.size() && (static_cast<uint32_t>(length) & 1)) {
169         for (int32_t i = 0; i < length; i++) {
170             dashArray.emplace_back(dashArray[i]);
171         }
172     }
173     ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
174     info.SetReturnValue(info.This());
175 }
176 
SetStroke(const JSCallbackInfo & info)177 void JSShape::SetStroke(const JSCallbackInfo& info)
178 {
179     if (info.Length() < 1) {
180         return;
181     }
182     Color strokeColor = Color::TRANSPARENT;
183     ParseJsColor(info[0], strokeColor);
184     ShapeModel::GetInstance()->SetStroke(strokeColor);
185 }
186 
SetFill(const JSCallbackInfo & info)187 void JSShape::SetFill(const JSCallbackInfo& info)
188 {
189     if (info.Length() < 1) {
190         return;
191     }
192     if (info[0]->IsString() && info[0]->ToString() == "none") {
193         ShapeModel::GetInstance()->SetFill(Color::TRANSPARENT);
194     } else {
195         Color fillColor;
196         if (ParseJsColor(info[0], fillColor)) {
197             ShapeModel::GetInstance()->SetFill(fillColor);
198         } else {
199             ShapeModel::GetInstance()->SetFill(Color::BLACK);
200         }
201     }
202 }
203 
SetStrokeDashOffset(const JSCallbackInfo & info)204 void JSShape::SetStrokeDashOffset(const JSCallbackInfo& info)
205 {
206     if (info.Length() < 1) {
207         return;
208     }
209     CalcDimension offset(0.0f);
210     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
211         if (!ParseJsDimensionVp(info[0], offset)) {
212             return;
213         }
214     } else {
215         if (!ParseJsDimensionVpNG(info[0], offset)) {
216             // set to default value(0.0f)
217             offset.SetValue(0.0f);
218         }
219     }
220     ShapeModel::GetInstance()->SetStrokeDashOffset(offset);
221 }
222 
SetStrokeLineCap(int lineCap)223 void JSShape::SetStrokeLineCap(int lineCap)
224 {
225     ShapeModel::GetInstance()->SetStrokeLineCap(lineCap);
226 }
227 
SetStrokeLineJoin(int lineJoin)228 void JSShape::SetStrokeLineJoin(int lineJoin)
229 {
230     ShapeModel::GetInstance()->SetStrokeLineJoin(lineJoin);
231 }
232 
SetStrokeMiterLimit(const JSCallbackInfo & info)233 void JSShape::SetStrokeMiterLimit(const JSCallbackInfo& info)
234 {
235     if (info.Length() < 1) {
236         return;
237     }
238     double miterLimit = STROKE_MITERLIMIT_DEFAULT;
239     ParseJsDouble(info[0], miterLimit);
240     ShapeModel::GetInstance()->SetStrokeMiterLimit(miterLimit);
241 }
242 
SetStrokeOpacity(const JSCallbackInfo & info)243 void JSShape::SetStrokeOpacity(const JSCallbackInfo& info)
244 {
245     if (info.Length() < 1) {
246         return;
247     }
248     double strokeOpacity = DEFAULT_OPACITY;
249     ParseJsDouble(info[0], strokeOpacity);
250     ShapeModel::GetInstance()->SetStrokeOpacity(strokeOpacity);
251 }
252 
SetFillOpacity(const JSCallbackInfo & info)253 void JSShape::SetFillOpacity(const JSCallbackInfo& info)
254 {
255     if (info.Length() < 1) {
256         return;
257     }
258     double fillOpacity = DEFAULT_OPACITY;
259     ParseJsDouble(info[0], fillOpacity);
260     ShapeModel::GetInstance()->SetFillOpacity(fillOpacity);
261 }
262 
SetStrokeWidth(const JSCallbackInfo & info)263 void JSShape::SetStrokeWidth(const JSCallbackInfo& info)
264 {
265     if (info.Length() < 1) {
266         return;
267     }
268     // the default value is 1.0_vp
269     CalcDimension lineWidth = 1.0_vp;
270     if (info[0]->IsString()) {
271         const std::string& value = info[0]->ToString();
272         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
273             lineWidth = StringUtils::StringToDimensionWithUnit(value, DimensionUnit::VP, 1.0);
274         } else {
275             if (!StringUtils::StringToDimensionWithUnitNG(value, lineWidth, DimensionUnit::VP, 1.0)) {
276                 // unit is invalid, use default value(1.0vp) instead.
277                 lineWidth = 1.0_vp;
278             }
279         }
280     } else {
281         ParseJsDimensionVp(info[0], lineWidth);
282     }
283     if (lineWidth.IsNegative()) {
284         lineWidth = 1.0_vp;
285     }
286     ShapeModel::GetInstance()->SetStrokeWidth(lineWidth);
287 }
288 
SetAntiAlias(bool antiAlias)289 void JSShape::SetAntiAlias(bool antiAlias)
290 {
291     ShapeModel::GetInstance()->SetAntiAlias(antiAlias);
292 }
293 
SetBitmapMesh(const JSCallbackInfo & info)294 void JSShape::SetBitmapMesh(const JSCallbackInfo& info)
295 {
296     if (info.Length() != 3) {
297         return;
298     }
299     std::vector<float> mesh;
300     uint32_t column = 0;
301     uint32_t row = 0;
302     JSRef<JSVal> columnValue = info[1];
303     JSRef<JSVal> rowValue = info[2];
304     if (!ParseJsInteger(columnValue, column)) {
305         ShapeModel::GetInstance()->SetBitmapMesh(mesh, 0, 0);
306         return;
307     }
308     if (!ParseJsInteger(rowValue, row)) {
309         ShapeModel::GetInstance()->SetBitmapMesh(mesh, 0, 0);
310         return;
311     }
312     if (info[0]->IsArray()) {
313         auto meshValue = JSRef<JSArray>::Cast(info[0]);
314         auto meshSize = meshValue->Length();
315         auto tempMeshSize = static_cast<uint64_t>(column + 1) * (row + 1) * 2;
316         if (tempMeshSize != meshSize) {
317             ShapeModel::GetInstance()->SetBitmapMesh(mesh, 0, 0);
318             return;
319         }
320         for (size_t i = 0; i < meshSize; i++) {
321             JSRef<JSVal> value = meshValue->GetValueAt(i);
322             // only support number
323             if (value->IsNumber()) {
324                 auto vert = value->ToNumber<float>();
325                 mesh.emplace_back(vert);
326             } else {
327                 ShapeModel::GetInstance()->SetBitmapMesh(std::vector<float>(), 0, 0);
328                 return;
329             }
330         }
331     }
332     ShapeModel::GetInstance()->SetBitmapMesh(mesh, static_cast<int32_t>(column), static_cast<int32_t>(row));
333 }
334 
SetForegroundColor(const JSCallbackInfo & info)335 void JSShape::SetForegroundColor(const JSCallbackInfo& info)
336 {
337     if (info.Length() < 1) {
338         return;
339     }
340     Color foregroundColor;
341     ForegroundColorStrategy strategy;
342     if (ParseJsColorStrategy(info[0], strategy)) {
343         ShapeModel::GetInstance()->SetFill(Color::FOREGROUND);
344         ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
345         return;
346     }
347     if (!ParseJsColor(info[0], foregroundColor)) {
348         return;
349     }
350     ShapeModel::GetInstance()->SetForegroundColor(foregroundColor);
351     ViewAbstractModel::GetInstance()->SetForegroundColor(foregroundColor);
352 }
353 
JSBind(BindingTarget globalObj)354 void JSShape::JSBind(BindingTarget globalObj)
355 {
356     JSClass<JSShape>::Declare("Shape");
357     JSClass<JSShape>::StaticMethod("create", &JSShape::Create);
358     JSClass<JSShape>::StaticMethod("viewPort", &JSShape::SetViewPort);
359 
360     JSClass<JSShape>::StaticMethod("width", &JSShape::JsWidth);
361     JSClass<JSShape>::StaticMethod("height", &JSShape::JsHeight);
362     JSClass<JSShape>::StaticMethod("size", &JSShape::JsSize);
363 
364     JSClass<JSShape>::StaticMethod("stroke", &JSShape::SetStroke);
365     JSClass<JSShape>::StaticMethod("fill", &JSShape::SetFill);
366     JSClass<JSShape>::StaticMethod("strokeDashOffset", &JSShape::SetStrokeDashOffset);
367     JSClass<JSShape>::StaticMethod("strokeDashArray", &JSShape::SetStrokeDashArray);
368     JSClass<JSShape>::StaticMethod("strokeLineCap", &JSShape::SetStrokeLineCap);
369     JSClass<JSShape>::StaticMethod("strokeLineJoin", &JSShape::SetStrokeLineJoin);
370     JSClass<JSShape>::StaticMethod("strokeMiterLimit", &JSShape::SetStrokeMiterLimit);
371     JSClass<JSShape>::StaticMethod("strokeOpacity", &JSShape::SetStrokeOpacity);
372     JSClass<JSShape>::StaticMethod("fillOpacity", &JSShape::SetFillOpacity);
373     JSClass<JSShape>::StaticMethod("strokeWidth", &JSShape::SetStrokeWidth);
374     JSClass<JSShape>::StaticMethod("antiAlias", &JSShape::SetAntiAlias);
375     JSClass<JSShape>::StaticMethod("mesh", &JSShape::SetBitmapMesh);
376     JSClass<JSShape>::StaticMethod("foregroundColor", &JSShape::SetForegroundColor);
377 
378     JSClass<JSShape>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
379     JSClass<JSShape>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
380     JSClass<JSShape>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
381     JSClass<JSShape>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
382     JSClass<JSShape>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
383     JSClass<JSShape>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
384     JSClass<JSShape>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
385     JSClass<JSShape>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
386     JSClass<JSShape>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
387     JSClass<JSShape>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
388     JSClass<JSShape>::InheritAndBind<JSContainerBase>(globalObj);
389 }
390 
391 } // namespace OHOS::Ace::Framework
392