1 /*
2 * Copyright (c) 2021-2022 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 } // namespace
30 std::unique_ptr<ShapeModel> ShapeModel::instance_;
31
GetInstance()32 ShapeModel* ShapeModel::GetInstance()
33 {
34 if (!instance_) {
35 #ifdef NG_BUILD
36 instance_.reset(new NG::ShapeModelNG());
37 #else
38 if (Container::IsCurrentUseNewPipeline()) {
39 instance_.reset(new NG::ShapeModelNG());
40 } else {
41 instance_.reset(new Framework::ShapeModelImpl());
42 }
43 #endif
44 }
45 return instance_.get();
46 }
47
48 } // namespace OHOS::Ace
49
50 namespace OHOS::Ace::Framework {
51
Create(const JSCallbackInfo & info)52 void JSShape::Create(const JSCallbackInfo& info)
53 {
54 ShapeModel::GetInstance()->Create();
55 JSInteractableView::SetFocusable(true);
56 InitBox(info);
57 }
58
InitBox(const JSCallbackInfo & info)59 void JSShape::InitBox(const JSCallbackInfo& info)
60 {
61 RefPtr<PixelMap> pixMap = nullptr;
62 if (info.Length() == 1 && info[0]->IsObject()) {
63 #if !defined(PREVIEW)
64 pixMap = CreatePixelMapFromNapiValue(info[0]);
65 #endif
66 }
67 ShapeModel::GetInstance()->InitBox(pixMap);
68 }
69
SetViewPort(const JSCallbackInfo & info)70 void JSShape::SetViewPort(const JSCallbackInfo& info)
71 {
72 if (info.Length() < 1) {
73 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
74 return;
75 }
76 if (info[0]->IsObject()) {
77 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
78 JSRef<JSVal> leftValue = obj->GetProperty("x");
79 JSRef<JSVal> topValue = obj->GetProperty("y");
80 JSRef<JSVal> widthValue = obj->GetProperty("width");
81 JSRef<JSVal> heightValue = obj->GetProperty("height");
82 ShapeViewBox viewBox;
83 Dimension dimLeft;
84 ParseJsDimensionVp(leftValue, dimLeft);
85 Dimension dimTop;
86 ParseJsDimensionVp(topValue, dimTop);
87 Dimension dimWidth;
88 ParseJsDimensionVp(widthValue, dimWidth);
89 Dimension dimHeight;
90 ParseJsDimensionVp(heightValue, dimHeight);
91 ShapeModel::GetInstance()->SetViewPort(dimLeft, dimTop, dimWidth, dimHeight);
92 }
93 info.SetReturnValue(info.This());
94 }
95
JsWidth(const JSCallbackInfo & info)96 void JSShape::JsWidth(const JSCallbackInfo& info)
97 {
98 if (info.Length() < 1) {
99 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
100 return;
101 }
102
103 JsWidth(info[0]);
104 }
105
JsWidth(const JSRef<JSVal> & jsValue)106 void JSShape::JsWidth(const JSRef<JSVal>& jsValue)
107 {
108 JSViewAbstract::JsWidth(jsValue);
109 ShapeModel::GetInstance()->SetWidth();
110 }
111
JsHeight(const JSCallbackInfo & info)112 void JSShape::JsHeight(const JSCallbackInfo& info)
113 {
114 if (info.Length() < 1) {
115 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
116 return;
117 }
118
119 JsHeight(info[0]);
120 }
121
JsHeight(const JSRef<JSVal> & jsValue)122 void JSShape::JsHeight(const JSRef<JSVal>& jsValue)
123 {
124 JSViewAbstract::JsHeight(jsValue);
125 ShapeModel::GetInstance()->SetHeight();
126 }
127
JsSize(const JSCallbackInfo & info)128 void JSShape::JsSize(const JSCallbackInfo& info)
129 {
130 if (info.Length() < 1) {
131 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
132 return;
133 }
134
135 if (!info[0]->IsObject()) {
136 LOGE("arg is not Object or String.");
137 return;
138 }
139
140 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
141 JsWidth(sizeObj->GetProperty("width"));
142 JsHeight(sizeObj->GetProperty("height"));
143 }
144
SetStrokeDashArray(const JSCallbackInfo & info)145 void JSShape::SetStrokeDashArray(const JSCallbackInfo& info)
146 {
147 if (info.Length() < 1 || !info[0]->IsArray()) {
148 LOGE("info is not array");
149 return;
150 }
151 JSRef<JSArray> array = JSRef<JSArray>::Cast(info[0]);
152 int32_t length = static_cast<int32_t>(array->Length());
153 if (length <= 0) {
154 LOGE("info is invalid");
155 return;
156 }
157 std::vector<Dimension> dashArray;
158 for (int32_t i = 0; i < length; i++) {
159 JSRef<JSVal> value = array->GetValueAt(i);
160 Dimension dim;
161 if (ParseJsDimensionVp(value, dim)) {
162 dashArray.emplace_back(dim);
163 }
164 }
165 if (length != static_cast<int32_t>(dashArray.size())) {
166 LOGE("ParseJsDimensionVp failed");
167 return;
168 }
169 // if odd,add twice
170 if ((static_cast<uint32_t>(length) & 1)) {
171 for (int32_t i = 0; i < length; i++) {
172 dashArray.emplace_back(dashArray[i]);
173 }
174 }
175 ShapeModel::GetInstance()->SetStrokeDashArray(dashArray);
176 info.SetReturnValue(info.This());
177 }
178
SetStroke(const JSCallbackInfo & info)179 void JSShape::SetStroke(const JSCallbackInfo& info)
180 {
181 if (info.Length() < 1) {
182 LOGE("The argv is wrong, it is supposed to have at least 1 argument");
183 return;
184 }
185 Color strokeColor = Color::TRANSPARENT;
186 ParseJsColor(info[0], strokeColor);
187 ShapeModel::GetInstance()->SetStroke(strokeColor);
188 }
189
SetFill(const JSCallbackInfo & info)190 void JSShape::SetFill(const JSCallbackInfo& info)
191 {
192 if (info.Length() < 1) {
193 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
194 return;
195 }
196 if (info[0]->IsString() && info[0]->ToString() == "none") {
197 ShapeModel::GetInstance()->SetFill(Color::TRANSPARENT);
198 } else {
199 Color fillColor;
200 if (ParseJsColor(info[0], fillColor)) {
201 ShapeModel::GetInstance()->SetFill(fillColor);
202 }
203 }
204 }
205
SetStrokeDashOffset(const JSCallbackInfo & info)206 void JSShape::SetStrokeDashOffset(const JSCallbackInfo& info)
207 {
208 if (info.Length() < 1) {
209 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
210 return;
211 }
212 Dimension offset;
213 if (!ParseJsDimensionVp(info[0], offset)) {
214 return;
215 }
216 ShapeModel::GetInstance()->SetStrokeDashOffset(offset);
217 }
218
SetStrokeLineCap(int lineCap)219 void JSShape::SetStrokeLineCap(int lineCap)
220 {
221 ShapeModel::GetInstance()->SetStrokeLineCap(lineCap);
222 }
223
SetStrokeLineJoin(int lineJoin)224 void JSShape::SetStrokeLineJoin(int lineJoin)
225 {
226 ShapeModel::GetInstance()->SetStrokeLineJoin(lineJoin);
227 }
228
SetStrokeMiterLimit(const JSCallbackInfo & info)229 void JSShape::SetStrokeMiterLimit(const JSCallbackInfo& info)
230 {
231 if (info.Length() < 1) {
232 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
233 return;
234 }
235 double miterLimit;
236 if (!ParseJsDouble(info[0], miterLimit)) {
237 return;
238 }
239 if (GreatOrEqual(miterLimit, 1.0)) {
240 ShapeModel::GetInstance()->SetStrokeMiterLimit(miterLimit);
241 }
242 }
243
SetStrokeOpacity(const JSCallbackInfo & info)244 void JSShape::SetStrokeOpacity(const JSCallbackInfo& info)
245 {
246 if (info.Length() < 1) {
247 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
248 return;
249 }
250 double strokeOpacity = DEFAULT_OPACITY;
251 ParseJsDouble(info[0], strokeOpacity);
252 ShapeModel::GetInstance()->SetStrokeOpacity(strokeOpacity);
253 }
254
SetFillOpacity(const JSCallbackInfo & info)255 void JSShape::SetFillOpacity(const JSCallbackInfo& info)
256 {
257 if (info.Length() < 1) {
258 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
259 return;
260 }
261 double fillOpacity = DEFAULT_OPACITY;
262 ParseJsDouble(info[0], fillOpacity);
263 ShapeModel::GetInstance()->SetFillOpacity(fillOpacity);
264 }
265
SetStrokeWidth(const JSCallbackInfo & info)266 void JSShape::SetStrokeWidth(const JSCallbackInfo& info)
267 {
268 if (info.Length() < 1) {
269 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
270 return;
271 }
272 // the default value is 1.0_vp
273 Dimension lineWidth = 1.0_vp;
274 if (info[0]->IsString()) {
275 const std::string& value = info[0]->ToString();
276 lineWidth = StringUtils::StringToDimensionWithUnit(value, DimensionUnit::VP, 1.0);
277 } else {
278 ParseJsDimensionVp(info[0], lineWidth);
279 }
280 if (lineWidth.IsNegative()) {
281 lineWidth = 1.0_vp;
282 }
283 ShapeModel::GetInstance()->SetStrokeWidth(lineWidth);
284 }
285
SetAntiAlias(bool antiAlias)286 void JSShape::SetAntiAlias(bool antiAlias)
287 {
288 ShapeModel::GetInstance()->SetAntiAlias(antiAlias);
289 }
290
SetBitmapMesh(const JSCallbackInfo & info)291 void JSShape::SetBitmapMesh(const JSCallbackInfo& info)
292 {
293 if (info.Length() != 3) {
294 LOGE("The arg is wrong, it is supposed to have at least 3 argument");
295 return;
296 }
297 std::vector<double> mesh;
298 JSRef<JSVal> meshValue = info[0];
299
300 if (meshValue->IsObject()) {
301 JSRef<JSObject> meshObj = JSRef<JSObject>::Cast(meshValue);
302 JSRef<JSArray> array = meshObj->GetPropertyNames();
303 for (size_t i = 0; i < array->Length(); i++) {
304 JSRef<JSVal> value = array->GetValueAt(i);
305 if (value->IsString()) {
306 std::string valueStr;
307 if (ParseJsString(value, valueStr)) {
308 double vert;
309 if (ParseJsDouble(meshObj->GetProperty(valueStr.c_str()), vert)) {
310 mesh.push_back(vert);
311 }
312 }
313 }
314 }
315 }
316 uint32_t column = 0;
317 uint32_t row = 0;
318 JSRef<JSVal> columnValue = info[1];
319 JSRef<JSVal> rowValue = info[2];
320 if (!ParseJsInteger(columnValue, column)) {
321 return;
322 }
323 if (!ParseJsInteger(rowValue, row)) {
324 return;
325 }
326 ShapeModel::GetInstance()->SetBitmapMesh(mesh, static_cast<int32_t>(column), static_cast<int32_t>(row));
327 }
328
JSBind(BindingTarget globalObj)329 void JSShape::JSBind(BindingTarget globalObj)
330 {
331 JSClass<JSShape>::Declare("Shape");
332 JSClass<JSShape>::StaticMethod("create", &JSShape::Create);
333 JSClass<JSShape>::StaticMethod("viewPort", &JSShape::SetViewPort);
334
335 JSClass<JSShape>::StaticMethod("width", &JSShape::JsWidth);
336 JSClass<JSShape>::StaticMethod("height", &JSShape::JsHeight);
337 JSClass<JSShape>::StaticMethod("size", &JSShape::JsSize);
338
339 JSClass<JSShape>::StaticMethod("stroke", &JSShape::SetStroke);
340 JSClass<JSShape>::StaticMethod("fill", &JSShape::SetFill);
341 JSClass<JSShape>::StaticMethod("strokeDashOffset", &JSShape::SetStrokeDashOffset);
342 JSClass<JSShape>::StaticMethod("strokeDashArray", &JSShape::SetStrokeDashArray);
343 JSClass<JSShape>::StaticMethod("strokeLineCap", &JSShape::SetStrokeLineCap);
344 JSClass<JSShape>::StaticMethod("strokeLineJoin", &JSShape::SetStrokeLineJoin);
345 JSClass<JSShape>::StaticMethod("strokeMiterLimit", &JSShape::SetStrokeMiterLimit);
346 JSClass<JSShape>::StaticMethod("strokeOpacity", &JSShape::SetStrokeOpacity);
347 JSClass<JSShape>::StaticMethod("fillOpacity", &JSShape::SetFillOpacity);
348 JSClass<JSShape>::StaticMethod("strokeWidth", &JSShape::SetStrokeWidth);
349 JSClass<JSShape>::StaticMethod("antiAlias", &JSShape::SetAntiAlias);
350 JSClass<JSShape>::StaticMethod("mesh", &JSShape::SetBitmapMesh);
351
352 JSClass<JSShape>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
353 JSClass<JSShape>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
354 JSClass<JSShape>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
355 JSClass<JSShape>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
356 JSClass<JSShape>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
357 JSClass<JSShape>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
358 JSClass<JSShape>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
359 JSClass<JSShape>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
360 JSClass<JSShape>::Inherit<JSContainerBase>();
361 JSClass<JSShape>::Inherit<JSViewAbstract>();
362 JSClass<JSShape>::Bind<>(globalObj);
363 }
364
365 } // namespace OHOS::Ace::Framework
366