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