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