1 /*
2 * Copyright (c) 2021-2022 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_flex_impl.h"
17
18 #include "core/components_ng/pattern/flex/flex_model.h"
19 #include "frameworks/bridge/declarative_frontend/engine/js_ref_ptr.h"
20 #include "frameworks/bridge/declarative_frontend/jsview/js_view_common_def.h"
21 #include "frameworks/bridge/declarative_frontend/jsview/models/flex_model_impl.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23 #include "frameworks/core/components_ng/pattern/flex/flex_model_ng.h"
24
25 namespace OHOS::Ace::Framework {
26
27 constexpr int32_t REVERSE_OFFSET_ZOOM = 2;
Create(const JSCallbackInfo & info)28 void JSFlexImpl::Create(const JSCallbackInfo& info)
29 {
30 if (info.Length() < 1) {
31 FlexModel::GetInstance()->CreateFlexRow();
32 return;
33 }
34 if (!info[0]->IsObject()) {
35 FlexModel::GetInstance()->CreateFlexRow();
36 return;
37 }
38 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
39 JSRef<JSVal> wrapVal = obj->GetProperty("wrap");
40 if (wrapVal->IsNumber()) {
41 auto wrapNum = wrapVal->ToNumber<int32_t>();
42 if (wrapNum == 0) {
43 CreateFlexComponent(info);
44 } else {
45 CreateWrapComponent(info, wrapNum);
46 }
47 } else {
48 CreateFlexComponent(info);
49 }
50 }
51
CreateFlexComponent(const JSCallbackInfo & info)52 void JSFlexImpl::CreateFlexComponent(const JSCallbackInfo& info)
53 {
54 if (info.Length() < 1) {
55 FlexModel::GetInstance()->CreateFlexRow();
56 return;
57 }
58 if (!info[0]->IsObject()) {
59 FlexModel::GetInstance()->CreateFlexRow();
60 return;
61 }
62 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
63 JSRef<JSVal> directionVal = obj->GetProperty("direction");
64 JSRef<JSVal> justifyVal = obj->GetProperty("justifyContent");
65 JSRef<JSVal> alignItemVal = obj->GetProperty("alignItems");
66 FlexModel::GetInstance()->CreateFlexRow();
67 if (directionVal->IsNumber()) {
68 auto direction = directionVal->ToNumber<int32_t>();
69 if (direction >= 0 && direction <= DIRECTION_MAX_VALUE) {
70 FlexModel::GetInstance()->SetDirection(static_cast<FlexDirection>(direction));
71 }
72 }
73 if (justifyVal->IsNumber()) {
74 auto mainAlign = justifyVal->ToNumber<int32_t>();
75 if (mainAlign >= 0 && mainAlign <= MAIN_ALIGN_MAX_VALUE) {
76 FlexModel::GetInstance()->SetMainAxisAlign(static_cast<FlexAlign>(mainAlign));
77 }
78 } else if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
79 FlexModel::GetInstance()->SetMainAxisAlign(FlexAlign::FLEX_START);
80 }
81 if (alignItemVal->IsNumber()) {
82 auto crossAlign = alignItemVal->ToNumber<int32_t>();
83 if (crossAlign >= 0 && crossAlign <= CROSS_ALIGN_MAX_VALUE) {
84 FlexModel::GetInstance()->SetCrossAxisAlign(static_cast<FlexAlign>(crossAlign));
85 }
86 } else if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
87 FlexModel::GetInstance()->SetCrossAxisAlign(FlexAlign::FLEX_START);
88 }
89 if (obj->HasProperty("space")) {
90 JSRef<JSVal> spaceVal = obj->GetProperty("space");
91 if (spaceVal->IsUndefined()) {
92 return;
93 }
94 CalcDimension value;
95 JSRef<JSObject> spaceObj = JSRef<JSObject>::Cast(obj->GetProperty("space"));
96 JSRef<JSVal> mainSpaceVal = spaceObj->GetProperty("main");
97 if (!ParseLengthMetricsToPositiveDimension(mainSpaceVal, value) || value.IsNegative()) {
98 value.Reset();
99 }
100 FlexModel::GetInstance()->SetMainSpace(value);
101 }
102 }
103
CreateWrapComponent(const JSCallbackInfo & info,int32_t wrapVal)104 void JSFlexImpl::CreateWrapComponent(const JSCallbackInfo& info, int32_t wrapVal)
105 {
106 if (info.Length() < 1 || !info[0]->IsObject()) {
107 return;
108 }
109 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
110 WrapComponent(obj, wrapVal);
111 if (obj->HasProperty("space")) {
112 JSRef<JSVal> spaceVal = obj->GetProperty("space");
113 if (spaceVal->IsUndefined()) {
114 return;
115 }
116 CalcDimension mainValue;
117 CalcDimension crossValue;
118 JSRef<JSObject> spaceObj = JSRef<JSObject>::Cast(obj->GetProperty("space"));
119 JSRef<JSVal> mainSpaceVal = spaceObj->GetProperty("main");
120 JSRef<JSVal> crossSpaceVal = spaceObj->GetProperty("cross");
121 if (!ParseLengthMetricsToPositiveDimension(mainSpaceVal, mainValue) || mainValue.IsNegative()) {
122 mainValue.Reset();
123 }
124 if (!ParseLengthMetricsToPositiveDimension(crossSpaceVal, crossValue) || crossValue.IsNegative()) {
125 crossValue.Reset();
126 }
127 FlexModel::GetInstance()->SetMainSpace(mainValue);
128 FlexModel::GetInstance()->SetCrossSpace(crossValue);
129 }
130 }
131
WrapComponent(const JSRef<JSObject> & obj,int32_t wrapVal)132 void JSFlexImpl::WrapComponent(const JSRef<JSObject>& obj, int32_t wrapVal)
133 {
134 JSRef<JSVal> directionVal = obj->GetProperty("direction");
135 JSRef<JSVal> justifyVal = obj->GetProperty("justifyContent");
136 JSRef<JSVal> alignItemVal = obj->GetProperty("alignItems");
137 JSRef<JSVal> alignContentVal = obj->GetProperty("alignContent");
138 FlexModel::GetInstance()->CreateWrap();
139 if (directionVal->IsNumber()) {
140 auto direction = directionVal->ToNumber<int32_t>();
141 if (direction >= 0 && direction <= DIRECTION_MAX_VALUE) {
142 FlexModel::GetInstance()->SetDirection(static_cast<FlexDirection>(direction));
143 // WrapReverse means wrapVal = 2. Wrap means wrapVal = 1.
144 if (direction <= 1) {
145 direction += REVERSE_OFFSET_ZOOM * (wrapVal - 1);
146 } else {
147 direction -= REVERSE_OFFSET_ZOOM * (wrapVal - 1);
148 }
149 FlexModel::GetInstance()->SetWrapDirection(static_cast<WrapDirection>(direction));
150 }
151 } else {
152 // No direction set case: wrapVal == 2 means FlexWrap.WrapReverse.
153 WrapDirection wrapDirection = wrapVal == 2 ? WrapDirection::HORIZONTAL_REVERSE : WrapDirection::HORIZONTAL;
154 FlexModel::GetInstance()->SetWrapDirection(wrapDirection);
155 }
156 if (justifyVal->IsNumber()) {
157 auto mainAlign = justifyVal->ToNumber<int32_t>();
158 if (mainAlign >= 0 && mainAlign <= MAIN_ALIGN_MAX_VALUE) {
159 FlexModel::GetInstance()->SetWrapMainAlignment(WRAP_TABLE[mainAlign]);
160 }
161 }
162 if (alignItemVal->IsNumber()) {
163 auto crossAlign = alignItemVal->ToNumber<int32_t>();
164 if (crossAlign >= 0 && crossAlign <= CROSS_ALIGN_MAX_VALUE) {
165 FlexModel::GetInstance()->SetWrapCrossAlignment(WRAP_TABLE[crossAlign]);
166 }
167 }
168 if (alignContentVal->IsNumber()) {
169 auto alignContent = alignContentVal->ToNumber<int32_t>();
170 if (alignContent >= 0 && alignContent <= MAIN_ALIGN_MAX_VALUE) {
171 FlexModel::GetInstance()->SetWrapAlignment(WRAP_TABLE[alignContent]);
172 }
173 }
174 }
175
JsFlexWidth(const JSCallbackInfo & info)176 void JSFlexImpl::JsFlexWidth(const JSCallbackInfo& info)
177 {
178 if (info.Length() < 1) {
179 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
180 return;
181 }
182
183 JsFlexWidth(info[0]);
184 }
185
JsFlexWidth(const JSRef<JSVal> & jsValue)186 void JSFlexImpl::JsFlexWidth(const JSRef<JSVal>& jsValue)
187 {
188 JSViewAbstract::JsWidth(jsValue);
189 FlexModel::GetInstance()->SetFlexWidth();
190 }
191
JsFlexHeight(const JSCallbackInfo & info)192 void JSFlexImpl::JsFlexHeight(const JSCallbackInfo& info)
193 {
194 if (info.Length() < 1) {
195 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
196 return;
197 }
198
199 JsFlexHeight(info[0]);
200 }
201
JsFlexHeight(const JSRef<JSVal> & jsValue)202 void JSFlexImpl::JsFlexHeight(const JSRef<JSVal>& jsValue)
203 {
204 JSViewAbstract::JsHeight(jsValue);
205 FlexModel::GetInstance()->SetFlexHeight();
206 }
207
JsFlexSize(const JSCallbackInfo & info)208 void JSFlexImpl::JsFlexSize(const JSCallbackInfo& info)
209 {
210 if (info.Length() < 1) {
211 LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
212 return;
213 }
214
215 if (!info[0]->IsObject()) {
216 LOGE("arg is not Object or String.");
217 return;
218 }
219
220 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
221 JsFlexWidth(sizeObj->GetProperty("width"));
222 JsFlexHeight(sizeObj->GetProperty("height"));
223 }
224
JSBind(BindingTarget globalObj)225 void JSFlexImpl::JSBind(BindingTarget globalObj)
226 {
227 JSClass<JSFlexImpl>::Declare("Flex");
228 MethodOptions opt = MethodOptions::NONE;
229 JSClass<JSFlexImpl>::StaticMethod("create", &JSFlexImpl::Create, opt);
230
231 JSClass<JSFlexImpl>::StaticMethod("width", &JSFlexImpl::JsFlexWidth);
232 JSClass<JSFlexImpl>::StaticMethod("height", &JSFlexImpl::JsFlexHeight);
233 JSClass<JSFlexImpl>::StaticMethod("size", &JSFlexImpl::JsFlexSize);
234
235 JSClass<JSFlexImpl>::StaticMethod("fillParent", &JSFlex::SetFillParent, opt);
236 JSClass<JSFlexImpl>::StaticMethod("wrapContent", &JSFlex::SetWrapContent, opt);
237 JSClass<JSFlexImpl>::StaticMethod("justifyContent", &JSFlex::SetJustifyContent, opt);
238 JSClass<JSFlexImpl>::StaticMethod("alignItems", &JSFlex::SetAlignItems, opt);
239 JSClass<JSFlexImpl>::StaticMethod("alignContent", &JSFlex::SetAlignContent, opt);
240 JSClass<JSFlexImpl>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
241 JSClass<JSFlexImpl>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
242 JSClass<JSFlexImpl>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
243 JSClass<JSFlexImpl>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
244 JSClass<JSFlexImpl>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
245 JSClass<JSFlexImpl>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
246 JSClass<JSFlexImpl>::StaticMethod("onPan", &JSInteractableView::JsOnPan);
247 JSClass<JSFlexImpl>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
248 JSClass<JSFlexImpl>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
249 JSClass<JSFlexImpl>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
250 JSClass<JSFlexImpl>::StaticMethod("pointLight", &JSViewAbstract::JsPointLight, opt);
251 JSClass<JSFlexImpl>::InheritAndBind<JSContainerBase>(globalObj);
252 }
253
254 } // namespace OHOS::Ace::Framework
255