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