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