• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "core/components_ng/pattern/window_scene/helper/starting_window_layout_helper.h"
17 
18 #include <algorithm>
19 
20 #include "adapter/ohos/entrance/ace_view_ohos.h"
21 #include "base/geometry/dimension.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/utils.h"
24 #include "core/common/container.h"
25 #include "core/components_ng/pattern/window_scene/scene/system_window_scene.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
28 #include "core/components_ng/pattern/search/search_pattern.h"
29 #include "core/pipeline_ng/pipeline_context.h"
30 #include "session/host/include/session.h"
31 #include "session_manager/include/scene_session_manager.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr Dimension FIXED_TOP_SAFE_AREA_HEIGHT_VP = 36.0_vp;
36 constexpr Dimension FIXED_BOTTOM_SAFE_AREA_HEIGHT_VP = 28.0_vp;
37 constexpr Dimension FIXED_BRAND_HORIZONTAL_MARGIN_VP = 24.0_vp;
38 constexpr Dimension MIN_BRAND_AREA_HEIGHT_VP = 100.0_vp;
39 constexpr Dimension MAX_BRAND_CONTENT_WIDTH_VP = 400.0_vp;
40 constexpr Dimension MIN_BRAND_CONTENT_HEIGHT_VP = 80.0_vp;
41 constexpr float UPPER_AREA_CONTAINER_HEIGHT_PERCENT = 0.7f;
42 constexpr float BRAND_CONTAINER_HEIGHT_PERCENT = 0.3f;
43 constexpr float BRAND_CONTENT_HEIGHT_PERCENT = 0.4f;
44 constexpr float ILLUSTRATION_CONTENT_SIZE_PERCENT = 0.8f;
45 constexpr float FULL_PERCENT = 1.0f;
46 constexpr float ZERO_FACTOR = 0.0f;
47 constexpr float HALF_FACTOR = 0.5f;
48 constexpr float DOUBLE_FACTOR = 2.0f;
49 const std::vector<std::pair<float, std::string>> WIDTH_BREAKPOINTS_VP = {
50     { 320.0f, "XSmall" },
51     { 600.0f, "Small" },
52     { 840.0f, "Medium" },
53     { 1440.0f, "Large" },
54     { FLT_MAX, "XLarge" },
55 };
56 const std::vector<std::pair<float, std::string>> ASPECT_RATIO_BREAKPOINTS = {
57     { 0.8f, "Landscape" },
58     { 1.2f, "Square" },
59     { FLT_MAX, "Portrait" },
60 };
61 
BuildLayoutKey(float widthVp,float aspectRatio)62 std::string BuildLayoutKey(float widthVp, float aspectRatio)
63 {
64     std::string key = "-";
65     for (const auto& p : WIDTH_BREAKPOINTS_VP) {
66         if (LessOrEqual(widthVp, p.first)) {
67             key = p.second + key;
68             break;
69         }
70     }
71     for (const auto& p : ASPECT_RATIO_BREAKPOINTS) {
72         if (LessOrEqual(aspectRatio, p.first)) {
73             key += p.second;
74             break;
75         }
76     }
77     return key;
78 }
79 
80 const std::map<std::string, ImageFit> STRING_TO_IMAGEFIT_MAP = {
81     { "Contain", ImageFit::CONTAIN },
82     { "Cover", ImageFit::COVER },
83     { "Auto", ImageFit::FITWIDTH },  // same as the mapping of image pattern
84     { "Fill", ImageFit::FILL },
85     { "ScaleDown", ImageFit::SCALE_DOWN },
86     { "None", ImageFit::NONE },
87 };
88 
89 const std::map<std::string, LayoutParams> LAYOUT_RULES_MAP = {
90     { "XSmall-Landscape", { 128.0_vp } },
91     { "XSmall-Square", { 128.0_vp } },
92     { "XSmall-Portrait", { 128.0_vp } },
93     { "Small-Landscape", { 128.0_vp } },
94     { "Small-Square", { 128.0_vp } },
95     { "Small-Portrait", { 192.0_vp } },
96     { "Medium-Landscape", { 192.0_vp } },
97     { "Medium-Square", { 256.0_vp } },
98     { "Medium-Portrait", { 256.0_vp } },
99     { "Large-Landscape", { 256.0_vp } },
100     { "Large-Square", { 256.0_vp } },
101     { "Large-Portrait", { 256.0_vp } },
102     { "XLarge-Landscape", { 256.0_vp } },
103     { "XLarge-Square", { 256.0_vp } },
104     { "XLarge-Portrait", { 256.0_vp } },
105 };
106 } // namespace
107 
CreateUpperAreaNode(const ImageSourceInfo & imageSource)108 RefPtr<FrameNode> CreateUpperAreaNode(const ImageSourceInfo& imageSource)
109 {
110     auto upperAreaNode = FrameNode::CreateFrameNode(
111         V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
112     CHECK_NULL_RETURN(upperAreaNode, nullptr);
113     auto upperAreaLayoutProperty = upperAreaNode->GetLayoutProperty<ImageLayoutProperty>();
114     CHECK_NULL_RETURN(upperAreaLayoutProperty, nullptr);
115     upperAreaLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
116     upperAreaLayoutProperty->UpdateImageSourceInfo(imageSource);
117     upperAreaLayoutProperty->UpdateImageFit(ImageFit::SCALE_DOWN);
118     upperAreaNode->MarkModifyDone();
119     return upperAreaNode;
120 }
121 
CreateBrandNode(const ImageSourceInfo & brandImageSource)122 RefPtr<FrameNode> CreateBrandNode(const ImageSourceInfo& brandImageSource)
123 {
124     auto brandNode = FrameNode::CreateFrameNode(
125         V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
126     CHECK_NULL_RETURN(brandNode, nullptr);
127     auto brandLayoutProperty = brandNode->GetLayoutProperty<ImageLayoutProperty>();
128     CHECK_NULL_RETURN(brandLayoutProperty, nullptr);
129     brandLayoutProperty->UpdateImageSourceInfo(brandImageSource);
130     brandLayoutProperty->UpdateImageFit(ImageFit::SCALE_DOWN);
131     brandNode->MarkModifyDone();
132     return brandNode;
133 }
134 
CreateBackgroundImageNode(const std::string & imageFit,const ImageSourceInfo & bgImageSource)135 RefPtr<FrameNode> CreateBackgroundImageNode(
136     const std::string& imageFit, const ImageSourceInfo& bgImageSource)
137 {
138     auto bgImgNode = FrameNode::CreateFrameNode(
139         V2::IMAGE_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ImagePattern>());
140     CHECK_NULL_RETURN(bgImgNode, nullptr);
141     auto bgImgLayoutProperty = bgImgNode->GetLayoutProperty<ImageLayoutProperty>();
142     CHECK_NULL_RETURN(bgImgLayoutProperty, nullptr);
143     bgImgLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
144     bgImgLayoutProperty->UpdateImageSourceInfo(bgImageSource);
145     auto imageFitType = ImageFit::COVER;
146     if (STRING_TO_IMAGEFIT_MAP.find(imageFit) != STRING_TO_IMAGEFIT_MAP.end()) {
147         imageFitType = STRING_TO_IMAGEFIT_MAP.at(imageFit);
148     }
149     bgImgLayoutProperty->UpdateImageFit(imageFitType);
150     bgImgNode->MarkModifyDone();
151     return bgImgNode;
152 }
153 
CreateStartingWindowNode(const Rosen::StartingWindowInfo & startingWindowInfo,const std::string & bundleName,const std::string & moduleName)154 RefPtr<FrameNode> StartingWindowLayoutHelper::CreateStartingWindowNode(
155     const Rosen::StartingWindowInfo& startingWindowInfo, const std::string& bundleName, const std::string& moduleName)
156 {
157     startingWindowInfo_ = startingWindowInfo;
158     // -root node of starting window
159     auto startingWindow = FrameNode::CreateFrameNode(
160         V2::STACK_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<StackPattern>());
161     CHECK_NULL_RETURN(startingWindow, nullptr);
162     auto startingWindowLayoutProperty = startingWindow->GetLayoutProperty<StackLayoutProperty>();
163     CHECK_NULL_RETURN(startingWindowLayoutProperty, nullptr);
164     startingWindowLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
165     startingWindow->GetRenderContext()->UpdateBackgroundColor(Color(startingWindowInfo_.backgroundColor_));
166     startingWindow->SetHitTestMode(HitTestMode::HTMNONE);
167 
168     if (!startingWindowInfo_.backgroundImagePath_.empty()) {
169         auto bgImgNode = CreateBackgroundImageNode(startingWindowInfo_.backgroundImageFit_,
170             ImageSourceInfo(startingWindowInfo_.backgroundImagePath_, bundleName, moduleName));
171         startingWindow->AddChild(bgImgNode);
172     }
173 
174     // --full size container
175     auto columnNode = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG,
176         ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<LinearLayoutPattern>(true));
177     CHECK_NULL_RETURN(columnNode, nullptr);
178     auto columnLayoutProps = columnNode->GetLayoutProperty<LinearLayoutProperty>();
179     CHECK_NULL_RETURN(columnLayoutProps, nullptr);
180     columnLayoutProps->UpdateMeasureType(MeasureType::MATCH_PARENT);
181 
182     auto upperAreaNode = CreateUpperAreaNode(ImageSourceInfo(
183         startingWindowInfo_.iconPath_.empty() ? startingWindowInfo_.illustrationPath_ : startingWindowInfo_.iconPath_,
184         bundleName, moduleName));
185     CHECK_NULL_RETURN(upperAreaNode, nullptr);
186     columnNode->AddChild(upperAreaNode);
187     auto brandNode = CreateBrandNode(ImageSourceInfo(startingWindowInfo_.brandingPath_, bundleName, moduleName));
188     CHECK_NULL_RETURN(brandNode, nullptr);
189     columnNode->AddChild(brandNode);
190     columnNode->MarkModifyDone();
191 
192     startingWindow->AddChild(columnNode);
193     startingWindow->MarkModifyDone();
194     upperAreaNode_ = upperAreaNode;
195     brandNode_ = brandNode;
196     return startingWindow;
197 }
198 
MeasureUpperAreaNode(const SizeF & parentSize,const RefPtr<FrameNode> upperAreaNode,bool needHideBrand)199 void StartingWindowLayoutHelper::MeasureUpperAreaNode(
200     const SizeF& parentSize, const RefPtr<FrameNode> upperAreaNode, bool needHideBrand)
201 {
202     auto upperAreaLayoutProperty = upperAreaNode->GetLayoutProperty<ImageLayoutProperty>();
203     CHECK_NULL_VOID(upperAreaLayoutProperty);
204     float upperHeightPercent = needHideBrand ? FULL_PERCENT : UPPER_AREA_CONTAINER_HEIGHT_PERCENT;
205     float upperContentSizePx = std::min(parentSize.Height() * HALF_FACTOR, parentSize.Width()) *
206         ILLUSTRATION_CONTENT_SIZE_PERCENT;
207     if (!startingWindowInfo_.iconPath_.empty()) {
208         upperAreaLayoutProperty->UpdateImageFit(ImageFit::CONTAIN);
209         CHECK_EQUAL_VOID(NearZero(parentSize.Width()), true);
210         auto key = BuildLayoutKey(Dimension(parentSize.Width(), DimensionUnit::PX).ConvertToVp(),
211             parentSize.Height() / parentSize.Width());
212         if (LAYOUT_RULES_MAP.find(key) != LAYOUT_RULES_MAP.end()) {
213             upperContentSizePx = LAYOUT_RULES_MAP.at(key).iconSize.ConvertToPx();
214         }
215     }
216     float totalSafeAreaHeightPx = FIXED_TOP_SAFE_AREA_HEIGHT_VP.ConvertToPx() +
217         (needHideBrand ? FIXED_BOTTOM_SAFE_AREA_HEIGHT_VP.ConvertToPx() : ZERO_FACTOR);
218     float upperContainerHeightPx = parentSize.Height() * upperHeightPercent - totalSafeAreaHeightPx;
219     float upperContentVerticalMarginPx = (upperContainerHeightPx - upperContentSizePx) * HALF_FACTOR;
220     MarginProperty upperContentMargin = {
221         .top = CalcLength(Dimension(
222             upperContentVerticalMarginPx + FIXED_TOP_SAFE_AREA_HEIGHT_VP.ConvertToPx(), DimensionUnit::PX)),
223         .bottom = CalcLength(Dimension(upperContentVerticalMarginPx, DimensionUnit::PX)),
224     };
225     upperAreaLayoutProperty->UpdateMargin(upperContentMargin);
226     upperAreaLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(
227         CalcLength(Dimension(upperContentSizePx, DimensionUnit::PX)),
228         CalcLength(Dimension(upperContentSizePx, DimensionUnit::PX))));
229 }
230 
MeasureChildNode(const SizeF & parentSize)231 void StartingWindowLayoutHelper::MeasureChildNode(const SizeF& parentSize)
232 {
233     auto upperAreaNode = upperAreaNode_.Upgrade();
234     CHECK_NULL_VOID(upperAreaNode);
235     auto brandNode = brandNode_.Upgrade();
236     CHECK_NULL_VOID(brandNode);
237     bool needHideBrand = LessOrEqual(parentSize.Height() * BRAND_CONTAINER_HEIGHT_PERCENT,
238         MIN_BRAND_AREA_HEIGHT_VP.ConvertToPx());
239     MeasureUpperAreaNode(parentSize, upperAreaNode, needHideBrand);
240 
241     auto brandLayoutProperty = brandNode->GetLayoutProperty<ImageLayoutProperty>();
242     CHECK_NULL_VOID(brandLayoutProperty);
243     if (needHideBrand) {
244         brandLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE, true);
245         return;
246     }
247     brandLayoutProperty->UpdateVisibility(VisibleType::VISIBLE, true);
248     float brandWidthPx = std::min(parentSize.Width() - FIXED_BRAND_HORIZONTAL_MARGIN_VP.ConvertToPx() * DOUBLE_FACTOR,
249         MAX_BRAND_CONTENT_WIDTH_VP.ConvertToPx());
250     float brandContainerHeightPx = parentSize.Height() * BRAND_CONTAINER_HEIGHT_PERCENT -
251         FIXED_BOTTOM_SAFE_AREA_HEIGHT_VP.ConvertToPx();
252     float brandHeightPx = std::max(brandContainerHeightPx * BRAND_CONTENT_HEIGHT_PERCENT,
253         static_cast<float>(MIN_BRAND_CONTENT_HEIGHT_VP.ConvertToPx()));
254     float brandVerticalMarginPx = (brandContainerHeightPx - brandHeightPx) * HALF_FACTOR;
255     float brandHorizontalMarginPx = (parentSize.Width() - brandWidthPx) * HALF_FACTOR;
256     MarginProperty brandMargin = {
257         .left = CalcLength(Dimension(brandHorizontalMarginPx, DimensionUnit::PX)),
258         .right = CalcLength(Dimension(brandHorizontalMarginPx, DimensionUnit::PX)),
259         .top = CalcLength(Dimension(brandVerticalMarginPx, DimensionUnit::PX)),
260         .bottom = CalcLength(Dimension(brandVerticalMarginPx + FIXED_BOTTOM_SAFE_AREA_HEIGHT_VP.ConvertToPx(),
261             DimensionUnit::PX)),
262     };
263     brandLayoutProperty->UpdateMargin(brandMargin);
264     brandLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(
265         CalcLength(Dimension(brandWidthPx, DimensionUnit::PX)),
266         CalcLength(Dimension(brandHeightPx, DimensionUnit::PX))));
267 }
268 } // namespace OHOS::Ace::NG
269