• 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<Dimension> (& gutterSizeArray)[MAX_NUMBER_BREAKPOINT],bool isHorizontal)73 void InheritGridRowGutterOption(const RefPtr<V2::Gutter>& gutter,
74     std::optional<Dimension> (&gutterSizeArray)[MAX_NUMBER_BREAKPOINT], bool isHorizontal)
75 {
76     if (!gutterSizeArray[0].has_value()) {
77         gutterSizeArray[0] = Dimension(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     Dimension 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<Dimension> gutterOptions[MAX_NUMBER_BREAKPOINT];
112     auto gutterParam = JSRef<JSObject>::Cast(gutterObject);
113     auto xs = gutterParam->GetProperty("xs");
114     Dimension xsDimension;
115     if (JSContainerBase::ParseJsDimensionVp(xs, xsDimension)) {
116         gutterOptions[0] = xsDimension;
117     }
118     auto sm = gutterParam->GetProperty("sm");
119     Dimension smDimension;
120     if (JSContainerBase::ParseJsDimensionVp(sm, smDimension)) {
121         gutterOptions[1] = smDimension;
122     }
123     auto md = gutterParam->GetProperty("md");
124     Dimension mdDimension;
125     if (JSContainerBase::ParseJsDimensionVp(md, mdDimension)) {
126         gutterOptions[2] = mdDimension;
127     }
128     auto lg = gutterParam->GetProperty("lg");
129     Dimension lgDimension;
130     if (JSContainerBase::ParseJsDimensionVp(lg, lgDimension)) {
131         gutterOptions[3] = lgDimension;
132     }
133     auto xl = gutterParam->GetProperty("xl");
134     Dimension xlDimension;
135     if (JSContainerBase::ParseJsDimensionVp(xl, xlDimension)) {
136         gutterOptions[4] = xlDimension;
137     }
138     auto xxl = gutterParam->GetProperty("xxl");
139     Dimension 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     Dimension 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                 Dimension 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.Length() > 0 && 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 
270         GridRowModel::GetInstance()->Create(parsedColumns, parsedGutter, parsedBreakpoints, parsedDirection);
271     } else {
272         GridRowModel::GetInstance()->Create();
273     }
274 }
275 
JsBreakpointEvent(const JSCallbackInfo & info)276 void JSGridRow::JsBreakpointEvent(const JSCallbackInfo& info)
277 {
278     if (info.Length() < 1) {
279         LOGW("No breakpoint event info.");
280         return;
281     }
282     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
283     auto onBreakpointChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](
284                                   const std::string& value) {
285         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
286         ACE_SCORING_EVENT("GridRow.onBreakpointChange");
287         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(value));
288         func->ExecuteJS(1, &newJSVal);
289     };
290     GridRowModel::GetInstance()->SetOnBreakPointChange(onBreakpointChange);
291 }
292 
Height(const JSCallbackInfo & info)293 void JSGridRow::Height(const JSCallbackInfo& info)
294 {
295     if (info.Length() < 1) {
296         LOGI("The arg is wrong, it is supposed to have at least 1 argument");
297         return;
298     }
299     JSViewAbstract::JsHeight(info[0]);
300     GridRowModel::GetInstance()->SetHeight();
301 }
302 
JSBind(BindingTarget globalObj)303 void JSGridRow::JSBind(BindingTarget globalObj)
304 {
305     JSClass<JSGridRow>::Declare("GridRow");
306     JSClass<JSGridRow>::StaticMethod("create", &JSGridRow::Create);
307     JSClass<JSGridRow>::StaticMethod("onBreakpointChange", &JSGridRow::JsBreakpointEvent);
308     JSClass<JSGridRow>::StaticMethod("height", &JSGridRow::Height);
309     JSClass<JSGridRow>::Inherit<JSContainerBase>();
310     JSClass<JSGridRow>::Bind<>(globalObj);
311 }
312 
313 } // namespace OHOS::Ace::Framework
314