1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/security_component/security_component_layout_algorithm.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "core/components/common/layout/constants.h"
20 #include "core/components_ng/base/frame_node.h"
21 #include "core/components_ng/pattern/button/button_layout_property.h"
22 #include "core/components_ng/pattern/image/image_layout_property.h"
23 #include "core/components_ng/pattern/image/image_render_property.h"
24 #include "core/components_ng/pattern/security_component/security_component_layout_element.h"
25 #include "core/components_ng/pattern/text/text_layout_property.h"
26 #include "core/components_ng/pattern/text/text_pattern.h"
27 #include "core/components_v2/inspector/inspector_constants.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 #include "unicode/uchar.h"
30 
31 namespace {
32 constexpr float HALF = 2.0f;
33 constexpr float TEXT_OUT_OF_RANGE_PERCENT = 0.3f; // 30%
34 constexpr float TEXT_OUT_OF_WIDTH_PERCENT = 0.1f; // 10%
35 constexpr float RANGE_RATIO = 1.414f;
36 }
37 
38 namespace OHOS::Ace::NG {
GetChildWrapper(LayoutWrapper * layoutWrapper,const std::string & tag)39 RefPtr<LayoutWrapper> SecurityComponentLayoutAlgorithm::GetChildWrapper(LayoutWrapper* layoutWrapper,
40     const std::string& tag)
41 {
42     int32_t count = layoutWrapper->GetTotalChildCount();
43     for (int32_t i = 0; i < count; i++) {
44         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(i);
45         if (childWrapper == nullptr) {
46             continue;
47         }
48         if (childWrapper->GetHostTag() == tag) {
49             return childWrapper;
50         }
51     }
52     return nullptr;
53 }
54 
UpdateChildPosition(LayoutWrapper * layoutWrapper,const std::string & tag,OffsetF & offset)55 void SecurityComponentLayoutAlgorithm::UpdateChildPosition(LayoutWrapper* layoutWrapper, const std::string& tag,
56     OffsetF& offset)
57 {
58     auto childWrapper = GetChildWrapper(layoutWrapper, tag);
59     CHECK_NULL_VOID(childWrapper);
60     auto childNode = childWrapper->GetHostNode();
61     CHECK_NULL_VOID(childNode);
62     auto geometryNode = childNode->GetGeometryNode();
63     CHECK_NULL_VOID(geometryNode);
64     geometryNode->SetMarginFrameOffset(
65         OffsetF(std::round(offset.GetX()), std::round(offset.GetY())));
66 }
67 
CreateDefaultChildConstraint(RefPtr<SecurityComponentLayoutProperty> & securityComponentProperty)68 static LayoutConstraintF CreateDefaultChildConstraint(
69     RefPtr<SecurityComponentLayoutProperty>& securityComponentProperty)
70 {
71     auto constraint = securityComponentProperty->CreateChildConstraint();
72     SizeT<float> maxSize { Infinity<float>(), Infinity<float>() };
73     constraint.maxSize = maxSize;
74     return constraint;
75 }
76 
MeasureButton(LayoutWrapper * layoutWrapper,RefPtr<SecurityComponentLayoutProperty> & securityComponentProperty)77 void SecurityComponentLayoutAlgorithm::MeasureButton(LayoutWrapper* layoutWrapper,
78     RefPtr<SecurityComponentLayoutProperty>& securityComponentProperty)
79 {
80     auto buttonWrapper = GetChildWrapper(layoutWrapper, V2::BUTTON_ETS_TAG);
81     CHECK_NULL_VOID(buttonWrapper);
82     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(buttonWrapper->GetLayoutProperty());
83     CHECK_NULL_VOID(buttonLayoutProperty);
84     auto buttonConstraint = CreateDefaultChildConstraint(securityComponentProperty);
85     if (securityComponentProperty->GetBackgroundType() == static_cast<int32_t>(ButtonType::CIRCLE)) {
86         buttonConstraint.selfIdealSize.SetSize(SizeF(std::min(componentWidth_, componentHeight_),
87             std::min(componentWidth_, componentHeight_)));
88         if (GreatNotEqual(componentWidth_, componentHeight_)) {
89             left_.ShrinkWidth((componentWidth_ / HALF) - (componentHeight_ / HALF));
90         } else if (GreatNotEqual(componentHeight_, componentWidth_)) {
91             top_.ShrinkHeight((componentHeight_ / HALF) - (componentWidth_ / HALF));
92         }
93         componentWidth_ = componentHeight_ = std::min(componentWidth_, componentHeight_);
94     } else {
95         buttonConstraint.selfIdealSize.SetSize(SizeF(componentWidth_, componentHeight_));
96     }
97 
98     buttonWrapper->Measure(std::optional<LayoutConstraintF>(buttonConstraint));
99     auto geometryNode = buttonWrapper->GetGeometryNode();
100     CHECK_NULL_VOID(geometryNode);
101     geometryNode->SetFrameSize(SizeF(componentWidth_, componentHeight_));
102 }
103 
InitPadding(RefPtr<SecurityComponentLayoutProperty> & property)104 void SecurityComponentLayoutAlgorithm::InitPadding(RefPtr<SecurityComponentLayoutProperty>& property)
105 {
106     auto context = PipelineContext::GetCurrentContextSafely();
107     CHECK_NULL_VOID(context);
108     auto theme = context->GetTheme<SecurityComponentTheme>();
109     CHECK_NULL_VOID(theme);
110 
111     double borderWidth = property->GetBackgroundBorderWidth().value_or(Dimension(0.0)).ConvertToPx();
112     double size = property->GetBackgroundLeftPadding().value_or(theme->GetBackgroundLeftPadding()).ConvertToPx() +
113         borderWidth;
114     left_.Init(false,
115         property->GetBackgroundLeftPadding().has_value(), size, borderWidth);
116 
117     size = property->GetBackgroundTopPadding().value_or(theme->GetBackgroundTopPadding()).ConvertToPx() +
118         borderWidth;
119     top_.Init(true,
120         property->GetBackgroundTopPadding().has_value(), size, borderWidth);
121 
122     size = property->GetBackgroundRightPadding().value_or(theme->GetBackgroundRightPadding()).ConvertToPx() +
123         borderWidth;
124     right_.Init(false,
125         property->GetBackgroundRightPadding().has_value(), size, borderWidth);
126 
127     size = property->GetBackgroundBottomPadding().value_or(theme->GetBackgroundBottomPadding()).ConvertToPx() +
128         borderWidth;
129     bottom_.Init(true,
130         property->GetBackgroundBottomPadding().has_value(), size, borderWidth);
131 
132     size = property->GetTextIconSpace().value_or(theme->GetTextIconSpace()).ConvertToPx();
133     middle_.Init(isVertical_, property->GetTextIconSpace().has_value(), size, 0.0);
134 }
135 
UpdateTextSize()136 void SecurityComponentLayoutAlgorithm::UpdateTextSize()
137 {
138     auto minWidth = std::min(maxWidth_, componentWidth_);
139     if (!NearEqual(idealWidth_, 0.0)) {
140         minWidth = std::min(minWidth, idealWidth_);
141     }
142     float leftSpace;
143     if (isVertical_) {
144         leftSpace = left_.width_ + icon_.width_ + right_.width_;
145     } else {
146         leftSpace = left_.width_ + middle_.width_ + icon_.width_ + right_.width_;
147     }
148     text_.DoMeasure(isVertical_, minWidth, leftSpace);
149 }
150 
ShrinkWidth(double diff)151 double SecurityComponentLayoutAlgorithm::ShrinkWidth(double diff)
152 {
153     // first shrink left and right padding
154     double remain = left_.ShrinkWidth(diff / HALF);
155     remain = right_.ShrinkWidth(remain + (diff / HALF));
156     remain = left_.ShrinkWidth(remain);
157     if (NearEqual(remain, 0.0)) {
158         MeasureIntegralSize();
159         return componentWidth_;
160     }
161 
162     // if horizontal shrink IconTextSpace
163     remain = middle_.ShrinkWidth(remain);
164     if (NearEqual(remain, 0.0)) {
165         MeasureIntegralSize();
166         return componentWidth_;
167     }
168 
169     double iconWidth = icon_.width_;
170     double textWidth = text_.width_;
171     if (isVertical_) {
172         // Shrink max width, then shrink another proportionally if vertical
173         if (GreatNotEqual(textWidth, iconWidth)) {
174             double textRemain = text_.ShrinkWidth(remain);
175             double iconRemain = (remain - textRemain) * iconWidth / textWidth;
176             icon_.ShrinkWidth(iconRemain);
177         } else {
178             double iconRemain = icon_.ShrinkWidth(remain);
179             double textRemain = (remain - iconRemain) * textWidth / iconWidth;
180             text_.ShrinkWidth(textRemain);
181         }
182     } else {
183         // Shrink proportional text and icon if horizontal
184         double iconRemain = iconWidth * remain / (iconWidth + textWidth);
185         double textRemain = textWidth * remain / (iconWidth + textWidth);
186         double resIcon = icon_.ShrinkWidth(iconRemain);
187         double resText = text_.ShrinkWidth(textRemain);
188         if (!NearEqual(resIcon, 0.0)) {
189             text_.ShrinkWidth(resIcon);
190         } else if (!NearEqual(resText, 0.0)) {
191             icon_.ShrinkWidth(resText);
192         }
193     }
194     UpdateTextSize();
195     MeasureIntegralSize();
196     return componentWidth_;
197 }
198 
EnlargeWidth(double diff)199 double SecurityComponentLayoutAlgorithm::EnlargeWidth(double diff)
200 {
201     double remain = left_.EnlargeWidth(diff / HALF);
202     remain = right_.EnlargeWidth(remain + (diff / HALF));
203     remain = left_.EnlargeWidth(remain);
204     if (GreatNotEqual(remain, 0.0) && !isVertical_) {
205         middle_.EnlargeWidth(remain);
206     }
207     MeasureIntegralSize();
208     return componentWidth_;
209 }
210 
ShrinkHeight(double diff)211 double SecurityComponentLayoutAlgorithm::ShrinkHeight(double diff)
212 {
213     // first shrink left and right padding
214     double remain = top_.ShrinkHeight(diff / HALF);
215     remain = bottom_.ShrinkHeight(remain + (diff / HALF));
216     remain = top_.ShrinkHeight(remain);
217     if (NearEqual(remain, 0.0)) {
218         MeasureIntegralSize();
219         return componentHeight_;
220     }
221 
222     // if vertical shrink IconTextSpace
223     remain = middle_.ShrinkHeight(remain);
224     if (NearEqual(remain, 0.0)) {
225         MeasureIntegralSize();
226         return componentHeight_;
227     }
228 
229     double iconHeight = icon_.height_;
230     double textHeight = text_.height_;
231     if (!isVertical_) {
232          // Shrink max width, then shrink another proportionally if horizontal
233         if (GreatNotEqual(textHeight, iconHeight)) {
234             double textRemain = text_.ShrinkHeight(remain);
235             double iconRemain = (remain - textRemain) * iconHeight / textHeight;
236             icon_.ShrinkHeight(iconRemain);
237         } else {
238             double iconRemain = icon_.ShrinkHeight(remain);
239             double textRemain = (remain - iconRemain) * textHeight / iconHeight;
240             text_.ShrinkHeight(textRemain);
241         }
242     } else {
243         double iconRemain = iconHeight * remain / (iconHeight + textHeight);
244         double textRemain = textHeight * remain / (iconHeight + textHeight);
245         double resIcon = icon_.ShrinkHeight(iconRemain);
246         double resText = text_.ShrinkHeight(textRemain);
247         if (!NearEqual(resIcon, 0.0)) {
248             text_.ShrinkHeight(resIcon);
249         } else if (!NearEqual(resText, 0.0)) {
250             icon_.ShrinkHeight(resText);
251         }
252     }
253     isNeedReadaptWidth_ = true;
254     MeasureIntegralSize();
255     return componentHeight_;
256 }
257 
EnlargeHeight(double diff)258 double SecurityComponentLayoutAlgorithm::EnlargeHeight(double diff)
259 {
260     double remain = top_.EnlargeHeight(diff / HALF);
261     remain = bottom_.EnlargeHeight(remain + (diff / HALF));
262     remain = top_.EnlargeHeight(remain);
263     if (GreatNotEqual(remain, 0.0) && isVertical_) {
264         middle_.EnlargeHeight(remain);
265     }
266     MeasureIntegralSize();
267     return componentHeight_;
268 }
269 
AdaptWidth()270 void SecurityComponentLayoutAlgorithm::AdaptWidth()
271 {
272     if (idealWidth_ != 0.0) {
273         if (componentWidth_ > idealWidth_) {
274             ShrinkWidth(componentWidth_ - idealWidth_);
275         } else if (componentWidth_ < idealWidth_) {
276             EnlargeWidth(idealWidth_ - componentWidth_);
277         }
278         return;
279     }
280 
281     if (componentWidth_ > maxWidth_) {
282         ShrinkWidth(componentWidth_ - maxWidth_);
283     } else if (componentWidth_ < minWidth_) {
284         EnlargeWidth(minWidth_ - componentWidth_);
285     }
286 }
287 
AdaptHeight()288 void SecurityComponentLayoutAlgorithm::AdaptHeight()
289 {
290     if (idealHeight_ != 0.0) {
291         if (componentHeight_ > idealHeight_) {
292             ShrinkHeight(componentHeight_ - idealHeight_);
293         } else if (componentHeight_ < idealHeight_) {
294             EnlargeHeight(idealHeight_ - componentHeight_);
295         }
296         return;
297     }
298     if (componentHeight_ > maxHeight_) {
299         ShrinkHeight(componentHeight_ - maxHeight_);
300     } else if (componentHeight_ < minHeight_) {
301         EnlargeHeight(minHeight_ - componentHeight_);
302     }
303 }
304 
MeasureIntegralSize()305 void SecurityComponentLayoutAlgorithm::MeasureIntegralSize()
306 {
307     if (isVertical_) {
308         double contextWidth = std::max(text_.width_, icon_.width_);
309         componentHeight_ = top_.height_ + text_.height_ +
310             middle_.height_ + icon_.height_ + bottom_.height_;
311         componentWidth_ = left_.width_ + contextWidth + right_.width_;
312     } else {
313         double contextHeight = std::max(text_.height_, icon_.height_);
314         componentHeight_ = top_.height_ + contextHeight + bottom_.height_;
315         componentWidth_ = left_.width_ + icon_.width_ +
316             middle_.width_ + text_.width_ + right_.width_;
317     }
318 }
319 
UpdateVerticalOffset(OffsetF & offsetIcon,OffsetF & offsetText)320 void SecurityComponentLayoutAlgorithm::UpdateVerticalOffset(OffsetF& offsetIcon,
321     OffsetF& offsetText)
322 {
323     offsetText = offsetIcon + OffsetF(0.0, icon_.height_ + middle_.height_);
324     if (icon_.width_ > text_.width_) {
325         offsetText += OffsetF((icon_.width_ - text_.width_) / HALF, 0.0);
326     } else {
327         offsetIcon += OffsetF((text_.width_ - icon_.width_) / HALF, 0.0);
328     }
329 }
330 
UpdateHorizontalOffset(LayoutWrapper * layoutWrapper,OffsetF & offsetIcon,OffsetF & offsetText)331 void SecurityComponentLayoutAlgorithm::UpdateHorizontalOffset(LayoutWrapper* layoutWrapper,
332     OffsetF& offsetIcon, OffsetF& offsetText)
333 {
334     if (GetTextDirection(layoutWrapper) == TextDirection::RTL) {
335         offsetIcon = offsetText +
336             OffsetF(text_.width_ + middle_.width_, 0.0);
337     } else {
338         offsetText = offsetIcon +
339             OffsetF(icon_.width_ + middle_.width_, 0.0);
340     }
341     if (icon_.height_ > text_.height_) {
342         offsetText +=
343             OffsetF(0.0, (icon_.height_ - text_.height_) / HALF);
344     } else {
345         offsetIcon +=
346             OffsetF(0.0, (text_.height_ - icon_.height_) / HALF);
347     }
348 }
349 
Layout(LayoutWrapper * layoutWrapper)350 void SecurityComponentLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
351 {
352     CHECK_NULL_VOID(layoutWrapper);
353     OffsetF offsetIcon = OffsetF(left_.width_, top_.height_);
354     OffsetF offsetText = OffsetF(left_.width_, top_.height_);
355     if (isVertical_) {
356         UpdateVerticalOffset(offsetIcon, offsetText);
357     } else {
358         UpdateHorizontalOffset(layoutWrapper, offsetIcon, offsetText);
359     }
360 
361     UpdateChildPosition(layoutWrapper, V2::IMAGE_ETS_TAG, offsetIcon);
362     UpdateChildPosition(layoutWrapper, V2::TEXT_ETS_TAG, offsetText);
363 
364     for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
365         child->Layout();
366     }
367 }
368 
UpdateCircleButtonConstraint()369 void SecurityComponentLayoutAlgorithm::UpdateCircleButtonConstraint()
370 {
371     double circleIdealSize = std::max(componentWidth_, componentHeight_);
372     if ((idealWidth_ != 0.0) && (idealHeight_ != 0.0)) {
373         circleIdealSize = std::min(idealWidth_, idealHeight_);
374     } else if (idealWidth_ != 0.0) {
375         circleIdealSize = idealWidth_;
376     } else if (idealHeight_ != 0.0) {
377         circleIdealSize = idealHeight_;
378     } else {
379         if ((componentWidth_ < minWidth_) || (componentHeight_ < minHeight_)) {
380             circleIdealSize = std::max(minWidth_, minHeight_);
381         } else if ((componentWidth_ > maxWidth_) || (componentHeight_ > maxHeight_)) {
382             circleIdealSize = std::min(maxWidth_, maxHeight_);
383         }
384     }
385     idealWidth_ = idealHeight_ = circleIdealSize;
386 }
387 
FillBlank()388 void SecurityComponentLayoutAlgorithm::FillBlank()
389 {
390     if (isNobg_) {
391         return;
392     }
393     if (GreatNotEqual(idealWidth_, componentWidth_)) {
394         left_.width_ += ((idealWidth_ - componentWidth_) / HALF);
395         right_.width_ += ((idealWidth_ - componentWidth_) / HALF);
396     } else if (GreatNotEqual(minWidth_, componentWidth_)) {
397         left_.width_ += ((minWidth_ - componentWidth_) / HALF);
398         right_.width_ += ((minWidth_ - componentWidth_) / HALF);
399     }
400     if (GreatNotEqual(idealHeight_, componentHeight_)) {
401         top_.height_ += ((idealHeight_ - componentHeight_) / HALF);
402         bottom_.height_ += ((idealHeight_ - componentHeight_) / HALF);
403     } else if (GreatNotEqual(minHeight_, componentHeight_)) {
404         top_.height_ += ((minHeight_ - componentHeight_) / HALF);
405         bottom_.height_ += ((minHeight_ - componentHeight_) / HALF);
406     }
407     MeasureIntegralSize();
408 }
409 
GetSecCompChildNode(RefPtr<FrameNode> & parent,const std::string & tag)410 RefPtr<FrameNode> SecurityComponentLayoutAlgorithm::GetSecCompChildNode(RefPtr<FrameNode>& parent,
411     const std::string& tag)
412 {
413     for (const auto& child : parent->GetChildren()) {
414         auto node = AceType::DynamicCast<FrameNode, UINode>(child);
415         CHECK_NULL_RETURN(node, nullptr);
416         if (node->GetTag() == tag) {
417             return node;
418         }
419     }
420     return nullptr;
421 }
422 
UpdateTextRectPoint()423 void SecurityComponentLayoutAlgorithm::UpdateTextRectPoint()
424 {
425     if (isVertical_) {
426         if (icon_.width_ > text_.width_) {
427             textLeftTopPoint_ = SizeF(left_.width_ + icon_.width_ / HALF - text_.width_ / HALF,
428                 top_.height_ + icon_.height_ + middle_.height_);
429             textRightTopPoint_ = SizeF(left_.width_ + icon_.width_ / HALF + text_.width_ / HALF,
430                 top_.height_ + icon_.height_ + middle_.height_);
431             textLeftBottomPoint_ = SizeF(left_.width_ + icon_.width_ / HALF - text_.width_ / HALF,
432                 top_.height_ + icon_.height_ + middle_.height_ + text_.height_);
433             textRightBottomPoint_ = SizeF(left_.width_ + icon_.width_ / HALF + text_.width_ / HALF,
434                 top_.height_ + icon_.height_ + middle_.height_ + text_.height_);
435         } else {
436             textLeftTopPoint_ = SizeF(left_.width_, top_.height_ + icon_.height_ + middle_.height_);
437             textRightTopPoint_ = SizeF(left_.width_ + text_.width_, top_.height_ + icon_.height_ + middle_.height_);
438             textLeftBottomPoint_ = SizeF(left_.width_, top_.height_ + icon_.height_ + middle_.height_ + text_.height_);
439             textRightBottomPoint_ = SizeF(left_.width_ + text_.width_,
440                 top_.height_ + icon_.height_ + middle_.height_ + text_.height_);
441         }
442     } else {
443         if (icon_.height_ > text_.height_) {
444             textLeftTopPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_,
445                 top_.height_ + icon_.height_ / HALF - text_.height_ / HALF);
446             textRightTopPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_ + text_.width_,
447                 top_.height_ + icon_.height_ / HALF - text_.height_ / HALF);
448             textLeftBottomPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_,
449                 top_.height_ + icon_.height_ / HALF + text_.height_ / HALF);
450             textRightBottomPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_ + text_.width_,
451                 top_.height_ + icon_.height_ / HALF + text_.height_ / HALF);
452         } else {
453             textLeftTopPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_, top_.height_);
454             textRightTopPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_ + text_.width_, top_.height_);
455             textLeftBottomPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_, top_.height_ + text_.height_);
456             textRightBottomPoint_ = SizeF(left_.width_ + icon_.width_ + middle_.width_ + text_.width_,
457                 top_.height_ + text_.height_);
458         }
459     }
460 }
461 
IsTextAdaptOutOfRange(SizeF & leftPoint,SizeF & rightPoint,SizeF & circlePoint,float maxDistance)462 bool SecurityComponentLayoutAlgorithm::IsTextAdaptOutOfRange(SizeF& leftPoint, SizeF& rightPoint, SizeF& circlePoint,
463     float maxDistance)
464 {
465     if (LessOrEqual(rightPoint.Width(), circlePoint.Width())) {
466         return true;
467     }
468 
469     auto pointDistance = rightPoint.Width() - circlePoint.Width();
470     auto maxSpaceToShrink = rightPoint.Width() - leftPoint.Width();
471     maxSpaceToShrink = GreatNotEqual(maxSpaceToShrink, pointDistance) ? pointDistance : maxSpaceToShrink;
472     auto threshold = currentFontSize_.ConvertToPx() * (1.0 - TEXT_OUT_OF_WIDTH_PERCENT);
473     auto res = text_.TryShrinkTextWidth(rightPoint, circlePoint, maxSpaceToShrink, maxDistance, threshold);
474     if (res) {
475         UpdateTextRectPoint();
476         return false;
477     }
478     return true;
479 }
480 
IsTextOutOfRangeInCircle()481 bool SecurityComponentLayoutAlgorithm::IsTextOutOfRangeInCircle()
482 {
483     auto circlePoint = SizeF(componentWidth_ / HALF, componentHeight_ / HALF);
484     auto threshold = TEXT_OUT_OF_RANGE_PERCENT * RANGE_RATIO * currentFontSize_.ConvertToPx();
485     auto maxDistance = pow(circlePoint.Width() + threshold);
486     auto leftTopDistance = pow(textLeftTopPoint_.Width() - circlePoint.Width()) +
487         pow(textLeftTopPoint_.Height() - circlePoint.Height());
488     if (GreatNotEqual(leftTopDistance, maxDistance)) {
489         return true;
490     }
491     auto leftBottomDistance = pow(textLeftBottomPoint_.Width() - circlePoint.Width()) +
492         pow(textLeftBottomPoint_.Height() - circlePoint.Height());
493     if (GreatNotEqual(leftBottomDistance, maxDistance)) {
494         return true;
495     }
496     auto rightTopDistance = pow(textRightTopPoint_.Width() - circlePoint.Width()) +
497         pow(textRightTopPoint_.Height() - circlePoint.Height());
498     if (GreatNotEqual(rightTopDistance, maxDistance) && IsTextAdaptOutOfRange(textLeftTopPoint_,
499         textRightTopPoint_, circlePoint, maxDistance)) {
500         return true;
501     }
502     auto rightBottomDistance = pow(textRightBottomPoint_.Width() - circlePoint.Width()) +
503         pow(textRightBottomPoint_.Height() - circlePoint.Height());
504     if (GreatNotEqual(rightBottomDistance, maxDistance) && IsTextAdaptOutOfRange(textLeftBottomPoint_,
505         textRightBottomPoint_, circlePoint, maxDistance)) {
506         return true;
507     }
508     return false;
509 }
510 
CompareDistance(SizeF & point,SizeF & circlePoint,float maxDistance)511 bool SecurityComponentLayoutAlgorithm::CompareDistance(SizeF& point, SizeF& circlePoint, float maxDistance)
512 {
513     auto distance = pow(point.Width() - circlePoint.Width()) + pow(point.Height() - circlePoint.Height());
514     if (GreatNotEqual(distance, maxDistance)) {
515         return true;
516     }
517     return false;
518 }
519 
IsOutOfRangeInHoriCapsule(SizeF & leftCirclePoint,SizeF & rightCirclePoint,float maxDistance)520 bool SecurityComponentLayoutAlgorithm::IsOutOfRangeInHoriCapsule(SizeF& leftCirclePoint, SizeF& rightCirclePoint,
521     float maxDistance)
522 {
523     if (GreatNotEqual(textRightTopPoint_.Width(), rightCirclePoint.Width()) &&
524         LessNotEqual(textRightTopPoint_.Height(), rightCirclePoint.Height())) {
525         if (CompareDistance(textRightTopPoint_, rightCirclePoint, maxDistance) &&
526             IsTextAdaptOutOfRange(textLeftTopPoint_, textRightTopPoint_, rightCirclePoint, maxDistance)) {
527             return true;
528         }
529     }
530     if (LessNotEqual(textLeftBottomPoint_.Width(), leftCirclePoint.Width()) &&
531         GreatNotEqual(textLeftBottomPoint_.Height(), leftCirclePoint.Height())) {
532         if (CompareDistance(textLeftBottomPoint_, leftCirclePoint, maxDistance)) {
533             return true;
534         }
535     }
536     return false;
537 }
538 
IsOutOfRangeInVertiCapsule(SizeF & topCirclePoint,SizeF & bottomCirclePoint,float maxDistance)539 bool SecurityComponentLayoutAlgorithm::IsOutOfRangeInVertiCapsule(SizeF& topCirclePoint, SizeF& bottomCirclePoint,
540     float maxDistance)
541 {
542     if (GreatNotEqual(textRightTopPoint_.Width(), topCirclePoint.Width()) &&
543         LessNotEqual(textRightTopPoint_.Height(), topCirclePoint.Height())) {
544         if (CompareDistance(textRightTopPoint_, topCirclePoint, maxDistance) &&
545             IsTextAdaptOutOfRange(textLeftTopPoint_, textRightTopPoint_, topCirclePoint, maxDistance)) {
546             return true;
547         }
548     }
549     if (LessNotEqual(textLeftBottomPoint_.Width(), bottomCirclePoint.Width()) &&
550         GreatNotEqual(textLeftBottomPoint_.Height(), bottomCirclePoint.Height())) {
551         if (CompareDistance(textLeftBottomPoint_, bottomCirclePoint, maxDistance)) {
552             return true;
553         }
554     }
555     return false;
556 }
557 
IsTextOutOfRangeInCapsule()558 bool SecurityComponentLayoutAlgorithm::IsTextOutOfRangeInCapsule()
559 {
560     SizeF rightBottomCirclePoint;
561     auto capsuleRadius = std::min(componentWidth_, componentHeight_) / HALF;
562     auto maxDistance = pow(capsuleRadius + TEXT_OUT_OF_RANGE_PERCENT * RANGE_RATIO * currentFontSize_.ConvertToPx());
563     auto leftTopCirclePoint = SizeF(capsuleRadius, capsuleRadius);
564     if (LessNotEqual(textLeftTopPoint_.Width(), leftTopCirclePoint.Width()) &&
565         LessNotEqual(textLeftTopPoint_.Height(), leftTopCirclePoint.Height())) {
566         if (CompareDistance(textLeftTopPoint_, leftTopCirclePoint, maxDistance)) {
567             return true;
568         }
569     }
570     if (GreatOrEqual(componentWidth_, componentHeight_)) {
571         rightBottomCirclePoint = SizeF(componentWidth_ - capsuleRadius, capsuleRadius);
572         auto res = IsOutOfRangeInHoriCapsule(leftTopCirclePoint, rightBottomCirclePoint, maxDistance);
573         if (res) {
574             return res;
575         }
576     } else {
577         rightBottomCirclePoint = SizeF(capsuleRadius, componentHeight_ - capsuleRadius);
578         auto res = IsOutOfRangeInVertiCapsule(leftTopCirclePoint, rightBottomCirclePoint, maxDistance);
579         if (res) {
580             return res;
581         }
582     }
583     if (GreatNotEqual(textRightBottomPoint_.Width(), rightBottomCirclePoint.Width()) &&
584         GreatNotEqual(textRightBottomPoint_.Height(), rightBottomCirclePoint.Height())) {
585         if (CompareDistance(textRightBottomPoint_, rightBottomCirclePoint, maxDistance) &&
586             IsTextAdaptOutOfRange(textLeftBottomPoint_, textRightBottomPoint_, rightBottomCirclePoint, maxDistance)) {
587             return true;
588         }
589     }
590     return false;
591 }
592 
TopLeftCompDistance(float obtainedRadius,float maxRadius,float threshold)593 bool SecurityComponentLayoutAlgorithm::TopLeftCompDistance(float obtainedRadius, float maxRadius, float threshold)
594 {
595     auto radius = GreatNotEqual(obtainedRadius, maxRadius) ? maxRadius : obtainedRadius;
596     auto circlePoint = SizeF(radius, radius);
597     if (LessNotEqual(textLeftTopPoint_.Width(), circlePoint.Width()) &&
598         LessNotEqual(textLeftTopPoint_.Height(), circlePoint.Height())) {
599         auto distance = pow(textLeftTopPoint_.Width() - circlePoint.Width()) +
600             pow(textLeftTopPoint_.Height() - circlePoint.Height());
601         auto maxDistance = pow(radius + threshold);
602         if (GreatNotEqual(distance, maxDistance)) {
603             return true;
604         }
605     }
606     return false;
607 }
608 
BottomLeftCompDistance(float obtainedRadius,float maxRadius,float threshold)609 bool SecurityComponentLayoutAlgorithm::BottomLeftCompDistance(float obtainedRadius, float maxRadius, float threshold)
610 {
611     auto radius = GreatNotEqual(obtainedRadius, maxRadius) ? maxRadius : obtainedRadius;
612     auto circlePoint = SizeF(radius, componentHeight_ - radius);
613     if (LessNotEqual(textLeftBottomPoint_.Width(), circlePoint.Width()) &&
614         GreatNotEqual(textLeftBottomPoint_.Height(), circlePoint.Height())) {
615         auto distance = pow(textLeftBottomPoint_.Width() - circlePoint.Width()) +
616             pow(textLeftBottomPoint_.Height() - circlePoint.Height());
617         auto maxDistance = pow(radius + threshold);
618         if (GreatNotEqual(distance, maxDistance)) {
619             return true;
620         }
621     }
622     return false;
623 }
624 
TopRightCompDistance(float obtainedRadius,float maxRadius,float threshold)625 bool SecurityComponentLayoutAlgorithm::TopRightCompDistance(float obtainedRadius, float maxRadius, float threshold)
626 {
627     auto radius = GreatNotEqual(obtainedRadius, maxRadius) ? maxRadius : obtainedRadius;
628     auto circlePoint = SizeF(componentWidth_ - radius, radius);
629     if (GreatNotEqual(textRightTopPoint_.Width(), circlePoint.Width()) &&
630         LessNotEqual(textRightTopPoint_.Height(), circlePoint.Height())) {
631         auto distance = pow(textRightTopPoint_.Width() - circlePoint.Width()) +
632             pow(textRightTopPoint_.Height() - circlePoint.Height());
633         auto maxDistance = pow(radius + threshold);
634         if (GreatNotEqual(distance, maxDistance) && IsTextAdaptOutOfRange(textLeftTopPoint_,
635             textRightTopPoint_, circlePoint, maxDistance)) {
636             return true;
637         }
638     }
639     return false;
640 }
641 
BottomRightCompDistance(float obtainedRadius,float maxRadius,float threshold)642 bool SecurityComponentLayoutAlgorithm::BottomRightCompDistance(float obtainedRadius, float maxRadius, float threshold)
643 {
644     auto radius = GreatNotEqual(obtainedRadius, maxRadius) ? maxRadius : obtainedRadius;
645     auto circlePoint = SizeF(componentWidth_ - radius, componentHeight_ - radius);
646     if (GreatNotEqual(textRightBottomPoint_.Width(), circlePoint.Width()) &&
647         GreatNotEqual(textRightBottomPoint_.Height(), circlePoint.Height())) {
648         auto distance = pow(textRightBottomPoint_.Width() - circlePoint.Width()) +
649             pow(textRightBottomPoint_.Height() - circlePoint.Height());
650         auto maxDistance = pow(radius + threshold);
651         if (GreatNotEqual(distance, maxDistance) && IsTextAdaptOutOfRange(textLeftBottomPoint_,
652             textRightBottomPoint_, circlePoint, maxDistance)) {
653             return true;
654         }
655     }
656     return false;
657 }
658 
IsTextOutOfRangeInNormal()659 bool SecurityComponentLayoutAlgorithm::IsTextOutOfRangeInNormal()
660 {
661     auto borderRadius = buttonLayoutProperty_->GetBorderRadius();
662     if (!borderRadius.has_value()) {
663         return false;
664     }
665     auto maxRadius = std::min(componentWidth_, componentHeight_) / HALF;
666     auto threshold = TEXT_OUT_OF_RANGE_PERCENT * RANGE_RATIO * currentFontSize_.ConvertToPx();
667     if (borderRadius->radiusTopLeft.has_value() &&
668         GreatNotEqual(borderRadius->radiusTopLeft.value().ConvertToPx(), currentFontSize_.ConvertToPx())) {
669         if (TopLeftCompDistance(borderRadius->radiusTopLeft.value().ConvertToPx(), maxRadius, threshold)) {
670             return true;
671         }
672     }
673     if (borderRadius->radiusBottomLeft.has_value() &&
674         GreatNotEqual(borderRadius->radiusBottomLeft.value().ConvertToPx(), currentFontSize_.ConvertToPx())) {
675         if (BottomLeftCompDistance(borderRadius->radiusBottomLeft.value().ConvertToPx(), maxRadius, threshold)) {
676             return true;
677         }
678     }
679     if (borderRadius->radiusTopRight.has_value() &&
680         GreatNotEqual(borderRadius->radiusTopRight.value().ConvertToPx(), currentFontSize_.ConvertToPx())) {
681         if (TopRightCompDistance(borderRadius->radiusTopRight.value().ConvertToPx(), maxRadius, threshold)) {
682             return true;
683         }
684     }
685     if (borderRadius->radiusBottomRight.has_value() &&
686         GreatNotEqual(borderRadius->radiusBottomRight.value().ConvertToPx(), currentFontSize_.ConvertToPx())) {
687         if (BottomRightCompDistance(borderRadius->radiusBottomRight.value().ConvertToPx(), maxRadius, threshold)) {
688             return true;
689         }
690     }
691     return false;
692 }
693 
IsTextOutOfOneColumn(RefPtr<FrameNode> & frameNode,float threshold)694 bool SecurityComponentLayoutAlgorithm::IsTextOutOfOneColumn(RefPtr<FrameNode>& frameNode, float threshold)
695 {
696     auto textNode = GetSecCompChildNode(frameNode, V2::TEXT_ETS_TAG);
697     CHECK_NULL_RETURN(textNode, false);
698     auto textPattern = textNode->GetPattern<TextPattern>();
699     CHECK_NULL_RETURN(textPattern, false);
700     auto realWidth = textPattern->GetLineMetrics(0).width;
701     auto allowWidth = text_.width_ + threshold;
702     if (LessNotEqual(allowWidth, realWidth)) {
703         return true;
704     }
705 
706     return false;
707 }
708 
GetTextLimitExceededFlag(RefPtr<SecurityComponentLayoutProperty> & property,LayoutWrapper * layoutWrapper)709 bool SecurityComponentLayoutAlgorithm::GetTextLimitExceededFlag(RefPtr<SecurityComponentLayoutProperty>& property,
710     LayoutWrapper* layoutWrapper)
711 {
712     CHECK_NULL_RETURN(layoutWrapper, false);
713     auto frameNode = layoutWrapper->GetHostNode();
714     CHECK_NULL_RETURN(frameNode, false);
715     auto buttonNode = GetSecCompChildNode(frameNode, V2::BUTTON_ETS_TAG);
716     CHECK_NULL_RETURN(buttonNode, false);
717     buttonLayoutProperty_ = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
718     CHECK_NULL_RETURN(buttonLayoutProperty_, false);
719 
720     std::optional<SizeF> currentTextSize;
721     auto res = text_.GetCurrentTextSize(currentTextSize, currentFontSize_);
722     if (!res) {
723         return false;
724     }
725 
726     UpdateTextRectPoint();
727 
728     auto isCircle = (property->GetBackgroundType() == static_cast<int32_t>(ButtonType::CIRCLE));
729     auto isCapsule = (property->GetBackgroundType() == static_cast<int32_t>(ButtonType::CAPSULE));
730     if (isCircle) {
731         res = IsTextOutOfRangeInCircle();
732     } else if (isCapsule) {
733         res = IsTextOutOfRangeInCapsule();
734     } else {
735         res = IsTextOutOfRangeInNormal();
736     }
737 
738     if (!res) {
739         auto threshold = currentFontSize_.ConvertToPx() * TEXT_OUT_OF_WIDTH_PERCENT;
740         res = IsTextOutOfOneColumn(frameNode, threshold);
741     }
742 
743     return res;
744 }
745 
Measure(LayoutWrapper * layoutWrapper)746 void SecurityComponentLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
747 {
748     CHECK_NULL_VOID(layoutWrapper);
749     auto securityComponentLayoutProperty =
750         AceType::DynamicCast<SecurityComponentLayoutProperty>(layoutWrapper->GetLayoutProperty());
751     CHECK_NULL_VOID(securityComponentLayoutProperty);
752 
753     auto iconWrapper = GetChildWrapper(layoutWrapper, V2::IMAGE_ETS_TAG);
754     icon_.Init(securityComponentLayoutProperty, iconWrapper);
755 
756     auto textWrapper = GetChildWrapper(layoutWrapper, V2::TEXT_ETS_TAG);
757     text_.Init(securityComponentLayoutProperty, textWrapper);
758 
759     constraint_ = securityComponentLayoutProperty->GetContentLayoutConstraint();
760     CHECK_NULL_VOID(constraint_);
761     isVertical_ = (securityComponentLayoutProperty->GetTextIconLayoutDirection().value() ==
762         SecurityComponentLayoutDirection::VERTICAL);
763     isNobg_ = (securityComponentLayoutProperty->GetBackgroundType().value() == BUTTON_TYPE_NULL);
764     idealWidth_ = constraint_->selfIdealSize.Width().value_or(0.0);
765     idealHeight_ = constraint_->selfIdealSize.Height().value_or(0.0);
766     minWidth_ = constraint_->minSize.Width();
767     minHeight_ = constraint_->minSize.Height();
768     maxWidth_ = constraint_->maxSize.Width();
769     maxHeight_ = constraint_->maxSize.Height();
770     InitPadding(securityComponentLayoutProperty);
771     if (GetTextDirection(layoutWrapper) == TextDirection::RTL) {
772         PaddingLayoutElement temp = left_;
773         left_ = right_;
774         right_ = temp;
775     }
776 
777     MeasureIntegralSize();
778 
779     if (securityComponentLayoutProperty->GetBackgroundType() == static_cast<int32_t>(ButtonType::CIRCLE)) {
780         UpdateCircleButtonConstraint();
781     }
782     AdaptWidth();
783     AdaptHeight();
784     if (isNeedReadaptWidth_) {
785         AdaptWidth();
786     }
787     // fill blank when all paddings can not be enlarged because it has been set
788     FillBlank();
789 
790     icon_.DoMeasure();
791     MeasureButton(layoutWrapper, securityComponentLayoutProperty);
792     auto geometryNode = layoutWrapper->GetGeometryNode();
793     CHECK_NULL_VOID(geometryNode);
794     geometryNode->SetFrameSize(SizeF(componentWidth_, componentHeight_));
795     securityComponentLayoutProperty->UpdateIsTextLimitExceeded(GetTextLimitExceededFlag(securityComponentLayoutProperty,
796         layoutWrapper));
797 }
798 
GetTextDirection(LayoutWrapper * layoutWrapper)799 TextDirection SecurityComponentLayoutAlgorithm::GetTextDirection(LayoutWrapper* layoutWrapper)
800 {
801     auto frameNode = layoutWrapper->GetHostNode();
802     // default return LTR
803     CHECK_NULL_RETURN(frameNode, TextDirection::LTR);
804     std::string text = "";
805     // get button string
806     for (const auto& child : frameNode->GetChildren()) {
807         auto node = AceType::DynamicCast<FrameNode, UINode>(child);
808         if (node == nullptr) {
809             continue;
810         }
811         if (node->GetTag() == V2::TEXT_ETS_TAG) {
812             auto textLayoutProperty = node->GetLayoutProperty<TextLayoutProperty>();
813             if (textLayoutProperty == nullptr) {
814                 continue;
815             }
816             text = textLayoutProperty->GetContentValue(text);
817             break;
818         }
819     }
820     if (text.empty()) {
821         return TextDirection::LTR;
822     }
823     auto wString = StringUtils::ToWstring(text);
824     for (const auto& charInStr : wString) {
825         auto direction = u_charDirection(charInStr);
826         if (direction == UCharDirection::U_LEFT_TO_RIGHT) {
827             return TextDirection::LTR;
828         }
829         if (direction == UCharDirection::U_RIGHT_TO_LEFT || direction == UCharDirection::U_RIGHT_TO_LEFT_ARABIC) {
830             return TextDirection::RTL;
831         }
832     }
833     return TextDirection::LTR;
834 }
835 } // namespace OHOS::Ace::NG
836