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