• 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     UnRegisterResource("ShapeViewPort");
74     if (info[0]->IsObject()) {
75         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
76         JSRef<JSVal> leftValue = obj->GetProperty("x");
77         JSRef<JSVal> topValue = obj->GetProperty("y");
78         JSRef<JSVal> widthValue = obj->GetProperty("width");
79         JSRef<JSVal> heightValue = obj->GetProperty("height");
80         ShapeViewBox viewBox;
81         CalcDimension dimLeft;
82         RefPtr<ResourceObject> dimLeftResObj;
83         ParseJsDimensionVp(leftValue, dimLeft, dimLeftResObj);
84         CalcDimension dimTop;
85         RefPtr<ResourceObject> dimTopResObj;
86         ParseJsDimensionVp(topValue, dimTop, dimTopResObj);
87         CalcDimension dimWidth;
88         RefPtr<ResourceObject> dimWidthResObj;
89         ParseJsDimensionVp(widthValue, dimWidth, dimWidthResObj);
90         CalcDimension dimHeight;
91         RefPtr<ResourceObject> dimHeightResObj;
92         ParseJsDimensionVp(heightValue, dimHeight, dimHeightResObj);
93         if (SystemProperties::ConfigChangePerform() &&
94             (dimLeftResObj || dimTopResObj || dimWidthResObj || dimHeightResObj)) {
95             std::vector<RefPtr<ResourceObject>> resObjArray = { dimLeftResObj, dimTopResObj, dimWidthResObj,
96                 dimHeightResObj };
97             std::vector<Dimension> dimArray = { dimLeft, dimTop, dimWidth, dimHeight };
98             ShapeModel::GetInstance()->SetViewPort(dimArray, resObjArray);
99         }
100         ShapeModel::GetInstance()->SetViewPort(dimLeft, dimTop, dimWidth, dimHeight);
101     }
102     info.SetReturnValue(info.This());
103 }
104 
JsWidth(const JSCallbackInfo & info)105 void JSShape::JsWidth(const JSCallbackInfo& info)
106 {
107     if (info.Length() < 1) {
108         return;
109     }
110 
111     JsWidth(info[0]);
112 }
113 
JsWidth(const JSRef<JSVal> & jsValue)114 void JSShape::JsWidth(const JSRef<JSVal>& jsValue)
115 {
116     JSViewAbstract::JsWidth(jsValue);
117     ShapeModel::GetInstance()->SetWidth();
118 }
119 
JsHeight(const JSCallbackInfo & info)120 void JSShape::JsHeight(const JSCallbackInfo& info)
121 {
122     if (info.Length() < 1) {
123         return;
124     }
125 
126     JsHeight(info[0]);
127 }
128 
JsHeight(const JSRef<JSVal> & jsValue)129 void JSShape::JsHeight(const JSRef<JSVal>& jsValue)
130 {
131     JSViewAbstract::JsHeight(jsValue);
132     ShapeModel::GetInstance()->SetHeight();
133 }
134 
JsSize(const JSCallbackInfo & info)135 void JSShape::JsSize(const JSCallbackInfo& info)
136 {
137     if (info.Length() < 1) {
138         return;
139     }
140 
141     if (!info[0]->IsObject()) {
142         return;
143     }
144 
145     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
146     JsWidth(sizeObj->GetProperty("width"));
147     JsHeight(sizeObj->GetProperty("height"));
148 }
149 
SetStrokeDashArray(const JSCallbackInfo & info)150 void JSShape::SetStrokeDashArray(const JSCallbackInfo& info)
151 {
152     std::vector<Dimension> dashArray;
153     std::vector<RefPtr<ResourceObject>> resObjArray;
154     bool hasResObj = false;
155     UnRegisterResource("ShapeStrokeDashArray");
156     if (info.Length() < 1 || !info[0]->IsArray()) {
157         ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
158         return;
159     }
160     JSRef<JSArray> array = JSRef<JSArray>::Cast(info[0]);
161     int32_t length = static_cast<int32_t>(array->Length());
162     if (length <= 0) {
163         ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
164         return;
165     }
166     for (int32_t i = 0; i < length; i++) {
167         JSRef<JSVal> value = array->GetValueAt(i);
168         CalcDimension dim;
169         RefPtr<ResourceObject> resObj;
170         bool paramIsValid = false;
171         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
172             paramIsValid = ParseJsDimensionVp(value, dim, resObj);
173         } else {
174             paramIsValid = ParseJsDimensionVpNG(value, dim, resObj);
175         }
176         if (resObj) {
177             hasResObj = true;
178         }
179         if (paramIsValid) {
180             dashArray.emplace_back(dim);
181             resObjArray.emplace_back(resObj);
182         } else {
183             dashArray.clear();
184             resObjArray.clear();
185             break;
186         }
187     }
188     // if odd,add twice
189     if (static_cast<uint32_t>(length) == dashArray.size() && (static_cast<uint32_t>(length) & 1)) {
190         for (int32_t i = 0; i < length; i++) {
191             dashArray.emplace_back(dashArray[i]);
192             resObjArray.emplace_back(resObjArray[i]);
193         }
194     }
195     if (SystemProperties::ConfigChangePerform() &&  hasResObj) {
196         ShapeModel::GetInstance()->SetStrokeDashArray(dashArray, resObjArray);
197     }
198     ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
199     info.SetReturnValue(info.This());
200 }
201 
SetStroke(const JSCallbackInfo & info)202 void JSShape::SetStroke(const JSCallbackInfo& info)
203 {
204     if (info.Length() < 1) {
205         return;
206     }
207     Color strokeColor = Color::TRANSPARENT;
208     RefPtr<ResourceObject> strokeResObj;
209     ParseJsColor(info[0], strokeColor, strokeResObj);
210     UnRegisterResource("ShapeStroke");
211     if (SystemProperties::ConfigChangePerform() && strokeResObj) {
212         RegisterResource<Color>("ShapeStroke", strokeResObj, strokeColor);
213     }
214     ShapeModel::GetInstance()->SetStroke(strokeColor);
215 }
216 
SetFill(const JSCallbackInfo & info)217 void JSShape::SetFill(const JSCallbackInfo& info)
218 {
219     if (info.Length() < 1) {
220         return;
221     }
222     if (info[0]->IsString() && info[0]->ToString() == "none") {
223         ShapeModel::GetInstance()->SetFill(Color::TRANSPARENT);
224         return;
225     }
226     Color fillColor;
227     RefPtr<ResourceObject> fillResObj;
228     UnRegisterResource("ShapeFill");
229     if (!ParseJsColor(info[0], fillColor, fillResObj)) {
230         ShapeModel::GetInstance()->SetFill(Color::BLACK);
231         return;
232     }
233     if (SystemProperties::ConfigChangePerform() && fillResObj) {
234         RegisterResource<Color>("ShapeFill", fillResObj, fillColor);
235     }
236     ShapeModel::GetInstance()->SetFill(fillColor);
237 }
238 
SetStrokeDashOffset(const JSCallbackInfo & info)239 void JSShape::SetStrokeDashOffset(const JSCallbackInfo& info)
240 {
241     if (info.Length() < 1) {
242         return;
243     }
244     CalcDimension offset(0.0f);
245     RefPtr<ResourceObject> dashOffsetResObj;
246     UnRegisterResource("ShapeDashOffset");
247     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
248         if (!ParseJsDimensionVp(info[0], offset, dashOffsetResObj)) {
249             return;
250         }
251     } else {
252         if (!ParseJsDimensionVpNG(info[0], offset, dashOffsetResObj)) {
253             // set to default value(0.0f)
254             offset.SetValue(0.0f);
255         }
256     }
257     if (SystemProperties::ConfigChangePerform() && dashOffsetResObj) {
258         RegisterResource<CalcDimension>("ShapeDashOffset", dashOffsetResObj, offset);
259     }
260     ShapeModel::GetInstance()->SetStrokeDashOffset(offset);
261 }
262 
SetStrokeLineCap(int lineCap)263 void JSShape::SetStrokeLineCap(int lineCap)
264 {
265     ShapeModel::GetInstance()->SetStrokeLineCap(lineCap);
266 }
267 
SetStrokeLineJoin(int lineJoin)268 void JSShape::SetStrokeLineJoin(int lineJoin)
269 {
270     ShapeModel::GetInstance()->SetStrokeLineJoin(lineJoin);
271 }
272 
SetStrokeMiterLimit(const JSCallbackInfo & info)273 void JSShape::SetStrokeMiterLimit(const JSCallbackInfo& info)
274 {
275     if (info.Length() < 1) {
276         return;
277     }
278     double miterLimit = STROKE_MITERLIMIT_DEFAULT;
279     RefPtr<ResourceObject> miterLimitResObj;
280     ParseJsDouble(info[0], miterLimit, miterLimitResObj);
281     UnRegisterResource("ShapeMiterLimit");
282     if (SystemProperties::ConfigChangePerform() && miterLimitResObj) {
283         RegisterResource<double>("ShapeMiterLimit", miterLimitResObj, miterLimit);
284     }
285     ShapeModel::GetInstance()->SetStrokeMiterLimit(miterLimit);
286 }
287 
SetStrokeOpacity(const JSCallbackInfo & info)288 void JSShape::SetStrokeOpacity(const JSCallbackInfo& info)
289 {
290     if (info.Length() < 1) {
291         return;
292     }
293     double strokeOpacity = DEFAULT_OPACITY;
294     RefPtr<ResourceObject> strokeOpacityResObj;
295     ParseJsDouble(info[0], strokeOpacity, strokeOpacityResObj);
296     UnRegisterResource("ShapeStrokeOpacity");
297     if (SystemProperties::ConfigChangePerform() && strokeOpacityResObj) {
298         RegisterResource<double>("ShapeStrokeOpacity", strokeOpacityResObj, strokeOpacity);
299     }
300     ShapeModel::GetInstance()->SetStrokeOpacity(strokeOpacity);
301 }
302 
SetFillOpacity(const JSCallbackInfo & info)303 void JSShape::SetFillOpacity(const JSCallbackInfo& info)
304 {
305     if (info.Length() < 1) {
306         return;
307     }
308     double fillOpacity = DEFAULT_OPACITY;
309     RefPtr<ResourceObject> fillOpacityResObj;
310     ParseJsDouble(info[0], fillOpacity, fillOpacityResObj);
311     UnRegisterResource("ShapeFillOpacity");
312     if (SystemProperties::ConfigChangePerform() && fillOpacityResObj) {
313         RegisterResource<double>("ShapeFillOpacity", fillOpacityResObj, fillOpacity);
314     }
315     ShapeModel::GetInstance()->SetFillOpacity(fillOpacity);
316 }
317 
SetStrokeWidth(const JSCallbackInfo & info)318 void JSShape::SetStrokeWidth(const JSCallbackInfo& info)
319 {
320     if (info.Length() < 1) {
321         return;
322     }
323     // the default value is 1.0_vp
324     CalcDimension lineWidth = 1.0_vp;
325     UnRegisterResource("ShapeStrokeWidth");
326     if (info[0]->IsString()) {
327         const std::string& value = info[0]->ToString();
328         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
329             lineWidth = StringUtils::StringToDimensionWithUnit(value, DimensionUnit::VP, 1.0);
330         } else {
331             if (!StringUtils::StringToDimensionWithUnitNG(value, lineWidth, DimensionUnit::VP, 1.0)) {
332                 // unit is invalid, use default value(1.0vp) instead.
333                 lineWidth = 1.0_vp;
334             }
335         }
336     } else {
337         RefPtr<ResourceObject> strokeWidthResObj;
338         ParseJsDimensionVp(info[0], lineWidth, strokeWidthResObj);
339         if (SystemProperties::ConfigChangePerform() && strokeWidthResObj) {
340             RegisterResource<CalcDimension>("ShapeStrokeWidth", strokeWidthResObj, lineWidth);
341         }
342     }
343     if (lineWidth.IsNegative()) {
344         lineWidth = 1.0_vp;
345     }
346     ShapeModel::GetInstance()->SetStrokeWidth(lineWidth);
347 }
348 
SetAntiAlias(bool antiAlias)349 void JSShape::SetAntiAlias(bool antiAlias)
350 {
351     ShapeModel::GetInstance()->SetAntiAlias(antiAlias);
352 }
353 
SetBitmapMesh(const JSCallbackInfo & info)354 void JSShape::SetBitmapMesh(const JSCallbackInfo& info)
355 {
356     if (info.Length() != 3) {
357         return;
358     }
359     std::vector<float> mesh;
360     uint32_t column = 0;
361     uint32_t row = 0;
362     JSRef<JSVal> columnValue = info[1];
363     JSRef<JSVal> rowValue = info[2];
364     if (!ParseJsInteger(columnValue, column)) {
365         ShapeModel::GetInstance()->SetBitmapMesh(mesh, 0, 0);
366         return;
367     }
368     if (!ParseJsInteger(rowValue, row)) {
369         ShapeModel::GetInstance()->SetBitmapMesh(mesh, 0, 0);
370         return;
371     }
372     if (info[0]->IsArray()) {
373         auto meshValue = JSRef<JSArray>::Cast(info[0]);
374         auto meshSize = meshValue->Length();
375         auto tempMeshSize = static_cast<uint64_t>(column + 1) * (row + 1) * 2;
376         if (tempMeshSize != meshSize) {
377             ShapeModel::GetInstance()->SetBitmapMesh(mesh, 0, 0);
378             return;
379         }
380         for (size_t i = 0; i < meshSize; i++) {
381             JSRef<JSVal> value = meshValue->GetValueAt(i);
382             // only support number
383             if (value->IsNumber()) {
384                 auto vert = value->ToNumber<float>();
385                 mesh.emplace_back(vert);
386             } else {
387                 ShapeModel::GetInstance()->SetBitmapMesh(std::vector<float>(), 0, 0);
388                 return;
389             }
390         }
391     }
392     ShapeModel::GetInstance()->SetBitmapMesh(mesh, static_cast<int32_t>(column), static_cast<int32_t>(row));
393 }
394 
SetForegroundColor(const JSCallbackInfo & info)395 void JSShape::SetForegroundColor(const JSCallbackInfo& info)
396 {
397     if (info.Length() < 1) {
398         return;
399     }
400     Color foregroundColor;
401     RefPtr<ResourceObject> foregroundColorResObj;
402     ForegroundColorStrategy strategy;
403     UnRegisterResource("ShapeForegroundColor");
404     if (ParseJsColorStrategy(info[0], strategy)) {
405         ShapeModel::GetInstance()->SetFill(Color::FOREGROUND);
406         ViewAbstractModel::GetInstance()->SetForegroundColorStrategy(strategy);
407         return;
408     }
409     if (!ParseJsColor(info[0], foregroundColor, foregroundColorResObj)) {
410         return;
411     }
412     if (SystemProperties::ConfigChangePerform() && foregroundColorResObj) {
413         RegisterResource<Color>("ShapeForegroundColor", foregroundColorResObj, foregroundColor);
414     }
415     ShapeModel::GetInstance()->SetForegroundColor(foregroundColor);
416     ViewAbstractModel::GetInstance()->SetForegroundColor(foregroundColor);
417 }
418 
JSBind(BindingTarget globalObj)419 void JSShape::JSBind(BindingTarget globalObj)
420 {
421     JSClass<JSShape>::Declare("Shape");
422     JSClass<JSShape>::StaticMethod("create", &JSShape::Create);
423     JSClass<JSShape>::StaticMethod("viewPort", &JSShape::SetViewPort);
424 
425     JSClass<JSShape>::StaticMethod("width", &JSShape::JsWidth);
426     JSClass<JSShape>::StaticMethod("height", &JSShape::JsHeight);
427     JSClass<JSShape>::StaticMethod("size", &JSShape::JsSize);
428 
429     JSClass<JSShape>::StaticMethod("stroke", &JSShape::SetStroke);
430     JSClass<JSShape>::StaticMethod("fill", &JSShape::SetFill);
431     JSClass<JSShape>::StaticMethod("strokeDashOffset", &JSShape::SetStrokeDashOffset);
432     JSClass<JSShape>::StaticMethod("strokeDashArray", &JSShape::SetStrokeDashArray);
433     JSClass<JSShape>::StaticMethod("strokeLineCap", &JSShape::SetStrokeLineCap);
434     JSClass<JSShape>::StaticMethod("strokeLineJoin", &JSShape::SetStrokeLineJoin);
435     JSClass<JSShape>::StaticMethod("strokeMiterLimit", &JSShape::SetStrokeMiterLimit);
436     JSClass<JSShape>::StaticMethod("strokeOpacity", &JSShape::SetStrokeOpacity);
437     JSClass<JSShape>::StaticMethod("fillOpacity", &JSShape::SetFillOpacity);
438     JSClass<JSShape>::StaticMethod("strokeWidth", &JSShape::SetStrokeWidth);
439     JSClass<JSShape>::StaticMethod("antiAlias", &JSShape::SetAntiAlias);
440     JSClass<JSShape>::StaticMethod("mesh", &JSShape::SetBitmapMesh);
441     JSClass<JSShape>::StaticMethod("foregroundColor", &JSShape::SetForegroundColor);
442 
443     JSClass<JSShape>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
444     JSClass<JSShape>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
445     JSClass<JSShape>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
446     JSClass<JSShape>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
447     JSClass<JSShape>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
448     JSClass<JSShape>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
449     JSClass<JSShape>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
450     JSClass<JSShape>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
451     JSClass<JSShape>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
452     JSClass<JSShape>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
453     JSClass<JSShape>::InheritAndBind<JSContainerBase>(globalObj);
454 }
455 
456 } // namespace OHOS::Ace::Framework
457