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