1 /*
2 * Copyright (c) 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_grid_row.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/log/ace_scoring_log.h"
20 #include "base/log/ace_trace.h"
21 #include "base/memory/referenced.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "bridge/declarative_frontend/jsview/models/grid_row_model_impl.h"
24 #include "core/components_ng/base/view_stack_processor.h"
25 #include "core/components_ng/pattern/grid_row/grid_row_model_ng.h"
26 #include "core/components_v2/grid_layout/grid_container_util_class.h"
27
28 namespace OHOS::Ace {
GetInstance()29 GridRowModel* GridRowModel::GetInstance()
30 {
31 #ifdef NG_BUILD
32 static NG::GridRowModelNG instance;
33 return &instance;
34 #else
35 if (Container::IsCurrentUseNewPipeline()) {
36 static NG::GridRowModelNG instance;
37 return &instance;
38 } else {
39 static Framework::GridRowModelImpl instance;
40 return &instance;
41 }
42 #endif
43 }
44 } // namespace OHOS::Ace
45
46 namespace OHOS::Ace::Framework {
47 namespace {
48
49 constexpr size_t MAX_NUMBER_BREAKPOINT = 6;
50
InheritGridRowOption(const RefPtr<V2::GridContainerSize> & gridContainerSize,std::optional<int32_t> (& containerSizeArray)[MAX_NUMBER_BREAKPOINT])51 void InheritGridRowOption(const RefPtr<V2::GridContainerSize>& gridContainerSize,
52 std::optional<int32_t> (&containerSizeArray)[MAX_NUMBER_BREAKPOINT])
53 {
54 if (!containerSizeArray[0].has_value()) {
55 containerSizeArray[0] = V2::DEFAULT_COLUMN_NUMBER;
56 }
57 for (size_t i = 1; i < MAX_NUMBER_BREAKPOINT; i++) {
58 if (!containerSizeArray[i].has_value()) {
59 containerSizeArray[i] = containerSizeArray[i - 1].value();
60 }
61 }
62 gridContainerSize->xs = containerSizeArray[0].value();
63 gridContainerSize->sm = containerSizeArray[1].value();
64 gridContainerSize->md = containerSizeArray[2].value();
65 gridContainerSize->lg = containerSizeArray[3].value();
66 gridContainerSize->xl = containerSizeArray[4].value();
67 gridContainerSize->xxl = containerSizeArray[5].value();
68 }
69
InheritGridRowGutterOption(const RefPtr<V2::Gutter> & gutter,std::optional<CalcDimension> (& gutterSizeArray)[MAX_NUMBER_BREAKPOINT],bool isHorizontal)70 void InheritGridRowGutterOption(const RefPtr<V2::Gutter>& gutter,
71 std::optional<CalcDimension> (&gutterSizeArray)[MAX_NUMBER_BREAKPOINT], bool isHorizontal)
72 {
73 if (!gutterSizeArray[0].has_value()) {
74 gutterSizeArray[0] = CalcDimension(0);
75 }
76 for (size_t i = 1; i < MAX_NUMBER_BREAKPOINT; i++) {
77 if (!gutterSizeArray[i].has_value()) {
78 gutterSizeArray[i] = gutterSizeArray[i - 1].value();
79 }
80 }
81 if (isHorizontal) {
82 gutter->xXs = gutterSizeArray[0].value();
83 gutter->xSm = gutterSizeArray[1].value();
84 gutter->xMd = gutterSizeArray[2].value();
85 gutter->xLg = gutterSizeArray[3].value();
86 gutter->xXl = gutterSizeArray[4].value();
87 gutter->xXXl = gutterSizeArray[5].value();
88 return;
89 }
90 gutter->yXs = gutterSizeArray[0].value();
91 gutter->ySm = gutterSizeArray[1].value();
92 gutter->yMd = gutterSizeArray[2].value();
93 gutter->yLg = gutterSizeArray[3].value();
94 gutter->yXl = gutterSizeArray[4].value();
95 gutter->yXXl = gutterSizeArray[5].value();
96 }
97
ParseGutterObject(const JSRef<JSVal> & gutterObject,RefPtr<V2::Gutter> & gutter,bool isHorizontal)98 void ParseGutterObject(const JSRef<JSVal>& gutterObject, RefPtr<V2::Gutter>& gutter, bool isHorizontal)
99 {
100 CalcDimension dim;
101 if (JSContainerBase::ParseJsDimensionVp(gutterObject, dim)) {
102 isHorizontal ? gutter->SetXGutter(dim) : gutter->SetYGutter(dim);
103 return;
104 }
105 if (!gutterObject->IsObject()) {
106 return;
107 }
108 std::optional<CalcDimension> gutterOptions[MAX_NUMBER_BREAKPOINT];
109 auto gutterParam = JSRef<JSObject>::Cast(gutterObject);
110 auto xs = gutterParam->GetProperty("xs");
111 CalcDimension xsDimension;
112 if (JSContainerBase::ParseJsDimensionVp(xs, xsDimension)) {
113 gutterOptions[0] = xsDimension;
114 }
115 auto sm = gutterParam->GetProperty("sm");
116 CalcDimension smDimension;
117 if (JSContainerBase::ParseJsDimensionVp(sm, smDimension)) {
118 gutterOptions[1] = smDimension;
119 }
120 auto md = gutterParam->GetProperty("md");
121 CalcDimension mdDimension;
122 if (JSContainerBase::ParseJsDimensionVp(md, mdDimension)) {
123 gutterOptions[2] = mdDimension;
124 }
125 auto lg = gutterParam->GetProperty("lg");
126 CalcDimension lgDimension;
127 if (JSContainerBase::ParseJsDimensionVp(lg, lgDimension)) {
128 gutterOptions[3] = lgDimension;
129 }
130 auto xl = gutterParam->GetProperty("xl");
131 CalcDimension xlDimension;
132 if (JSContainerBase::ParseJsDimensionVp(xl, xlDimension)) {
133 gutterOptions[4] = xlDimension;
134 }
135 auto xxl = gutterParam->GetProperty("xxl");
136 CalcDimension xxlDimension;
137 if (JSContainerBase::ParseJsDimensionVp(xxl, xxlDimension)) {
138 gutterOptions[5] = xxlDimension;
139 }
140 InheritGridRowGutterOption(gutter, gutterOptions, isHorizontal);
141 }
142
ParserGutter(const JSRef<JSVal> & jsValue)143 RefPtr<V2::Gutter> ParserGutter(const JSRef<JSVal>& jsValue)
144 {
145 CalcDimension result;
146 if (JSContainerBase::ParseJsDimensionVp(jsValue, result)) {
147 auto gutter = AceType::MakeRefPtr<V2::Gutter>(result);
148 return gutter;
149 } else {
150 if (!jsValue->IsObject()) {
151 return AceType::MakeRefPtr<V2::Gutter>();
152 }
153 auto paramGutter = JSRef<JSObject>::Cast(jsValue);
154 auto xObject = paramGutter->GetProperty("x");
155 auto yObject = paramGutter->GetProperty("y");
156 auto gutter = AceType::MakeRefPtr<V2::Gutter>();
157 ParseGutterObject(xObject, gutter, true);
158 ParseGutterObject(yObject, gutter, false);
159 return gutter;
160 }
161 }
162
ParserColumns(const JSRef<JSVal> & jsValue)163 RefPtr<V2::GridContainerSize> ParserColumns(const JSRef<JSVal>& jsValue)
164 {
165 if (jsValue->IsNumber()) {
166 auto columnNumber = jsValue->ToNumber<int32_t>();
167 return columnNumber > 0 ? AceType::MakeRefPtr<V2::GridContainerSize>(columnNumber)
168 : AceType::MakeRefPtr<V2::GridContainerSize>();
169 } else if (jsValue->IsObject()) {
170 auto gridContainerSize = AceType::MakeRefPtr<V2::GridContainerSize>(12);
171 auto gridParam = JSRef<JSObject>::Cast(jsValue);
172 std::optional<int32_t> containerSizeArray[MAX_NUMBER_BREAKPOINT];
173 auto xs = gridParam->GetProperty("xs");
174 if (xs->IsNumber() && xs->ToNumber<int32_t>() > 0) {
175 containerSizeArray[0] = xs->ToNumber<int32_t>();
176 }
177 auto sm = gridParam->GetProperty("sm");
178 if (sm->IsNumber() && sm->ToNumber<int32_t>() > 0) {
179 containerSizeArray[1] = sm->ToNumber<int32_t>();
180 }
181 auto md = gridParam->GetProperty("md");
182 if (md->IsNumber() && md->ToNumber<int32_t>() > 0) {
183 containerSizeArray[2] = md->ToNumber<int32_t>();
184 }
185 auto lg = gridParam->GetProperty("lg");
186 if (lg->IsNumber() && lg->ToNumber<int32_t>() > 0) {
187 containerSizeArray[3] = lg->ToNumber<int32_t>();
188 }
189 auto xl = gridParam->GetProperty("xl");
190 if (xl->IsNumber() && xl->ToNumber<int32_t>() > 0) {
191 containerSizeArray[4] = xl->ToNumber<int32_t>();
192 }
193 auto xxl = gridParam->GetProperty("xxl");
194 if (xxl->IsNumber() && xxl->ToNumber<int32_t>() > 0) {
195 containerSizeArray[5] = xxl->ToNumber<int32_t>();
196 }
197 InheritGridRowOption(gridContainerSize, containerSizeArray);
198 return gridContainerSize;
199 } else {
200 return AceType::MakeRefPtr<V2::GridContainerSize>();
201 }
202 }
203
ParserBreakpoints(const JSRef<JSVal> & jsValue)204 RefPtr<V2::BreakPoints> ParserBreakpoints(const JSRef<JSVal>& jsValue)
205 {
206 if (!jsValue->IsObject()) {
207 return AceType::MakeRefPtr<V2::BreakPoints>();
208 }
209 auto breakpoints = JSRef<JSObject>::Cast(jsValue);
210 auto value = breakpoints->GetProperty("value");
211 auto reference = breakpoints->GetProperty("reference");
212 auto breakpoint = AceType::MakeRefPtr<V2::BreakPoints>();
213 if (reference->IsNumber()) {
214 breakpoint->reference = static_cast<V2::BreakPointsReference>(reference->ToNumber<int32_t>());
215 }
216 if (value->IsArray()) {
217 JSRef<JSArray> array = JSRef<JSArray>::Cast(value);
218 breakpoint->breakpoints.clear();
219 if (array->Length() > MAX_NUMBER_BREAKPOINT - 1) {
220 return breakpoint;
221 }
222 double width = -1.0;
223 for (size_t i = 0; i < array->Length(); i++) {
224 JSRef<JSVal> threshold = array->GetValueAt(i);
225 if (threshold->IsString() || threshold->IsNumber()) {
226 CalcDimension valueDimension;
227 JSContainerBase::ParseJsDimensionVp(threshold, valueDimension);
228 if (GreatNotEqual(width, valueDimension.Value())) {
229 return breakpoint;
230 }
231 width = valueDimension.Value();
232 breakpoint->breakpoints.push_back(threshold->ToString());
233 }
234 }
235 }
236 return breakpoint;
237 }
238
ParserDirection(const JSRef<JSVal> & jsValue)239 V2::GridRowDirection ParserDirection(const JSRef<JSVal>& jsValue)
240 {
241 V2::GridRowDirection direction(V2::GridRowDirection::Row);
242 if (jsValue->IsNumber()) {
243 direction = static_cast<V2::GridRowDirection>(jsValue->ToNumber<int32_t>());
244 }
245 return direction;
246 }
247
248 } // namespace
249
Create(const JSCallbackInfo & info)250 void JSGridRow::Create(const JSCallbackInfo& info)
251 {
252 if (info[0]->IsObject()) {
253 auto gridRow = JSRef<JSObject>::Cast(info[0]);
254 auto columns = gridRow->GetProperty("columns");
255 auto gutter = gridRow->GetProperty("gutter");
256 auto breakpoints = gridRow->GetProperty("breakpoints");
257 auto direction = gridRow->GetProperty("direction");
258
259 auto parsedColumns = ParserColumns(columns);
260 auto parsedGutter = ParserGutter(gutter);
261 auto parsedBreakpoints = ParserBreakpoints(breakpoints);
262 auto parsedDirection = ParserDirection(direction);
263 GridRowModel::GetInstance()->Create(parsedColumns, parsedGutter, parsedBreakpoints, parsedDirection);
264 } else {
265 GridRowModel::GetInstance()->Create();
266 }
267 }
268
JsBreakpointEvent(const JSCallbackInfo & info)269 void JSGridRow::JsBreakpointEvent(const JSCallbackInfo& info)
270 {
271 if (!info[0]->IsFunction()) {
272 return;
273 }
274 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
275 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
276 auto onBreakpointChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
277 const std::string& value) {
278 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
279 ACE_SCORING_EVENT("GridRow.onBreakpointChange");
280 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(value));
281 PipelineContext::SetCallBackNode(node);
282 func->ExecuteJS(1, &newJSVal);
283 };
284 GridRowModel::GetInstance()->SetOnBreakPointChange(onBreakpointChange);
285 }
286
Height(const JSCallbackInfo & info)287 void JSGridRow::Height(const JSCallbackInfo& info)
288 {
289 JSViewAbstract::JsHeight(info[0]);
290 GridRowModel::GetInstance()->SetHeight();
291 }
292
AlignItems(const JSCallbackInfo & info)293 void JSGridRow::AlignItems(const JSCallbackInfo& info)
294 {
295 if (info[0]->IsNumber()) {
296 auto value = info[0]->ToNumber<int32_t>();
297 ParseAlignItems(value);
298 } else if (info[0]->IsUndefined()) {
299 GridRowModel::GetInstance()->SetAlignItems(FlexAlign::FLEX_START);
300 }
301 }
302
ParseAlignItems(int32_t alignItem)303 void JSGridRow::ParseAlignItems(int32_t alignItem)
304 {
305 if (alignItem == static_cast<int32_t>(FlexAlign::FLEX_START) ||
306 alignItem == static_cast<int32_t>(FlexAlign::FLEX_END) ||
307 alignItem == static_cast<int32_t>(FlexAlign::CENTER) || alignItem == static_cast<int32_t>(FlexAlign::STRETCH)) {
308 GridRowModel::GetInstance()->SetAlignItems(static_cast<FlexAlign>(alignItem));
309 } else if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
310 GridRowModel::GetInstance()->SetAlignItems(FlexAlign::FLEX_START);
311 }
312 }
313
JSBind(BindingTarget globalObj)314 void JSGridRow::JSBind(BindingTarget globalObj)
315 {
316 JSClass<JSGridRow>::Declare("GridRow");
317 JSClass<JSGridRow>::StaticMethod("create", &JSGridRow::Create);
318 JSClass<JSGridRow>::StaticMethod("onBreakpointChange", &JSGridRow::JsBreakpointEvent);
319 JSClass<JSGridRow>::StaticMethod("height", &JSGridRow::Height);
320 JSClass<JSGridRow>::StaticMethod("alignItems", &JSGridRow::AlignItems);
321 JSClass<JSGridRow>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
322 JSClass<JSGridRow>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
323 JSClass<JSGridRow>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
324 JSClass<JSGridRow>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
325 JSClass<JSGridRow>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
326 JSClass<JSGridRow>::InheritAndBind<JSContainerBase>(globalObj);
327 }
328
329 } // namespace OHOS::Ace::Framework
330