1 /*
2  * Copyright (c) 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_rect_shape.h"
17 #include "core/components_ng/base/view_stack_model.h"
18 
19 namespace OHOS::Ace::Framework {
20 namespace {
21 const int32_t LENGTH_RADIUS_ARRAY = 2;
22 const int32_t LENGTH_ARRAY = 4;
23 }
ObjectRadiusWidth(const JSCallbackInfo & info)24 void JSRectShape::ObjectRadiusWidth(const JSCallbackInfo& info)
25 {
26     info.ReturnSelf();
27     if (info.Length() < 1) {
28         return;
29     }
30 
31     CalcDimension radiusWidth;
32     if (!ParseJsDimensionVp(info[0], radiusWidth)) {
33         return;
34     }
35     if (LessNotEqual(radiusWidth.Value(), 0.0)) {
36         return;
37     }
38 
39     auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
40     if (rect) {
41         rect->SetRadiusWidth(radiusWidth);
42     }
43 }
44 
ObjectRadiusHeight(const JSCallbackInfo & info)45 void JSRectShape::ObjectRadiusHeight(const JSCallbackInfo& info)
46 {
47     info.ReturnSelf();
48     if (info.Length() < 1) {
49         return;
50     }
51 
52     CalcDimension radiusHeight;
53     if (!ParseJsDimensionVp(info[0], radiusHeight)) {
54         return;
55     }
56     if (LessNotEqual(radiusHeight.Value(), 0.0)) {
57         return;
58     }
59 
60     auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
61     if (rect) {
62         rect->SetRadiusHeight(radiusHeight);
63     }
64 }
65 
ObjectRadius(const JSCallbackInfo & info)66 void JSRectShape::ObjectRadius(const JSCallbackInfo& info)
67 {
68     info.ReturnSelf();
69     if (info.Length() < 1) {
70         return;
71     }
72 
73     auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
74     if (!rect) {
75         return;
76     }
77 
78     if (info[0]->IsNumber() || info[0]->IsString()) {
79         SetRadiusWithJsVal(rect, info[0]);
80     }
81 
82     if (info[0]->IsArray()) {
83         SetRadiusWithArrayValue(rect, info[0]);
84     }
85 }
86 
SetRadiusWithJsVal(const RefPtr<ShapeRect> & shapeRect,const JSRef<JSVal> & jsVal)87 void JSRectShape::SetRadiusWithJsVal(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)
88 {
89     CalcDimension value(0.0f);
90     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
91         ParseJsDimensionVp(jsVal, value);
92     } else {
93         if (!ParseJsDimensionVpNG(jsVal, value)) {
94             value.SetValue(0.0f);
95         }
96     }
97 
98     if (shapeRect) {
99         AnimationOption option = ViewStackModel::GetInstance()->GetImplicitAnimationOption();
100         shapeRect->SetRadiusWidth(value, option);
101         shapeRect->SetRadiusHeight(value, option);
102         return;
103     }
104 }
105 
SetRadiusWithArrayValue(const RefPtr<ShapeRect> & shapeRect,const JSRef<JSVal> & jsVal)106 void JSRectShape::SetRadiusWithArrayValue(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)
107 {
108     if (!jsVal->IsArray() || !shapeRect) {
109         return;
110     }
111 
112     JSRef<JSArray> array = JSRef<JSArray>::Cast(jsVal);
113 
114     auto length = static_cast<int32_t>(array->Length());
115     if (length <= 0) {
116         return;
117     }
118     length = std::min(length, LENGTH_ARRAY);
119 
120     for (int32_t i = 0; i < length; i++) {
121         JSRef<JSVal> radiusItem = array->GetValueAt(i);
122         if (!radiusItem->IsArray()) {
123             CalcDimension radiusXYValue(0.0f);
124             if (!ParseJsDimensionVpNG(radiusItem, radiusXYValue)) {
125                 radiusXYValue.SetValue(0.0f);
126             }
127             SetRadiusValue(shapeRect, radiusXYValue, radiusXYValue, i);
128             continue;
129         }
130         JSRef<JSArray> radiusArray = JSRef<JSArray>::Cast(radiusItem);
131         if (radiusArray->Length() != LENGTH_RADIUS_ARRAY) {
132             break;
133         }
134         JSRef<JSVal> radiusX = radiusArray->GetValueAt(0);
135         JSRef<JSVal> radiusY = radiusArray->GetValueAt(1);
136         CalcDimension radiusXValue(0.0f);
137         CalcDimension radiusYValue(0.0f);
138 
139         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
140             if (ParseJsDimensionVp(radiusX, radiusXValue)) {
141                 ParseJsDimensionVp(radiusY, radiusYValue);
142             }
143         } else {
144             if (!ParseJsDimensionVpNG(radiusX, radiusXValue)) {
145                 radiusXValue.SetValue(0.0f);
146             }
147             if (!ParseJsDimensionVpNG(radiusY, radiusYValue)) {
148                 radiusYValue.SetValue(0.0f);
149             }
150         }
151 
152         SetRadiusValue(shapeRect, radiusXValue, radiusYValue, i);
153     }
154 }
155 
SetRadiusValue(const RefPtr<ShapeRect> & shapeRect,const CalcDimension & radiusX,const CalcDimension & radiusY,int32_t index)156 void JSRectShape::SetRadiusValue(
157     const RefPtr<ShapeRect>& shapeRect, const CalcDimension& radiusX, const CalcDimension& radiusY, int32_t index)
158 {
159     CHECK_NULL_VOID(shapeRect);
160     auto newRadius = Ace::Radius(Dimension(radiusX), Dimension(radiusY));
161     switch (index) {
162         case TOP_LEFT_RADIUS:
163             shapeRect->SetTopLeftRadius(newRadius);
164             break;
165         case TOP_RIGHT_RADIUS:
166             shapeRect->SetTopRightRadius(newRadius);
167             break;
168         case BOTTOM_RIGHT_RADIUS:
169             shapeRect->SetBottomRightRadius(newRadius);
170             break;
171         case BOTTOM_LEFT_RADIUS:
172             shapeRect->SetBottomLeftRadius(newRadius);
173             break;
174         default:
175             break;
176     }
177 }
178 
ConstructorCallback(const JSCallbackInfo & info)179 void JSRectShape::ConstructorCallback(const JSCallbackInfo& info)
180 {
181     auto jsRectShape = AceType::MakeRefPtr<JSRectShape>();
182     auto rect = AceType::MakeRefPtr<ShapeRect>();
183 
184     if (info.Length() > 0 && info[0]->IsObject()) {
185         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
186         CalcDimension width;
187         if (ParseJsDimensionVpNG(obj->GetProperty("width"), width) && width.IsValid()) {
188             rect->SetWidth(width);
189         }
190 
191         CalcDimension height;
192         if (ParseJsDimensionVpNG(obj->GetProperty("height"), height) && height.IsValid()) {
193             rect->SetHeight(height);
194         }
195 
196         CalcDimension radiusWidth;
197         if (ParseJsDimensionVpNG(obj->GetProperty("radiusWidth"), radiusWidth) && radiusWidth.IsValid()) {
198             rect->SetRadiusWidth(radiusWidth);
199         }
200 
201         CalcDimension radiusHeight;
202         if (ParseJsDimensionVpNG(obj->GetProperty("radiusHeight"), radiusHeight) && radiusHeight.IsValid()) {
203             rect->SetRadiusHeight(radiusHeight);
204         }
205 
206         JSRef<JSVal> radius = obj->GetProperty("radius");
207         if (radius->IsNumber() || radius->IsString()) {
208             SetRadiusWithJsVal(rect, radius);
209         }
210         if (radius->IsArray()) {
211             SetRadiusWithArrayValue(rect, radius);
212         }
213         info.SetReturnValue(info.This());
214     }
215 
216     jsRectShape->SetBasicShape(rect);
217     jsRectShape->IncRefCount();
218     info.SetReturnValue(AceType::RawPtr(jsRectShape));
219 }
220 
DestructorCallback(JSRectShape * jsRectShape)221 void JSRectShape::DestructorCallback(JSRectShape* jsRectShape)
222 {
223     if (jsRectShape != nullptr) {
224         jsRectShape->DecRefCount();
225     }
226 }
227 
JSBind(BindingTarget globalObj)228 void JSRectShape::JSBind(BindingTarget globalObj)
229 {
230     JSClass<JSRectShape>::Declare("__RectShape__");
231 
232     JSClass<JSRectShape>::CustomMethod("width", &JSShapeAbstract::ObjectWidth);
233     JSClass<JSRectShape>::CustomMethod("height", &JSShapeAbstract::ObjectHeight);
234     JSClass<JSRectShape>::CustomMethod("size", &JSShapeAbstract::ObjectSize);
235     JSClass<JSRectShape>::CustomMethod("offset", &JSShapeAbstract::ObjectOffset);
236     JSClass<JSRectShape>::CustomMethod("radiusWidth", &JSRectShape::ObjectRadiusWidth);
237     JSClass<JSRectShape>::CustomMethod("radiusHeight", &JSRectShape::ObjectRadiusHeight);
238     JSClass<JSRectShape>::CustomMethod("radius", &JSRectShape::ObjectRadius);
239     JSClass<JSRectShape>::CustomMethod("fill", &JSShapeAbstract::ObjectFill);
240     JSClass<JSRectShape>::CustomMethod("position", &JSShapeAbstract::ObjectPosition);
241 
242     JSClass<JSRectShape>::InheritAndBind<JSShapeAbstract>(
243         globalObj, JSRectShape::ConstructorCallback, JSRectShape::DestructorCallback);
244 }
245 
246 } // namespace OHOS::Ace::Framework
247