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 return;
106 }
107 SetRadiusWidth(info[0]);
108 }
109
JsRadiusHeight(const JSCallbackInfo & info)110 void JSRect::JsRadiusHeight(const JSCallbackInfo& info)
111 {
112 if (info.Length() < 1) {
113 return;
114 }
115 SetRadiusHeight(info[0]);
116 }
117
SetRadiusWidth(const JSRef<JSVal> & jsVal)118 void JSRect::SetRadiusWidth(const JSRef<JSVal>& jsVal)
119 {
120 CalcDimension value(0.0f);
121 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
122 ParseJsDimensionVp(jsVal, value);
123 } else {
124 if (!ParseJsDimensionVpNG(jsVal, value)) {
125 value.SetValue(0.0f);
126 }
127 }
128 RectModel::GetInstance()->SetRadiusWidth(value);
129 }
130
SetRadiusHeight(const JSRef<JSVal> & jsVal)131 void JSRect::SetRadiusHeight(const JSRef<JSVal>& jsVal)
132 {
133 CalcDimension value(0.0f);
134 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
135 ParseJsDimensionVp(jsVal, value);
136 } else {
137 if (!ParseJsDimensionVpNG(jsVal, value)) {
138 value.SetValue(0.0f);
139 }
140 }
141 RectModel::GetInstance()->SetRadiusHeight(value);
142 }
143
SetRadius(const JSCallbackInfo & info)144 void JSRect::SetRadius(const JSCallbackInfo& info)
145 {
146 if (info.Length() < 1) {
147 return;
148 }
149 CalcDimension value(0.0f);
150 RectModel::GetInstance()->SetRadiusWidth(value);
151 RectModel::GetInstance()->SetRadiusHeight(value);
152 if (info[0]->IsArray()) {
153 SetRadiusWithArrayValue(nullptr, info[0]);
154 info.SetReturnValue(info.This());
155 return;
156 }
157 if (info[0]->IsNumber() || info[0]->IsString() || info[0]->IsObject()) {
158 SetRadiusWithJsVal(nullptr, info[0]);
159 info.SetReturnValue(info.This());
160 }
161 }
162
SetRadiusWithJsVal(const RefPtr<ShapeRect> & shapeRect,const JSRef<JSVal> & jsVal)163 void JSRect::SetRadiusWithJsVal(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)
164 {
165 CalcDimension value(0.0f);
166 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
167 ParseJsDimensionVp(jsVal, value);
168 } else {
169 if (!ParseJsDimensionVpNG(jsVal, value)) {
170 value.SetValue(0.0f);
171 }
172 }
173 if (shapeRect) {
174 AnimationOption option = ViewStackModel::GetInstance()->GetImplicitAnimationOption();
175 shapeRect->SetRadiusWidth(value, option);
176 shapeRect->SetRadiusHeight(value, option);
177 return;
178 }
179 RectModel::GetInstance()->SetRadiusWidth(value);
180 RectModel::GetInstance()->SetRadiusHeight(value);
181 }
182
SetRadiusWithArrayValue(const RefPtr<ShapeRect> & shapeRect,const JSRef<JSVal> & jsVal)183 void JSRect::SetRadiusWithArrayValue(const RefPtr<ShapeRect>& shapeRect, const JSRef<JSVal>& jsVal)
184 {
185 if (!jsVal->IsArray()) {
186 return;
187 }
188 JSRef<JSArray> array = JSRef<JSArray>::Cast(jsVal);
189 auto length = static_cast<int32_t>(array->Length());
190 if (length <= 0) {
191 return;
192 }
193 length = std::min(length, 4);
194 for (int32_t i = 0; i < length; i++) {
195 JSRef<JSVal> radiusItem = array->GetValueAt(i);
196 if (!radiusItem->IsArray()) {
197 break;
198 }
199 JSRef<JSArray> radiusArray = JSRef<JSArray>::Cast(radiusItem);
200 if (radiusArray->Length() != 2) {
201 break;
202 }
203 JSRef<JSVal> radiusX = radiusArray->GetValueAt(0);
204 JSRef<JSVal> radiusY = radiusArray->GetValueAt(1);
205 CalcDimension radiusXValue(0.0f);
206 CalcDimension radiusYValue(0.0f);
207 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
208 if (ParseJsDimensionVp(radiusX, radiusXValue)) {
209 ParseJsDimensionVp(radiusY, radiusYValue);
210 }
211 } else {
212 if (!ParseJsDimensionVpNG(radiusX, radiusXValue)) {
213 radiusXValue.SetValue(0.0f);
214 }
215 if (!ParseJsDimensionVpNG(radiusY, radiusYValue)) {
216 radiusYValue.SetValue(0.0f);
217 }
218 }
219 SetRadiusValue(shapeRect, radiusXValue, radiusYValue, i);
220 }
221 }
222
SetRadiusValue(const RefPtr<ShapeRect> & shapeRect,const CalcDimension & radiusX,const CalcDimension & radiusY,int32_t index)223 void JSRect::SetRadiusValue(
224 const RefPtr<ShapeRect>& shapeRect, const CalcDimension& radiusX, const CalcDimension& radiusY, int32_t index)
225 {
226 if (shapeRect) {
227 RectModel::GetInstance()->SetShapeRectRadius(shapeRect, radiusX, radiusY, index);
228 } else {
229 RectModel::GetInstance()->SetRadiusValue(radiusX, radiusY, index);
230 }
231 }
232
ObjectRadiusWidth(const JSCallbackInfo & info)233 void JSRect::ObjectRadiusWidth(const JSCallbackInfo& info)
234 {
235 info.ReturnSelf();
236 if (info.Length() < 1) {
237 return;
238 }
239 CalcDimension value;
240 if (!ParseJsDimensionVp(info[0], value)) {
241 return;
242 }
243 if (LessNotEqual(value.Value(), 0.0)) {
244 return;
245 }
246 auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
247 if (rect) {
248 rect->SetRadiusWidth(value);
249 }
250 }
251
ObjectRadiusHeight(const JSCallbackInfo & info)252 void JSRect::ObjectRadiusHeight(const JSCallbackInfo& info)
253 {
254 info.ReturnSelf();
255 if (info.Length() < 1) {
256 return;
257 }
258 CalcDimension value;
259 if (!ParseJsDimensionVp(info[0], value)) {
260 return;
261 }
262 if (LessNotEqual(value.Value(), 0.0)) {
263 return;
264 }
265 auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
266 if (rect) {
267 rect->SetRadiusHeight(value);
268 }
269 }
270
ObjectRadius(const JSCallbackInfo & info)271 void JSRect::ObjectRadius(const JSCallbackInfo& info)
272 {
273 info.ReturnSelf();
274 if (info.Length() < 1) {
275 return;
276 }
277 auto rect = AceType::DynamicCast<ShapeRect>(basicShape_);
278 if (!rect) {
279 return;
280 }
281 if (info[0]->IsNumber() || info[0]->IsString()) {
282 SetRadiusWithJsVal(rect, info[0]);
283 }
284 if (info[0]->IsArray()) {
285 SetRadiusWithArrayValue(rect, info[0]);
286 }
287 }
288
ParseRectObjBelowApi12(const RefPtr<ShapeRect> & rect,const JSRef<JSObject> & obj)289 void JSRect::ParseRectObjBelowApi12(const RefPtr<ShapeRect>& rect, const JSRef<JSObject>& obj)
290 {
291 CalcDimension width;
292 CalcDimension height;
293 CalcDimension radiusWidth;
294 CalcDimension radiusHeight;
295 if (ParseJsDimensionVp(obj->GetProperty("width"), width) && width.IsValid()) {
296 rect->SetWidth(width);
297 }
298 if (ParseJsDimensionVp(obj->GetProperty("height"), height) && height.IsValid()) {
299 rect->SetHeight(height);
300 }
301 if (ParseJsDimensionVp(obj->GetProperty("radiusWidth"), radiusWidth) && radiusWidth.IsValid()) {
302 rect->SetRadiusWidth(radiusWidth);
303 }
304 if (ParseJsDimensionVp(obj->GetProperty("radiusHeight"), radiusHeight) && radiusHeight.IsValid()) {
305 rect->SetRadiusHeight(radiusHeight);
306 }
307 }
308
ParseRectObjAboveApi12(const RefPtr<ShapeRect> & rect,const JSRef<JSObject> & obj)309 void JSRect::ParseRectObjAboveApi12(const RefPtr<ShapeRect>& rect, const JSRef<JSObject>& obj)
310 {
311 CalcDimension width;
312 CalcDimension height;
313 CalcDimension radiusWidth;
314 CalcDimension radiusHeight;
315 if (ParseJsDimensionVpNG(obj->GetProperty("width"), width) && width.IsValid()) {
316 rect->SetWidth(width);
317 }
318 if (ParseJsDimensionVpNG(obj->GetProperty("height"), height) && height.IsValid()) {
319 rect->SetHeight(height);
320 }
321 if (ParseJsDimensionVpNG(obj->GetProperty("radiusWidth"), radiusWidth) && radiusWidth.IsValid()) {
322 rect->SetRadiusWidth(radiusWidth);
323 }
324 if (ParseJsDimensionVpNG(obj->GetProperty("radiusHeight"), radiusHeight) && radiusHeight.IsValid()) {
325 rect->SetRadiusHeight(radiusHeight);
326 }
327 }
328
ConstructorCallback(const JSCallbackInfo & info)329 void JSRect::ConstructorCallback(const JSCallbackInfo& info)
330 {
331 auto jsRect = AceType::MakeRefPtr<JSRect>();
332 auto rect = AceType::MakeRefPtr<ShapeRect>();
333 if (info.Length() > 0 && info[0]->IsObject()) {
334 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
335 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
336 ParseRectObjBelowApi12(rect, obj);
337 } else {
338 ParseRectObjAboveApi12(rect, obj);
339 }
340 JSRef<JSVal> radius = obj->GetProperty("radius");
341 if (radius->IsNumber() || radius->IsString()) {
342 SetRadiusWithJsVal(rect, radius);
343 } else if (radius->IsArray()) {
344 SetRadiusWithArrayValue(rect, radius);
345 }
346 info.SetReturnValue(info.This());
347 }
348 jsRect->SetBasicShape(rect);
349 jsRect->IncRefCount();
350 info.SetReturnValue(AceType::RawPtr(jsRect));
351 }
352
DestructorCallback(JSRect * jsRect)353 void JSRect::DestructorCallback(JSRect* jsRect)
354 {
355 if (jsRect != nullptr) {
356 jsRect->DecRefCount();
357 }
358 }
359
JSBind(BindingTarget globalObj)360 void JSRect::JSBind(BindingTarget globalObj)
361 {
362 JSClass<JSRect>::Declare("Rect");
363 JSClass<JSRect>::StaticMethod("create", &JSRect::Create);
364 JSClass<JSRect>::StaticMethod("radiusWidth", &JSRect::JsRadiusWidth);
365 JSClass<JSRect>::StaticMethod("radiusHeight", &JSRect::JsRadiusHeight);
366 JSClass<JSRect>::StaticMethod("radius", &JSRect::SetRadius);
367
368 JSClass<JSRect>::CustomMethod("width", &JSShapeAbstract::ObjectWidth);
369 JSClass<JSRect>::CustomMethod("height", &JSShapeAbstract::ObjectHeight);
370 JSClass<JSRect>::CustomMethod("size", &JSShapeAbstract::ObjectSize);
371 JSClass<JSRect>::CustomMethod("offset", &JSShapeAbstract::ObjectOffset);
372 JSClass<JSRect>::CustomMethod("radiusWidth", &JSRect::ObjectRadiusWidth);
373 JSClass<JSRect>::CustomMethod("radiusHeight", &JSRect::ObjectRadiusHeight);
374 JSClass<JSRect>::CustomMethod("radius", &JSRect::ObjectRadius);
375 JSClass<JSRect>::CustomMethod("fill", &JSShapeAbstract::ObjectFill);
376 JSClass<JSRect>::CustomMethod("position", &JSShapeAbstract::ObjectPosition);
377
378 JSClass<JSRect>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
379 JSClass<JSRect>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
380 JSClass<JSRect>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
381 JSClass<JSRect>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
382 JSClass<JSRect>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
383
384 JSClass<JSRect>::InheritAndBind<JSShapeAbstract>(
385 globalObj, JSRect::ConstructorCallback, JSRect::DestructorCallback);
386 }
387
388 } // namespace OHOS::Ace::Framework
389