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