• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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_tab_content.h"
17 
18 #include <optional>
19 
20 #include "base/log/ace_scoring_log.h"
21 #include "base/log/ace_trace.h"
22 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
23 #include "bridge/declarative_frontend/jsview/models/tab_content_model_impl.h"
24 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
25 #include "core/components/tab_bar/tab_theme.h"
26 #include "core/components_ng/base/view_stack_model.h"
27 #include "core/components_ng/pattern/tabs/tab_content_model_ng.h"
28 #include "core/components_ng/pattern/tabs/tabs_layout_property.h"
29 #include "core/components_ng/pattern/tabs/tabs_node.h"
30 #include "core/components_ng/property/measure_property.h"
31 
32 namespace OHOS::Ace {
33 
34 std::unique_ptr<TabContentModel> TabContentModel::instance_ = nullptr;
35 std::mutex TabContentModel::mutex_;
36 
37 const std::vector<TextOverflow> TEXT_OVERFLOWS = { TextOverflow::NONE, TextOverflow::CLIP, TextOverflow::ELLIPSIS,
38     TextOverflow::MARQUEE };
39 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
40 const std::vector<TextHeightAdaptivePolicy> HEIGHT_ADAPTIVE_POLICIES = { TextHeightAdaptivePolicy::MAX_LINES_FIRST,
41     TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST, TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST };
42 
GetInstance()43 TabContentModel* TabContentModel::GetInstance()
44 {
45     if (!instance_) {
46         std::lock_guard<std::mutex> lock(mutex_);
47         if (!instance_) {
48 #ifdef NG_BUILD
49             instance_.reset(new NG::TabContentModelNG());
50 #else
51             if (Container::IsCurrentUseNewPipeline()) {
52                 instance_.reset(new NG::TabContentModelNG());
53             } else {
54                 instance_.reset(new Framework::TabContentModelImpl());
55             }
56 #endif
57         }
58     }
59     return instance_.get();
60 }
61 
62 } // namespace OHOS::Ace
63 
64 namespace OHOS::Ace::Framework {
65 
Create(const JSCallbackInfo & info)66 void JSTabContent::Create(const JSCallbackInfo& info)
67 {
68     if (Container::IsCurrentUsePartialUpdate()) {
69         CreateForPartialUpdate(info);
70         return;
71     }
72     TabContentModel::GetInstance()->Create();
73 }
74 
CreateForPartialUpdate(const JSCallbackInfo & info)75 void JSTabContent::CreateForPartialUpdate(const JSCallbackInfo& info)
76 {
77     if (info.Length() <= 0 || !info[0]->IsFunction()) {
78         TabContentModel::GetInstance()->Create();
79         return;
80     }
81 
82     JSRef<JSVal> builderFunctionJS = info[0];
83     auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() {
84         JAVASCRIPT_EXECUTION_SCOPE(context)
85         JSRef<JSFunc>::Cast(builder)->Call(JSRef<JSObject>());
86     };
87     TabContentModel::GetInstance()->Create(std::move(builderFunc));
88 }
89 
SetTabBar(const JSCallbackInfo & info)90 void JSTabContent::SetTabBar(const JSCallbackInfo& info)
91 {
92     if (info.Length() <= 0) {
93         return;
94     }
95     auto tabBarInfo = info[0];
96 
97     std::string infoStr;
98     if (ParseJsString(tabBarInfo, infoStr)) {
99         TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
100         TabContentModel::GetInstance()->SetTabBar(infoStr, std::nullopt, std::nullopt, nullptr, true);
101         TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
102         return;
103     }
104 
105     if (!tabBarInfo->IsObject()) {
106         TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
107         TabContentModel::GetInstance()->SetTabBar(std::nullopt, std::nullopt, std::nullopt, nullptr, false);
108         TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
109         return;
110     }
111 
112     auto paramObject = JSRef<JSObject>::Cast(tabBarInfo);
113     JSRef<JSVal> contentParam = paramObject->GetProperty("builderNode_");
114     if (contentParam->IsObject()) {
115         auto builderNodeObject = JSRef<JSObject>::Cast(contentParam);
116         JSRef<JSVal> nodeptr = builderNodeObject->GetProperty("nodePtr_");
117         if (!nodeptr.IsEmpty()) {
118             const auto* vm = nodeptr->GetEcmaVM();
119             auto* node = nodeptr->GetLocalHandle()->ToNativePointer(vm)->Value();
120             auto* frameNode = reinterpret_cast<NG::FrameNode*>(node);
121             CHECK_NULL_VOID(frameNode);
122             RefPtr<NG::FrameNode> refPtrFrameNode = AceType::Claim(frameNode);
123             CHECK_NULL_VOID(refPtrFrameNode);
124             TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
125             TabContentModel::GetInstance()->SetTabBar(std::nullopt, std::nullopt, std::nullopt, nullptr, false);
126             TabContentModel::GetInstance()->SetTabBarWithContent(refPtrFrameNode);
127             return;
128         }
129     }
130     JSRef<JSVal> builderFuncParam = paramObject->GetProperty("builder");
131     if (builderFuncParam->IsFunction()) {
132         auto tabBarBuilder = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(builderFuncParam));
133         auto tabBarBuilderFunc = [execCtx = info.GetExecutionContext(),
134                                      tabBarBuilderFunc = std::move(tabBarBuilder)]() {
135             if (tabBarBuilderFunc) {
136                 ACE_SCOPED_TRACE("JSTabContent::Execute TabBar builder");
137                 JAVASCRIPT_EXECUTION_SCOPE(execCtx);
138                 tabBarBuilderFunc->ExecuteJS();
139             }
140         };
141         TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
142         TabContentModel::GetInstance()->SetTabBar(
143             std::nullopt, std::nullopt, std::nullopt, std::move(tabBarBuilderFunc), false);
144         TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
145         return;
146     }
147     JSRef<JSVal> typeParam = paramObject->GetProperty("type");
148     if (typeParam->IsString()) {
149         auto type = typeParam->ToString();
150         if (type == "SubTabBarStyle") {
151             SetSubTabBarStyle(paramObject);
152             return;
153         }
154         if (type == "BottomTabBarStyle") {
155             SetBottomTabBarStyle(info);
156             return;
157         }
158     }
159 
160     JSRef<JSVal> textParam = paramObject->GetProperty("text");
161     auto isTextEmpty = textParam->IsEmpty() || textParam->IsUndefined() || textParam->IsNull();
162     std::optional<std::string> textOpt = std::nullopt;
163     if (!isTextEmpty) {
164         std::string text;
165         if (ParseJsString(textParam, text)) {
166             textOpt = text;
167         }
168     }
169 
170     JSRef<JSVal> iconParam = paramObject->GetProperty("icon");
171     auto isIconEmpty = iconParam->IsEmpty() || iconParam->IsUndefined() || iconParam->IsNull();
172     std::optional<std::string> iconOpt = std::nullopt;
173     if (!isIconEmpty) {
174         std::string icon;
175         if (ParseJsMedia(iconParam, icon)) {
176             iconOpt = icon;
177         }
178     }
179     TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::NOSTYLE);
180     TabContentModel::GetInstance()->SetTabBar(textOpt, iconOpt, std::nullopt, nullptr, false);
181     TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
182 }
183 
Pop()184 void JSTabContent::Pop()
185 {
186     if (ViewStackModel::GetInstance()->IsPrebuilding()) {
187         return ViewStackModel::GetInstance()->PushPrebuildCompCmd("[JSTabContent][pop]", &JSTabContent::Pop);
188     }
189     TabContentModel::GetInstance()->Pop();
190 }
191 
SetIndicator(const JSRef<JSVal> & info)192 void JSTabContent::SetIndicator(const JSRef<JSVal>& info)
193 {
194     JSRef<JSObject> obj = JSRef<JSObject>::New();
195     if (info->IsObject()) {
196         obj = JSRef<JSObject>::Cast(info);
197     }
198     IndicatorStyle indicator;
199     CalcDimension indicatorHeight;
200     CalcDimension indicatorWidth;
201     CalcDimension indicatorBorderRadius;
202     CalcDimension indicatorMarginTop;
203     if (!info->IsObject() || !ConvertFromJSValue(obj->GetProperty("color"), indicator.color)) {
204         RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
205         if (tabTheme) {
206             indicator.color = tabTheme->GetActiveIndicatorColor();
207         }
208     }
209     if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("height"), indicatorHeight) ||
210         indicatorHeight.Value() < 0.0f || indicatorHeight.Unit() == DimensionUnit::PERCENT) {
211         RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
212         if (tabTheme) {
213             indicator.height = tabTheme->GetActiveIndicatorWidth();
214         }
215     } else {
216         indicator.height = indicatorHeight;
217     }
218     if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("width"), indicatorWidth) ||
219         indicatorWidth.Value() < 0.0f || indicatorWidth.Unit() == DimensionUnit::PERCENT) {
220         indicator.width = 0.0_vp;
221     } else {
222         indicator.width = indicatorWidth;
223     }
224     if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("borderRadius"), indicatorBorderRadius) ||
225         indicatorBorderRadius.Value() < 0.0f || indicatorBorderRadius.Unit() == DimensionUnit::PERCENT) {
226         indicator.borderRadius = 0.0_vp;
227     } else {
228         indicator.borderRadius = indicatorBorderRadius;
229     }
230     if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("marginTop"), indicatorMarginTop) ||
231         indicatorMarginTop.Value() < 0.0f || indicatorMarginTop.Unit() == DimensionUnit::PERCENT) {
232         RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
233         if (tabTheme) {
234             indicator.marginTop = tabTheme->GetSubTabIndicatorGap();
235         }
236     } else {
237         indicator.marginTop = indicatorMarginTop;
238     }
239     TabContentModel::GetInstance()->SetIndicator(indicator);
240 }
241 
SetBoard(const JSRef<JSVal> & info)242 void JSTabContent::SetBoard(const JSRef<JSVal>& info)
243 {
244     JSRef<JSObject> obj = JSRef<JSObject>::New();
245     if (info->IsObject()) {
246         obj = JSRef<JSObject>::Cast(info);
247     }
248     BoardStyle board;
249     CalcDimension borderRadius;
250     if (!info->IsObject() || !ParseJsDimensionVp(obj->GetProperty("borderRadius"), borderRadius) ||
251         borderRadius.Value() < 0.0f || borderRadius.Unit() == DimensionUnit::PERCENT) {
252         RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
253         if (tabTheme) {
254             board.borderRadius = tabTheme->GetFocusIndicatorRadius();
255         }
256     } else {
257         board.borderRadius = borderRadius;
258     }
259     TabContentModel::GetInstance()->SetBoard(board);
260 }
261 
SetSelectedMode(const JSRef<JSVal> & info)262 void JSTabContent::SetSelectedMode(const JSRef<JSVal>& info)
263 {
264     int32_t selectedMode;
265     if (!ConvertFromJSValue(info, selectedMode)) {
266         TabContentModel::GetInstance()->SetSelectedMode(SelectedMode::INDICATOR);
267     } else {
268         TabContentModel::GetInstance()->SetSelectedMode(static_cast<SelectedMode>(selectedMode));
269     }
270 }
271 
GetFontContent(const JSRef<JSVal> font,LabelStyle & labelStyle,bool isSubTabStyle)272 void JSTabContent::GetFontContent(const JSRef<JSVal> font, LabelStyle& labelStyle, bool isSubTabStyle)
273 {
274     JSRef<JSObject> obj = JSRef<JSObject>::Cast(font);
275     JSRef<JSVal> size = obj->GetProperty("size");
276     CalcDimension fontSize;
277     if (ParseJsDimensionFp(size, fontSize) && NonNegative(fontSize.Value()) &&
278         fontSize.Unit() != DimensionUnit::PERCENT) {
279         labelStyle.fontSize = fontSize;
280     }
281 
282     JSRef<JSVal> weight = obj->GetProperty("weight");
283     if (weight->IsString() || weight->IsNumber()) {
284         auto parseResult = ParseFontWeight(weight->ToString());
285         if (parseResult.first || !isSubTabStyle) {
286             labelStyle.fontWeight = parseResult.second;
287         }
288     }
289 
290     JSRef<JSVal> family = obj->GetProperty("family");
291     std::vector<std::string> fontFamilies;
292     if (ParseJsFontFamilies(family, fontFamilies)) {
293         labelStyle.fontFamily = fontFamilies;
294     }
295 
296     JSRef<JSVal> style = obj->GetProperty("style");
297     if (style->IsNumber()) {
298         int32_t value = style->ToNumber<int32_t>();
299         if (value >= 0 && value < static_cast<int32_t>(FONT_STYLES.size())) {
300             labelStyle.fontStyle = FONT_STYLES[value];
301         }
302     }
303 }
304 
SetLabelStyle(const JSRef<JSVal> & info,bool isSubTabStyle)305 void JSTabContent::SetLabelStyle(const JSRef<JSVal>& info, bool isSubTabStyle)
306 {
307     LabelStyle labelStyle;
308     if (!info->IsObject()) {
309         LOGW("info not is Object");
310     } else {
311         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info);
312         JSRef<JSVal> overflowValue = obj->GetProperty("overflow");
313         if (!overflowValue->IsNull() && overflowValue->IsNumber()) {
314             auto overflow = overflowValue->ToNumber<int32_t>();
315             if (overflow >= 0 && overflow < static_cast<int32_t>(TEXT_OVERFLOWS.size())) {
316                 labelStyle.textOverflow = TEXT_OVERFLOWS[overflow];
317             }
318         }
319 
320         JSRef<JSVal> maxLines = obj->GetProperty("maxLines");
321         if (!maxLines->IsNull() && maxLines->IsNumber() && maxLines->ToNumber<int32_t>() > 0) {
322             labelStyle.maxLines = maxLines->ToNumber<int32_t>();
323         }
324 
325         JSRef<JSVal> minFontSizeValue = obj->GetProperty("minFontSize");
326         CalcDimension minFontSize;
327         if (ParseJsDimensionFp(minFontSizeValue, minFontSize) && NonNegative(minFontSize.Value()) &&
328             minFontSize.Unit() != DimensionUnit::PERCENT) {
329             labelStyle.minFontSize = minFontSize;
330         }
331 
332         JSRef<JSVal> maxFontSizeValue = obj->GetProperty("maxFontSize");
333         CalcDimension maxFontSize;
334         if (ParseJsDimensionFp(maxFontSizeValue, maxFontSize) && NonNegative(maxFontSize.Value()) &&
335             maxFontSize.Unit() != DimensionUnit::PERCENT) {
336             labelStyle.maxFontSize = maxFontSize;
337         }
338 
339         JSRef<JSVal> heightAdaptivePolicyValue = obj->GetProperty("heightAdaptivePolicy");
340         if (!heightAdaptivePolicyValue->IsNull() && heightAdaptivePolicyValue->IsNumber()) {
341             auto heightAdaptivePolicy = heightAdaptivePolicyValue->ToNumber<int32_t>();
342             if (heightAdaptivePolicy >= 0 &&
343                 heightAdaptivePolicy < static_cast<int32_t>(HEIGHT_ADAPTIVE_POLICIES.size())) {
344                 labelStyle.heightAdaptivePolicy = HEIGHT_ADAPTIVE_POLICIES[heightAdaptivePolicy];
345             }
346         }
347 
348         JSRef<JSVal> font = obj->GetProperty("font");
349         if (!font->IsNull() && font->IsObject()) {
350             GetFontContent(font, labelStyle, isSubTabStyle);
351         }
352 
353         GetLabelUnselectedContent(obj->GetProperty("unselectedColor"), labelStyle);
354 
355         GetLabelSelectedContent(obj->GetProperty("selectedColor"), labelStyle);
356     }
357     CompleteParameters(labelStyle, isSubTabStyle);
358     TabContentModel::GetInstance()->SetLabelStyle(labelStyle);
359 }
360 
SetIconStyle(const JSRef<JSVal> & info)361 void JSTabContent::SetIconStyle(const JSRef<JSVal>& info)
362 {
363     IconStyle iconStyle;
364     if (info->IsObject()) {
365         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info);
366         Color unselectedColor;
367         JSRef<JSVal> unselectedColorValue = obj->GetProperty("unselectedColor");
368         if (ConvertFromJSValue(unselectedColorValue, unselectedColor)) {
369             iconStyle.unselectedColor = unselectedColor;
370         }
371 
372         Color selectedColor;
373         JSRef<JSVal> selectedColorValue = obj->GetProperty("selectedColor");
374         if (ConvertFromJSValue(selectedColorValue, selectedColor)) {
375             iconStyle.selectedColor = selectedColor;
376         }
377     }
378     TabContentModel::GetInstance()->SetIconStyle(iconStyle);
379 }
380 
GetLabelUnselectedContent(const JSRef<JSVal> unselectedColorValue,LabelStyle & labelStyle)381 void JSTabContent::GetLabelUnselectedContent(const JSRef<JSVal> unselectedColorValue, LabelStyle& labelStyle)
382 {
383     Color unselectedColor;
384     if (ConvertFromJSValue(unselectedColorValue, unselectedColor)) {
385         labelStyle.unselectedColor = unselectedColor;
386     }
387 }
388 
GetLabelSelectedContent(const JSRef<JSVal> selectedColorValue,LabelStyle & labelStyle)389 void JSTabContent::GetLabelSelectedContent(const JSRef<JSVal> selectedColorValue, LabelStyle& labelStyle)
390 {
391     Color selectedColor;
392     if (ConvertFromJSValue(selectedColorValue, selectedColor)) {
393         labelStyle.selectedColor = selectedColor;
394     }
395 }
396 
ParseJsLengthMetrics(const JSRef<JSObject> & obj,CalcDimension & result)397 bool ParseJsLengthMetrics(const JSRef<JSObject>& obj, CalcDimension& result)
398 {
399     if (!obj->HasProperty("value")) {
400         return false;
401     }
402     auto value = obj->GetProperty("value");
403     if (!value->IsNumber()) {
404         return false;
405     }
406     auto unit = DimensionUnit::VP;
407     auto jsUnit = obj->GetProperty("unit");
408     if (jsUnit->IsNumber()) {
409         unit = static_cast<DimensionUnit>(jsUnit->ToNumber<int32_t>());
410     }
411     CalcDimension dimension(value->ToNumber<double>(), unit);
412     result = dimension;
413     return true;
414 }
415 
SetPadding(const JSRef<JSVal> & info,bool isSubTabStyle)416 void JSTabContent::SetPadding(const JSRef<JSVal>& info, bool isSubTabStyle)
417 {
418     CalcDimension length;
419     NG::PaddingProperty padding;
420     bool useLocalizedPadding = false;
421     if (ParseJsDimensionVp(info, length) && NonNegative(length.Value()) && length.Unit() != DimensionUnit::PERCENT) {
422         padding.left = NG::CalcLength(length);
423         padding.right = NG::CalcLength(length);
424         padding.top = NG::CalcLength(length);
425         padding.bottom = NG::CalcLength(length);
426         TabContentModel::GetInstance()->SetPadding(padding);
427         return;
428     }
429 
430     RefPtr<TabTheme> tabTheme = GetTheme<TabTheme>();
431     if (tabTheme) {
432         if (isSubTabStyle) {
433             padding.top = NG::CalcLength(tabTheme->GetSubTabTopPadding());
434             padding.bottom = NG::CalcLength(tabTheme->GetSubTabBottomPadding());
435             padding.left = NG::CalcLength(tabTheme->GetSubTabHorizontalPadding());
436             padding.right = NG::CalcLength(tabTheme->GetSubTabHorizontalPadding());
437         } else {
438             padding.top = NG::CalcLength(0.0_vp);
439             padding.bottom = NG::CalcLength(0.0_vp);
440             padding.left = NG::CalcLength(tabTheme->GetBottomTabHorizontalPadding());
441             padding.right = NG::CalcLength(tabTheme->GetBottomTabHorizontalPadding());
442         }
443     }
444     if (info->IsObject()) {
445         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info);
446         CalcDimension left;
447         if (ParseJsDimensionVp(paddingObj->GetProperty("left"), left) && NonNegative(left.Value()) &&
448             left.Unit() != DimensionUnit::PERCENT) {
449             padding.left = NG::CalcLength(left);
450         }
451         CalcDimension right;
452         if (ParseJsDimensionVp(paddingObj->GetProperty("right"), right) && NonNegative(right.Value()) &&
453             right.Unit() != DimensionUnit::PERCENT) {
454             padding.right = NG::CalcLength(right);
455         }
456         CalcDimension top;
457         if (ParseJsDimensionVp(paddingObj->GetProperty("top"), top) && NonNegative(top.Value()) &&
458             top.Unit() != DimensionUnit::PERCENT) {
459             padding.top = NG::CalcLength(top);
460         }
461         CalcDimension bottom;
462         if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottom) && NonNegative(bottom.Value()) &&
463             bottom.Unit() != DimensionUnit::PERCENT) {
464             padding.bottom = NG::CalcLength(bottom);
465         }
466     }
467     if (info->IsObject()) {
468         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info);
469         CalcDimension start;
470         CalcDimension end;
471         CalcDimension top;
472         CalcDimension bottom;
473         if (paddingObj->GetProperty("start")->IsObject()) {
474             JSRef<JSObject> startObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("start"));
475             if (ParseJsLengthMetrics(startObj, start)) {
476                 padding.left = NG::CalcLength(start);
477                 useLocalizedPadding = true;
478             }
479         }
480         if (paddingObj->GetProperty("end")->IsObject()) {
481             JSRef<JSObject> endObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("end"));
482             if (ParseJsLengthMetrics(endObj, end)) {
483                 padding.right = NG::CalcLength(end);
484                 useLocalizedPadding = true;
485             }
486         }
487         if (paddingObj->GetProperty("top")->IsObject()) {
488             JSRef<JSObject> topObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("top"));
489             if (ParseJsLengthMetrics(topObj, top)) {
490                 padding.top = NG::CalcLength(top);
491                 useLocalizedPadding = true;
492             }
493         }
494         if (paddingObj->GetProperty("bottom")->IsObject()) {
495             JSRef<JSObject> bottomObj = JSRef<JSObject>::Cast(paddingObj->GetProperty("bottom"));
496             if (ParseJsLengthMetrics(bottomObj, bottom)) {
497                 padding.bottom = NG::CalcLength(bottom);
498                 useLocalizedPadding = true;
499             }
500         }
501     }
502     TabContentModel::GetInstance()->SetPadding(padding);
503     TabContentModel::GetInstance()->SetUseLocalizedPadding(useLocalizedPadding);
504 }
505 
SetId(const JSRef<JSVal> & info)506 void JSTabContent::SetId(const JSRef<JSVal>& info)
507 {
508     std::string id;
509     if (!ParseJsString(info, id)) {
510         return;
511     }
512     TabContentModel::GetInstance()->SetId(id);
513 }
514 
CompleteParameters(LabelStyle & labelStyle,bool isSubTabStyle)515 void JSTabContent::CompleteParameters(LabelStyle& labelStyle, bool isSubTabStyle)
516 {
517     auto tabTheme = GetTheme<TabTheme>();
518     if (!tabTheme) {
519         return;
520     }
521     if (!labelStyle.maxLines.has_value()) {
522         labelStyle.maxLines = 1;
523     }
524     if (!labelStyle.minFontSize.has_value()) {
525         labelStyle.minFontSize = 0.0_vp;
526     }
527     if (!labelStyle.maxFontSize.has_value()) {
528         labelStyle.maxFontSize = 0.0_vp;
529     }
530     if (!labelStyle.fontSize.has_value()) {
531         if (isSubTabStyle) {
532             labelStyle.fontSize = tabTheme->GetSubTabTextDefaultFontSize();
533         } else if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
534             labelStyle.fontSize = tabTheme->GetBottomTabTextSize();
535         }
536     }
537     if (!labelStyle.fontWeight.has_value() && !isSubTabStyle) {
538         labelStyle.fontWeight = FontWeight::MEDIUM;
539     }
540     if (!labelStyle.fontStyle.has_value()) {
541         labelStyle.fontStyle = FontStyle::NORMAL;
542     }
543     if (!labelStyle.heightAdaptivePolicy.has_value()) {
544         labelStyle.heightAdaptivePolicy = TextHeightAdaptivePolicy::MAX_LINES_FIRST;
545     }
546     if (!labelStyle.textOverflow.has_value()) {
547         labelStyle.textOverflow = TextOverflow::ELLIPSIS;
548     }
549 }
550 
SetBuilderNode(const JSRef<JSObject> & paramObject)551 void SetBuilderNode(const JSRef<JSObject>& paramObject)
552 {
553     JSRef<JSVal> contentParam = paramObject->GetProperty("content");
554     if (!contentParam->IsObject()) {
555         return;
556     }
557     auto contentObject = JSRef<JSObject>::Cast(contentParam);
558     JSRef<JSVal> builderNodeParam = contentObject->GetProperty("builderNode_");
559     if (!builderNodeParam->IsObject()) {
560         return;
561     }
562     auto builderNodeObject = JSRef<JSObject>::Cast(builderNodeParam);
563     JSRef<JSVal> nodeptr = builderNodeObject->GetProperty("nodePtr_");
564     if (nodeptr.IsEmpty()) {
565         return;
566     }
567     const auto* vm = nodeptr->GetEcmaVM();
568     CHECK_NULL_VOID(nodeptr->GetLocalHandle()->IsNativePointer(vm));
569     auto* node = nodeptr->GetLocalHandle()->ToNativePointer(vm)->Value();
570     auto* frameNode = reinterpret_cast<NG::FrameNode*>(node);
571     CHECK_NULL_VOID(frameNode);
572     RefPtr<NG::FrameNode> refPtrFrameNode = AceType::Claim(frameNode);
573     TabContentModel::GetInstance()->SetCustomStyleNode(refPtrFrameNode);
574 }
575 
SetSubTabBarStyle(const JSRef<JSObject> & paramObject)576 void JSTabContent::SetSubTabBarStyle(const JSRef<JSObject>& paramObject)
577 {
578     JSRef<JSVal> contentParam = paramObject->GetProperty("content");
579     SetBuilderNode(paramObject);
580 
581     auto isContentEmpty = contentParam->IsEmpty() || contentParam->IsUndefined() || contentParam->IsNull();
582     if (isContentEmpty) {
583         LOGW("The content param is empty");
584     }
585     std::optional<std::string> contentOpt;
586     std::string content;
587     if (ParseJsString(contentParam, content)) {
588         contentOpt = content;
589     }
590 
591     JSRef<JSVal> indicatorParam = paramObject->GetProperty("indicator");
592     SetIndicator(indicatorParam);
593 
594     JSRef<JSVal> selectedModeParam = paramObject->GetProperty("selectedMode");
595     SetSelectedMode(selectedModeParam);
596 
597     JSRef<JSVal> boardParam = paramObject->GetProperty("board");
598     SetBoard(boardParam);
599 
600     JSRef<JSVal> labelStyleParam = paramObject->GetProperty("labelStyle");
601     SetLabelStyle(labelStyleParam, true);
602 
603     JSRef<JSVal> paddingParam = paramObject->GetProperty("padding");
604     SetPadding(paddingParam, true);
605 
606     JSRef<JSVal> idParam = paramObject->GetProperty("id");
607     SetId(idParam);
608 
609     TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::SUBTABBATSTYLE);
610     TabContentModel::GetInstance()->SetTabBar(contentOpt, std::nullopt, std::nullopt, nullptr, false);
611     TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
612 }
613 
SetLayoutMode(const JSRef<JSVal> & info)614 void JSTabContent::SetLayoutMode(const JSRef<JSVal>& info)
615 {
616     int32_t layoutMode;
617     if (!ConvertFromJSValue(info, layoutMode)) {
618         TabContentModel::GetInstance()->SetLayoutMode(LayoutMode::VERTICAL);
619     } else {
620         TabContentModel::GetInstance()->SetLayoutMode(static_cast<LayoutMode>(layoutMode));
621     }
622 }
623 
SetVerticalAlign(const JSRef<JSVal> & info)624 void JSTabContent::SetVerticalAlign(const JSRef<JSVal>& info)
625 {
626     auto align = FlexAlign::CENTER;
627     if (info->IsNumber()) {
628         auto value = info->ToNumber<int32_t>();
629         if (value >= static_cast<int32_t>(FlexAlign::FLEX_START) &&
630             value <= static_cast<int32_t>(FlexAlign::FLEX_END)) {
631             align = static_cast<FlexAlign>(value);
632         }
633     }
634     TabContentModel::GetInstance()->SetVerticalAlign(align);
635 }
636 
SetSymmetricExtensible(const JSRef<JSVal> & info)637 void JSTabContent::SetSymmetricExtensible(const JSRef<JSVal>& info)
638 {
639     bool isExtensible = false;
640     ParseJsBool(info, isExtensible);
641     TabContentModel::GetInstance()->SetSymmetricExtensible(isExtensible);
642 }
643 
SetBottomTabBarStyle(const JSCallbackInfo & info)644 void JSTabContent::SetBottomTabBarStyle(const JSCallbackInfo& info)
645 {
646     auto paramObject = JSRef<JSObject>::Cast(info[0]);
647     JSRef<JSVal> textParam = paramObject->GetProperty("text");
648     std::optional<std::string> textOpt = std::nullopt;
649     std::string text;
650     if (ParseJsString(textParam, text)) {
651         textOpt = text;
652     }
653 
654     JSRef<JSVal> iconParam = paramObject->GetProperty("icon");
655     std::optional<std::string> iconOpt = std::nullopt;
656     std::string icon;
657     std::optional<TabBarSymbol> tabBarSymbol = std::nullopt;
658     if (ParseJsMedia(iconParam, icon)) {
659         iconOpt = icon;
660     } else if (iconParam->IsObject()) {
661         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(iconParam);
662         JSRef<JSVal> normalModifier = jsObj->GetProperty("normal");
663         JSRef<JSVal> selectedModifier = jsObj->GetProperty("selected");
664         if (normalModifier->IsObject()) {
665             TabBarSymbol symbolApply;
666             JSViewAbstract::SetTabBarSymbolOptionApply(info, symbolApply, normalModifier, selectedModifier);
667             if (selectedModifier->IsObject()) {
668                 symbolApply.selectedFlag = true;
669             }
670             tabBarSymbol = symbolApply;
671         }
672     }
673 
674     JSRef<JSVal> paddingParam = paramObject->GetProperty("padding");
675     SetPadding(paddingParam, false);
676 
677     JSRef<JSVal> layoutParam = paramObject->GetProperty("layoutMode");
678     SetLayoutMode(layoutParam);
679 
680     JSRef<JSVal> verticalAlignParam = paramObject->GetProperty("verticalAlign");
681     SetVerticalAlign(verticalAlignParam);
682 
683     JSRef<JSVal> extensibleParam = paramObject->GetProperty("symmetricExtensible");
684     SetSymmetricExtensible(extensibleParam);
685 
686     JSRef<JSVal> labelStyleParam = paramObject->GetProperty("labelStyle");
687     SetLabelStyle(labelStyleParam, false);
688 
689     SetIconStyle(paramObject->GetProperty("iconStyle"));
690 
691     JSRef<JSVal> idParam = paramObject->GetProperty("id");
692     SetId(idParam);
693 
694     TabContentModel::GetInstance()->SetTabBarStyle(TabBarStyle::BOTTOMTABBATSTYLE);
695     TabContentModel::GetInstance()->SetTabBar(textOpt, iconOpt, tabBarSymbol, nullptr, false);
696     TabContentModel::GetInstance()->SetTabBarWithContent(nullptr);
697 }
698 
SetOnWillShow(const JSCallbackInfo & info)699 void JSTabContent::SetOnWillShow(const JSCallbackInfo& info)
700 {
701     if (info.Length() < 1 || !info[0]->IsFunction()) {
702         return;
703     }
704     auto willShowHandler = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
705     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
706     auto onWillShow = [executionContext = info.GetExecutionContext(), func = std::move(willShowHandler)]() {
707         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
708         ACE_SCORING_EVENT("TabContent.onWillShow");
709         func->Execute();
710     };
711     TabContentModel::GetInstance()->SetOnWillShow(std::move(onWillShow));
712 }
713 
SetOnWillHide(const JSCallbackInfo & info)714 void JSTabContent::SetOnWillHide(const JSCallbackInfo& info)
715 {
716     if (info.Length() < 1 || !info[0]->IsFunction()) {
717         return;
718     }
719     auto willHideHandler = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
720     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
721     auto onWillHide = [executionContext = info.GetExecutionContext(), func = std::move(willHideHandler)]() {
722         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
723         ACE_SCORING_EVENT("TabContent.onWillHide");
724         func->Execute();
725     };
726     TabContentModel::GetInstance()->SetOnWillHide(std::move(onWillHide));
727 }
728 
JSBind(BindingTarget globalObj)729 void JSTabContent::JSBind(BindingTarget globalObj)
730 {
731     JSClass<JSTabContent>::Declare("TabContent");
732     JSClass<JSTabContent>::StaticMethod("create", &JSTabContent::Create);
733     JSClass<JSTabContent>::StaticMethod("pop", &JSTabContent::Pop);
734     JSClass<JSTabContent>::StaticMethod("tabBar", &JSTabContent::SetTabBar);
735     JSClass<JSTabContent>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
736     JSClass<JSTabContent>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
737     JSClass<JSTabContent>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
738     JSClass<JSTabContent>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
739     JSClass<JSTabContent>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
740     JSClass<JSTabContent>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
741     JSClass<JSTabContent>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
742     JSClass<JSTabContent>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
743     JSClass<JSTabContent>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
744     JSClass<JSTabContent>::StaticMethod("width", &JSTabContent::SetTabContentWidth);
745     JSClass<JSTabContent>::StaticMethod("height", &JSTabContent::SetTabContentHeight);
746     JSClass<JSTabContent>::StaticMethod("size", &JSTabContent::SetTabContentSize);
747     JSClass<JSTabContent>::StaticMethod("onWillShow", &JSTabContent::SetOnWillShow);
748     JSClass<JSTabContent>::StaticMethod("onWillHide", &JSTabContent::SetOnWillHide);
749     JSClass<JSTabContent>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
750     JSClass<JSTabContent>::InheritAndBind<JSContainerBase>(globalObj);
751 }
752 
753 } // namespace OHOS::Ace::Framework
754