1 /*
2  * Copyright (c) 2021 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_rect.h"
17 
18 #include "base/log/ace_trace.h"
19 #include "bridge/declarative_frontend/jsview/models/rect_model_impl.h"
20 #include "core/components_ng/base/view_stack_model.h"
21 #include "core/components_ng/pattern/shape/rect_model.h"
22 #include "core/components_ng/pattern/shape/rect_model_ng.h"
23 
24 namespace OHOS::Ace {
GetInstance()25 RectModel* RectModel::GetInstance()
26 {
27 #ifdef NG_BUILD
28     static NG::RectModelNG instance;
29     return &instance;
30 #else
31     if (Container::IsCurrentUseNewPipeline()) {
32         static NG::RectModelNG instance;
33         return &instance;
34     } else {
35         static Framework::RectModelImpl instance;
36         return &instance;
37     }
38 #endif
39 }
40 } // namespace OHOS::Ace
41 
42 namespace OHOS::Ace::Framework {
43 namespace {
44 constexpr uint32_t HAS_RADIUS_WIDTH = 1;
45 constexpr uint32_t HAS_RADIUS_HEIGHT = 1 << 1;
46 constexpr uint32_t HAS_RADIUS = 1 << 2;
47 } // namespace
48 
Create(const JSCallbackInfo& info)49 void JSRect::Create(const JSCallbackInfo& info)
50 {
51     RectModel::GetInstance()->Create();
52     JSShapeAbstract::SetSize(info);
53     if (info.Length() > 0 && info[0]->IsObject()) {
54         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
55         auto propertyNames = obj->GetPropertyNames();
56         if (!propertyNames->IsArray()) {
57             return;
58         }
59         auto propertyFlag = 0U;
60         for (size_t i = 0; i < propertyNames->Length(); i++) {
61             JSRef<JSVal> value = propertyNames->GetValueAt(i);
62             if (!value->IsString()) {
63                 continue;
64             }
65             auto propertyName = value->ToString();
66             if (propertyName == "radiusWidth") {
67                 propertyFlag = propertyFlag | HAS_RADIUS_WIDTH;
68             } else if (propertyName == "radiusHeight") {
69                 propertyFlag = propertyFlag | HAS_RADIUS_HEIGHT;
70             } else if (propertyName == "radius") {
71                 propertyFlag = propertyFlag | HAS_RADIUS;
72             }
73         }
74         if ((propertyFlag & HAS_RADIUS_WIDTH) == HAS_RADIUS_WIDTH) {
75             JSRef<JSVal> radiusWidth = obj->GetProperty("radiusWidth");
76             SetRadiusWidth(radiusWidth);
77         }
78         if ((propertyFlag & HAS_RADIUS_HEIGHT) == HAS_RADIUS_HEIGHT) {
79             JSRef<JSVal> radiusHeight = obj->GetProperty("radiusHeight");
80             SetRadiusHeight(radiusHeight);
81         }
82         if ((propertyFlag & HAS_RADIUS) == HAS_RADIUS) {
83             JSRef<JSVal> radius = obj->GetProperty("radius");
84             if (radius->IsNumber() || radius->IsString()) {
85                 SetRadiusWithJsVal(nullptr, radius);
86             } else if (radius->IsArray()) {
87                 SetRadiusWithArrayValue(nullptr, radius);
88             }
89         }
90         info.SetReturnValue(info.This());
91     }
92 }
93 
JsRadiusWidth(const JSCallbackInfo& info)94 void JSRect::JsRadiusWidth(const JSCallbackInfo& info)
95 {
96     if (info.Length() < 1) {
97         return;
98     }
99     SetRadiusWidth(info[0]);
100 }
101 
JsRadiusHeight(const JSCallbackInfo& info)102 void JSRect::JsRadiusHeight(const JSCallbackInfo& info)
103 {
104     if (info.Length() < 1) {
105         return;
106     }
107     SetRadiusHeight(info[0]);
108 }
109 
SetRadiusWidth(const JSRef<JSVal>& jsVal)110 void JSRect::SetRadiusWidth(const JSRef<JSVal>& jsVal)
111 {
112     CalcDimension value(0.0f);
113     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
114         ParseJsDimensionVp(jsVal, value);
115     } else {
116         if (!ParseJsDimensionVpNG(jsVal, value)) {
117             value.SetValue(0.0f);
118         }
119     }
120     RectModel::GetInstance()->SetRadiusWidth(value);
121 }
122 
SetRadiusHeight(const JSRef<JSVal>& jsVal)123 void JSRect::SetRadiusHeight(const JSRef<JSVal>& jsVal)
124 {
125     CalcDimension value(0.0f);
126     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
127         ParseJsDimensionVp(jsVal, value);
128     } else {
129         if (!ParseJsDimensionVpNG(jsVal, value)) {
130             value.SetValue(0.0f);
131         }
132     }
133     RectModel::GetInstance()->SetRadiusHeight(value);
134 }
135 
SetRadius(const JSCallbackInfo& info)136 void JSRect::SetRadius(const JSCallbackInfo& info)
137 {
138     if (info.Length() < 1) {
139         return;
140     }
141     CalcDimension value(0.0f);
142     RectModel::GetInstance()->SetRadiusWidth(value);
143     RectModel::GetInstance()->SetRadiusHeight(value);
144     if (info[0]->IsArray()) {
145         SetRadiusWithArrayValue(nullptr, info[0]);
146         info.SetReturnValue(info.This());
147         return;
148     }
149     if (info[0]->IsNumber() || info[0]->IsString() || info[0]->IsObject()) {
150         SetRadiusWithJsVal(nullptr, info[0]);
151         info.SetReturnValue(info.This());
152     }
153 }
154 
SetRadiusWithJsVal(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)155 void JSRect::SetRadiusWithJsVal(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)
156 {
157     CalcDimension value(0.0f);
158     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
159         ParseJsDimensionVp(jsVal, value);
160     } else {
161         if (!ParseJsDimensionVpNG(jsVal, value)) {
162             value.SetValue(0.0f);
163         }
164     }
165     if (shapeRect) {
166         AnimationOption option = ViewStackModel::GetInstance()->GetImplicitAnimationOption();
167         shapeRect->SetRadiusWidth(value, option);
168         shapeRect->SetRadiusHeight(value, option);
169         return;
170     }
171     RectModel::GetInstance()->SetRadiusWidth(value);
172     RectModel::GetInstance()->SetRadiusHeight(value);
173 }
174 
SetRadiusWithArrayValue(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)175 void JSRect::SetRadiusWithArrayValue(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)
176 {
177     if (!jsVal->IsArray()) {
178         return;
179     }
180     JSRef<JSArray> array = JSRef<JSArray>::Cast(jsVal);
181     auto length = static_cast<int32_t>(array->Length());
182     if (length <= 0) {
183         return;
184     }
185     length = std::min(length, 4);
186     for (int32_t i = 0; i < length; i++) {
187         JSRef<JSVal> radiusItem = array->GetValueAt(i);
188         if (!radiusItem->IsArray()) {
189             break;
190         }
191         JSRef<JSArray> radiusArray = JSRef<JSArray>::Cast(radiusItem);
192         if (radiusArray->Length() != 2) {
193             break;
194         }
195         JSRef<JSVal> radiusX = radiusArray->GetValueAt(0);
196         JSRef<JSVal> radiusY = radiusArray->GetValueAt(1);
197         CalcDimension radiusXValue(0.0f);
198         CalcDimension radiusYValue(0.0f);
199         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
200             if (ParseJsDimensionVp(radiusX, radiusXValue)) {
201                 ParseJsDimensionVp(radiusY, radiusYValue);
202             }
203         } else {
204             if (!ParseJsDimensionVpNG(radiusX, radiusXValue)) {
205                 radiusXValue.SetValue(0.0f);
206             }
207             if (!ParseJsDimensionVpNG(radiusY, radiusYValue)) {
208                 radiusYValue.SetValue(0.0f);
209             }
210         }
211         SetRadiusValue(shapeRect, radiusXValue, radiusYValue, i);
212     }
213 }
214 
SetRadiusValue( const RefPtr<ShapeRect>& shapeRect, const CalcDimension& radiusX, const CalcDimension& radiusY, int32_t index)215 void JSRect::SetRadiusValue(
216     const RefPtr<ShapeRect>& shapeRect, const CalcDimension& radiusX, const CalcDimension& radiusY, int32_t index)
217 {
218     if (shapeRect) {
219         RectModel::GetInstance()->SetShapeRectRadius(shapeRect, radiusX, radiusY, index);
220     } else {
221         RectModel::GetInstance()->SetRadiusValue(radiusX, radiusY, index);
222     }
223 }
224 
ObjectRadiusWidth(const JSCallbackInfo& info)225 void JSRect::ObjectRadiusWidth(const JSCallbackInfo& info)
226 {
227     info.ReturnSelf();
228     if (info.Length() < 1) {
229         return;
230     }
231     CalcDimension value;
232     if (!ParseJsDimensionVp(info[0], value)) {
233         return;
234     }
235     if (LessNotEqual(value.Value(), 0.0)) {
236         return;
237     }
238     auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
239     if (rect) {
240         rect->SetRadiusWidth(value);
241     }
242 }
243 
ObjectRadiusHeight(const JSCallbackInfo& info)244 void JSRect::ObjectRadiusHeight(const JSCallbackInfo& info)
245 {
246     info.ReturnSelf();
247     if (info.Length() < 1) {
248         return;
249     }
250     CalcDimension value;
251     if (!ParseJsDimensionVp(info[0], value)) {
252         return;
253     }
254     if (LessNotEqual(value.Value(), 0.0)) {
255         return;
256     }
257     auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
258     if (rect) {
259         rect->SetRadiusHeight(value);
260     }
261 }
262 
ObjectRadius(const JSCallbackInfo& info)263 void JSRect::ObjectRadius(const JSCallbackInfo& info)
264 {
265     info.ReturnSelf();
266     if (info.Length() < 1) {
267         return;
268     }
269     auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
270     if (!rect) {
271         return;
272     }
273     if (info[0]->IsNumber() || info[0]->IsString()) {
274         SetRadiusWithJsVal(rect, info[0]);
275     }
276     if (info[0]->IsArray()) {
277         SetRadiusWithArrayValue(rect, info[0]);
278     }
279 }
280 
ParseRectObjBelowApi12(const RefPtr<ShapeRect>& rect, const JSRef<JSObject>& obj)281 void JSRect::ParseRectObjBelowApi12(const RefPtr<ShapeRect>& rect, const JSRef<JSObject>& obj)
282 {
283     CalcDimension width;
284     CalcDimension height;
285     CalcDimension radiusWidth;
286     CalcDimension radiusHeight;
287     if (ParseJsDimensionVp(obj->GetProperty("width"), width) && width.IsValid()) {
288         rect->SetWidth(width);
289     }
290     if (ParseJsDimensionVp(obj->GetProperty("height"), height) && height.IsValid()) {
291         rect->SetHeight(height);
292     }
293     if (ParseJsDimensionVp(obj->GetProperty("radiusWidth"), radiusWidth) && radiusWidth.IsValid()) {
294         rect->SetRadiusWidth(radiusWidth);
295     }
296     if (ParseJsDimensionVp(obj->GetProperty("radiusHeight"), radiusHeight) && radiusHeight.IsValid()) {
297         rect->SetRadiusHeight(radiusHeight);
298     }
299 }
300 
ParseRectObjAboveApi12(const RefPtr<ShapeRect>& rect, const JSRef<JSObject>& obj)301 void JSRect::ParseRectObjAboveApi12(const RefPtr<ShapeRect>& rect, const JSRef<JSObject>& obj)
302 {
303     CalcDimension width;
304     CalcDimension height;
305     CalcDimension radiusWidth;
306     CalcDimension radiusHeight;
307     if (ParseJsDimensionVpNG(obj->GetProperty("width"), width) && width.IsValid()) {
308         rect->SetWidth(width);
309     }
310     if (ParseJsDimensionVpNG(obj->GetProperty("height"), height) && height.IsValid()) {
311         rect->SetHeight(height);
312     }
313     if (ParseJsDimensionVpNG(obj->GetProperty("radiusWidth"), radiusWidth) && radiusWidth.IsValid()) {
314         rect->SetRadiusWidth(radiusWidth);
315     }
316     if (ParseJsDimensionVpNG(obj->GetProperty("radiusHeight"), radiusHeight) && radiusHeight.IsValid()) {
317         rect->SetRadiusHeight(radiusHeight);
318     }
319 }
320 
ConstructorCallback(const JSCallbackInfo& info)321 void JSRect::ConstructorCallback(const JSCallbackInfo& info)
322 {
323     auto jsRect = AceType::MakeRefPtr<JSRect>();
324     auto rect = AceType::MakeRefPtr<ShapeRect>();
325     if (info.Length() > 0 && info[0]->IsObject()) {
326         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
327         if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
328             ParseRectObjBelowApi12(rect, obj);
329         } else {
330             ParseRectObjAboveApi12(rect, obj);
331         }
332         JSRef<JSVal> radius = obj->GetProperty("radius");
333         if (radius->IsNumber() || radius->IsString()) {
334             SetRadiusWithJsVal(rect, radius);
335         } else if (radius->IsArray()) {
336             SetRadiusWithArrayValue(rect, radius);
337         }
338         info.SetReturnValue(info.This());
339     }
340     jsRect->SetBasicShape(rect);
341     jsRect->IncRefCount();
342     info.SetReturnValue(AceType::RawPtr(jsRect));
343 }
344 
DestructorCallback(JSRect* jsRect)345 void JSRect::DestructorCallback(JSRect* jsRect)
346 {
347     if (jsRect != nullptr) {
348         jsRect->DecRefCount();
349     }
350 }
351 
JSBind(BindingTarget globalObj)352 void JSRect::JSBind(BindingTarget globalObj)
353 {
354     JSClass<JSRect>::Declare("Rect");
355     JSClass<JSRect>::StaticMethod("create", &JSRect::Create);
356     JSClass<JSRect>::StaticMethod("radiusWidth", &JSRect::JsRadiusWidth);
357     JSClass<JSRect>::StaticMethod("radiusHeight", &JSRect::JsRadiusHeight);
358     JSClass<JSRect>::StaticMethod("radius", &JSRect::SetRadius);
359 
360     JSClass<JSRect>::CustomMethod("width", &JSShapeAbstract::ObjectWidth);
361     JSClass<JSRect>::CustomMethod("height", &JSShapeAbstract::ObjectHeight);
362     JSClass<JSRect>::CustomMethod("size", &JSShapeAbstract::ObjectSize);
363     JSClass<JSRect>::CustomMethod("offset", &JSShapeAbstract::ObjectOffset);
364     JSClass<JSRect>::CustomMethod("radiusWidth", &JSRect::ObjectRadiusWidth);
365     JSClass<JSRect>::CustomMethod("radiusHeight", &JSRect::ObjectRadiusHeight);
366     JSClass<JSRect>::CustomMethod("radius", &JSRect::ObjectRadius);
367     JSClass<JSRect>::CustomMethod("fill", &JSShapeAbstract::ObjectFill);
368     JSClass<JSRect>::CustomMethod("position", &JSShapeAbstract::ObjectPosition);
369 
370     JSClass<JSRect>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
371     JSClass<JSRect>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
372     JSClass<JSRect>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
373     JSClass<JSRect>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
374     JSClass<JSRect>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
375 
376     JSClass<JSRect>::InheritAndBind<JSShapeAbstract>(
377         globalObj, JSRect::ConstructorCallback, JSRect::DestructorCallback);
378 }
379 
380 } // namespace OHOS::Ace::Framework
381