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