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