• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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