• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/bubble/bubble_layout_algorithm.h"
17 
18 #include <algorithm>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/geometry/ng/offset_t.h"
22 #include "base/geometry/ng/point_t.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/memory/ace_type.h"
25 #include "base/subwindow/subwindow_manager.h"
26 #include "base/utils/device_config.h"
27 #include "base/utils/system_properties.h"
28 #include "base/utils/utils.h"
29 #include "core/common/ace_engine.h"
30 #include "core/common/container.h"
31 #include "core/components/common/layout/grid_system_manager.h"
32 #include "core/components/common/properties/placement.h"
33 #include "core/components/popup/popup_theme.h"
34 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
35 #include "core/components_ng/pattern/menu/menu_paint_property.h"
36 #include "core/components_ng/pattern/overlay/overlay_manager.h"
37 #include "core/components_ng/pattern/text/text_pattern.h"
38 #include "core/pipeline/pipeline_base.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
41 
42 namespace OHOS::Ace::NG {
43 namespace {
44 constexpr double HALF = 2.0;
45 constexpr double DOUBLE = 2.0;
46 constexpr Dimension ARROW_RADIUS = 2.0_vp;
47 constexpr Dimension MARGIN_SPACE = 6.0_vp;
48 constexpr Dimension DRAW_EDGES_SPACE = 1.0_vp;
49 constexpr double BUBBLE_ARROW_HALF = 2.0;
50 constexpr size_t ALIGNMENT_STEP_OFFSET = 1;
51 constexpr Dimension KEYBOARD_SPACE = 8.0_vp;
52 
53 // help value to calculate p2 p4 position
54 constexpr Dimension DEFAULT_BUBBLE_ARROW_WIDTH = 16.0_vp;
55 constexpr Dimension DEFAULT_BUBBLE_ARROW_HEIGHT = 8.0_vp;
56 Dimension DEFAULT_P2_HEIGHT = 7.32_vp;
57 Dimension DEFAULT_P2_WIDTH = 1.5_vp;
58 Dimension DEFAULT_P4_END_Y = 6.0_vp;
59 Dimension DEFAULT_P2_END_X = 12.8_vp;
60 Dimension DEFAULT_P2_END_Y = 7.6_vp;
61 
62 Dimension BUBBLE_ARROW_WIDTH = 16.0_vp;
63 Dimension BUBBLE_ARROW_HEIGHT = 8.0_vp;
64 constexpr double ARROW_OFFSET_START_VALUE = 0.0;
65 constexpr double ARROW_OFFSET_CENTER_VALUE = 0.5;
66 constexpr Dimension HORIZON_SPACING_WITH_SCREEN = 8.0_vp;
67 constexpr Dimension BEZIER_WIDTH_HALF = 8.0_vp;
68 
69 Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
70 Dimension ARROW_VERTICAL_P2_OFFSET_X = 1.5_vp;
71 Dimension ARROW_VERTICAL_P2_OFFSET_Y = 7.32_vp;
72 Dimension ARROW_VERTICAL_P4_OFFSET_X = 1.5_vp;
73 Dimension ARROW_VERTICAL_P4_OFFSET_Y = 7.32_vp;
74 Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
75 
76 Dimension ARROW_HORIZON_P1_OFFSET_Y = 8.0_vp;
77 Dimension ARROW_HORIZON_P2_OFFSET_Y = 1.5_vp;
78 Dimension ARROW_HORIZON_P2_OFFSET_X = 7.32_vp;
79 Dimension ARROW_HORIZON_P4_OFFSET_Y = 1.5_vp;
80 Dimension ARROW_HORIZON_P4_OFFSET_X = 7.32_vp;
81 Dimension ARROW_HORIZON_P5_OFFSET_Y = 8.0_vp;
82 
83 Dimension ARROW_REPLACE_START_VERTICAL_P1_OFFSET_X = 8.0_vp;
84 Dimension ARROW_REPLACE_START_VERTICAL_P2_OFFSET_X = 8.0_vp;
85 Dimension ARROW_REPLACE_START_VERTICAL_P2_OFFSET_Y = 6.0_vp;
86 Dimension ARROW_REPLACE_START_VERTICAL_P4_OFFSET_X = 4.8_vp;
87 Dimension ARROW_REPLACE_START_VERTICAL_P4_OFFSET_Y = 7.6_vp;
88 Dimension ARROW_REPLACE_START_VERTICAL_P5_OFFSET_X = 8.0_vp;
89 
90 Dimension ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X = 8.0_vp;
91 Dimension ARROW_REPLACE_END_VERTICAL_P2_OFFSET_X = 4.8_vp;
92 Dimension ARROW_REPLACE_END_VERTICAL_P2_OFFSET_Y = 7.6_vp;
93 Dimension ARROW_REPLACE_END_VERTICAL_P4_OFFSET_X = 8.0_vp;
94 Dimension ARROW_REPLACE_END_VERTICAL_P4_OFFSET_Y = 6.0_vp;
95 Dimension ARROW_REPLACE_END_VERTICAL_P5_OFFSET_X = 8.0_vp;
96 
97 Dimension ARROW_REPLACE_START_HORIZON_P1_OFFSET_Y = 8.0_vp;
98 Dimension ARROW_REPLACE_START_HORIZON_P2_OFFSET_X = 6.0_vp;
99 Dimension ARROW_REPLACE_START_HORIZON_P2_OFFSET_Y = 8.0_vp;
100 Dimension ARROW_REPLACE_START_HORIZON_P4_OFFSET_X = 7.6_vp;
101 Dimension ARROW_REPLACE_START_HORIZON_P4_OFFSET_Y = 4.8_vp;
102 Dimension ARROW_REPLACE_START_HORIZON_P5_OFFSET_Y = 8.0_vp;
103 
104 Dimension ARROW_REPLACE_END_HORIZON_P1_OFFSET_Y = 8.0_vp;
105 Dimension ARROW_REPLACE_END_HORIZON_P2_OFFSET_X = 7.6_vp;
106 Dimension ARROW_REPLACE_END_HORIZON_P2_OFFSET_Y = 4.8_vp;
107 Dimension ARROW_REPLACE_END_HORIZON_P4_OFFSET_X = 6.0_vp;
108 Dimension ARROW_REPLACE_END_HORIZON_P4_OFFSET_Y = 8.0_vp;
109 Dimension ARROW_REPLACE_END_HORIZON_P5_OFFSET_Y = 8.0_vp;
110 
111 constexpr Dimension BUBBLE_ARROW_ZERO_PERCENT_VALUE = 0.0_pct;
112 constexpr Dimension BUBBLE_ARROW_HALF_PERCENT_VALUE = 0.5_pct;
113 constexpr Dimension BUBBLE_ARROW_ONE_HUNDRED_PERCENT_VALUE = 1.0_pct;
114 constexpr Dimension OUT_RANGE_SPACE = 40.0_vp;
115 
116 constexpr int16_t ARROW_OFFSETS_INDEX_ZERO = 0;
117 constexpr int16_t ARROW_OFFSETS_INDEX_ONE = 1;
118 constexpr int16_t ARROW_OFFSETS_INDEX_TWO = 2;
119 constexpr int16_t ARROW_OFFSETS_INDEX_THREE = 3;
120 
GetEndP2P4(const Dimension & radius)121 void GetEndP2P4(const Dimension& radius)
122 {
123     auto h1 = BUBBLE_ARROW_HEIGHT.ConvertToPx() - radius.ConvertToPx();
124     auto w1 = BUBBLE_ARROW_WIDTH.ConvertToPx() - radius.ConvertToPx();
125     CHECK_EQUAL_VOID(w1, 0);
126     auto theta = std::atan(h1 / w1);
127     auto side = w1 /std::cos(theta);
128     auto alpha = std::asin(radius.ConvertToPx() / side);
129     auto beta = theta + alpha;
130     DEFAULT_P4_END_Y = Dimension(h1);
131     auto side1 = side * std::cos(alpha);
132     DEFAULT_P2_END_X = Dimension(side1 * std::cos(beta));
133     DEFAULT_P2_END_Y = Dimension(side1 * std::sin(beta));
134 }
135 
GetP2(const Dimension & radius)136 void GetP2(const Dimension& radius)
137 {
138     auto h1 = BUBBLE_ARROW_HEIGHT.ConvertToPx() - radius.ConvertToPx();
139     auto w1 = BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
140     CHECK_EQUAL_VOID(w1, 0);
141     auto theta = std::atan(h1 / w1);
142     auto side = w1 /std::cos(theta);
143     auto alpha = std::asin(radius.ConvertToPx() / side);
144     auto side1 = radius.ConvertToPx() / std::tan(alpha);
145     auto beta = alpha + theta;
146     DEFAULT_P2_HEIGHT = Dimension(side1 * std::sin(beta));
147     DEFAULT_P2_WIDTH = Dimension(w1 - side1 * std::cos(beta));
148 }
149 
calculateArrowPoint(Dimension height,Dimension width)150 void calculateArrowPoint(Dimension height, Dimension width)
151 {
152     auto rateX = width.ConvertToPx() / BUBBLE_ARROW_WIDTH.ConvertToPx();
153     BUBBLE_ARROW_WIDTH = width;
154     BUBBLE_ARROW_HEIGHT = height;
155 
156     GetEndP2P4(ARROW_RADIUS);
157     GetP2(ARROW_RADIUS);
158 
159     ARROW_VERTICAL_P1_OFFSET_X = ARROW_VERTICAL_P1_OFFSET_X * rateX;
160     ARROW_VERTICAL_P2_OFFSET_Y = DEFAULT_P2_HEIGHT;
161     ARROW_VERTICAL_P2_OFFSET_X = DEFAULT_P2_WIDTH;
162     ARROW_VERTICAL_P4_OFFSET_Y = DEFAULT_P2_HEIGHT;
163     ARROW_VERTICAL_P4_OFFSET_X = DEFAULT_P2_WIDTH;
164     ARROW_VERTICAL_P5_OFFSET_X = ARROW_VERTICAL_P5_OFFSET_X * rateX;
165 
166     ARROW_HORIZON_P1_OFFSET_Y = ARROW_HORIZON_P1_OFFSET_Y * rateX;
167     ARROW_HORIZON_P2_OFFSET_X = DEFAULT_P2_HEIGHT;
168     ARROW_HORIZON_P2_OFFSET_Y = DEFAULT_P2_WIDTH;
169     ARROW_HORIZON_P4_OFFSET_X = DEFAULT_P2_HEIGHT;
170     ARROW_HORIZON_P4_OFFSET_Y = DEFAULT_P2_WIDTH;
171     ARROW_HORIZON_P5_OFFSET_Y = ARROW_HORIZON_P5_OFFSET_Y * rateX;
172 
173     auto p1x = BUBBLE_ARROW_WIDTH / HALF;
174     auto p2x = Dimension(DEFAULT_P2_END_X.ConvertToPx() - p1x.ConvertToPx());
175     auto p2y = DEFAULT_P2_END_Y;
176     auto p4y = DEFAULT_P4_END_Y;
177 
178     ARROW_REPLACE_START_VERTICAL_P1_OFFSET_X = p1x;
179     ARROW_REPLACE_START_VERTICAL_P2_OFFSET_X = p1x;
180     ARROW_REPLACE_START_VERTICAL_P2_OFFSET_Y = p4y;
181     ARROW_REPLACE_START_VERTICAL_P4_OFFSET_X = p2x;
182     ARROW_REPLACE_START_VERTICAL_P4_OFFSET_Y = p2y;
183     ARROW_REPLACE_START_VERTICAL_P5_OFFSET_X = p1x;
184 
185     ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X = p1x;
186     ARROW_REPLACE_END_VERTICAL_P2_OFFSET_X = p2x;
187     ARROW_REPLACE_END_VERTICAL_P2_OFFSET_Y = p2y;
188     ARROW_REPLACE_END_VERTICAL_P4_OFFSET_X = p1x;
189     ARROW_REPLACE_END_VERTICAL_P4_OFFSET_Y = p4y;
190     ARROW_REPLACE_END_VERTICAL_P5_OFFSET_X = p1x;
191 
192     ARROW_REPLACE_START_HORIZON_P1_OFFSET_Y = p1x;
193     ARROW_REPLACE_START_HORIZON_P2_OFFSET_X = p4y;
194     ARROW_REPLACE_START_HORIZON_P2_OFFSET_Y = p1x;
195     ARROW_REPLACE_START_HORIZON_P4_OFFSET_X = p2y;
196     ARROW_REPLACE_START_HORIZON_P4_OFFSET_Y = p2x;
197     ARROW_REPLACE_START_HORIZON_P5_OFFSET_Y = p1x;
198 
199     ARROW_REPLACE_END_HORIZON_P1_OFFSET_Y = p1x;
200     ARROW_REPLACE_END_HORIZON_P2_OFFSET_X = p2y;
201     ARROW_REPLACE_END_HORIZON_P2_OFFSET_Y = p2x;
202     ARROW_REPLACE_END_HORIZON_P4_OFFSET_X = p4y;
203     ARROW_REPLACE_END_HORIZON_P4_OFFSET_Y = p1x;
204     ARROW_REPLACE_END_HORIZON_P5_OFFSET_Y = p1x;
205 }
206 
207 // get main window's pipeline
GetMainPipelineContext(LayoutWrapper * layoutWrapper)208 RefPtr<PipelineContext> GetMainPipelineContext(LayoutWrapper* layoutWrapper)
209 {
210     auto containerId = Container::CurrentId();
211     auto host = layoutWrapper->GetHostNode();
212     CHECK_NULL_RETURN(host, nullptr);
213     RefPtr<PipelineContext> context;
214     if (containerId >= MIN_SUBCONTAINER_ID) {
215         auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(containerId);
216         auto parentContainer = AceEngine::Get().GetContainer(parentContainerId);
217         CHECK_NULL_RETURN(parentContainer, nullptr);
218         context = AceType::DynamicCast<PipelineContext>(parentContainer->GetPipelineContext());
219     } else {
220         context = host->GetContextRefPtr();
221     }
222     return context;
223 }
224 } // namespace
225 
BubbleLayoutAlgorithm(int32_t id,const std::string & tag,const std::optional<OffsetF> & targetOffset,const std::optional<SizeF> & targetSize)226 BubbleLayoutAlgorithm::BubbleLayoutAlgorithm(int32_t id, const std::string& tag,
227     const std::optional<OffsetF>& targetOffset, const std::optional<SizeF>& targetSize)
228     : targetNodeId_(id), targetTag_(tag)
229 {
230     if (targetOffset.has_value()) {
231         targetOffset_ = targetOffset.value();
232     }
233     if (targetSize.has_value()) {
234         targetSize_ = targetSize.value();
235     }
236     placementFuncMap_[Placement::TOP] = &BubbleLayoutAlgorithm::GetPositionWithPlacementTop;
237     placementFuncMap_[Placement::TOP_LEFT] = &BubbleLayoutAlgorithm::GetPositionWithPlacementTopLeft;
238     placementFuncMap_[Placement::TOP_RIGHT] = &BubbleLayoutAlgorithm::GetPositionWithPlacementTopRight;
239     placementFuncMap_[Placement::BOTTOM] = &BubbleLayoutAlgorithm::GetPositionWithPlacementBottom;
240     placementFuncMap_[Placement::BOTTOM_LEFT] = &BubbleLayoutAlgorithm::GetPositionWithPlacementBottomLeft;
241     placementFuncMap_[Placement::BOTTOM_RIGHT] = &BubbleLayoutAlgorithm::GetPositionWithPlacementBottomRight;
242     placementFuncMap_[Placement::LEFT] = &BubbleLayoutAlgorithm::GetPositionWithPlacementLeft;
243     placementFuncMap_[Placement::LEFT_TOP] = &BubbleLayoutAlgorithm::GetPositionWithPlacementLeftTop;
244     placementFuncMap_[Placement::LEFT_BOTTOM] = &BubbleLayoutAlgorithm::GetPositionWithPlacementLeftBottom;
245     placementFuncMap_[Placement::RIGHT] = &BubbleLayoutAlgorithm::GetPositionWithPlacementRight;
246     placementFuncMap_[Placement::RIGHT_TOP] = &BubbleLayoutAlgorithm::GetPositionWithPlacementRightTop;
247     placementFuncMap_[Placement::RIGHT_BOTTOM] = &BubbleLayoutAlgorithm::GetPositionWithPlacementRightBottom;
248 
249     setHorizontal_ = { Placement::LEFT, Placement::LEFT_BOTTOM, Placement::LEFT_TOP, Placement::RIGHT,
250         Placement::RIGHT_BOTTOM, Placement::RIGHT_TOP };
251     setVertical_ = { Placement::TOP, Placement::TOP_LEFT, Placement::TOP_RIGHT, Placement::BOTTOM,
252         Placement::BOTTOM_LEFT, Placement::BOTTOM_RIGHT };
253 }
254 
Measure(LayoutWrapper * layoutWrapper)255 void BubbleLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
256 {
257     CHECK_NULL_VOID(layoutWrapper);
258     auto bubbleProp = DynamicCast<BubbleLayoutProperty>(layoutWrapper->GetLayoutProperty());
259     CHECK_NULL_VOID(bubbleProp);
260     auto bubbleLayoutProperty = AceType::DynamicCast<BubbleLayoutProperty>(layoutWrapper->GetLayoutProperty());
261     CHECK_NULL_VOID(bubbleLayoutProperty);
262     bool showInSubWindow = bubbleLayoutProperty->GetShowInSubWindowValue(false);
263     useCustom_ = bubbleLayoutProperty->GetUseCustom().value_or(false);
264     InitProps(bubbleProp, showInSubWindow, layoutWrapper);
265     auto bubbleNode = layoutWrapper->GetHostNode();
266     CHECK_NULL_VOID(bubbleNode);
267     const auto& layoutConstraint = bubbleLayoutProperty->GetLayoutConstraint();
268     if (!layoutConstraint) {
269         LOGE("fail to measure bubble due to layoutConstraint is nullptr");
270         return;
271     }
272     // bubble size fit screen.
273     layoutWrapper->GetGeometryNode()->SetFrameSize(layoutConstraint->maxSize);
274     layoutWrapper->GetGeometryNode()->SetContentSize(layoutConstraint->maxSize);
275     // update child layout constraint
276     LayoutConstraintF childLayoutConstraint = bubbleLayoutProperty->CreateChildConstraint();
277     if (avoidKeyboard_) {
278         childLayoutConstraint.maxSize.SetHeight(wrapperSize_.Height() - marginTop_ - KEYBOARD_SPACE.ConvertToPx());
279         childLayoutConstraint.maxSize.SetWidth(wrapperSize_.Width());
280     }
281     float minHeight = minHeight_.ConvertToPx();
282     if (GreatNotEqual(static_cast<double>(minHeight), 0.0)) {
283         childLayoutConstraint.minSize.SetHeight(minHeight);
284     }
285     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
286     if (children.empty()) {
287         return;
288     }
289     auto child = children.front();
290     CHECK_NULL_VOID(child);
291     measureChildSizeBefore_ = child->GetGeometryNode()->GetFrameSize();
292     if (isHalfFoldHover_) {
293         SizeF size = SizeF(childLayoutConstraint.maxSize.Width(),
294             static_cast<float>(std::floor(wrapperRect_.Height())));
295         childLayoutConstraint.UpdateMaxSizeWithCheck(size);
296     }
297     // childSize_ and childOffset_ is used in Layout.
298     auto childProp = child->GetLayoutProperty();
299     CHECK_NULL_VOID(childProp);
300     childProp->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
301     child->Measure(childLayoutConstraint);
302     measureChildSizeAfter_ = child->GetGeometryNode()->GetFrameSize();
303     if (!NearEqual(measureChildSizeBefore_, measureChildSizeAfter_)) {
304         auto childShowWidth = child->GetGeometryNode()->GetFrameSize().Width() + BUBBLE_ARROW_HEIGHT.ConvertToPx() * 2;
305         auto childShowHeight =
306             child->GetGeometryNode()->GetFrameSize().Height() + BUBBLE_ARROW_HEIGHT.ConvertToPx() * 2;
307         child->GetGeometryNode()->SetFrameSize(SizeF { childShowWidth, childShowHeight });
308         measureChildSizeLast_ = child->GetGeometryNode()->GetFrameSize();
309     } else {
310         measureChildSizeLast_ = child->GetGeometryNode()->GetFrameSize();
311     }
312     if (useCustom_ && !showInSubWindow) {
313         auto context = PipelineBase::GetCurrentContext();
314         CHECK_NULL_VOID(context);
315         float rootH = context->GetRootHeight();
316         float rootW = context->GetRootWidth();
317         auto childHeight = child->GetGeometryNode()->GetMarginFrameSize().Height();
318         auto childWidth = child->GetGeometryNode()->GetMarginFrameSize().Width();
319         auto scaledBubbleSpacing = scaledBubbleSpacing_ * 2;
320         auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
321         CHECK_NULL_VOID(targetNode);
322         auto geometryNode = targetNode->GetGeometryNode();
323         CHECK_NULL_VOID(geometryNode);
324         auto targetSize = geometryNode->GetFrameSize();
325         auto targetOffset = targetNode->GetPaintRectOffset();
326         auto constrainHeight = layoutWrapper->GetGeometryNode()->GetFrameSize().Height();
327         auto constrainWidth = layoutWrapper->GetGeometryNode()->GetFrameSize().Width();
328         float maxWidth = constrainWidth - targetSecurity_ * DOUBLE;
329         auto placement = bubbleLayoutProperty->GetPlacement().value_or(Placement::BOTTOM);
330         std::unordered_set<Placement> setHorizontal = { Placement::LEFT, Placement::LEFT_BOTTOM, Placement::LEFT_TOP,
331             Placement::RIGHT, Placement::RIGHT_BOTTOM, Placement::RIGHT_TOP };
332         std::unordered_set<Placement> setVertical = { Placement::TOP, Placement::TOP_LEFT, Placement::TOP_RIGHT,
333             Placement::BOTTOM, Placement::BOTTOM_LEFT, Placement::BOTTOM_RIGHT };
334         if (setHorizontal.find(placement) != setHorizontal.end()) {
335             if (childWidth + targetOffset.GetX() + targetSize.Width() + scaledBubbleSpacing <= rootW &&
336                 targetOffset.GetX() - childWidth - scaledBubbleSpacing >= 0) {
337                 return;
338             }
339             constrainWidth = rootW - scaledBubbleSpacing;
340         }
341         if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
342             if (setVertical.find(placement) != setVertical.end()) {
343                 if (childHeight + targetOffset.GetY() + targetSize.Height() + scaledBubbleSpacing <= rootH &&
344                     targetOffset.GetY() - childHeight - scaledBubbleSpacing >= 0) {
345                     return;
346                 }
347                 constrainHeight = std::max(rootH - targetOffset.GetY() - targetSize.Height() - scaledBubbleSpacing,
348                     targetOffset.GetY() - scaledBubbleSpacing);
349             }
350         }
351         constrainWidth = std::min(constrainWidth, maxWidth);
352         SizeF size = SizeF(constrainWidth, constrainHeight);
353         childLayoutConstraint.UpdateMaxSizeWithCheck(size);
354         child->Measure(childLayoutConstraint);
355     }
356 }
357 
GetMaxWith(uint32_t maxColumns)358 Dimension GetMaxWith(uint32_t maxColumns)
359 {
360     auto gridColumnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::BUBBLE_TYPE);
361     auto parent = gridColumnInfo->GetParent();
362     if (parent) {
363         parent->BuildColumnWidth();
364     }
365     auto maxWidth = Dimension(gridColumnInfo->GetMaxWidth());
366     if (maxColumns > 0) {
367         maxWidth = Dimension(gridColumnInfo->GetWidth(maxColumns));
368     }
369     return maxWidth;
370 }
371 
GetPopupMaxWidthAndHeight(bool showInSubWindow,const RefPtr<FrameNode> & frameNode)372 SizeF BubbleLayoutAlgorithm::GetPopupMaxWidthAndHeight(bool showInSubWindow, const RefPtr<FrameNode>& frameNode)
373 {
374     auto pipelineContext = PipelineContext::GetMainPipelineContext();
375     CHECK_NULL_RETURN(pipelineContext, SizeF());
376     auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
377 
378     CHECK_NULL_RETURN(frameNode, SizeF());
379     auto geometryNode = frameNode->GetGeometryNode();
380     CHECK_NULL_RETURN(geometryNode, SizeF());
381     auto width = geometryNode->GetMarginFrameSize().Width();
382 
383     auto safeAreaInsets = OverlayManager::GetSafeAreaInsets(frameNode);
384     // system safeArea(AvoidAreaType.TYPE_SYSTEM) only include status bar, the bottom is 0
385     auto bottom = 0.0;
386     auto top = safeAreaInsets.top_.Length();
387     auto maxHeight = windowGlobalRect.Height();
388     if (showInSubWindow) {
389         maxHeight = SystemProperties::GetDeviceHeight();
390     }
391     auto popupMaxWidth = GetMaxWith(maxColumns_).Value();
392     if (useCustom_) {
393         popupMaxWidth = width;
394     }
395     auto popupMaxHeight = maxHeight - OUT_RANGE_SPACE.ConvertToPx() - OUT_RANGE_SPACE.ConvertToPx() - bottom - top;
396     return SizeF(popupMaxWidth, popupMaxHeight);
397 }
398 
SetBubbleRadius()399 void BubbleLayoutAlgorithm::SetBubbleRadius()
400 {
401     auto littleSide = childSize_.Height() > childSize_.Width() ? childSize_.Width() : childSize_.Height();
402     auto littleSideHalf = littleSide / HALF;
403     if (borderRadius_.Unit() == DimensionUnit::PERCENT) {
404         auto value = borderRadius_.Value() * littleSideHalf;
405         borderRadius_.SetValue(value);
406         borderRadius_.SetUnit(DimensionUnit::PX);
407         border_.SetBorderRadius(Radius(borderRadius_));
408     }
409     auto borderRadius = ModifyBorderRadius(border_.BottomLeftRadius().GetY().ConvertToPx(), childSize_.Height() / 2);
410     auto borderRadius2 = ModifyBorderRadius(border_.BottomLeftRadius().GetY().ConvertToPx(), childSize_.Width() / 2);
411     float radiusPx = borderRadius < borderRadius2 ? borderRadius : borderRadius2;
412     borderRadius_.SetValue(radiusPx);
413     borderRadius_.SetUnit(DimensionUnit::PX);
414     border_.SetBorderRadius(Radius(borderRadius_));
415 }
416 
BubbleAvoidanceRule(RefPtr<LayoutWrapper> child,RefPtr<BubbleLayoutProperty> bubbleProp,RefPtr<FrameNode> bubbleNode,bool showInSubWindow,LayoutWrapper * layoutWrapper)417 void BubbleLayoutAlgorithm::BubbleAvoidanceRule(RefPtr<LayoutWrapper> child, RefPtr<BubbleLayoutProperty> bubbleProp,
418     RefPtr<FrameNode> bubbleNode, bool showInSubWindow, LayoutWrapper* layoutWrapper)
419 {
420     enableArrow_ = bubbleProp->GetEnableArrow().value_or(false);
421     auto bubblePattern = bubbleNode->GetPattern<BubblePattern>();
422     CHECK_NULL_VOID(bubblePattern);
423     auto bubblePaintProperty = bubbleNode->GetPaintProperty<BubbleRenderProperty>();
424     CHECK_NULL_VOID(bubblePaintProperty);
425     bool UseArrowOffset = bubblePaintProperty->GetArrowOffset().has_value();
426     if (!bubblePattern->IsExiting()) {
427         InitTargetSizeAndPosition(showInSubWindow, layoutWrapper);
428         if (isCaretMode_) {
429             InitCaretTargetSizeAndPosition();
430         }
431         // subtract the global offset of the overlay node,
432         // because the final node position is set relative to the overlay node.
433         auto overlayGlobalOffset = bubbleNode->GetOffsetRelativeToWindow();
434         targetOffset_ -= overlayGlobalOffset;
435     }
436     childSize_ = child->GetGeometryNode()->GetMarginFrameSize(); // bubble's size
437     auto childShowWidth = childSize_.Width() - BUBBLE_ARROW_HEIGHT.ConvertToPx() * 2;
438     auto childShowHeight = childSize_.Height() - BUBBLE_ARROW_HEIGHT.ConvertToPx() * 2;
439     childSize_ = SizeF(childShowWidth, childShowHeight);
440     SetBubbleRadius();
441     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
442         childOffset_ = GetChildPosition(childSize_, bubbleProp, UseArrowOffset); // bubble's offset
443         placement_ = arrowPlacement_;
444         UpdateChildPosition(childOffset_);
445         if (arrowPlacement_ == Placement::TOP) {
446             if (bCaretMode_) {
447                 arrowPosition_ = OffsetF(targetOffset_.GetX(), targetOffset_.GetY() - scaledBubbleSpacing_);
448             }
449         }
450         if (arrowPlacement_ == Placement::BOTTOM) {
451             if (bCaretMode_) {
452                 arrowPosition_ =
453                     OffsetF(targetOffset_.GetX(), targetOffset_.GetY() + targetSize_.Height() + scaledBubbleSpacing_);
454             }
455         }
456     } else {
457         UpdateMarginByWidth();
458         childOffset_ = GetChildPositionNew(childSize_, bubbleProp); // bubble's offset
459         childOffset_ = AddOffset(childOffset_);
460         dumpInfo_.finalPlacement = PlacementUtils::ConvertPlacementToString(placement_);
461     }
462 }
463 
Layout(LayoutWrapper * layoutWrapper)464 void BubbleLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
465 {
466     CHECK_NULL_VOID(layoutWrapper);
467     auto bubbleProp = DynamicCast<BubbleLayoutProperty>(layoutWrapper->GetLayoutProperty());
468     CHECK_NULL_VOID(bubbleProp);
469     auto frameNode = layoutWrapper->GetHostNode();
470     CHECK_NULL_VOID(frameNode);
471     auto bubblePattern = frameNode->GetPattern<BubblePattern>();
472     CHECK_NULL_VOID(bubblePattern);
473     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
474     if (children.empty()) {
475         return;
476     }
477     selfSize_ = layoutWrapper->GetGeometryNode()->GetFrameSize(); // window's size
478     auto childWrapper = children.front();
479     CHECK_NULL_VOID(childWrapper);
480     bool showInSubWindow = bubbleProp->GetShowInSubWindowValue(false);
481     auto layoutChildSize = childWrapper->GetGeometryNode()->GetMarginFrameSize();
482     auto childMaxSize = GetPopupMaxWidthAndHeight(showInSubWindow, childWrapper->GetHostNode());
483     if (NearEqual(childMaxSize, layoutChildSize) || !NearEqual(measureChildSizeLast_, layoutChildSize)) {
484         auto childShowWidth =
485             childWrapper->GetGeometryNode()->GetFrameSize().Width() + BUBBLE_ARROW_HEIGHT.ConvertToPx() * 2;
486         auto childShowHeight =
487             childWrapper->GetGeometryNode()->GetFrameSize().Height() + BUBBLE_ARROW_HEIGHT.ConvertToPx() * 2;
488         childWrapper->GetGeometryNode()->SetFrameSize(SizeF { childShowWidth, childShowHeight });
489     }
490     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
491     if (!targetNode) {
492         TAG_LOGD(AceLogTag::ACE_OVERLAY, "Popup can not get target node, stop layout");
493         return;
494     }
495     if (bubblePattern->IsExiting()) {
496         return;
497     }
498     BubbleAvoidanceRule(childWrapper, bubbleProp, frameNode, showInSubWindow, layoutWrapper);
499     UpdateTouchRegion();
500     auto childShowOffset = OffsetF(childOffset_.GetX() - BUBBLE_ARROW_HEIGHT.ConvertToPx(),
501         childOffset_.GetY() - BUBBLE_ARROW_HEIGHT.ConvertToPx());
502     childWrapper->GetGeometryNode()->SetMarginFrameOffset(childShowOffset);
503     childWrapper->Layout();
504     auto childLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
505     CHECK_NULL_VOID(childLayoutWrapper);
506     const auto& columnChild = childLayoutWrapper->GetAllChildrenWithBuild();
507     if (columnChild.size() > 1 && !useCustom_) {
508         auto buttonRow = columnChild.back();
509         buttonRowSize_ = buttonRow->GetGeometryNode()->GetMarginFrameSize();
510         buttonRowOffset_ = buttonRow->GetGeometryNode()->GetMarginFrameOffset() + childOffset_;
511     }
512     targetOffsetForPaint_ = targetOffset_;
513     childOffsetForPaint_ = childOffset_;
514     arrowPositionForPaint_ = arrowPosition_;
515     auto isBlock = bubbleProp->GetBlockEventValue(true);
516     dumpInfo_.mask = isBlock;
517     UpdateHostWindowRect();
518     SetHotAreas(showInSubWindow, isBlock, frameNode, bubblePattern->GetContainerId());
519     UpdateClipOffset(frameNode);
520 }
521 
UpdateHostWindowRect()522 void BubbleLayoutAlgorithm::UpdateHostWindowRect()
523 {
524     hostWindowRect_ = SubwindowManager::GetInstance()->GetParentWindowRect();
525     auto currentId = Container::CurrentId();
526     auto container = Container::Current();
527     CHECK_NULL_VOID(container);
528     if (container->IsSubContainer()) {
529         auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
530         container = AceEngine::Get().GetContainer(parentContainerId);
531         CHECK_NULL_VOID(container);
532     }
533     if (container->IsUIExtensionWindow()) {
534         auto subwindow = SubwindowManager::GetInstance()->GetSubwindowByType(currentId, SubwindowType::TYPE_POPUP);
535         CHECK_NULL_VOID(subwindow);
536         hostWindowRect_ = subwindow->GetUIExtensionHostWindowRect();
537     }
538 }
539 
SetHotAreas(bool showInSubWindow,bool isBlock,RefPtr<FrameNode> frameNode,int32_t containerId)540 void BubbleLayoutAlgorithm::SetHotAreas(bool showInSubWindow, bool isBlock,
541     RefPtr<FrameNode> frameNode, int32_t containerId)
542 {
543     if (showInSubWindow) {
544         std::vector<Rect> rects;
545         if (!isBlock) {
546             auto rect = Rect(childOffsetForPaint_.GetX(), childOffsetForPaint_.GetY(),
547                 childSize_.Width(), childSize_.Height());
548             rects.emplace_back(rect);
549         } else {
550             auto rect = Rect(childOffsetForPaint_.GetX(), childOffsetForPaint_.GetY(),
551                 childSize_.Width(), childSize_.Height());
552             rects.emplace_back(hostWindowRect_);
553             rects.emplace_back(rect);
554         }
555         auto context = frameNode->GetContextRefPtr();
556         CHECK_NULL_VOID(context);
557         auto taskExecutor = context->GetTaskExecutor();
558         CHECK_NULL_VOID(taskExecutor);
559         taskExecutor->PostTask(
560             [rects, containerId, frameNodeWK = WeakClaim(RawPtr(frameNode))]() {
561                 auto frameNode = frameNodeWK.Upgrade();
562                 CHECK_NULL_VOID(frameNode);
563                 auto subWindowMgr = SubwindowManager::GetInstance();
564                 subWindowMgr->SetHotAreas(rects, SubwindowType::TYPE_POPUP, frameNode->GetId(), containerId);
565             },
566             TaskExecutor::TaskType::UI, "ArkUIPopupSetHotAreas");
567     }
568 }
569 
IsUIExtensionWindow()570 bool BubbleLayoutAlgorithm::IsUIExtensionWindow()
571 {
572     auto currentId = Container::CurrentId();
573     auto container = Container::Current();
574     CHECK_NULL_RETURN(container, false);
575     if (container->IsSubContainer()) {
576         currentId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
577         container = AceEngine::Get().GetContainer(currentId);
578         CHECK_NULL_RETURN(container, false);
579     }
580     if (container->IsUIExtensionWindow()) {
581         return true;
582     }
583     return false;
584 }
585 
GetIfNeedArrow(const RefPtr<BubbleLayoutProperty> & bubbleProp,const SizeF & childSize)586 bool BubbleLayoutAlgorithm::GetIfNeedArrow(const RefPtr<BubbleLayoutProperty>& bubbleProp, const SizeF& childSize)
587 {
588     auto enableArrow = bubbleProp->GetEnableArrow().value_or(true);
589     if (!enableArrow) {
590         return false;
591     }
592     double arrowWidth = BUBBLE_ARROW_WIDTH.ConvertToPx();
593     double twoRadiusPx = borderRadius_.ConvertToPx() * 2.0;
594     if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
595         if (childSize.Height() >= twoRadiusPx + arrowWidth) {
596             return true;
597         }
598     }
599     if (setVertical_.find(placement_) != setVertical_.end()) {
600         if (childSize.Width() >= twoRadiusPx + arrowWidth) {
601             return true;
602         }
603     }
604     return false;
605 }
606 
UpdateDumpInfo()607 void BubbleLayoutAlgorithm::UpdateDumpInfo()
608 {
609     dumpInfo_.targetSpace = targetSpace_;
610     dumpInfo_.originPlacement = PlacementUtils::ConvertPlacementToString(placement_);
611     dumpInfo_.userOffset = positionOffset_;
612     dumpInfo_.enableArrow = enableArrow_;
613     dumpInfo_.top = top_;
614     dumpInfo_.bottom = bottom_;
615     dumpInfo_.targetNode = targetTag_;
616     dumpInfo_.targetID = targetNodeId_;
617 }
618 
InitProps(const RefPtr<BubbleLayoutProperty> & layoutProp,bool showInSubWindow,LayoutWrapper * layoutWrapper)619 void BubbleLayoutAlgorithm::InitProps(const RefPtr<BubbleLayoutProperty>& layoutProp, bool showInSubWindow,
620     LayoutWrapper* layoutWrapper)
621 {
622     auto pipeline = PipelineBase::GetCurrentContext();
623     CHECK_NULL_VOID(pipeline);
624     auto popupTheme = pipeline->GetTheme<PopupTheme>();
625     CHECK_NULL_VOID(popupTheme);
626     padding_ = popupTheme->GetPadding();
627     CHECK_NULL_VOID(layoutProp);
628     userSetTargetSpace_ = layoutProp->GetTargetSpace().value_or(Dimension(0.0f));
629     borderRadius_ = layoutProp->GetRadius().value_or(popupTheme->GetRadius().GetX());
630     border_.SetBorderRadius(Radius(borderRadius_));
631     targetSpace_ = layoutProp->GetTargetSpace().value_or(popupTheme->GetTargetSpace());
632     placement_ = layoutProp->GetPlacement().value_or(Placement::BOTTOM);
633     isCaretMode_ = layoutProp->GetIsCaretMode().value_or(true);
634     auto height = layoutProp->GetArrowHeight().value_or(DEFAULT_BUBBLE_ARROW_HEIGHT);
635     auto width = layoutProp->GetArrowWidth().value_or(DEFAULT_BUBBLE_ARROW_WIDTH);
636     calculateArrowPoint(height, width);
637     arrowHeight_ = height.ConvertToPx();
638     scaledBubbleSpacing_ = arrowHeight_;
639     realArrowWidth_ = BUBBLE_ARROW_WIDTH.ConvertToPx();
640     realArrowHeight_ = BUBBLE_ARROW_HEIGHT.ConvertToPx();
641     positionOffset_ = layoutProp->GetPositionOffset().value_or(OffsetF());
642     auto constraint = layoutProp->GetLayoutConstraint();
643     enableArrow_ = layoutProp->GetEnableArrow().value_or(true);
644     followTransformOfTarget_ = layoutProp->GetFollowTransformOfTarget().value_or(false);
645     auto wrapperIdealSize =
646         CreateIdealSize(constraint.value(), Axis::FREE, layoutProp->GetMeasureType(MeasureType::MATCH_PARENT), true);
647     wrapperSize_ = wrapperIdealSize;
648     targetSecurity_ = HORIZON_SPACING_WITH_SCREEN.ConvertToPx();
649     auto pipelineContext = PipelineContext::GetMainPipelineContext();
650     CHECK_NULL_VOID(pipelineContext);
651     CHECK_NULL_VOID(layoutWrapper);
652     auto safeAreaInsets = OverlayManager::GetSafeAreaInsets(layoutWrapper->GetHostNode());
653     top_ = safeAreaInsets.top_.Length();
654     bottom_ = safeAreaInsets.bottom_.Length();
655     UpdateDumpInfo();
656     marginStart_ = MARGIN_SPACE.ConvertToPx() + DRAW_EDGES_SPACE.ConvertToPx();
657     marginEnd_ = MARGIN_SPACE.ConvertToPx() + DRAW_EDGES_SPACE.ConvertToPx();
658     marginTop_ = top_ + DRAW_EDGES_SPACE.ConvertToPx();
659     marginBottom_ = bottom_ + DRAW_EDGES_SPACE.ConvertToPx();
660     HandleKeyboard(layoutWrapper, showInSubWindow);
661     showArrow_ = false;
662     minHeight_ = popupTheme->GetMinHeight();
663     maxColumns_ = popupTheme->GetMaxColumns();
664     isHalfFoldHover_ = pipelineContext->IsHalfFoldHoverStatus();
665     InitWrapperRect(layoutWrapper);
666     if (!useCustom_) {
667         UpdateScrollHeight(layoutWrapper, showInSubWindow);
668     }
669 }
670 
HandleKeyboard(LayoutWrapper * layoutWrapper,bool showInSubWindow)671 void BubbleLayoutAlgorithm::HandleKeyboard(LayoutWrapper* layoutWrapper, bool showInSubWindow)
672 {
673     auto bubbleNode = layoutWrapper->GetHostNode();
674     CHECK_NULL_VOID(bubbleNode);
675     auto bubblePattern = bubbleNode->GetPattern<BubblePattern>();
676     CHECK_NULL_VOID(bubblePattern);
677     avoidKeyboard_ = bubblePattern->GetAvoidKeyboard();
678     dumpInfo_.avoidKeyboard = avoidKeyboard_;
679     if (!avoidKeyboard_) {
680         return;
681     }
682     if (IsUIExtensionWindow()) {
683         HandleUIExtensionKeyboard(layoutWrapper, showInSubWindow);
684         return;
685     }
686     auto pipelineContext = PipelineContext::GetMainPipelineContext();
687     CHECK_NULL_VOID(pipelineContext);
688     auto safeAreaManager = pipelineContext->GetSafeAreaManager();
689     CHECK_NULL_VOID(safeAreaManager);
690     auto keyboardHeight = safeAreaManager->GetKeyboardInset().Length();
691     auto container = Container::Current();
692     CHECK_NULL_VOID(container);
693     if (GreatNotEqual(keyboardHeight, 0)) {
694         auto wrapperHeight =  container->IsSceneBoardEnabled() ? wrapperSize_.Height() - keyboardHeight :
695             wrapperSize_.Height() - keyboardHeight - marginBottom_;
696         wrapperSize_.SetHeight(wrapperHeight);
697         marginBottom_ = KEYBOARD_SPACE.ConvertToPx();
698     } else if (showInSubWindow) {
699         auto currentContext = bubbleNode->GetContextRefPtr();
700         CHECK_NULL_VOID(currentContext);
701         auto currentSafeAreaManager = currentContext->GetSafeAreaManager();
702         CHECK_NULL_VOID(currentSafeAreaManager);
703         auto currentKeyboardHeight = currentSafeAreaManager->GetKeyboardInset().Length();
704         if (GreatNotEqual(currentKeyboardHeight, 0)) {
705             auto wrapperHeight =  container->IsSceneBoardEnabled() ? wrapperSize_.Height() - currentKeyboardHeight :
706                 wrapperSize_.Height() - currentKeyboardHeight - marginBottom_;
707             wrapperSize_.SetHeight(wrapperHeight);
708             marginBottom_ = KEYBOARD_SPACE.ConvertToPx();
709         }
710     }
711 }
712 
HandleUIExtensionKeyboard(LayoutWrapper * layoutWrapper,bool showInSubWindow)713 void BubbleLayoutAlgorithm::HandleUIExtensionKeyboard(LayoutWrapper* layoutWrapper, bool showInSubWindow)
714 {
715     auto pipelineContext = PipelineContext::GetMainPipelineContext();
716     CHECK_NULL_VOID(pipelineContext);
717     auto safeAreaManager = pipelineContext->GetSafeAreaManager();
718     CHECK_NULL_VOID(safeAreaManager);
719     auto keyboardInset = safeAreaManager->GetKeyboardInset();
720     auto keyboardHeight = keyboardInset.Length();
721     auto wrapperRect = pipelineContext->GetDisplayWindowRectInfo();
722     if (showInSubWindow) {
723         if (GreatNotEqual(keyboardHeight, 0)) {
724             keyboardHeight = wrapperSize_.Height() - wrapperRect.Top() - wrapperRect.Height() + keyboardHeight;
725             wrapperSize_.SetHeight(wrapperSize_.Height() - keyboardHeight);
726             marginBottom_ = KEYBOARD_SPACE.ConvertToPx();
727         } else {
728             auto bubbleNode = layoutWrapper->GetHostNode();
729             CHECK_NULL_VOID(bubbleNode);
730             auto currentContext = bubbleNode->GetContextRefPtr();
731             CHECK_NULL_VOID(currentContext);
732             auto currentSafeAreaManager = currentContext->GetSafeAreaManager();
733             CHECK_NULL_VOID(currentSafeAreaManager);
734             auto currentKeyboardHeight = currentSafeAreaManager->GetKeyboardInset().Length();
735             if (GreatNotEqual(currentKeyboardHeight, 0)) {
736                 marginBottom_ = KEYBOARD_SPACE.ConvertToPx();
737                 wrapperSize_.SetHeight(wrapperSize_.Height() - currentKeyboardHeight);
738             }
739         }
740     } else {
741         auto topInset = safeAreaManager->GetSafeAreaWithoutProcess().top_;
742         auto bottomInset = safeAreaManager->GetSafeAreaWithoutProcess().bottom_;
743         marginTop_ = DRAW_EDGES_SPACE.ConvertToPx();
744         if (topInset.Length() > 0 && LessNotEqual(wrapperRect.Top(), topInset.end)) {
745             marginTop_ = topInset.end - wrapperRect.Top() + marginTop_;
746         }
747         marginBottom_ = DRAW_EDGES_SPACE.ConvertToPx();
748         if (keyboardHeight > 0) {
749             marginBottom_ = KEYBOARD_SPACE.ConvertToPx();
750             wrapperSize_.SetHeight(wrapperSize_.Height() - keyboardHeight);
751         } else if (bottomInset.Length() > 0 && GreatNotEqual(wrapperRect.Top() + wrapperRect.Height(),
752             bottomInset.start)) {
753             marginBottom_ = wrapperRect.Top() + wrapperRect.Height() - bottomInset.start + marginBottom_;
754         }
755     }
756 }
757 
InitWrapperRect(LayoutWrapper * layoutWrapper)758 void BubbleLayoutAlgorithm::InitWrapperRect(LayoutWrapper* layoutWrapper)
759 {
760     auto container = Container::Current();
761     CHECK_NULL_VOID(container);
762     auto displayInfo = container->GetDisplayInfo();
763     auto foldCreaseRects = displayInfo->GetCurrentFoldCreaseRegion();
764     if (!foldCreaseRects.empty()) {
765         auto foldCrease = foldCreaseRects.front();
766         foldCreaseTop_ = foldCrease.Top();
767         foldCreaseBottom_ = foldCrease.Bottom();
768     }
769     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
770     CHECK_NULL_VOID(targetNode);
771     auto targetOffset = targetNode->GetPaintRectOffset();
772     float getY = 0;
773     getY = targetOffset.GetY();
774     auto bubbleNode = layoutWrapper->GetHostNode();
775     CHECK_NULL_VOID(bubbleNode);
776     auto bubblePattern = bubbleNode->GetPattern<BubblePattern>();
777     CHECK_NULL_VOID(bubblePattern);
778     auto enableHoverMode = bubblePattern->GetEnableHoverMode();
779     dumpInfo_.enableHoverMode = enableHoverMode;
780     if (!enableHoverMode) {
781         isHalfFoldHover_ = false;
782     }
783     if (isHalfFoldHover_ && enableHoverMode) {
784         if (getY < foldCreaseTop_) {
785             wrapperRect_.SetRect(marginStart_, marginTop_,
786                 wrapperSize_.Width() - marginEnd_ - marginStart_, foldCreaseTop_ - marginTop_);
787         } else if (getY > foldCreaseBottom_) {
788             wrapperRect_.SetRect(marginStart_, foldCreaseBottom_,
789                 wrapperSize_.Width() - marginEnd_ - marginStart_,
790                     wrapperSize_.Height() - foldCreaseBottom_ - marginBottom_);
791         } else {
792             isHalfFoldHover_ = false;
793         }
794     }
795 }
796 
UpdateScrollHeight(LayoutWrapper * layoutWrapper,bool showInSubWindow)797 void BubbleLayoutAlgorithm::UpdateScrollHeight(LayoutWrapper* layoutWrapper, bool showInSubWindow)
798 {
799     auto bubbleNode = layoutWrapper->GetHostNode();
800     CHECK_NULL_VOID(bubbleNode);
801     auto bubblePattern = bubbleNode->GetPattern<BubblePattern>();
802     CHECK_NULL_VOID(bubblePattern);
803     auto enableHoverMode = bubblePattern->GetEnableHoverMode();
804     if (!enableHoverMode) {
805         return;
806     }
807 
808     const auto& children = layoutWrapper->GetAllChildrenWithBuild();
809     if (children.empty()) {
810         return;
811     }
812     auto childWrapper = children.front();
813     CHECK_NULL_VOID(childWrapper);
814     auto childMaxSize = GetPopupMaxWidthAndHeight(showInSubWindow, childWrapper->GetHostNode());
815 
816     auto columnNode = AceType::DynamicCast<FrameNode>(bubbleNode->GetLastChild());
817     CHECK_NULL_VOID(columnNode);
818     auto lastColumnNode = AceType::DynamicCast<FrameNode>(columnNode->GetLastChild());
819     CHECK_NULL_VOID(lastColumnNode);
820     auto buttonRowNode = AceType::DynamicCast<FrameNode>(lastColumnNode->GetLastChild());
821     CHECK_NULL_VOID(buttonRowNode);
822 
823     if (buttonRowNode->GetChildren().empty()) {
824         return;
825     }
826     const auto& lastChildren = lastColumnNode->GetChildren();
827     buttonRowSize_ = buttonRowNode->GetGeometryNode()->GetFrameSize();
828 
829     for (const auto& uinode : lastChildren) {
830         if (uinode->GetTag() == V2::SCROLL_ETS_TAG) {
831             auto scrollNode = AceType::DynamicCast<FrameNode>(uinode);
832             CHECK_NULL_VOID(scrollNode);
833 
834             auto scrollProps = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
835             CHECK_NULL_VOID(scrollProps);
836             if (isHalfFoldHover_) {
837                 scrollProps->UpdateCalcMaxSize(CalcSize(
838                     std::nullopt,
839                     CalcLength(Dimension(wrapperRect_.Height() - buttonRowSize_.Height()))));
840             } else {
841                 scrollProps->UpdateCalcMaxSize(CalcSize(
842                     std::nullopt,
843                     CalcLength(Dimension(childMaxSize.Height() - buttonRowSize_.Height()))));
844             }
845             scrollNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
846         }
847     }
848 }
849 
GetChildPositionNew(const SizeF & childSize,const RefPtr<BubbleLayoutProperty> & bubbleProp)850 OffsetF BubbleLayoutAlgorithm::GetChildPositionNew(
851     const SizeF& childSize, const RefPtr<BubbleLayoutProperty>& bubbleProp)
852 {
853     static std::map<Placement, std::vector<Placement>> PLACEMENT_STATES = {
854         { Placement::BOTTOM_LEFT,
855             {
856                 Placement::BOTTOM_LEFT,
857                 Placement::TOP_LEFT,
858                 Placement::RIGHT_TOP,
859                 Placement::LEFT_TOP,
860                 Placement::NONE,
861             } },
862         { Placement::BOTTOM,
863             {
864                 Placement::BOTTOM,
865                 Placement::TOP,
866                 Placement::RIGHT,
867                 Placement::LEFT,
868                 Placement::NONE,
869             } },
870         { Placement::BOTTOM_RIGHT,
871             {
872                 Placement::BOTTOM_RIGHT,
873                 Placement::TOP_RIGHT,
874                 Placement::RIGHT_BOTTOM,
875                 Placement::LEFT_BOTTOM,
876                 Placement::NONE,
877             } },
878         { Placement::TOP_LEFT,
879             {
880                 Placement::TOP_LEFT,
881                 Placement::BOTTOM_LEFT,
882                 Placement::RIGHT_TOP,
883                 Placement::LEFT_TOP,
884                 Placement::NONE,
885             } },
886         { Placement::TOP,
887             {
888                 Placement::TOP,
889                 Placement::BOTTOM,
890                 Placement::RIGHT,
891                 Placement::LEFT,
892                 Placement::NONE,
893             } },
894         { Placement::TOP_RIGHT,
895             {
896                 Placement::TOP_RIGHT,
897                 Placement::BOTTOM_RIGHT,
898                 Placement::RIGHT_BOTTOM,
899                 Placement::LEFT_BOTTOM,
900                 Placement::NONE,
901             } },
902         { Placement::LEFT_TOP,
903             {
904                 Placement::LEFT_TOP,
905                 Placement::RIGHT_TOP,
906                 Placement::BOTTOM_LEFT,
907                 Placement::TOP_LEFT,
908                 Placement::NONE,
909             } },
910         { Placement::LEFT,
911             {
912                 Placement::LEFT,
913                 Placement::RIGHT,
914                 Placement::BOTTOM,
915                 Placement::TOP,
916                 Placement::NONE,
917             } },
918         { Placement::LEFT_BOTTOM,
919             {
920                 Placement::LEFT_BOTTOM,
921                 Placement::RIGHT_BOTTOM,
922                 Placement::BOTTOM_RIGHT,
923                 Placement::TOP_RIGHT,
924                 Placement::NONE,
925             } },
926         { Placement::RIGHT_TOP,
927             {
928                 Placement::RIGHT_TOP,
929                 Placement::LEFT_TOP,
930                 Placement::BOTTOM_LEFT,
931                 Placement::TOP_LEFT,
932                 Placement::NONE,
933             } },
934         { Placement::RIGHT,
935             {
936                 Placement::RIGHT,
937                 Placement::LEFT,
938                 Placement::BOTTOM,
939                 Placement::TOP,
940                 Placement::NONE,
941             } },
942         { Placement::RIGHT_BOTTOM,
943             {
944                 Placement::RIGHT_BOTTOM,
945                 Placement::LEFT_BOTTOM,
946                 Placement::BOTTOM_RIGHT,
947                 Placement::TOP_RIGHT,
948                 Placement::NONE,
949             } },
950     };
951     OffsetF bottomPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
952         targetOffset_.GetY() + targetSize_.Height() + targetSpace_.ConvertToPx() + arrowHeight_);
953     OffsetF topPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
954         targetOffset_.GetY() - childSize.Height() - targetSpace_.ConvertToPx() - arrowHeight_);
955     OffsetF defaultPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
956         targetOffset_.GetY() + (targetSize_.Height() - childSize.Height()) / 2.0);
957     OffsetF childPosition;
958     OffsetF ArrowOffset;
959     OffsetF position = defaultPosition;
960     auto positionOffset = positionOffset_;
961     auto originPlacement = placement_;
962     auto originPosition = GetPositionWithPlacementNew(childSize, topPosition, bottomPosition, ArrowOffset);
963     bool didNeedArrow = false;
964     std::vector<Placement> currentPlacementStates = PLACEMENT_STATES.find(Placement::BOTTOM)->second;
965     if (PLACEMENT_STATES.find(placement_) != PLACEMENT_STATES.end()) {
966         currentPlacementStates = PLACEMENT_STATES.find(placement_)->second;
967     }
968     size_t step = ALIGNMENT_STEP_OFFSET;
969     bVertical_ = false;
970     bHorizontal_ = false;
971     for (size_t i = 0, len = currentPlacementStates.size(); i < len;) {
972         placement_ = currentPlacementStates[i];
973         if (placement_ == Placement::NONE) {
974             break;
975         }
976         if (bCaretMode_) { // Caret mode
977             if ((placement_ != Placement::BOTTOM) && (placement_ != Placement::TOP)) {
978                 i++;
979                 continue;
980             }
981         }
982         if (bVertical_) {
983             if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
984                 i++;
985                 continue;
986             }
987         }
988         if (bHorizontal_) {
989             if (setVertical_.find(placement_) != setVertical_.end()) {
990                 i++;
991                 continue;
992             }
993         }
994         if (i >= step) {
995             positionOffset_ = OffsetF(0.0f, 0.0f);
996         }
997         childPosition = GetPositionWithPlacementNew(childSize, topPosition, bottomPosition, ArrowOffset);
998         UpdateChildPosition(childPosition);
999         didNeedArrow = GetIfNeedArrow(bubbleProp, childSize_);
1000         position = FitToScreenNew(childPosition, step, i, childSize, didNeedArrow);
1001         if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1002             continue;
1003         }
1004         break;
1005     }
1006     if (placement_ == Placement::NONE) {
1007         bVertical_ = false;
1008         bHorizontal_ = false;
1009         position = GetAdjustPosition(currentPlacementStates, step, childSize, topPosition, bottomPosition, ArrowOffset);
1010         if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1011             showArrow_ = false;
1012             if (avoidKeyboard_ && !isHalfFoldHover_) {
1013                 placement_ = originPlacement;
1014                 position = AdjustPositionNew(originPosition, childSize.Width(), childSize.Height());
1015             } else {
1016                 position = AdjustPosition(defaultPosition, childSize.Width(), childSize.Height(), targetSecurity_);
1017             }
1018             if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1019                 auto x = std::clamp(
1020                     defaultPosition.GetX(), marginStart_, wrapperSize_.Width() - childSize.Width() - marginEnd_);
1021                 auto y = marginTop_;
1022                 position = OffsetF(x, y);
1023             }
1024         }
1025     }
1026     positionOffset_ = positionOffset;
1027     arrowPlacement_ = placement_;
1028     arrowPosition_ = ArrowOffset;
1029     return position;
1030 }
1031 
AdjustPositionNew(const OffsetF & position,float width,float height)1032 OffsetF BubbleLayoutAlgorithm::AdjustPositionNew(const OffsetF& position, float width, float height)
1033 {
1034     OffsetF result = position;
1035     OffsetF positionEnd = position + OffsetF(width, height);
1036     if (GreatNotEqual(positionEnd.GetX(), wrapperSize_.Width() - marginEnd_)) {
1037         result.SetX(wrapperSize_.Width() - marginEnd_ - width);
1038     }
1039     if (GreatNotEqual(positionEnd.GetY(), wrapperSize_.Height() - marginBottom_)) {
1040         result.SetY(wrapperSize_.Height()- marginBottom_ - height);
1041     }
1042     if (LessNotEqual(position.GetX(), marginStart_)) {
1043         result.SetX(marginStart_);
1044     }
1045     if (LessNotEqual(position.GetY(), marginTop_)) {
1046         result.SetY(marginTop_);
1047     }
1048     return result;
1049 }
1050 
GetAdjustPosition(std::vector<Placement> & currentPlacementStates,size_t step,const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1051 OffsetF BubbleLayoutAlgorithm::GetAdjustPosition(std::vector<Placement>& currentPlacementStates, size_t step,
1052     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1053 {
1054     OffsetF childPosition;
1055     OffsetF position;
1056     float width = 0.0f;
1057     float height = 0.0f;
1058     for (size_t i = 0, len = currentPlacementStates.size(); i < len;) {
1059         placement_ = currentPlacementStates[i];
1060         if (placement_ == Placement::NONE) {
1061             break;
1062         }
1063         if (bCaretMode_) { // Caret mode
1064             if ((placement_ != Placement::BOTTOM) && (placement_ != Placement::TOP)) {
1065                 i++;
1066                 continue;
1067             }
1068         }
1069         if (bVertical_) {
1070             if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
1071                 i++;
1072                 continue;
1073             }
1074         }
1075         if (bHorizontal_) {
1076             if (setVertical_.find(placement_) != setVertical_.end()) {
1077                 i++;
1078                 continue;
1079             }
1080         }
1081         childPosition = GetPositionWithPlacementNew(childSize, topPosition, bottomPosition, arrowPosition);
1082         UpdateChildPosition(childPosition);
1083         width = childSize.Width();
1084         height = childSize.Height();
1085         if (showArrow_) {
1086             if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
1087                 width += BUBBLE_ARROW_HEIGHT.ConvertToPx();
1088             }
1089             if (setVertical_.find(placement_) != setVertical_.end()) {
1090                 height += BUBBLE_ARROW_HEIGHT.ConvertToPx();
1091             }
1092         }
1093         position = AdjustPosition(childPosition, width, height, targetSpace_.ConvertToPx());
1094         if (NearEqual(position, OffsetF(0.0f, 0.0f))) {
1095             i += step;
1096             continue;
1097         }
1098         break;
1099     }
1100     return position;
1101 }
1102 
AdjustPosition(const OffsetF & position,float width,float height,float space)1103 OffsetF BubbleLayoutAlgorithm::AdjustPosition(const OffsetF& position, float width, float height, float space)
1104 {
1105     float xMax = 0.0f;
1106     float yMax = 0.0f;
1107     float xMin = 1.0f;
1108     float yMin = 1.0f;
1109     float yTargetOffset = 0.0f;
1110     switch (placement_) {
1111         case Placement::LEFT_TOP:
1112         case Placement::LEFT_BOTTOM:
1113         case Placement::LEFT: {
1114             xMin = marginStart_;
1115             xMax = std::min(targetOffset_.GetX() - width - space, wrapperSize_.Width() - marginEnd_ - width);
1116             yMin = marginTop_;
1117             yMax = wrapperSize_.Height() - height - marginBottom_;
1118             if (isHalfFoldHover_) {
1119                 yMin = wrapperRect_.Top();
1120                 yMax = wrapperRect_.Bottom() - height;
1121             }
1122             break;
1123         }
1124         case Placement::RIGHT_TOP:
1125         case Placement::RIGHT_BOTTOM:
1126         case Placement::RIGHT: {
1127             if (showArrow_) {
1128                 space = space + BUBBLE_ARROW_HEIGHT.ConvertToPx();
1129             }
1130             xMin = std::max(targetOffset_.GetX() + targetSize_.Width() + space, marginStart_);
1131             xMax = wrapperSize_.Width() - width - marginEnd_;
1132             yMin = marginTop_;
1133             yMax = wrapperSize_.Height() - height - marginBottom_;
1134             if (isHalfFoldHover_) {
1135                 yMin = wrapperRect_.Top();
1136                 yMax = wrapperRect_.Bottom() - height;
1137             }
1138             break;
1139         }
1140         case Placement::TOP_LEFT:
1141         case Placement::TOP_RIGHT:
1142         case Placement::TOP: {
1143             xMin = marginStart_;
1144             xMax = wrapperSize_.Width() - width - marginEnd_;
1145             yMin = marginTop_;
1146             yMax = std::min(targetOffset_.GetY() - height - space, wrapperSize_.Height() - marginBottom_ - height);
1147             if (isHalfFoldHover_) {
1148                 yMin = wrapperRect_.Top();
1149                 yMax = std::min(targetOffset_.GetY() - height - space,
1150                     static_cast<float>(wrapperRect_.Bottom()) - height);
1151             }
1152             yTargetOffset = targetSecurity_;
1153             break;
1154         }
1155         case Placement::BOTTOM_LEFT:
1156         case Placement::BOTTOM_RIGHT:
1157         case Placement::BOTTOM: {
1158             if (showArrow_) {
1159                 space = space + BUBBLE_ARROW_HEIGHT.ConvertToPx();
1160             }
1161             xMin = marginStart_;
1162             xMax = wrapperSize_.Width() - width - marginEnd_;
1163             yMin = std::max(targetOffset_.GetY() + targetSize_.Height() + space, marginTop_);
1164             yMax = wrapperSize_.Height() - height - marginBottom_;
1165             if (isHalfFoldHover_) {
1166                 yMin = std::max(targetOffset_.GetY() + targetSize_.Height() + space,
1167                     static_cast<float>(wrapperRect_.Top()));
1168                 yMax = wrapperRect_.Bottom() - height;
1169             }
1170             yTargetOffset = -targetSecurity_;
1171             break;
1172         }
1173         case Placement::NONE: {
1174             xMin = marginStart_;
1175             xMax = wrapperSize_.Width() - width - marginEnd_;
1176             yMin = marginTop_;
1177             yMax = wrapperSize_.Height() - height - marginBottom_;
1178             if (isHalfFoldHover_) {
1179                 yMin = wrapperRect_.Top();
1180                 yMax = wrapperRect_.Bottom() - height;
1181             }
1182             break;
1183         }
1184         default:
1185             break;
1186     }
1187     if ((LessNotEqual(xMax, xMin) && !isGreatWrapperWidth_) || LessNotEqual(yMax, yMin)) {
1188         if (!CheckIfNeedRemoveArrow(xMin, xMax, yMin, yMax)) {
1189             return OffsetF(0.0f, 0.0f);
1190         }
1191         TAG_LOGD(AceLogTag::ACE_OVERLAY, "Popup need remove arrow");
1192     } else if (LessNotEqual(xMax, xMin) && isGreatWrapperWidth_) {
1193         auto y = std::clamp(position.GetY(), yMin, yMax);
1194         return OffsetF(0.0f, y + yTargetOffset);
1195     }
1196     auto result = GetBubblePosition(position, xMin, xMax, yMin, yMax);
1197     CheckArrowPosition(result, width, height);
1198     return result;
1199 }
1200 
CheckIfNeedRemoveArrow(float & xMin,float & xMax,float & yMin,float & yMax)1201 bool BubbleLayoutAlgorithm::CheckIfNeedRemoveArrow(float& xMin, float& xMax, float& yMin, float& yMax)
1202 {
1203     if (!showArrow_ || !avoidKeyboard_) {
1204         return false;
1205     }
1206     bool isHorizontal = false;
1207     if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
1208         isHorizontal = true;
1209     }
1210     if ((isHorizontal && LessNotEqual(yMax, yMin)) || (!isHorizontal && LessNotEqual(xMax, xMin))) {
1211         return false;
1212     }
1213     if (isHorizontal && GreatOrEqual(xMax + BUBBLE_ARROW_HEIGHT.ConvertToPx(), xMin)) {
1214         xMax += BUBBLE_ARROW_HEIGHT.ConvertToPx();
1215         showArrow_ = false;
1216         return true;
1217     }
1218     if (!isHorizontal && GreatOrEqual(yMax + BUBBLE_ARROW_HEIGHT.ConvertToPx(), yMin)) {
1219         yMax += BUBBLE_ARROW_HEIGHT.ConvertToPx();
1220         showArrow_ = false;
1221         return true;
1222     }
1223     return false;
1224 }
1225 
GetBubblePosition(const OffsetF & position,float xMin,float xMax,float yMin,float yMax)1226 OffsetF BubbleLayoutAlgorithm::GetBubblePosition(const OffsetF& position, float xMin,
1227     float xMax, float yMin, float yMax)
1228 {
1229     auto x = std::clamp(position.GetX(), xMin, xMax);
1230     auto y = std::clamp(position.GetY(), yMin, yMax);
1231     if (!showArrow_ || !avoidKeyboard_) {
1232         return OffsetF(x, y);
1233     }
1234     bool isHorizontal = false;
1235     if (setHorizontal_.find(placement_) != setHorizontal_.end()) {
1236         isHorizontal = true;
1237     }
1238     if (isHorizontal) {
1239         if (GreatNotEqual(position.GetX(), xMax)) {
1240             showArrow_ = false;
1241             x += BUBBLE_ARROW_HEIGHT.ConvertToPx();
1242         } else if (LessNotEqual(position.GetX(), xMin)) {
1243             showArrow_ = false;
1244         }
1245     } else {
1246         if (GreatNotEqual(position.GetY(), yMax)) {
1247             showArrow_ = false;
1248             y += BUBBLE_ARROW_HEIGHT.ConvertToPx();
1249         } else if (LessNotEqual(position.GetY(), yMin)) {
1250             showArrow_ = false;
1251         }
1252     }
1253     return OffsetF(x, y);
1254 }
1255 
GetSimplePlacement(Placement & placement)1256 Placement GetSimplePlacement(Placement& placement)
1257 {
1258     switch (placement) {
1259         case Placement::LEFT_TOP:
1260         case Placement::LEFT_BOTTOM:
1261         case Placement::LEFT: {
1262             return Placement::LEFT;
1263         }
1264         case Placement::RIGHT_TOP:
1265         case Placement::RIGHT_BOTTOM:
1266         case Placement::RIGHT: {
1267             return Placement::RIGHT;
1268         }
1269         case Placement::TOP_LEFT:
1270         case Placement::TOP_RIGHT:
1271         case Placement::TOP: {
1272             return Placement::TOP;
1273         }
1274         case Placement::BOTTOM_LEFT:
1275         case Placement::BOTTOM_RIGHT:
1276         case Placement::BOTTOM: {
1277             return Placement::BOTTOM;
1278         }
1279         default:
1280             return Placement::NONE;
1281     }
1282 }
1283 
CheckArrowPosition(OffsetF & position,float width,float height)1284 void BubbleLayoutAlgorithm::CheckArrowPosition(OffsetF& position, float width, float height)
1285 {
1286     if (!showArrow_ || !avoidKeyboard_) {
1287         return;
1288     }
1289     float xMax = 0.0f;
1290     float yMax = 0.0f;
1291     float xMin = 1.0f;
1292     float yMin = 1.0f;
1293     float cornerDistance = borderRadius_.ConvertToPx() + BUBBLE_ARROW_WIDTH.ConvertToPx() / DOUBLE;
1294     auto simplePlacement = GetSimplePlacement(placement_);
1295     if (simplePlacement == Placement::LEFT) {
1296         yMin = position.GetY() + cornerDistance;
1297         yMax = position.GetY() + height - cornerDistance;
1298         if (GreatNotEqual(yMin, targetOffset_.GetY() + targetSize_.Height()) ||
1299             LessNotEqual(yMax, targetOffset_.GetY())) {
1300             showArrow_ = false;
1301             position.SetX(position.GetX() + BUBBLE_ARROW_HEIGHT.ConvertToPx());
1302         }
1303     } else if (simplePlacement == Placement::RIGHT) {
1304         yMin = position.GetY() + cornerDistance;
1305         yMax = position.GetY() + height - cornerDistance;
1306         if (GreatNotEqual(yMin, targetOffset_.GetY() + targetSize_.Height()) ||
1307             LessNotEqual(yMax, targetOffset_.GetY())) {
1308             showArrow_ = false;
1309             position.SetX(position.GetX() - BUBBLE_ARROW_HEIGHT.ConvertToPx());
1310         }
1311     } else if (simplePlacement == Placement::TOP) {
1312         xMin = position.GetX() + cornerDistance;
1313         xMax = position.GetX() + width - cornerDistance;
1314         if (GreatNotEqual(xMin, targetOffset_.GetX() + targetSize_.Width()) ||
1315             LessNotEqual(xMax, targetOffset_.GetX())) {
1316             showArrow_ = false;
1317             position.SetY(position.GetY() + BUBBLE_ARROW_HEIGHT.ConvertToPx());
1318         }
1319     } else if (simplePlacement == Placement::BOTTOM) {
1320         xMin = position.GetX() + cornerDistance;
1321         xMax = position.GetX() + width - cornerDistance;
1322         if (GreatNotEqual(xMin, targetOffset_.GetX() + targetSize_.Width()) ||
1323             LessNotEqual(xMax, targetOffset_.GetX())) {
1324             showArrow_ = false;
1325             position.SetY(position.GetY() - BUBBLE_ARROW_HEIGHT.ConvertToPx());
1326         }
1327     }
1328 }
1329 
GetPositionWithPlacementNew(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1330 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementNew(
1331     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1332 {
1333     OffsetF childPosition;
1334     auto func = placementFuncMap_.find(placement_);
1335     if (func != placementFuncMap_.end()) {
1336         auto placementFunc = func->second;
1337         if (placementFunc != nullptr) {
1338             childPosition = (this->*placementFunc)(childSize, topPosition, bottomPosition, arrowPosition);
1339         }
1340     }
1341     return childPosition;
1342 }
1343 
FitToScreenNew(const OffsetF & position,size_t step,size_t & i,const SizeF & childSize,bool didNeedArrow)1344 OffsetF BubbleLayoutAlgorithm::FitToScreenNew(
1345     const OffsetF& position, size_t step, size_t& i, const SizeF& childSize, bool didNeedArrow)
1346 {
1347     if (!CheckPosition(position, childSize, step, i)) {
1348         return OffsetF(0.0f, 0.0f);
1349     }
1350     return position;
1351 }
1352 
AddTargetSpace(const OffsetF & position)1353 OffsetF BubbleLayoutAlgorithm::AddTargetSpace(const OffsetF& position)
1354 {
1355     auto x = position.GetX();
1356     auto y = position.GetY();
1357     switch (placement_) {
1358         case Placement::BOTTOM_LEFT:
1359         case Placement::BOTTOM_RIGHT:
1360         case Placement::BOTTOM: {
1361             y += targetSpace_.ConvertToPx();
1362             break;
1363         }
1364         case Placement::TOP_LEFT:
1365         case Placement::TOP_RIGHT:
1366         case Placement::TOP: {
1367             y -= targetSpace_.ConvertToPx();
1368             break;
1369         }
1370         case Placement::RIGHT_TOP:
1371         case Placement::RIGHT_BOTTOM:
1372         case Placement::RIGHT: {
1373             x += targetSpace_.ConvertToPx();
1374             break;
1375         }
1376         case Placement::LEFT_TOP:
1377         case Placement::LEFT_BOTTOM:
1378         case Placement::LEFT: {
1379             x -= targetSpace_.ConvertToPx();
1380             break;
1381         }
1382         default: {
1383             y += targetSpace_.ConvertToPx();
1384             break;
1385         }
1386     }
1387     return OffsetF(x, y);
1388 }
1389 
AddOffset(const OffsetF & position)1390 OffsetF BubbleLayoutAlgorithm::AddOffset(const OffsetF& position)
1391 {
1392     auto x = position.GetX();
1393     auto y = position.GetY();
1394     x += positionOffset_.GetX();
1395     y += positionOffset_.GetY();
1396     return OffsetF(x, y);
1397 }
1398 
UpdateChildPosition(OffsetF & childOffset)1399 void BubbleLayoutAlgorithm::UpdateChildPosition(OffsetF& childOffset)
1400 {
1401     double arrowWidth = BUBBLE_ARROW_WIDTH.ConvertToPx();
1402     double twoRadiusPx = borderRadius_.ConvertToPx() * 2.0;
1403     float movingDistance = BUBBLE_ARROW_HEIGHT.ConvertToPx();
1404     switch (placement_) {
1405         case Placement::TOP:
1406         case Placement::TOP_LEFT:
1407         case Placement::TOP_RIGHT:
1408             showArrow_ = GreatOrEqual(childSize_.Width() - twoRadiusPx, arrowWidth);
1409             if (!showArrow_ || !enableArrow_) {
1410                 childOffset += OffsetF(0.0, movingDistance);
1411             }
1412             break;
1413         case Placement::BOTTOM:
1414         case Placement::BOTTOM_LEFT:
1415         case Placement::BOTTOM_RIGHT:
1416             showArrow_ = GreatOrEqual(childSize_.Width() - twoRadiusPx, arrowWidth);
1417             if (!showArrow_ || !enableArrow_) {
1418                 childOffset += OffsetF(0.0, -(movingDistance));
1419             }
1420             break;
1421         case Placement::LEFT:
1422         case Placement::LEFT_TOP:
1423         case Placement::LEFT_BOTTOM:
1424             showArrow_ = GreatOrEqual(childSize_.Height() - twoRadiusPx, arrowWidth);
1425             if (!showArrow_ || !enableArrow_) {
1426                 childOffset += OffsetF(movingDistance, 0.0);
1427             }
1428             break;
1429         case Placement::RIGHT:
1430         case Placement::RIGHT_TOP:
1431         case Placement::RIGHT_BOTTOM:
1432             showArrow_ = GreatOrEqual(childSize_.Height() - twoRadiusPx, arrowWidth);
1433             if (!showArrow_ || !enableArrow_) {
1434                 childOffset += OffsetF(-(movingDistance), 0.0);
1435             }
1436             break;
1437         default:
1438             break;
1439     }
1440     if (!enableArrow_) {
1441         showArrow_ = false;
1442     }
1443 }
1444 
UpdateTouchRegion()1445 void BubbleLayoutAlgorithm::UpdateTouchRegion()
1446 {
1447     OffsetF topLeft = childOffset_;
1448     OffsetF bottomRight = OffsetF(childSize_.Width(), childSize_.Height());
1449     switch (arrowPlacement_) {
1450         case Placement::TOP:
1451         case Placement::TOP_LEFT:
1452         case Placement::TOP_RIGHT:
1453             if (showArrow_) {
1454                 bottomRight += OffsetF(0.0, BUBBLE_ARROW_HEIGHT.ConvertToPx());
1455             }
1456             break;
1457         case Placement::BOTTOM:
1458         case Placement::BOTTOM_LEFT:
1459         case Placement::BOTTOM_RIGHT:
1460             if (showArrow_) {
1461                 topLeft += OffsetF(0.0, -BUBBLE_ARROW_HEIGHT.ConvertToPx());
1462                 bottomRight += OffsetF(0.0, BUBBLE_ARROW_HEIGHT.ConvertToPx());
1463             }
1464             break;
1465         case Placement::LEFT:
1466         case Placement::LEFT_TOP:
1467         case Placement::LEFT_BOTTOM:
1468             if (showArrow_) {
1469                 bottomRight += OffsetF(BUBBLE_ARROW_HEIGHT.ConvertToPx(), 0.0);
1470             }
1471             break;
1472         case Placement::RIGHT:
1473         case Placement::RIGHT_TOP:
1474         case Placement::RIGHT_BOTTOM:
1475             if (showArrow_) {
1476                 topLeft += OffsetF(-BUBBLE_ARROW_HEIGHT.ConvertToPx(), 0.0);
1477                 bottomRight += OffsetF(BUBBLE_ARROW_HEIGHT.ConvertToPx(), 0.0);
1478             }
1479             break;
1480         default:
1481             break;
1482     }
1483     touchRegion_ = RectF(topLeft, topLeft + bottomRight);
1484     dumpInfo_.touchRegion = touchRegion_;
1485 }
1486 
InitCaretTargetSizeAndPosition()1487 void BubbleLayoutAlgorithm::InitCaretTargetSizeAndPosition()
1488 {
1489     static std::vector<std::string> TEXT_STATES = { V2::TEXTAREA_ETS_TAG, V2::TEXTINPUT_ETS_TAG,
1490         V2::RICH_EDITOR_ETS_TAG, V2::SEARCH_ETS_TAG };
1491     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
1492     CHECK_NULL_VOID(targetNode);
1493     auto it = std::find(TEXT_STATES.begin(), TEXT_STATES.end(), targetTag_);
1494     bCaretMode_ = false;
1495     CaretMetricsF caretMetrics;
1496     if (it != TEXT_STATES.end()) {
1497         bCaretMode_ = true;
1498         positionOffset_ = OffsetF(0.0f, 0.0f);
1499         if ((placement_ != Placement::BOTTOM) && (placement_ != Placement::TOP)) {
1500             placement_ = Placement::BOTTOM;
1501         }
1502         GetTextCaretMetrics<TextBase>(targetNode, caretMetrics);
1503         targetOffset_ = caretMetrics.offset;
1504         targetSize_.SetHeight(caretMetrics.height);
1505         targetSize_.SetWidth(0.0f);
1506     }
1507 }
1508 
InitTargetSizeAndPosition(bool showInSubWindow,LayoutWrapper * layoutWrapper)1509 void BubbleLayoutAlgorithm::InitTargetSizeAndPosition(bool showInSubWindow, LayoutWrapper* layoutWrapper)
1510 {
1511     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
1512     CHECK_NULL_VOID(targetNode);
1513     if (!targetNode->IsOnMainTree() && !targetNode->IsVisible()) {
1514         return;
1515     }
1516     if (followTransformOfTarget_) {
1517         auto rect = targetNode->GetPaintRectToWindowWithTransform();
1518         targetSize_ = rect.GetSize();
1519         targetOffset_ = rect.GetOffset();
1520     } else {
1521         auto geometryNode = targetNode->GetGeometryNode();
1522         CHECK_NULL_VOID(geometryNode);
1523         targetSize_ = geometryNode->GetFrameSize();
1524         targetOffset_ = targetNode->GetPaintRectOffset();
1525     }
1526 
1527     auto expandDisplay = SubwindowManager::GetInstance()->GetIsExpandDisplay();
1528     auto pipelineContext = expandDisplay ? targetNode->GetContextRefPtr() : GetMainPipelineContext(layoutWrapper);
1529     CHECK_NULL_VOID(pipelineContext);
1530 
1531     TAG_LOGD(AceLogTag::ACE_OVERLAY, "popup targetOffset_: %{public}s, targetSize_: %{public}s",
1532         targetOffset_.ToString().c_str(), targetSize_.ToString().c_str());
1533     // Show in SubWindow
1534     if (showInSubWindow) {
1535         auto displayWindowOffset = OffsetF(pipelineContext->GetDisplayWindowRectInfo().GetOffset().GetX(),
1536             pipelineContext->GetDisplayWindowRectInfo().GetOffset().GetY());
1537         targetOffset_ += displayWindowOffset;
1538         auto currentSubwindow = SubwindowManager::GetInstance()->GetCurrentWindow();
1539         if (currentSubwindow) {
1540             auto subwindowRect = currentSubwindow->GetRect();
1541             targetOffset_ -= subwindowRect.GetOffset();
1542         }
1543     }
1544     dumpInfo_.targetOffset = targetOffset_;
1545     dumpInfo_.targetSize = targetSize_;
1546 }
1547 
CheckPositionInPlacementRect(const Rect & rect,const OffsetF & position,const SizeF & childSize)1548 bool BubbleLayoutAlgorithm::CheckPositionInPlacementRect(
1549     const Rect& rect, const OffsetF& position, const SizeF& childSize)
1550 {
1551     auto x = position.GetX();
1552     auto y = position.GetY();
1553     if (LessNotEqual(x, rect.Left()) || GreatNotEqual(x + childSize.Width(), rect.Right()) ||
1554         LessNotEqual(y, rect.Top()) || GreatNotEqual(y + childSize.Height(), rect.Bottom())) {
1555         return false;
1556     }
1557     return true;
1558 }
1559 
CheckPosition(const OffsetF & position,const SizeF & childSize,size_t step,size_t & i)1560 bool BubbleLayoutAlgorithm::CheckPosition(const OffsetF& position, const SizeF& childSize, size_t step, size_t& i)
1561 {
1562     float targetOffsetX = targetOffset_.GetX();
1563     float targetOffsetY = targetOffset_.GetY();
1564     Rect rect;
1565     switch (placement_) {
1566         case Placement::BOTTOM_LEFT:
1567         case Placement::BOTTOM_RIGHT:
1568         case Placement::BOTTOM: {
1569             targetOffsetY += (userSetTargetSpace_.ConvertToPx());
1570             auto y = std::max(targetOffsetY + targetSize_.Height(), marginTop_);
1571             auto height = std::min(wrapperSize_.Height() - marginBottom_ - targetOffsetY - targetSize_.Height(),
1572                 wrapperSize_.Height() - marginBottom_ - marginTop_);
1573             rect.SetRect(marginStart_, y, wrapperSize_.Width() - marginEnd_ - marginStart_, height);
1574             if (isHalfFoldHover_) {
1575                 y = std::max(targetOffsetY + targetSize_.Height(), static_cast<float>(wrapperRect_.Top()));
1576                 height = std::min(static_cast<float>(wrapperRect_.Bottom()) - targetOffsetY - targetSize_.Height(),
1577                     wrapperSize_.Height() - marginBottom_ - marginTop_);
1578                 rect.SetRect(marginStart_, y, wrapperSize_.Width() - marginEnd_ - marginStart_, height);
1579             }
1580             if (childSize.Height() > height) {
1581                 i += step;
1582                 return false;
1583             } else {
1584                 bVertical_ = true;
1585             }
1586             break;
1587         }
1588         case Placement::TOP_LEFT:
1589         case Placement::TOP_RIGHT:
1590         case Placement::TOP: {
1591             targetOffsetY += (-userSetTargetSpace_.ConvertToPx());
1592             auto height = std::min(targetOffsetY - marginTop_, wrapperSize_.Height() - marginTop_ - marginBottom_);
1593             rect.SetRect(marginStart_, marginTop_, wrapperSize_.Width() - marginEnd_ - marginStart_, height);
1594             if (isHalfFoldHover_) {
1595                 height = std::min(targetOffsetY - static_cast<float>(wrapperRect_.Top()),
1596                     wrapperSize_.Height() - marginTop_ - marginBottom_);
1597                 rect.SetRect(marginStart_, wrapperRect_.Top(),
1598                     wrapperSize_.Width() - marginEnd_ - marginStart_, height);
1599             }
1600             if (childSize.Height() > height) {
1601                 i += step;
1602                 return false;
1603             } else {
1604                 bVertical_ = true;
1605             }
1606             break;
1607         }
1608         case Placement::RIGHT_TOP:
1609         case Placement::RIGHT_BOTTOM:
1610         case Placement::RIGHT: {
1611             targetOffsetX += (userSetTargetSpace_.ConvertToPx());
1612             auto x = std::max(targetOffsetX + targetSize_.Width(), marginStart_);
1613             auto width = std::min(wrapperSize_.Width() - targetOffsetX - targetSize_.Width() - marginEnd_,
1614                 wrapperSize_.Width() - marginStart_ - marginEnd_);
1615             rect.SetRect(x, marginTop_, width, wrapperSize_.Height() - marginBottom_ - marginTop_);
1616             if (isHalfFoldHover_) {
1617                 rect.SetRect(x, wrapperRect_.Top(), width, wrapperRect_.Height());
1618             }
1619             if (childSize.Width() > width) {
1620                 i += step;
1621                 return false;
1622             } else {
1623                 bHorizontal_ = true;
1624             }
1625             break;
1626         }
1627         case Placement::LEFT_TOP:
1628         case Placement::LEFT_BOTTOM:
1629         case Placement::LEFT: {
1630             targetOffsetX += (-userSetTargetSpace_.ConvertToPx());
1631             auto width = std::min(targetOffsetX - marginStart_, wrapperSize_.Width() - marginEnd_ - marginStart_);
1632             rect.SetRect(marginStart_, marginTop_, width, wrapperSize_.Height() - marginBottom_ - marginTop_);
1633             if (isHalfFoldHover_) {
1634                 rect.SetRect(marginStart_, wrapperRect_.Top(), width, wrapperRect_.Height());
1635             }
1636             if (childSize.Width() > width) {
1637                 i += step;
1638                 return false;
1639             } else {
1640                 bHorizontal_ = true;
1641             }
1642             break;
1643         }
1644         default:
1645             return false;
1646     }
1647     i++;
1648     return CheckPositionInPlacementRect(rect, position, childSize);
1649 }
1650 
GetPositionWithPlacementTop(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1651 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementTop(
1652     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1653 {
1654     float bubbleSpacing = scaledBubbleSpacing_;
1655     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1656     float radius = borderRadius_.ConvertToPx();
1657     arrowPosition = topPosition + OffsetF(radius + arrowHalfWidth, childSize.Height() + bubbleSpacing);
1658     if (bCaretMode_) {
1659         arrowPosition = OffsetF(targetOffset_.GetX(), targetOffset_.GetY() - bubbleSpacing);
1660     }
1661     return topPosition;
1662 }
1663 
GetPositionWithPlacementTopLeft(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1664 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementTopLeft(
1665     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1666 {
1667     OffsetF childPosition;
1668     float marginRight = 0.0f;
1669     float marginBottom = 0.0f;
1670     float bubbleSpacing = scaledBubbleSpacing_;
1671     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1672     float radius = borderRadius_.ConvertToPx();
1673     childPosition = OffsetF(targetOffset_.GetX() - marginRight,
1674         targetOffset_.GetY() - childSize.Height() - bubbleSpacing - marginBottom - targetSpace_.ConvertToPx());
1675     arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, childSize.Height() + bubbleSpacing);
1676     return childPosition;
1677 }
1678 
GetPositionWithPlacementTopRight(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1679 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementTopRight(
1680     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1681 {
1682     OffsetF childPosition;
1683     float marginBottom = 0.0f;
1684     float marginLeft = 0.0f;
1685     float bubbleSpacing = scaledBubbleSpacing_;
1686     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1687     float radius = borderRadius_.ConvertToPx();
1688     childPosition = OffsetF(targetOffset_.GetX() + targetSize_.Width() - childSize.Width() + marginLeft,
1689         targetOffset_.GetY() - childSize.Height() - targetSpace_.ConvertToPx() - bubbleSpacing - marginBottom);
1690     arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, childSize.Height() + bubbleSpacing);
1691     return childPosition;
1692 }
1693 
GetPositionWithPlacementBottom(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1694 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementBottom(
1695     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1696 {
1697     float bubbleSpacing = scaledBubbleSpacing_;
1698     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1699     float radius = borderRadius_.ConvertToPx();
1700     arrowPosition = bottomPosition + OffsetF(radius + arrowHalfWidth, -bubbleSpacing);
1701     if (bCaretMode_) {
1702         arrowPosition = OffsetF(targetOffset_.GetX(), targetOffset_.GetY() + targetSize_.Height() + bubbleSpacing);
1703     }
1704     return bottomPosition;
1705 }
1706 
GetPositionWithPlacementBottomLeft(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1707 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementBottomLeft(
1708     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1709 {
1710     OffsetF childPosition;
1711     float marginRight = 0.0f;
1712     float marginTop = 0.0f;
1713     float bubbleSpacing = scaledBubbleSpacing_;
1714     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1715     float radius = borderRadius_.ConvertToPx();
1716     childPosition = OffsetF(targetOffset_.GetX() - marginRight,
1717         targetOffset_.GetY() + targetSize_.Height() + targetSpace_.ConvertToPx() + bubbleSpacing + marginTop);
1718     arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, -bubbleSpacing);
1719     return childPosition;
1720 }
1721 
GetPositionWithPlacementBottomRight(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1722 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementBottomRight(
1723     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1724 {
1725     OffsetF childPosition;
1726     float marginTop = 0.0f;
1727     float marginLeft = 0.0f;
1728     float bubbleSpacing = scaledBubbleSpacing_;
1729     float radius = borderRadius_.ConvertToPx();
1730     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1731     childPosition = OffsetF(targetOffset_.GetX() + targetSize_.Width() - childSize.Width() + marginLeft,
1732         targetOffset_.GetY() + targetSize_.Height() + targetSpace_.ConvertToPx() + bubbleSpacing + marginTop);
1733     arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, -bubbleSpacing);
1734     return childPosition;
1735 }
1736 
GetPositionWithPlacementLeft(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1737 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementLeft(
1738     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1739 {
1740     OffsetF childPosition;
1741     float marginRight = 0.0f;
1742     float bubbleSpacing = scaledBubbleSpacing_;
1743     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1744     float radius = borderRadius_.ConvertToPx();
1745     childPosition =
1746         OffsetF(targetOffset_.GetX() - targetSpace_.ConvertToPx() - bubbleSpacing - childSize.Width() - marginRight,
1747             targetOffset_.GetY() + targetSize_.Height() / 2.0 - childSize.Height() / 2.0);
1748     arrowPosition = childPosition + OffsetF(childSize_.Width() + bubbleSpacing, radius + arrowHalfWidth);
1749     return childPosition;
1750 }
1751 
GetPositionWithPlacementLeftTop(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1752 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementLeftTop(
1753     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1754 {
1755     OffsetF childPosition;
1756     float marginRight = 0.0f;
1757     float marginBottom = 0.0f;
1758     float bubbleSpacing = scaledBubbleSpacing_;
1759     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1760     float radius = borderRadius_.ConvertToPx();
1761     childPosition =
1762         OffsetF(targetOffset_.GetX() - targetSpace_.ConvertToPx() - bubbleSpacing - childSize.Width() - marginRight,
1763             targetOffset_.GetY() - marginBottom);
1764     arrowPosition = childPosition + OffsetF(childSize_.Width() + bubbleSpacing, radius + arrowHalfWidth);
1765     return childPosition;
1766 }
1767 
GetPositionWithPlacementLeftBottom(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1768 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementLeftBottom(
1769     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1770 {
1771     OffsetF childPosition;
1772     float marginRight = 0.0f;
1773     float marginTop = 0.0f;
1774     float bubbleSpacing = scaledBubbleSpacing_;
1775     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1776     float radius = borderRadius_.ConvertToPx();
1777     childPosition =
1778         OffsetF(targetOffset_.GetX() - targetSpace_.ConvertToPx() - bubbleSpacing - childSize.Width() - marginRight,
1779             targetOffset_.GetY() + targetSize_.Height() - childSize.Height() - marginTop);
1780     arrowPosition = childPosition + OffsetF(childSize_.Width() + bubbleSpacing, radius + arrowHalfWidth);
1781     return childPosition;
1782 }
1783 
GetPositionWithPlacementRight(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1784 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementRight(
1785     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1786 {
1787     OffsetF childPosition;
1788     float marginLeft = 0.0f;
1789     float bubbleSpacing = scaledBubbleSpacing_;
1790     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1791     float radius = borderRadius_.ConvertToPx();
1792     childPosition =
1793         OffsetF(targetOffset_.GetX() + targetSize_.Width() + targetSpace_.ConvertToPx() + bubbleSpacing + marginLeft,
1794             targetOffset_.GetY() + targetSize_.Height() / 2.0 - childSize.Height() / 2.0);
1795     arrowPosition = childPosition + OffsetF(-bubbleSpacing, radius + arrowHalfWidth);
1796     return childPosition;
1797 }
1798 
GetPositionWithPlacementRightTop(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1799 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementRightTop(
1800     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1801 {
1802     OffsetF childPosition;
1803     float marginBottom = 0.0f;
1804     float marginLeft = 0.0f;
1805     float bubbleSpacing = scaledBubbleSpacing_;
1806     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1807     float radius = borderRadius_.ConvertToPx();
1808     childPosition =
1809         OffsetF(targetOffset_.GetX() + targetSize_.Width() + targetSpace_.ConvertToPx() + bubbleSpacing + marginLeft,
1810             targetOffset_.GetY() - marginBottom);
1811     arrowPosition = childPosition + OffsetF(-bubbleSpacing, radius + arrowHalfWidth);
1812     return childPosition;
1813 }
1814 
GetPositionWithPlacementRightBottom(const SizeF & childSize,const OffsetF & topPosition,const OffsetF & bottomPosition,OffsetF & arrowPosition)1815 OffsetF BubbleLayoutAlgorithm::GetPositionWithPlacementRightBottom(
1816     const SizeF& childSize, const OffsetF& topPosition, const OffsetF& bottomPosition, OffsetF& arrowPosition)
1817 {
1818     OffsetF childPosition;
1819     float marginTop = 0.0f;
1820     float marginLeft = 0.0f;
1821     float bubbleSpacing = scaledBubbleSpacing_;
1822     float arrowHalfWidth = BUBBLE_ARROW_WIDTH.ConvertToPx() / BUBBLE_ARROW_HALF;
1823     float radius = borderRadius_.ConvertToPx();
1824     childPosition =
1825         OffsetF(targetOffset_.GetX() + targetSize_.Width() + targetSpace_.ConvertToPx() + bubbleSpacing + marginLeft,
1826             targetOffset_.GetY() + targetSize_.Height() - childSize.Height() - marginTop);
1827     arrowPosition = childPosition + OffsetF(-bubbleSpacing, radius + arrowHalfWidth);
1828     return childPosition;
1829 }
1830 
MoveTo(double x,double y)1831 std::string BubbleLayoutAlgorithm::MoveTo(double x, double y)
1832 {
1833     return "M" + std::to_string(x) + " " + std::to_string(y) + " ";
1834 }
1835 
LineTo(double x,double y)1836 std::string BubbleLayoutAlgorithm::LineTo(double x, double y)
1837 {
1838     return "L" + std::to_string(x) + " " + std::to_string(y) + " ";
1839 }
1840 
ArcTo(double rx,double ry,double rotation,int32_t arc_flag,double x,double y)1841 std::string BubbleLayoutAlgorithm::ArcTo(double rx, double ry, double rotation, int32_t arc_flag, double x, double y)
1842 {
1843     int32_t sweep_flag = 1;
1844     return "A" + std::to_string(rx) + " " + std::to_string(ry) + " " + std::to_string(rotation) + " " +
1845            std::to_string(arc_flag) + " " + std::to_string(sweep_flag) + " " + std::to_string(x) + " " +
1846            std::to_string(y) + " ";
1847 }
1848 
UpdateClipOffset(const RefPtr<FrameNode> & frameNode)1849 void BubbleLayoutAlgorithm::UpdateClipOffset(const RefPtr<FrameNode>& frameNode)
1850 {
1851     auto paintProperty = frameNode->GetPaintProperty<BubbleRenderProperty>();
1852     auto childNode = AceType::DynamicCast<FrameNode>(frameNode->GetFirstChild());
1853     if (!bCaretMode_) {
1854         arrowPosition_ =
1855             OffsetF(BUBBLE_ARROW_HEIGHT.ConvertToPx() * DOUBLE, BUBBLE_ARROW_HEIGHT.ConvertToPx() * DOUBLE);
1856         UpdateArrowOffset(paintProperty->GetArrowOffset(), arrowPlacement_);
1857     } else {
1858         arrowPosition_ = arrowPosition_ - childOffset_ + OffsetF(BUBBLE_ARROW_HEIGHT.ConvertToPx(), 0.0f);
1859     }
1860     targetOffset_ = targetOffset_ - childOffset_;
1861     childOffset_ = OffsetF(BUBBLE_ARROW_HEIGHT.ConvertToPx(), BUBBLE_ARROW_HEIGHT.ConvertToPx());
1862     clipFrameNode_ = childNode;
1863     clipPath_.clear();
1864     clipPath_ = ClipBubbleWithPath();
1865 }
1866 
ClipBubbleWithPath()1867 std::string BubbleLayoutAlgorithm::ClipBubbleWithPath()
1868 {
1869     std::string path;
1870     float arrowOffset = 0.0;
1871     if (!bCaretMode_) {
1872         arrowOffset = GetArrowOffset(arrowPlacement_);
1873     }
1874     float radiusPx = borderRadius_.ConvertToPx();
1875     Placement arrowBuildplacement = Placement::NONE;
1876     if (enableArrow_ && showArrow_) {
1877         GetArrowBuildPlacement(arrowBuildplacement);
1878         arrowBuildPlacement_ = arrowBuildplacement;
1879     }
1880     if ((arrowBuildplacement == Placement::TOP_LEFT) || (arrowBuildplacement == Placement::LEFT_TOP)) {
1881         path += MoveTo(childOffset_.GetX(), childOffset_.GetY());
1882     } else {
1883         path += MoveTo(childOffset_.GetX() + radiusPx, childOffset_.GetY());
1884     }
1885     path += BuildTopLinePath(arrowOffset, radiusPx, arrowBuildplacement);
1886     if ((arrowBuildplacement != Placement::TOP_RIGHT) && (arrowBuildplacement != Placement::RIGHT_TOP)) {
1887         path += BuildCornerPath(Placement::TOP_RIGHT, radiusPx);
1888     }
1889     path += BuildRightLinePath(arrowOffset, radiusPx, arrowBuildplacement);
1890     if ((arrowBuildplacement != Placement::RIGHT_BOTTOM) && (arrowBuildplacement != Placement::BOTTOM_RIGHT)) {
1891         path += BuildCornerPath(Placement::BOTTOM_RIGHT, radiusPx);
1892     }
1893     path += BuildBottomLinePath(arrowOffset, radiusPx, arrowBuildplacement);
1894     if ((arrowBuildplacement != Placement::BOTTOM_LEFT) && (arrowBuildplacement != Placement::LEFT_BOTTOM)) {
1895         path += BuildCornerPath(Placement::BOTTOM_LEFT, radiusPx);
1896     }
1897     path += BuildLeftLinePath(arrowOffset, radiusPx, arrowBuildplacement);
1898     if ((arrowBuildplacement != Placement::LEFT_TOP) && (arrowBuildplacement != Placement::TOP_LEFT)) {
1899         path += BuildCornerPath(Placement::TOP_LEFT, radiusPx);
1900     }
1901     return path + "Z";
1902 }
1903 
GetArrowOffset(const Placement & placement)1904 float BubbleLayoutAlgorithm::GetArrowOffset(const Placement& placement)
1905 {
1906     Edge edge;
1907     double arrowOffset;
1908     double maxMotionRange = 0.0;
1909     double minMotionRange = 0.0;
1910     double targetOffsetXOrY = 0.0;
1911     double childOffsetsetXOrY = 0.0;
1912     double childSizeWidthOrHeight = 0.0;
1913     double targetSizeWidthOrHeight = 0.0;
1914     bool bHorizontal = false;
1915 
1916     InitEdgeSize(edge);
1917     switch (placement) {
1918         case Placement::TOP:
1919         case Placement::TOP_LEFT:
1920         case Placement::TOP_RIGHT:
1921             bHorizontal = true;
1922             break;
1923         case Placement::BOTTOM:
1924         case Placement::BOTTOM_LEFT:
1925         case Placement::BOTTOM_RIGHT:
1926             bHorizontal = true;
1927             break;
1928         case Placement::LEFT:
1929         case Placement::LEFT_TOP:
1930         case Placement::LEFT_BOTTOM:
1931             break;
1932         case Placement::RIGHT:
1933         case Placement::RIGHT_TOP:
1934         case Placement::RIGHT_BOTTOM:
1935             break;
1936         default:
1937             break;
1938     }
1939     if (bHorizontal) {
1940         targetOffsetXOrY = targetOffset_.GetX();
1941         targetSizeWidthOrHeight = targetSize_.Width();
1942         childOffsetsetXOrY = childOffset_.GetX();
1943         childSizeWidthOrHeight = childSize_.Width();
1944     } else {
1945         targetOffsetXOrY = targetOffset_.GetY();
1946         targetSizeWidthOrHeight = targetSize_.Height();
1947         childOffsetsetXOrY = childOffset_.GetY();
1948         childSizeWidthOrHeight = childSize_.Height();
1949     }
1950     maxMotionRange = childSizeWidthOrHeight;
1951     if (arrowOfTargetOffset_ == ArrowOfTargetOffset::START) {
1952         arrowOffset = (targetOffsetXOrY + (arrowOffset_.Value() * targetSizeWidthOrHeight)) - childOffsetsetXOrY +
1953                       BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
1954         return arrowOffset;
1955     }
1956     if (arrowOfTargetOffset_ == ArrowOfTargetOffset::CENTER) {
1957         arrowOffset = (targetOffsetXOrY + (arrowOffset_.Value() * targetSizeWidthOrHeight)) - childOffsetsetXOrY;
1958         return arrowOffset;
1959     }
1960     if (arrowOfTargetOffset_ == ArrowOfTargetOffset::END) {
1961         arrowOffset = (targetOffsetXOrY + (arrowOffset_.Value() * targetSizeWidthOrHeight)) - childOffsetsetXOrY -
1962                       BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
1963         return arrowOffset;
1964     }
1965     return std::clamp(arrowOffset_.Unit() == DimensionUnit::PERCENT ? arrowOffset_.Value() * maxMotionRange
1966                                                                     : arrowOffset_.ConvertToPx(),
1967         minMotionRange, maxMotionRange);
1968 }
1969 
UpdateArrowOffset(const std::optional<Dimension> & offset,const Placement & placement)1970 void BubbleLayoutAlgorithm::UpdateArrowOffset(const std::optional<Dimension>& offset, const Placement& placement)
1971 {
1972     if (offset.has_value()) {
1973         arrowOffset_ = offset.value();
1974         arrowOfTargetOffset_ = ArrowOfTargetOffset::NONE;
1975         if (arrowOffset_.Unit() == DimensionUnit::PERCENT) {
1976             if (arrowOffset_.Value() == ARROW_OFFSET_START_VALUE) {
1977                 arrowOfTargetOffset_ = ArrowOfTargetOffset::START;
1978             } else if (arrowOffset_.Value() == ARROW_OFFSET_CENTER_VALUE) {
1979                 arrowOfTargetOffset_ = ArrowOfTargetOffset::CENTER;
1980             } else {
1981                 arrowOfTargetOffset_ = ArrowOfTargetOffset::END;
1982             }
1983             arrowOffset_.SetValue(std::clamp(arrowOffset_.Value(), 0.0, 1.0));
1984         }
1985         return;
1986     }
1987     arrowOfTargetOffset_ = ArrowOfTargetOffset::NONE;
1988     switch (placement) {
1989         case Placement::LEFT:
1990         case Placement::RIGHT:
1991         case Placement::TOP:
1992         case Placement::BOTTOM:
1993             arrowOffset_ = BUBBLE_ARROW_HALF_PERCENT_VALUE;
1994             arrowOfTargetOffset_ = ArrowOfTargetOffset::CENTER;
1995             break;
1996         case Placement::TOP_LEFT:
1997         case Placement::BOTTOM_LEFT:
1998         case Placement::LEFT_TOP:
1999         case Placement::RIGHT_TOP:
2000             arrowOffset_ = BUBBLE_ARROW_ZERO_PERCENT_VALUE;
2001             arrowOfTargetOffset_ = ArrowOfTargetOffset::START;
2002             break;
2003         case Placement::TOP_RIGHT:
2004         case Placement::BOTTOM_RIGHT:
2005         case Placement::LEFT_BOTTOM:
2006         case Placement::RIGHT_BOTTOM:
2007             arrowOffset_ = BUBBLE_ARROW_ONE_HUNDRED_PERCENT_VALUE;
2008             arrowOfTargetOffset_ = ArrowOfTargetOffset::END;
2009             break;
2010         default:
2011             break;
2012     }
2013 }
2014 
InitEdgeSize(Edge & edge)2015 void BubbleLayoutAlgorithm::InitEdgeSize(Edge& edge)
2016 {
2017     edge.SetTop(Dimension(std::max(padding_.Left().ConvertToPx(), border_.TopLeftRadius().GetX().ConvertToPx()) +
2018                           std::max(padding_.Right().ConvertToPx(), border_.TopRightRadius().GetX().ConvertToPx())));
2019     edge.SetBottom(
2020         Dimension(std::max(padding_.Left().ConvertToPx(), border_.BottomLeftRadius().GetX().ConvertToPx()) +
2021                   std::max(padding_.Right().ConvertToPx(), border_.BottomRightRadius().GetX().ConvertToPx())));
2022     edge.SetLeft(
2023         Dimension(std::max(padding_.Top().ConvertToPx(), border_.TopRightRadius().GetY().ConvertToPx()) +
2024                   std::max(padding_.Bottom().ConvertToPx(), border_.BottomRightRadius().GetY().ConvertToPx())));
2025     edge.SetRight(
2026         Dimension(std::max(padding_.Top().ConvertToPx(), border_.TopLeftRadius().GetY().ConvertToPx()) +
2027                   std::max(padding_.Bottom().ConvertToPx(), border_.BottomLeftRadius().GetY().ConvertToPx())));
2028 }
2029 
ModifyBorderRadius(float borderRadius,float halfChildHeight)2030 float BubbleLayoutAlgorithm::ModifyBorderRadius(float borderRadius, float halfChildHeight)
2031 {
2032     return GreatOrEqual(borderRadius, halfChildHeight) ? halfChildHeight : borderRadius;
2033 }
2034 
GetArrowBuildPlacement(Placement & arrowBuildplacement)2035 void BubbleLayoutAlgorithm::GetArrowBuildPlacement(Placement& arrowBuildplacement)
2036 {
2037     auto radius = borderRadius_.ConvertToPx();
2038     float maxOffset = 0.0;
2039     switch (arrowPlacement_) {
2040         case Placement::BOTTOM:
2041         case Placement::BOTTOM_LEFT:
2042         case Placement::BOTTOM_RIGHT: // TOP
2043             maxOffset = childOffset_.GetX() + childSize_.Width() - radius -
2044                         BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2045             if ((!bCaretMode_) && (arrowOffset_.Unit() != DimensionUnit::PERCENT)) {
2046                 if ((arrowPosition_.GetX() + arrowOffset_.ConvertToPx()) > maxOffset) {
2047                     arrowBuildplacement = Placement::TOP_RIGHT;
2048                     break;
2049                 }
2050                 if ((arrowOffset_.ConvertToPx()) < radius) {
2051                     arrowBuildplacement = Placement::TOP_LEFT;
2052                     break;
2053                 }
2054                 arrowBuildplacement = Placement::TOP;
2055             } else {
2056                 arrowBuildplacement = Placement::TOP;
2057             }
2058             break;
2059         case Placement::LEFT:
2060         case Placement::LEFT_TOP:
2061         case Placement::LEFT_BOTTOM: // Right
2062             maxOffset = childOffset_.GetY() + childSize_.Height() - radius -
2063                         BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2064             if ((!bCaretMode_) && (arrowOffset_.Unit() != DimensionUnit::PERCENT)) {
2065                 if ((arrowPosition_.GetY() + arrowOffset_.ConvertToPx()) > maxOffset) {
2066                     arrowBuildplacement = Placement::RIGHT_BOTTOM;
2067                     break;
2068                 }
2069                 if ((arrowOffset_.ConvertToPx()) < radius) {
2070                     arrowBuildplacement = Placement::RIGHT_TOP;
2071                     break;
2072                 }
2073                 arrowBuildplacement = Placement::RIGHT;
2074             } else {
2075                 arrowBuildplacement = Placement::RIGHT;
2076             }
2077             break;
2078         case Placement::TOP:
2079         case Placement::TOP_LEFT:
2080         case Placement::TOP_RIGHT: // Bottom
2081             maxOffset = childOffset_.GetX() + childSize_.Width() - radius -
2082                         BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2083             if ((!bCaretMode_) && (arrowOffset_.Unit() != DimensionUnit::PERCENT)) {
2084                 if ((arrowPosition_.GetX() + arrowOffset_.ConvertToPx()) > maxOffset) {
2085                     arrowBuildplacement = Placement::BOTTOM_RIGHT; // replace
2086                     break;
2087                 }
2088                 if ((arrowOffset_.ConvertToPx()) < radius) {
2089                     arrowBuildplacement = Placement::BOTTOM_LEFT; // replace
2090                     break;
2091                 }
2092                 arrowBuildplacement = Placement::BOTTOM; // nomal
2093             } else {
2094                 arrowBuildplacement = Placement::BOTTOM; // nomal
2095             }
2096             break;
2097         case Placement::RIGHT:
2098         case Placement::RIGHT_TOP:
2099         case Placement::RIGHT_BOTTOM: // Left
2100             maxOffset = childOffset_.GetY() + childSize_.Height() - radius -
2101                         BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2102             if ((!bCaretMode_) && (arrowOffset_.Unit() != DimensionUnit::PERCENT)) {
2103                 if ((arrowPosition_.GetY() + arrowOffset_.ConvertToPx()) > maxOffset) {
2104                     arrowBuildplacement = Placement::LEFT_BOTTOM;
2105                     break;
2106                 }
2107                 if ((arrowOffset_.ConvertToPx()) < radius) {
2108                     arrowBuildplacement = Placement::LEFT_TOP;
2109                     break;
2110                 }
2111                 arrowBuildplacement = Placement::LEFT;
2112             } else {
2113                 arrowBuildplacement = Placement::LEFT;
2114             }
2115             break;
2116         default:
2117             break;
2118     }
2119     if (arrowBuildplacement > Placement::BOTTOM) {
2120         arrowPosition_ += OffsetF(-BUBBLE_ARROW_HEIGHT.ConvertToPx(), -BUBBLE_ARROW_HEIGHT.ConvertToPx());
2121     }
2122 }
2123 
SetArrowOffsetsFromClip(const int16_t index,const float offsetX,const float offsetY)2124 void BubbleLayoutAlgorithm::SetArrowOffsetsFromClip(const int16_t index, const float offsetX, const float offsetY)
2125 {
2126     arrowOffsetsFromClip_[index] = { offsetX, offsetY };
2127 }
2128 
BuildTopLinePath(float arrowOffset,float radius,Placement & arrowBuildplacement)2129 std::string BubbleLayoutAlgorithm::BuildTopLinePath(float arrowOffset, float radius, Placement& arrowBuildplacement)
2130 {
2131     std::string path;
2132     float childOffsetY = childOffset_.GetY();
2133     auto leftOffset =
2134         childOffset_.GetX() + radius + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2135     auto rightOffset = childOffset_.GetX() + childSize_.Width() - radius -
2136                        BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2137     auto arrowTopOffset = std::clamp(
2138         arrowPosition_.GetX() + arrowOffset, static_cast<float>(leftOffset), static_cast<float>(rightOffset));
2139     switch (arrowPlacement_) {
2140         case Placement::BOTTOM:
2141         case Placement::BOTTOM_LEFT:
2142         case Placement::BOTTOM_RIGHT:
2143             if (arrowBuildplacement == Placement::TOP_RIGHT) {
2144                 path += ReplaceArrowTopRight(
2145                     arrowPosition_.GetX() + childSize_.Width() - BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF, childOffsetY);
2146             }
2147             if (arrowBuildplacement == Placement::TOP_LEFT) {
2148                 path +=
2149                     ReplaceArrowTopLeft(arrowPosition_.GetX() + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF, childOffsetY);
2150             }
2151             if (arrowBuildplacement == Placement::TOP) {
2152                 path += LineTo(arrowTopOffset - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffsetY); // P1
2153                 path += LineTo(arrowTopOffset - ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2154                     childOffsetY - ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx()); // P2
2155                 path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2156                     arrowTopOffset + ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2157                     childOffsetY - ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx());                            // P4
2158                 path += LineTo(arrowTopOffset + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffsetY); // P5
2159                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2160                     arrowTopOffset - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffsetY);
2161                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2162                     arrowTopOffset - ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2163                     childOffsetY - ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx());
2164                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2165                     arrowTopOffset + ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2166                     childOffsetY - ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx());
2167                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2168                     arrowTopOffset + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffsetY);
2169             }
2170             break;
2171         default:
2172             break;
2173     }
2174     if (arrowBuildplacement != Placement::TOP_RIGHT) {
2175         path += LineTo(childOffset_.GetX() + childSize_.Width() - radius, childOffsetY);
2176     }
2177     return path;
2178 }
2179 
BuildRightLinePath(float arrowOffset,float radius,Placement & arrowBuildplacement)2180 std::string BubbleLayoutAlgorithm::BuildRightLinePath(float arrowOffset, float radius, Placement& arrowBuildplacement)
2181 {
2182     std::string path;
2183     float childOffsetY = childOffset_.GetY();
2184     auto topOffset = childOffset_.GetY() + radius + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2185     auto bottomOffset = childOffset_.GetY() + childSize_.Height() - radius - BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2186     auto arrowRightOffset = std::clamp(
2187         arrowPosition_.GetY() + arrowOffset, static_cast<float>(topOffset), static_cast<float>(bottomOffset));
2188     switch (arrowPlacement_) {
2189         case Placement::LEFT:
2190         case Placement::LEFT_TOP:
2191         case Placement::LEFT_BOTTOM:
2192             if (arrowBuildplacement == Placement::RIGHT_BOTTOM) {
2193                 path += ReplaceArrowRightBottom(arrowPosition_.GetY() + childSize_.Height()
2194                     - BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF, childOffset_.GetX() + childSize_.Width());
2195             }
2196             if (arrowBuildplacement == Placement::RIGHT_TOP) {
2197                 path += ReplaceArrowRightTop(arrowPosition_.GetY() + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF,
2198                     childOffset_.GetX() + childSize_.Width());
2199             }
2200             if (arrowBuildplacement == Placement::RIGHT) {
2201                 path += LineTo(childOffset_.GetX() + childSize_.Width(),
2202                     arrowRightOffset - ARROW_HORIZON_P1_OFFSET_Y.ConvertToPx()); // P1
2203                 path += LineTo(childOffset_.GetX() + childSize_.Width() + ARROW_HORIZON_P2_OFFSET_X.ConvertToPx(),
2204                     arrowRightOffset - ARROW_HORIZON_P2_OFFSET_Y.ConvertToPx()); // P2
2205                 path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2206                     childOffset_.GetX() + childSize_.Width() + ARROW_HORIZON_P4_OFFSET_X.ConvertToPx(),
2207                     arrowRightOffset + ARROW_HORIZON_P4_OFFSET_Y.ConvertToPx()); // P4
2208                 path += LineTo(childOffset_.GetX() + childSize_.Width(),
2209                     arrowRightOffset + ARROW_HORIZON_P5_OFFSET_Y.ConvertToPx()); // P5
2210                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO, childOffset_.GetX() + childSize_.Width(),
2211                     arrowRightOffset - ARROW_HORIZON_P1_OFFSET_Y.ConvertToPx());
2212                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2213                     childOffset_.GetX() + childSize_.Width() + ARROW_HORIZON_P2_OFFSET_X.ConvertToPx(),
2214                     arrowRightOffset - ARROW_HORIZON_P2_OFFSET_Y.ConvertToPx());
2215                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2216                     childOffset_.GetX() + childSize_.Width() + ARROW_HORIZON_P4_OFFSET_X.ConvertToPx(),
2217                     arrowRightOffset + ARROW_HORIZON_P4_OFFSET_Y.ConvertToPx());
2218                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE, childOffset_.GetX() + childSize_.Width(),
2219                     arrowRightOffset + ARROW_HORIZON_P5_OFFSET_Y.ConvertToPx());
2220             }
2221             break;
2222         default:
2223             break;
2224     }
2225     if (arrowBuildplacement != Placement::RIGHT_BOTTOM) {
2226         path += LineTo(childOffset_.GetX() + childSize_.Width(), childOffsetY + childSize_.Height() - radius);
2227     }
2228     return path;
2229 }
2230 
BuildBottomLinePath(float arrowOffset,float radius,Placement & arrowBuildplacement)2231 std::string BubbleLayoutAlgorithm::BuildBottomLinePath(float arrowOffset, float radius, Placement& arrowBuildplacement)
2232 {
2233     std::string path;
2234     float childOffsetY = childOffset_.GetY();
2235     auto leftOffset = childOffset_.GetX() + radius + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2236     auto rightOffset = childOffset_.GetX() + childSize_.Width() - radius - BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2237     auto arrowBottomOffset = std::clamp(
2238         arrowPosition_.GetX() + arrowOffset, static_cast<float>(leftOffset), static_cast<float>(rightOffset));
2239     switch (arrowPlacement_) {
2240         case Placement::TOP:
2241         case Placement::TOP_LEFT:
2242         case Placement::TOP_RIGHT:
2243             if (arrowBuildplacement == Placement::BOTTOM_RIGHT) {
2244                 path += ReplaceArrowBottomRight(arrowPosition_.GetX() + childSize_.Width()
2245                     - BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF, childOffsetY + childSize_.Height());
2246             }
2247             if (arrowBuildplacement == Placement::BOTTOM_LEFT) {
2248                 path += ReplaceArrowBottomLeft(arrowPosition_.GetX() + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF,
2249                     childOffsetY + childSize_.Height());
2250             }
2251             if (arrowBuildplacement == Placement::BOTTOM) {
2252                 path += LineTo(arrowBottomOffset + ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(),
2253                     childOffsetY + childSize_.Height()); // P1
2254                 path += LineTo(arrowBottomOffset + ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2255                     childOffsetY + childSize_.Height() + ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx()); // P2
2256                 path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2257                     arrowBottomOffset - ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2258                     childOffsetY + childSize_.Height() + ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx()); // P4
2259                 path += LineTo(arrowBottomOffset - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(),
2260                     childOffsetY + childSize_.Height()); // P5
2261                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2262                     arrowBottomOffset + ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffsetY + childSize_.Height());
2263                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2264                     arrowBottomOffset + ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2265                     childOffsetY + childSize_.Height() + ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx());
2266                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2267                     arrowBottomOffset - ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2268                     childOffsetY + childSize_.Height() + ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx());
2269                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE, arrowBottomOffset
2270                     - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffsetY + childSize_.Height());
2271             }
2272             break;
2273         default:
2274             break;
2275     }
2276     if (arrowBuildplacement != Placement::BOTTOM_LEFT) {
2277         path += LineTo(childOffset_.GetX() + radius, childOffsetY + childSize_.Height());
2278     }
2279     return path;
2280 }
2281 
BuildLeftLinePath(float arrowOffset,float radius,Placement & arrowBuildplacement)2282 std::string BubbleLayoutAlgorithm::BuildLeftLinePath(float arrowOffset, float radius, Placement& arrowBuildplacement)
2283 {
2284     std::string path;
2285     float childOffsetY = childOffset_.GetY();
2286     auto topOffset =
2287         childOffset_.GetY() + radius + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2288     auto bottomOffset = childOffset_.GetY() + childSize_.Height() - radius -
2289                         BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF;
2290     auto arrowLeftOffset = std::clamp(
2291         arrowPosition_.GetY() + arrowOffset, static_cast<float>(topOffset), static_cast<float>(bottomOffset));
2292     switch (arrowPlacement_) {
2293         case Placement::RIGHT:
2294         case Placement::RIGHT_TOP:
2295         case Placement::RIGHT_BOTTOM:
2296             if (arrowBuildplacement == Placement::LEFT_BOTTOM) {
2297                 path += ReplaceArrowLeftBottom(
2298                     arrowPosition_.GetY() + childSize_.Height() - BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF,
2299                     childOffset_.GetX());
2300             }
2301             if (arrowBuildplacement == Placement::LEFT_TOP) {
2302                 path += ReplaceArrowLeftTop(
2303                     arrowPosition_.GetY() + BUBBLE_ARROW_WIDTH.ConvertToPx() / HALF, childOffset_.GetX());
2304             }
2305             if (arrowBuildplacement == Placement::LEFT) {
2306                 path += LineTo(childOffset_.GetX(), arrowLeftOffset + ARROW_HORIZON_P1_OFFSET_Y.ConvertToPx()); // P1
2307                 path += LineTo(childOffset_.GetX() - ARROW_HORIZON_P2_OFFSET_X.ConvertToPx(),
2308                     arrowLeftOffset + ARROW_HORIZON_P2_OFFSET_Y.ConvertToPx()); // P2
2309                 path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2310                     childOffset_.GetX() - ARROW_HORIZON_P4_OFFSET_X.ConvertToPx(),
2311                     arrowLeftOffset - ARROW_HORIZON_P4_OFFSET_Y.ConvertToPx());                                 // P4
2312                 path += LineTo(childOffset_.GetX(), arrowLeftOffset - ARROW_HORIZON_P5_OFFSET_Y.ConvertToPx()); // P5
2313                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2314                     childOffset_.GetX(), arrowLeftOffset + ARROW_HORIZON_P1_OFFSET_Y.ConvertToPx());
2315                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2316                     childOffset_.GetX() - ARROW_HORIZON_P2_OFFSET_X.ConvertToPx(),
2317                     arrowLeftOffset + ARROW_HORIZON_P2_OFFSET_Y.ConvertToPx());
2318                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2319                     childOffset_.GetX() - ARROW_HORIZON_P4_OFFSET_X.ConvertToPx(),
2320                     arrowLeftOffset - ARROW_HORIZON_P4_OFFSET_Y.ConvertToPx());
2321                 SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2322                     childOffset_.GetX(), arrowLeftOffset - ARROW_HORIZON_P5_OFFSET_Y.ConvertToPx());
2323             }
2324             break;
2325         default:
2326             break;
2327     }
2328     if (arrowBuildplacement != Placement::LEFT_TOP) {
2329         path += LineTo(childOffset_.GetX(), childOffsetY + radius);
2330     }
2331     return path;
2332 }
2333 
ReplaceArrowTopLeft(const float arrowOffset,const float childOffset)2334 std::string BubbleLayoutAlgorithm::ReplaceArrowTopLeft(const float arrowOffset, const float childOffset)
2335 {
2336     std::string path;
2337     path += LineTo(arrowOffset - ARROW_REPLACE_START_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset); // P1
2338     path += LineTo(arrowOffset - ARROW_REPLACE_START_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2339         childOffset - ARROW_REPLACE_START_VERTICAL_P2_OFFSET_Y.ConvertToPx()); // P2
2340     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2341         arrowOffset - ARROW_REPLACE_START_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2342         childOffset - ARROW_REPLACE_START_VERTICAL_P4_OFFSET_Y.ConvertToPx());                         // P4
2343     path += LineTo(arrowOffset + ARROW_REPLACE_START_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset); // P5
2344     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2345         arrowOffset - ARROW_REPLACE_START_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset);
2346     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2347         arrowOffset - ARROW_REPLACE_START_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2348         childOffset - ARROW_REPLACE_START_VERTICAL_P2_OFFSET_Y.ConvertToPx());
2349     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2350         arrowOffset - ARROW_REPLACE_START_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2351         childOffset - ARROW_REPLACE_START_VERTICAL_P4_OFFSET_Y.ConvertToPx());
2352     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2353         arrowOffset + ARROW_REPLACE_START_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset);
2354     return path;
2355 }
2356 
ReplaceArrowTopRight(const float arrowOffset,const float childOffset)2357 std::string BubbleLayoutAlgorithm::ReplaceArrowTopRight(const float arrowOffset, const float childOffset)
2358 {
2359     std::string path;
2360     path += LineTo((arrowOffset - ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X.ConvertToPx()) / HALF, childOffset); // P1
2361     path += LineTo(arrowOffset - ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset);          // P1
2362     path += LineTo(arrowOffset + ARROW_REPLACE_END_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2363         childOffset - ARROW_REPLACE_END_VERTICAL_P2_OFFSET_Y.ConvertToPx()); // P2
2364     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2365         arrowOffset + ARROW_REPLACE_END_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2366         childOffset - ARROW_REPLACE_END_VERTICAL_P4_OFFSET_Y.ConvertToPx());                         // P4
2367     path += LineTo(arrowOffset + ARROW_REPLACE_END_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset); // P5
2368     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2369         arrowOffset - ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset);
2370     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2371         arrowOffset + ARROW_REPLACE_END_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2372         childOffset - ARROW_REPLACE_END_VERTICAL_P2_OFFSET_Y.ConvertToPx());
2373     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2374         arrowOffset + ARROW_REPLACE_END_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2375         childOffset - ARROW_REPLACE_END_VERTICAL_P4_OFFSET_Y.ConvertToPx());
2376     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2377         arrowOffset + ARROW_REPLACE_END_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset);
2378     return path;
2379 }
2380 
ReplaceArrowRightTop(const float arrowOffset,const float childOffset)2381 std::string BubbleLayoutAlgorithm::ReplaceArrowRightTop(const float arrowOffset, const float childOffset)
2382 {
2383     std::string path;
2384     path += LineTo(childOffset, arrowOffset - ARROW_REPLACE_START_HORIZON_P1_OFFSET_Y.ConvertToPx()); // P1
2385     path += LineTo(childOffset + ARROW_REPLACE_START_HORIZON_P2_OFFSET_X.ConvertToPx(),
2386         arrowOffset - ARROW_REPLACE_START_HORIZON_P2_OFFSET_Y.ConvertToPx()); // P2
2387     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2388         childOffset + ARROW_REPLACE_START_HORIZON_P4_OFFSET_X.ConvertToPx(),
2389         arrowOffset - ARROW_REPLACE_START_HORIZON_P4_OFFSET_Y.ConvertToPx());                         // P4
2390     path += LineTo(childOffset, arrowOffset + ARROW_REPLACE_START_HORIZON_P5_OFFSET_Y.ConvertToPx()); // P5
2391     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO, childOffset,
2392         arrowOffset - ARROW_REPLACE_START_HORIZON_P1_OFFSET_Y.ConvertToPx());
2393     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2394         childOffset + ARROW_REPLACE_START_HORIZON_P2_OFFSET_X.ConvertToPx(),
2395         arrowOffset - ARROW_REPLACE_START_HORIZON_P2_OFFSET_Y.ConvertToPx());
2396     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2397         childOffset + ARROW_REPLACE_START_HORIZON_P4_OFFSET_X.ConvertToPx(),
2398         arrowOffset - ARROW_REPLACE_START_HORIZON_P4_OFFSET_Y.ConvertToPx());
2399     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2400         childOffset, arrowOffset + ARROW_REPLACE_START_HORIZON_P5_OFFSET_Y.ConvertToPx());
2401     return path;
2402 }
2403 
ReplaceArrowRightBottom(const float arrowOffset,const float childOffset)2404 std::string BubbleLayoutAlgorithm::ReplaceArrowRightBottom(const float arrowOffset, const float childOffset)
2405 {
2406     std::string path;
2407     path += LineTo(childOffset, arrowOffset - ARROW_REPLACE_END_HORIZON_P1_OFFSET_Y.ConvertToPx()); // P1
2408     path += LineTo(childOffset + ARROW_REPLACE_END_HORIZON_P2_OFFSET_X.ConvertToPx(),
2409         arrowOffset + ARROW_REPLACE_END_HORIZON_P2_OFFSET_Y.ConvertToPx()); // P2
2410     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2411         childOffset + ARROW_REPLACE_END_HORIZON_P4_OFFSET_X.ConvertToPx(),
2412         arrowOffset + ARROW_REPLACE_END_HORIZON_P4_OFFSET_Y.ConvertToPx());                         // P4
2413     path += LineTo(childOffset, arrowOffset + ARROW_REPLACE_END_HORIZON_P5_OFFSET_Y.ConvertToPx()); // P5
2414     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO, childOffset,
2415         arrowOffset - ARROW_REPLACE_END_HORIZON_P1_OFFSET_Y.ConvertToPx());
2416     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2417         childOffset + ARROW_REPLACE_END_HORIZON_P2_OFFSET_X.ConvertToPx(),
2418         arrowOffset + ARROW_REPLACE_END_HORIZON_P2_OFFSET_Y.ConvertToPx());
2419     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2420         childOffset + ARROW_REPLACE_END_HORIZON_P4_OFFSET_X.ConvertToPx(),
2421         arrowOffset + ARROW_REPLACE_END_HORIZON_P4_OFFSET_Y.ConvertToPx());
2422     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2423         childOffset, arrowOffset + ARROW_REPLACE_END_HORIZON_P5_OFFSET_Y.ConvertToPx());
2424     return path;
2425 }
2426 
ReplaceArrowBottomLeft(const float arrowOffset,const float childOffset)2427 std::string BubbleLayoutAlgorithm::ReplaceArrowBottomLeft(const float arrowOffset, const float childOffset)
2428 {
2429     std::string path;
2430     path += LineTo(arrowOffset + ARROW_REPLACE_START_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset); // P1
2431     path += LineTo(arrowOffset - ARROW_REPLACE_START_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2432         childOffset + ARROW_REPLACE_START_VERTICAL_P4_OFFSET_Y.ConvertToPx()); // P2
2433     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2434         arrowOffset - ARROW_REPLACE_START_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2435         childOffset + ARROW_REPLACE_START_VERTICAL_P2_OFFSET_Y.ConvertToPx());                         // P4
2436     path += LineTo(arrowOffset - ARROW_REPLACE_START_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset); // P5
2437     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2438         arrowOffset + ARROW_REPLACE_START_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset);
2439     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2440         arrowOffset - ARROW_REPLACE_START_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2441         childOffset + ARROW_REPLACE_START_VERTICAL_P4_OFFSET_Y.ConvertToPx());
2442     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2443         arrowOffset - ARROW_REPLACE_START_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2444         childOffset + ARROW_REPLACE_START_VERTICAL_P2_OFFSET_Y.ConvertToPx());
2445     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2446         arrowOffset - ARROW_REPLACE_START_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset);
2447     return path;
2448 }
2449 
ReplaceArrowBottomRight(const float arrowOffset,const float childOffset)2450 std::string BubbleLayoutAlgorithm::ReplaceArrowBottomRight(const float arrowOffset, const float childOffset)
2451 {
2452     std::string path;
2453     path += LineTo(arrowOffset + ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset); // P1
2454     path += LineTo(arrowOffset + ARROW_REPLACE_END_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2455         childOffset + ARROW_REPLACE_END_VERTICAL_P4_OFFSET_Y.ConvertToPx()); // P2
2456     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2457         arrowOffset + ARROW_REPLACE_END_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2458         childOffset + ARROW_REPLACE_END_VERTICAL_P2_OFFSET_Y.ConvertToPx());                         // P4
2459     path += LineTo(arrowOffset - ARROW_REPLACE_END_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset); // P5
2460     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2461         arrowOffset + ARROW_REPLACE_END_VERTICAL_P1_OFFSET_X.ConvertToPx(), childOffset);
2462     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2463         arrowOffset + ARROW_REPLACE_END_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2464         childOffset + ARROW_REPLACE_END_VERTICAL_P4_OFFSET_Y.ConvertToPx());
2465     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2466         arrowOffset + ARROW_REPLACE_END_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2467         childOffset + ARROW_REPLACE_END_VERTICAL_P2_OFFSET_Y.ConvertToPx());
2468     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2469         arrowOffset - ARROW_REPLACE_END_VERTICAL_P5_OFFSET_X.ConvertToPx(), childOffset);
2470     return path;
2471 }
2472 
ReplaceArrowLeftTop(const float arrowOffset,const float childOffset)2473 std::string BubbleLayoutAlgorithm::ReplaceArrowLeftTop(const float arrowOffset, const float childOffset)
2474 {
2475     std::string path;
2476     path += LineTo(childOffset, arrowOffset + ARROW_REPLACE_START_HORIZON_P1_OFFSET_Y.ConvertToPx()); // P1
2477     path += LineTo(childOffset - ARROW_REPLACE_START_HORIZON_P4_OFFSET_X.ConvertToPx(),
2478         arrowOffset - ARROW_REPLACE_START_HORIZON_P4_OFFSET_Y.ConvertToPx()); // P2
2479     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2480         childOffset - ARROW_REPLACE_START_HORIZON_P2_OFFSET_X.ConvertToPx(),
2481         arrowOffset - ARROW_REPLACE_START_HORIZON_P2_OFFSET_Y.ConvertToPx());                         // P4
2482     path += LineTo(childOffset, arrowOffset - ARROW_REPLACE_START_HORIZON_P5_OFFSET_Y.ConvertToPx()); // P5
2483     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2484         childOffset, arrowOffset + ARROW_REPLACE_START_HORIZON_P1_OFFSET_Y.ConvertToPx());
2485     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2486         childOffset - ARROW_REPLACE_START_HORIZON_P4_OFFSET_X.ConvertToPx(),
2487         arrowOffset - ARROW_REPLACE_START_HORIZON_P4_OFFSET_Y.ConvertToPx());
2488     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2489         childOffset - ARROW_REPLACE_START_HORIZON_P2_OFFSET_X.ConvertToPx(),
2490         arrowOffset - ARROW_REPLACE_START_HORIZON_P2_OFFSET_Y.ConvertToPx());
2491     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2492         childOffset, arrowOffset - ARROW_REPLACE_START_HORIZON_P5_OFFSET_Y.ConvertToPx());
2493     return path;
2494 }
2495 
ReplaceArrowLeftBottom(const float arrowOffset,const float childOffset)2496 std::string BubbleLayoutAlgorithm::ReplaceArrowLeftBottom(const float arrowOffset, const float childOffset)
2497 {
2498     std::string path;
2499     path += LineTo(childOffset, arrowOffset + ARROW_REPLACE_END_HORIZON_P1_OFFSET_Y.ConvertToPx()); // P1
2500     path += LineTo(childOffset - ARROW_REPLACE_END_HORIZON_P4_OFFSET_X.ConvertToPx(),
2501         arrowOffset + ARROW_REPLACE_END_HORIZON_P4_OFFSET_Y.ConvertToPx()); // P2
2502     path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2503         childOffset - ARROW_REPLACE_END_HORIZON_P2_OFFSET_X.ConvertToPx(),
2504         arrowOffset + ARROW_REPLACE_END_HORIZON_P2_OFFSET_Y.ConvertToPx());                         // P4
2505     path += LineTo(childOffset, arrowOffset - ARROW_REPLACE_END_HORIZON_P5_OFFSET_Y.ConvertToPx()); // P5
2506     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ZERO,
2507         childOffset, arrowOffset + ARROW_REPLACE_END_HORIZON_P1_OFFSET_Y.ConvertToPx());
2508     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_ONE,
2509         childOffset - ARROW_REPLACE_END_HORIZON_P4_OFFSET_X.ConvertToPx(),
2510         arrowOffset + ARROW_REPLACE_END_HORIZON_P4_OFFSET_Y.ConvertToPx());
2511     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_TWO,
2512         childOffset - ARROW_REPLACE_END_HORIZON_P2_OFFSET_X.ConvertToPx(),
2513         arrowOffset + ARROW_REPLACE_END_HORIZON_P2_OFFSET_Y.ConvertToPx());
2514     SetArrowOffsetsFromClip(ARROW_OFFSETS_INDEX_THREE,
2515         childOffset, arrowOffset - ARROW_REPLACE_END_HORIZON_P5_OFFSET_Y.ConvertToPx());
2516     return path;
2517 }
2518 
BuildCornerPath(const Placement & placement,float radius)2519 std::string BubbleLayoutAlgorithm::BuildCornerPath(const Placement& placement, float radius)
2520 {
2521     std::string path;
2522     float childOffsetY = childOffset_.GetY();
2523     switch (placement) {
2524         case Placement::TOP_LEFT:
2525             path += ArcTo(radius, radius, 0.0f, 0, childOffset_.GetX() + radius, childOffsetY);
2526             break;
2527         case Placement::TOP_RIGHT:
2528             path += ArcTo(radius, radius, 0.0f, 0, childOffset_.GetX() + childSize_.Width(), childOffsetY + radius);
2529             break;
2530         case Placement::BOTTOM_RIGHT:
2531             path += ArcTo(radius, radius, 0.0f, 0, childOffset_.GetX() + childSize_.Width() - radius,
2532                 childOffsetY + childSize_.Height());
2533             break;
2534         case Placement::BOTTOM_LEFT:
2535             path += ArcTo(radius, radius, 0.0f, 0, childOffset_.GetX(), childOffsetY + childSize_.Height() - radius);
2536             break;
2537         default:
2538             break;
2539     }
2540     return path;
2541 }
2542 
GetChildPosition(const SizeF & childSize,const RefPtr<BubbleLayoutProperty> & layoutProp,bool UseArrowOffset)2543 OffsetF BubbleLayoutAlgorithm::GetChildPosition(
2544     const SizeF& childSize, const RefPtr<BubbleLayoutProperty>& layoutProp, bool UseArrowOffset)
2545 {
2546     OffsetF bottomPosition;
2547     OffsetF topPosition;
2548     OffsetF topArrowPosition;
2549     OffsetF bottomArrowPosition;
2550     OffsetF fitPosition;
2551     OffsetF originOffset;
2552     OffsetF originArrowOffset;
2553     OffsetF childPosition;
2554 
2555     InitArrowTopAndBottomPosition(topArrowPosition, bottomArrowPosition, topPosition, bottomPosition, childSize);
2556     GetPositionWithPlacement(originOffset, originArrowOffset, childSize, placement_);
2557     originOffset = originOffset + positionOffset_;
2558     originArrowOffset += positionOffset_;
2559     arrowPlacement_ = placement_;
2560 
2561     // Fit popup to screen range.
2562     ErrorPositionType errorType = GetErrorPositionType(originOffset, childSize);
2563     if (errorType == ErrorPositionType::NORMAL) {
2564         arrowPosition_ = originArrowOffset;
2565         return originOffset;
2566     }
2567 
2568     if (placement_ == Placement::TOP || placement_ == Placement::TOP_LEFT || placement_ == Placement::TOP_RIGHT) {
2569         fitPosition = topPosition;
2570         arrowPosition_ = topArrowPosition;
2571         arrowPlacement_ = Placement::TOP;
2572     } else {
2573         placement_ = Placement::BOTTOM;
2574         fitPosition = bottomPosition;
2575         arrowPosition_ = bottomArrowPosition;
2576         arrowPlacement_ = Placement::BOTTOM;
2577     }
2578 
2579     childPosition = FitToScreen(fitPosition, childSize);
2580     if (UseArrowOffset) {
2581         arrowPosition_.SetX(
2582             childPosition.GetX() + border_.TopLeftRadius().GetX().ConvertToPx() + BEZIER_WIDTH_HALF.ConvertToPx());
2583     }
2584 
2585     if (GetErrorPositionType(childPosition, childSize) == ErrorPositionType::NORMAL) {
2586         return childPosition;
2587     }
2588 
2589     // Fit popup to opposite position
2590     fitPosition = fitPosition == topPosition ? bottomPosition : topPosition;
2591     arrowPosition_ = arrowPlacement_ == Placement::TOP ? bottomArrowPosition : topArrowPosition;
2592     arrowPlacement_ = arrowPlacement_ == Placement::TOP ? Placement::BOTTOM : Placement::TOP;
2593     placement_ = arrowPlacement_ == Placement::TOP ? Placement::BOTTOM : Placement::TOP;
2594 
2595     childPosition = FitToScreen(fitPosition, childSize);
2596     if (UseArrowOffset) {
2597         arrowPosition_.SetX(
2598             childPosition.GetX() + border_.TopLeftRadius().GetX().ConvertToPx() + BEZIER_WIDTH_HALF.ConvertToPx());
2599     }
2600 
2601     if (GetErrorPositionType(childPosition, childSize) == ErrorPositionType::NORMAL) {
2602         return childPosition;
2603     }
2604 
2605     // If childPosition is error, adjust bubble to origin position.
2606     arrowPlacement_ = placement_;
2607     arrowPosition_ = originArrowOffset;
2608 
2609     return originOffset;
2610 }
2611 
InitArrowTopAndBottomPosition(OffsetF & topArrowPosition,OffsetF & bottomArrowPosition,OffsetF & topPosition,OffsetF & bottomPosition,const SizeF & childSize)2612 void BubbleLayoutAlgorithm::InitArrowTopAndBottomPosition(OffsetF& topArrowPosition, OffsetF& bottomArrowPosition,
2613     OffsetF& topPosition, OffsetF& bottomPosition, const SizeF& childSize)
2614 {
2615     auto arrowCenter = targetOffset_.GetX() + targetSize_.Width() / 2.0;
2616     auto horizonSpacing = static_cast<float>(HORIZON_SPACING_WITH_SCREEN.ConvertToPx());
2617     double arrowWidth = ARROW_WIDTH.ConvertToPx();
2618     float radius = borderRadius_.ConvertToPx();
2619     auto safePosition = horizonSpacing + radius + arrowWidth / 2.0;
2620 
2621     GetPositionWithPlacement(topPosition, topArrowPosition, childSize, Placement::TOP);
2622     GetPositionWithPlacement(bottomPosition, bottomArrowPosition, childSize, Placement::BOTTOM);
2623 
2624     // move the arrow to safe position while arrow too close to window
2625     // In order not to separate the bubble from the arrow
2626     // If ArrowOffset is not set, arrow always point to the middle of the targetNode
2627     if (arrowCenter < safePosition) {
2628         topArrowPosition = topArrowPosition + OffsetF(safePosition - arrowCenter, 0);
2629         bottomArrowPosition = bottomArrowPosition + OffsetF(safePosition - arrowCenter, 0);
2630     }
2631     if (arrowCenter > selfSize_.Width() - safePosition) {
2632         topArrowPosition = topArrowPosition - OffsetF(arrowCenter + safePosition - selfSize_.Width(), 0);
2633         bottomArrowPosition = bottomArrowPosition - OffsetF(arrowCenter + safePosition - selfSize_.Width(), 0);
2634     }
2635 }
2636 
GetPositionWithPlacement(OffsetF & childPosition,OffsetF & arrowPosition,const SizeF & childSize,Placement placement)2637 void BubbleLayoutAlgorithm::GetPositionWithPlacement(
2638     OffsetF& childPosition, OffsetF& arrowPosition, const SizeF& childSize, Placement placement)
2639 {
2640     float bubbleSpacing = scaledBubbleSpacing_;
2641     float marginRight = 0.0f;
2642     float marginBottom = 0.0f;
2643     float marginTop = 0.0f;
2644     float marginLeft = 0.0f;
2645     float arrowHalfWidth = ARROW_WIDTH.ConvertToPx() / 2.0;
2646     float radius = borderRadius_.ConvertToPx();
2647     float targetSpace = targetSpace_.ConvertToPx();
2648     switch (placement) {
2649         case Placement::TOP:
2650             childPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
2651                 targetOffset_.GetY() - childSize.Height() - targetSpace - arrowHeight_);
2652             arrowPosition = childPosition + OffsetF(std::max(padding_.Left().ConvertToPx(),
2653             border_.TopLeftRadius().GetX().ConvertToPx()) +
2654             BEZIER_WIDTH_HALF.ConvertToPx(), childSize.Height() + arrowHeight_);
2655             break;
2656         case Placement::TOP_LEFT:
2657             childPosition = OffsetF(targetOffset_.GetX() - marginRight,
2658                 targetOffset_.GetY() - childSize.Height() - bubbleSpacing - marginBottom - targetSpace - arrowHeight_);
2659             arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, childSize.Height() + bubbleSpacing);
2660             break;
2661         case Placement::TOP_RIGHT:
2662             childPosition = OffsetF(targetOffset_.GetX() + targetSize_.Width() - childSize.Width() + marginLeft,
2663                 targetOffset_.GetY() - childSize.Height() - targetSpace - bubbleSpacing - marginBottom - arrowHeight_);
2664             arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, childSize.Height() + bubbleSpacing);
2665             break;
2666         case Placement::BOTTOM:
2667             childPosition = OffsetF(targetOffset_.GetX() + (targetSize_.Width() - childSize.Width()) / 2.0,
2668                 targetOffset_.GetY() + targetSize_.Height() + targetSpace + arrowHeight_);
2669             arrowPosition = childPosition + OffsetF(std::max(padding_.Left().ConvertToPx(),
2670             border_.BottomLeftRadius().GetX().ConvertToPx()) +
2671             BEZIER_WIDTH_HALF.ConvertToPx(), -arrowHeight_);
2672             break;
2673         case Placement::BOTTOM_LEFT:
2674             childPosition = OffsetF(targetOffset_.GetX() - marginRight,
2675                 targetOffset_.GetY() + targetSize_.Height() + targetSpace + bubbleSpacing + marginTop + arrowHeight_);
2676             arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, -bubbleSpacing);
2677             break;
2678         case Placement::BOTTOM_RIGHT:
2679             childPosition = OffsetF(targetOffset_.GetX() + targetSize_.Width() - childSize.Width() + marginLeft,
2680                 targetOffset_.GetY() + targetSize_.Height() + targetSpace + bubbleSpacing + marginTop + arrowHeight_);
2681             arrowPosition = childPosition + OffsetF(radius + arrowHalfWidth, -bubbleSpacing);
2682             break;
2683         case Placement::LEFT:
2684             childPosition = OffsetF(
2685                 targetOffset_.GetX() - targetSpace - bubbleSpacing - childSize.Width() - marginRight - arrowHeight_,
2686                 targetOffset_.GetY() + targetSize_.Height() / HALF - childSize.Height() / HALF);
2687             arrowPosition = childPosition + OffsetF(childSize_.Width() + bubbleSpacing, radius + arrowHalfWidth);
2688             break;
2689         case Placement::LEFT_TOP:
2690             childPosition = OffsetF(
2691                 targetOffset_.GetX() - targetSpace - bubbleSpacing - childSize.Width() - marginRight - arrowHeight_,
2692                 targetOffset_.GetY() - marginBottom);
2693             arrowPosition = childPosition + OffsetF(childSize_.Width() + bubbleSpacing, radius + arrowHalfWidth);
2694             break;
2695         case Placement::LEFT_BOTTOM:
2696             childPosition = OffsetF(
2697                 targetOffset_.GetX() - targetSpace - bubbleSpacing - childSize.Width() - marginRight - arrowHeight_,
2698                 targetOffset_.GetY() + targetSize_.Height() - childSize.Height() - marginTop);
2699             arrowPosition = childPosition + OffsetF(childSize_.Width() + bubbleSpacing, radius + arrowHalfWidth);
2700             break;
2701         case Placement::RIGHT:
2702             childPosition = OffsetF(
2703                 targetOffset_.GetX() + targetSize_.Width() + targetSpace + bubbleSpacing + marginLeft + arrowHeight_,
2704                 targetOffset_.GetY() + targetSize_.Height() / HALF - childSize.Height() / HALF);
2705             arrowPosition = childPosition + OffsetF(-bubbleSpacing, radius + arrowHalfWidth);
2706             break;
2707         case Placement::RIGHT_TOP:
2708             childPosition = OffsetF(
2709                 targetOffset_.GetX() + targetSize_.Width() + targetSpace + bubbleSpacing + marginLeft + arrowHeight_,
2710                 targetOffset_.GetY() - marginBottom);
2711             arrowPosition = childPosition + OffsetF(-bubbleSpacing, radius + arrowHalfWidth);
2712             break;
2713         case Placement::RIGHT_BOTTOM:
2714             childPosition = OffsetF(
2715                 targetOffset_.GetX() + targetSize_.Width() + targetSpace + bubbleSpacing + marginLeft + arrowHeight_,
2716                 targetOffset_.GetY() + targetSize_.Height() - childSize.Height() - marginTop);
2717             arrowPosition = childPosition + OffsetF(-bubbleSpacing, radius + arrowHalfWidth);
2718             break;
2719         default:
2720             break;
2721     }
2722 }
2723 
GetErrorPositionType(const OffsetF & childOffset,const SizeF & childSize)2724 BubbleLayoutAlgorithm::ErrorPositionType BubbleLayoutAlgorithm::GetErrorPositionType(
2725     const OffsetF& childOffset, const SizeF& childSize)
2726 {
2727     auto horizonSpacing = static_cast<float>(HORIZON_SPACING_WITH_SCREEN.ConvertToPx());
2728     RectF validRegion =
2729         RectF(OffsetF(horizonSpacing, top_), OffsetF(selfSize_.Width() - horizonSpacing, selfSize_.Height() - bottom_));
2730     PointF childPoint(childOffset.GetX(), childOffset.GetY());
2731     if (!validRegion.IsInRegion(childPoint)) {
2732         return ErrorPositionType::TOP_LEFT_ERROR;
2733     }
2734     if (!validRegion.IsInRegion(
2735             PointF(childOffset.GetX() + childSize.Width(), childOffset.GetY() + childSize.Height()))) {
2736         return ErrorPositionType::BOTTOM_RIGHT_ERROR;
2737     }
2738     return ErrorPositionType::NORMAL;
2739 }
2740 
FitToScreen(const OffsetF & fitPosition,const SizeF & childSize)2741 OffsetF BubbleLayoutAlgorithm::FitToScreen(const OffsetF& fitPosition, const SizeF& childSize)
2742 {
2743     auto validation = GetErrorPositionType(fitPosition, childSize);
2744     if (validation == ErrorPositionType::NORMAL) {
2745         return fitPosition;
2746     }
2747     OffsetF childPosition = fitPosition;
2748     auto horizonSpacing = static_cast<float>(HORIZON_SPACING_WITH_SCREEN.ConvertToPx());
2749     if (validation == ErrorPositionType::TOP_LEFT_ERROR) {
2750         childPosition.SetX(horizonSpacing);
2751     } else {
2752         childPosition.SetX(selfSize_.Width() - childSize.Width() - horizonSpacing);
2753     }
2754     return childPosition;
2755 }
2756 
UpdateMarginByWidth()2757 void BubbleLayoutAlgorithm::UpdateMarginByWidth()
2758 {
2759     isGreatWrapperWidth_ = GreatOrEqual(childSize_.Width(), wrapperSize_.Width() - marginStart_ - marginEnd_);
2760     marginStart_ = isGreatWrapperWidth_ ? 0.0f : marginStart_;
2761     marginEnd_ = isGreatWrapperWidth_ ? 0.0f : marginEnd_;
2762 }
2763 
2764 } // namespace OHOS::Ace::NG
2765