• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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/navigation/navdestination_node_base.h"
17 
18 #include "base/utils/utf_helper.h"
19 #include "base/json/json_util.h"
20 #include "core/components_ng/pattern/image/image_layout_property.h"
21 #include "core/components_ng/pattern/navigation/bar_item_node.h"
22 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
23 #include "core/components_ng/pattern/navigation/navdestination_content_pattern.h"
24 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
25 #include "core/components_ng/pattern/navigation/tool_bar_node.h"
26 #include "core/components_ng/pattern/navigation/tool_bar_pattern.h"
27 #include "core/components_ng/pattern/text/text_layout_property.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr double HALF = 0.5;
32 constexpr float REMOVE_CLIP_SIZE = 100000.0f;
33 constexpr float CONTENT_OFFSET_PERCENT = 0.2f;
34 }
35 
GetBarItemsString(bool isMenu) const36 std::string NavDestinationNodeBase::GetBarItemsString(bool isMenu) const
37 {
38     auto jsonValue = JsonUtil::Create(true);
39     auto parentNodeOfBarItems = isMenu ? DynamicCast<FrameNode>(GetMenu()) : DynamicCast<FrameNode>(GetToolBarNode());
40     CHECK_NULL_RETURN(parentNodeOfBarItems, "");
41     if (parentNodeOfBarItems->GetChildren().empty()) {
42         return "";
43     }
44     auto jsonOptions = JsonUtil::CreateArray(true);
45     int32_t i = 0;
46     for (auto iter = parentNodeOfBarItems->GetChildren().begin(); iter != parentNodeOfBarItems->GetChildren().end();
47             ++iter, i++) {
48         auto jsonToolBarItem = JsonUtil::CreateArray(true);
49         auto barItemNode = DynamicCast<BarItemNode>(*iter);
50         if (!barItemNode) {
51             jsonToolBarItem->Put("value", "");
52             jsonToolBarItem->Put("icon", "");
53             continue;
54         }
55         auto iconNode = DynamicCast<FrameNode>(barItemNode->GetIconNode());
56         if (iconNode) {
57             auto imageLayoutProperty = iconNode->GetLayoutProperty<ImageLayoutProperty>();
58             if (!imageLayoutProperty || !imageLayoutProperty->HasImageSourceInfo()) {
59                 jsonToolBarItem->Put("icon", "");
60             } else {
61                 jsonToolBarItem->Put("icon", imageLayoutProperty->GetImageSourceInfoValue().GetSrc().c_str());
62             }
63         } else {
64             jsonToolBarItem->Put("icon", "");
65         }
66         auto textNode = DynamicCast<FrameNode>(barItemNode->GetTextNode());
67         if (textNode) {
68             auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
69             if (!textLayoutProperty) {
70                 jsonToolBarItem->Put("value", "");
71             } else {
72                 jsonToolBarItem->Put("value", UtfUtils::Str16ToStr8(textLayoutProperty->GetContentValue(u"")).c_str());
73             }
74         } else {
75             jsonToolBarItem->Put("value", "");
76         }
77         auto index_ = std::to_string(i);
78         jsonOptions->Put(index_.c_str(), jsonToolBarItem);
79     }
80     jsonValue->Put("items", jsonOptions);
81     return jsonValue->ToString();
82 }
83 
IsToolBarVisible() const84 bool NavDestinationNodeBase::IsToolBarVisible() const
85 {
86     auto toolBarNode = AceType::DynamicCast<FrameNode>(GetToolBarNode());
87     CHECK_NULL_RETURN(toolBarNode, false);
88     auto layoutProperty = toolBarNode->GetLayoutProperty();
89     CHECK_NULL_RETURN(layoutProperty, false);
90     return layoutProperty->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE;
91 }
92 
CustomizeExpandSafeArea()93 bool NavDestinationNodeBase::CustomizeExpandSafeArea()
94 {
95     if (isCustomExpandRunning_) {
96         return false;
97     }
98     if (!(rotateAngle_.has_value() && viewportConfig_)) {
99         return false;
100     }
101     isCustomExpandRunning_ = true;
102     ScopePageViewportConfig scopeConfig(viewportConfig_);
103     auto geometryNode = GetGeometryNode();
104     RectF backupParentAdjust;
105     auto angle = rotateAngle_.value();
106     if (geometryNode) {
107         backupParentAdjust = geometryNode->GetParentAdjust();
108         if (angle == ROTATION_90 || angle == ROTATION_180 || angle == ROTATION_270) {
109             RectF parentAdjust{ safeAreaInsets_.left_.end, safeAreaInsets_.top_.end, 0.0f, 0.0f };
110             geometryNode->SetParentAdjust(parentAdjust);
111         }
112     }
113     FrameNode::ExpandSafeArea();
114     if (geometryNode) {
115         geometryNode->SetParentAdjust(backupParentAdjust);
116     }
117     isCustomExpandRunning_ = false;
118     return true;
119 }
120 
Measure(const std::optional<LayoutConstraintF> & parentConstraint)121 void NavDestinationNodeBase::Measure(const std::optional<LayoutConstraintF>& parentConstraint)
122 {
123     if (rotateAngle_.has_value() && rotateAngle_.value() != ROTATION_0 && viewportConfig_) {
124         ScopePageViewportConfig scopeConfig(viewportConfig_);
125         FrameNode::Measure(parentConstraint);
126         return;
127     }
128     FrameNode::Measure(parentConstraint);
129 }
130 
Layout()131 void NavDestinationNodeBase::Layout()
132 {
133     if (rotateAngle_.has_value() && rotateAngle_.value() != ROTATION_0 && viewportConfig_) {
134         ScopePageViewportConfig scopeConfig(viewportConfig_);
135         FrameNode::Layout();
136         return;
137     }
138     FrameNode::Layout();
139 }
140 
CalcHalfClipRectForTransition(const SizeF & frameSize)141 RectF NavDestinationNodeBase::CalcHalfClipRectForTransition(const SizeF& frameSize)
142 {
143     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
144     RectF rect;
145     float width = frameSize.Width();
146     float height = frameSize.Height();
147     if (angle == ROTATION_90 || angle == ROTATION_270) {
148         rect.SetSize({ REMOVE_CLIP_SIZE, height * HALF });
149     } else {
150         rect.SetSize({ width * HALF, REMOVE_CLIP_SIZE });
151     }
152 
153     OffsetF offset{ 0.0f, 0.0f };
154     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
155         if (angle == ROTATION_90) {
156             offset = OffsetF{ 0.0f, height * HALF };
157         } else if (angle == ROTATION_180) {
158             offset = OffsetF{ width * HALF, 0.0f };
159         }
160     } else {
161         if (angle == ROTATION_270) {
162             offset = OffsetF{ 0.0f, height * HALF };
163         } else if (angle == ROTATION_0) {
164             offset = OffsetF{ width * HALF, 0.0f };
165         }
166     }
167     rect.SetOffset(offset);
168     return rect;
169 }
170 
CalcFullClipRectForTransition(const SizeF & frameSize)171 RectF NavDestinationNodeBase::CalcFullClipRectForTransition(const SizeF& frameSize)
172 {
173     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
174     RectF rect;
175     if (angle == ROTATION_90 || angle == ROTATION_270) {
176         rect = RectF(0.0f, 0.0f, REMOVE_CLIP_SIZE, frameSize.Height());
177     } else {
178         rect = RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE);
179     }
180     return rect;
181 }
182 
CalcTranslateForTransitionPushStart(const SizeF & frameSize,bool transitionIn)183 OffsetF NavDestinationNodeBase::CalcTranslateForTransitionPushStart(const SizeF& frameSize, bool transitionIn)
184 {
185     if (!transitionIn) {
186         return OffsetF{ 0.0f, 0.0f };
187     }
188     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
189     float isRTL = GetLanguageDirection();
190     float width = frameSize.Width();
191     if (angle == ROTATION_90 || angle == ROTATION_270) {
192         width = frameSize.Height();
193     }
194     auto translate = OffsetF{ width * HALF * isRTL, 0.0f };
195     return translate;
196 }
197 
CalcTranslateForTransitionPushEnd(const SizeF & frameSize,bool transitionIn)198 OffsetF NavDestinationNodeBase::CalcTranslateForTransitionPushEnd(const SizeF& frameSize, bool transitionIn)
199 {
200     if (transitionIn) {
201         return OffsetF{ 0.0f, 0.0f };
202     }
203     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
204     float isRTL = GetLanguageDirection();
205     float width = frameSize.Width();
206     if (angle == ROTATION_90 || angle == ROTATION_270) {
207         width = frameSize.Height();
208     }
209     if (SystemProperties::IsSoftPageTransition()) {
210         auto translate = OffsetF{ -width * HALF * HALF * isRTL, 0.0f };
211         return translate;
212     }
213     auto translate = OffsetF{ -width * CONTENT_OFFSET_PERCENT * isRTL, 0.0f };
214     return translate;
215 }
216 
CalcTranslateForTransitionPopStart(const SizeF & frameSize,bool transitionIn)217 OffsetF NavDestinationNodeBase::CalcTranslateForTransitionPopStart(const SizeF& frameSize, bool transitionIn)
218 {
219     if (!transitionIn) {
220         return OffsetF{ 0.0f, 0.0f };
221     }
222     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
223     float isRTL = GetLanguageDirection();
224     float width = frameSize.Width();
225     if (angle == ROTATION_90 || angle == ROTATION_270) {
226         width = frameSize.Height();
227     }
228     if (SystemProperties::IsSoftPageTransition()) {
229         auto translate = OffsetF{ -width * HALF * HALF * isRTL, 0.0f };
230         return translate;
231     }
232     auto translate = OffsetF{ -width * CONTENT_OFFSET_PERCENT * isRTL, 0.0f };
233     return translate;
234 }
235 
CalcTranslateForTransitionPopEnd(const SizeF & frameSize,bool transitionIn)236 OffsetF NavDestinationNodeBase::CalcTranslateForTransitionPopEnd(const SizeF& frameSize, bool transitionIn)
237 {
238     if (transitionIn) {
239         return OffsetF{ 0.0f, 0.0f };
240     }
241     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
242     float isRTL = GetLanguageDirection();
243     float width = frameSize.Width();
244     if (angle == ROTATION_90 || angle == ROTATION_270) {
245         width = frameSize.Height();
246     }
247     auto translate = OffsetF{ width * HALF * isRTL, 0.0f };
248     return translate;
249 }
250 
RestoreRenderContext()251 void NavDestinationNodeBase::RestoreRenderContext()
252 {
253     viewportConfig_ = nullptr;
254     rotateAngle_ = std::nullopt;
255     auto renderContext = GetRenderContext();
256     CHECK_NULL_VOID(renderContext);
257     renderContext->SetBaseTranslateInXY(OffsetF(0.0f, 0.0f));
258     renderContext->SetBaseRotateInZ(0.0f);
259 }
260 
SetPageViewportConfig(const RefPtr<PageViewportConfig> & config)261 void NavDestinationNodeBase::SetPageViewportConfig(const RefPtr<PageViewportConfig>& config)
262 {
263     viewportConfig_ = config;
264     if (config) {
265         safeAreaInsets_ = config->GetSafeArea();
266     } else {
267         safeAreaInsets_ = SafeAreaInsets();
268     }
269     do {
270         auto titleNode = AceType::DynamicCast<TitleBarNode>(titleBarNode_);
271         CHECK_NULL_BREAK(titleNode);
272         auto titleBarPattern = titleNode->GetPattern<TitleBarPattern>();
273         CHECK_NULL_BREAK(titleBarPattern);
274         titleBarPattern->SetPageViewportConfig(config ? config->Clone() : nullptr);
275     } while (false);
276     do {
277         auto toolbarNode = AceType::DynamicCast<NavToolbarNode>(toolBarNode_);
278         CHECK_NULL_BREAK(toolbarNode);
279         auto toolBarPattern = toolbarNode->GetPattern<NavToolbarPattern>();
280         CHECK_NULL_BREAK(toolBarPattern);
281         toolBarPattern->SetPageViewportConfig(config ? config->Clone() : nullptr);
282     } while (false);
283     do {
284         auto contentNode = AceType::DynamicCast<FrameNode>(contentNode_);
285         CHECK_NULL_BREAK(contentNode);
286         auto contentPattern = contentNode->GetPattern<NavDestinationContentPattern>();
287         CHECK_NULL_BREAK(contentPattern);
288         contentPattern->SetPageViewportConfig(config ? config->Clone() : nullptr);
289     } while (false);
290 }
291 
AdjustLayoutConstarintIfNeeded(const LayoutConstraintF & originConstraint)292 LayoutConstraintF NavDestinationNodeBase::AdjustLayoutConstarintIfNeeded(const LayoutConstraintF& originConstraint)
293 {
294     if (!rotateAngle_.has_value() || !viewportConfig_) {
295         return originConstraint;
296     }
297     auto layoutConstraint = viewportConfig_->CreateRootLayoutConstraint();
298     ApplySafeArea(safeAreaInsets_, layoutConstraint);
299     return layoutConstraint;
300 }
301 
GetParentGlobalOffsetWithSafeArea(bool checkBoundary,bool checkPosition) const302 OffsetF NavDestinationNodeBase::GetParentGlobalOffsetWithSafeArea(bool checkBoundary, bool checkPosition) const
303 {
304     if (rotateAngle_.has_value()) {
305         return OffsetF(0.0f, 0.0f);
306     }
307     return LayoutWrapper::GetParentGlobalOffsetWithSafeArea(checkBoundary, checkPosition);
308 }
309 
CalcContentTranslateForDialog(const SizeF & frameSize)310 TranslateOptions NavDestinationNodeBase::CalcContentTranslateForDialog(const SizeF& frameSize)
311 {
312     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
313     switch (angle) {
314         case ROTATION_90:
315             return TranslateOptions{ frameSize.Width(), 0.0f, 0.0f };
316         case ROTATION_180:
317             return TranslateOptions{ 0.0f, -frameSize.Height(), 0.0f };
318         case ROTATION_270:
319             return TranslateOptions{ -frameSize.Width(), 0.0f, 0.0f };
320         default:
321             return TranslateOptions{ 0.0f, frameSize.Height(), 0.0f };
322     }
323 }
324 
AdjustRenderContextIfNeeded()325 void NavDestinationNodeBase::AdjustRenderContextIfNeeded()
326 {
327     auto renderContext = GetRenderContext();
328     CHECK_NULL_VOID(renderContext);
329     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
330     if (angle == ROTATION_0 || isRotated_) {
331         return;
332     }
333 
334     auto geometryNode = GetGeometryNode();
335     CHECK_NULL_VOID(geometryNode);
336     auto frameRect = geometryNode->GetFrameRect();
337     auto frameRectWithSafeArea = geometryNode->GetFrameRect(true);
338 
339     FrameNode::ExpandSafeArea();
340     frameRect = geometryNode->GetFrameRect();
341     frameRectWithSafeArea = geometryNode->GetFrameRect(true);
342     auto paintRect = renderContext->GetPaintRectWithoutTransform();
343     auto curCenter = paintRect.Center();
344     OffsetF targetCenter = curCenter;
345     if (angle == ROTATION_90 || angle == ROTATION_270) {
346         targetCenter = OffsetF(paintRect.Height() / 2.0f, paintRect.Width() / 2.0f);
347     }
348     auto offset = targetCenter - curCenter;
349     renderContext->SetBaseTranslateInXY(offset);
350     renderContext->SetBaseRotateInZ(angle);
351 
352     isRotated_ = true;
353 }
354 
CalcTranslateForSlideTransition(const SizeF & paintRect,bool isRight,bool isEnter,bool isEnd)355 OffsetF NavDestinationNodeBase::CalcTranslateForSlideTransition(
356     const SizeF& paintRect, bool isRight, bool isEnter, bool isEnd)
357 {
358     if ((isEnd && isEnter) || (!isEnd && !isEnter)) {
359         return OffsetF{ 0.0f, 0.0f };
360     }
361     auto angle = rotateAngle_.has_value() ? rotateAngle_.value() : ROTATION_0;
362     float width = paintRect.Width();
363     float height = paintRect.Height();
364     if (angle == ROTATION_90 || angle == ROTATION_270) {
365         std::swap(width, height);
366     }
367 
368     auto translate = OffsetF{ isRight ? width : 0.0f, isRight ? 0.0f : height };
369     return translate;
370 }
371 } // namespace OHOS::Ace::NG
372