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