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