• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/button/button_layout_algorithm.h"
17 
18 #include "core/components/toggle/toggle_theme.h"
19 #include "core/components_ng/pattern/button/button_pattern.h"
20 #include "core/components_ng/property/measure_utils.h"
21 
22 namespace OHOS::Ace::NG {
23 namespace {
checkNegativeBorderRadius(std::optional<Dimension> & radius,const float defaultBorderRadius)24 void checkNegativeBorderRadius(std::optional<Dimension>& radius, const float defaultBorderRadius)
25 {
26     // Change the borderRadius size of a negative number to the default.
27     if (!radius.has_value() || LessNotEqual(radius.value().ConvertToPx(), 0.0)) {
28         radius = Dimension(defaultBorderRadius);
29     }
30 }
31 }
Measure(LayoutWrapper * layoutWrapper)32 void ButtonLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
33 {
34     auto host = layoutWrapper->GetHostNode();
35     CHECK_NULL_VOID(host);
36     auto pattern = host->GetPattern<ButtonPattern>();
37     CHECK_NULL_VOID(pattern);
38     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
39     CHECK_NULL_VOID(buttonLayoutProperty);
40     bool isEnableChildrenMatchParent = pattern->IsEnableChildrenMatchParent();
41     if (buttonLayoutProperty->HasType() && buttonLayoutProperty->GetType() == ButtonType::CIRCLE &&
42         !pattern->GetHasCustomPadding()) {
43         NG::PaddingProperty paddings;
44         paddings.top = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
45         paddings.bottom = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
46         paddings.left = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
47         paddings.right = std::optional<CalcLength>(CalcLength(0.0, DimensionUnit::VP));
48         buttonLayoutProperty->UpdatePadding(paddings);
49     }
50     if (pattern->UseContentModifier()) {
51         const auto& childList = layoutWrapper->GetAllChildrenWithBuild();
52         std::list<RefPtr<LayoutWrapper>> builderChildList;
53         for (const auto& child : childList) {
54             if (child->GetHostNode()->GetId() != pattern->GetBuilderId()) {
55                 child->GetGeometryNode()->Reset();
56                 child->GetGeometryNode()->SetContentSize(SizeF());
57             } else {
58                 auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
59                 child->Measure(layoutConstraint);
60                 builderChildList.push_back(child);
61             }
62         }
63         BoxLayoutAlgorithm::PerformMeasureSelfWithChildList(layoutWrapper, builderChildList);
64         return;
65     }
66     auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
67     HandleChildLayoutConstraint(layoutWrapper, layoutConstraint);
68     if (buttonLayoutProperty->HasLabel()) {
69         // If the button has label, according to whether the font size is set to do the corresponding expansion button,
70         // font reduction, truncation and other operations.
71         HandleAdaptiveText(layoutWrapper, layoutConstraint);
72     } else {
73         // If the button has not label, measure the child directly.
74         for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
75             auto childLayoutProperty = child->GetLayoutProperty();
76             CHECK_NULL_CONTINUE(childLayoutProperty);
77             if (isEnableChildrenMatchParent &&
78                 ProcessLayoutPolicyIsNotNoMatch(childLayoutProperty->GetLayoutPolicyProperty())) {
79                 layoutPolicyChildren_.emplace_back(child);
80                 continue;
81             }
82             child->Measure(layoutConstraint);
83         }
84     }
85     PerformMeasureSelf(layoutWrapper);
86     if (isEnableChildrenMatchParent) {
87         auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
88         MeasureAdaptiveLayoutChildren(layoutWrapper, frameSize);
89     }
90 }
91 
ProcessLayoutPolicyIsNotNoMatch(std::optional<NG::LayoutPolicyProperty> layoutPolicy)92 bool ButtonLayoutAlgorithm::ProcessLayoutPolicyIsNotNoMatch(std::optional<NG::LayoutPolicyProperty> layoutPolicy)
93 {
94     if (layoutPolicy.has_value()) {
95         auto widthLayoutPolicy = layoutPolicy.value().widthLayoutPolicy_;
96         auto heightLayoutPolicy = layoutPolicy.value().heightLayoutPolicy_;
97         if (widthLayoutPolicy.value_or(LayoutCalPolicy::NO_MATCH) != LayoutCalPolicy::NO_MATCH ||
98             heightLayoutPolicy.value_or(LayoutCalPolicy::NO_MATCH) != LayoutCalPolicy::NO_MATCH) {
99             return true;
100         }
101         return false;
102     }
103     return false;
104 }
105 
HandleChildLayoutConstraint(LayoutWrapper * layoutWrapper,LayoutConstraintF & layoutConstraint)106 void ButtonLayoutAlgorithm::HandleChildLayoutConstraint(
107     LayoutWrapper* layoutWrapper, LayoutConstraintF& layoutConstraint)
108 {
109     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
110     CHECK_NULL_VOID(buttonLayoutProperty);
111     if (!buttonLayoutProperty->HasLabel()) {
112         return;
113     }
114     auto buttonType = buttonLayoutProperty->GetType().value_or(ButtonType::CAPSULE);
115     if (buttonType == ButtonType::CIRCLE) {
116         layoutConstraint.maxSize = HandleLabelCircleButtonConstraint(layoutWrapper).value_or(SizeF());
117         return;
118     }
119     const auto& selfLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
120     // If height is not set, apply the default height.
121     if (selfLayoutConstraint && !selfLayoutConstraint->selfIdealSize.Height().has_value()) {
122         auto maxHeight = selfLayoutConstraint->maxSize.Height();
123         if (IsAging(layoutWrapper)) {
124             layoutConstraint.maxSize.SetHeight(maxHeight);
125             return;
126         }
127         auto defaultHeight = GetDefaultHeight(layoutWrapper);
128         layoutConstraint.maxSize.SetHeight(maxHeight > defaultHeight ? defaultHeight : maxHeight);
129     }
130 }
131 
132 // If the ButtonType is CIRCLE, then omit text by the smaller edge.
HandleLabelCircleButtonConstraint(LayoutWrapper * layoutWrapper)133 std::optional<SizeF> ButtonLayoutAlgorithm::HandleLabelCircleButtonConstraint(LayoutWrapper* layoutWrapper)
134 {
135     SizeF constraintSize;
136     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
137     CHECK_NULL_RETURN(buttonLayoutProperty, constraintSize);
138     const auto& selfLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
139     CHECK_NULL_RETURN(selfLayoutConstraint, constraintSize);
140     auto host = layoutWrapper->GetHostNode();
141     CHECK_NULL_RETURN(host, constraintSize);
142     auto* context = host->GetContextWithCheck();
143     CHECK_NULL_RETURN(context, constraintSize);
144     auto buttonTheme = context->GetTheme<ButtonTheme>();
145     CHECK_NULL_RETURN(buttonTheme, constraintSize);
146     const auto& padding = buttonLayoutProperty->CreatePaddingAndBorder();
147     auto defaultHeight = GetDefaultHeight(layoutWrapper);
148     float minLength = 0.0f;
149     if (selfLayoutConstraint->selfIdealSize.IsNull()) {
150         // Width and height are not set.
151         minLength = defaultHeight;
152     } else if (selfLayoutConstraint->selfIdealSize.Width().has_value() &&
153                !selfLayoutConstraint->selfIdealSize.Height().has_value()) {
154         // Only width is set.
155         minLength = selfLayoutConstraint->selfIdealSize.Width().value();
156     } else if (selfLayoutConstraint->selfIdealSize.Height().has_value() &&
157                !selfLayoutConstraint->selfIdealSize.Width().has_value()) {
158         // Only height is set.
159         minLength = selfLayoutConstraint->selfIdealSize.Height().value();
160     } else {
161         // Both width and height are set.
162         auto buttonWidth = selfLayoutConstraint->selfIdealSize.Width().value();
163         auto buttonHeight = selfLayoutConstraint->selfIdealSize.Height().value();
164         minLength = std::min(buttonWidth, buttonHeight);
165     }
166     if (buttonLayoutProperty->HasBorderRadius() && selfLayoutConstraint->selfIdealSize.IsNull()) {
167         auto radius =
168             static_cast<float>(GetFirstValidRadius(buttonLayoutProperty->GetBorderRadius().value()).ConvertToPx());
169         minLength = 2 * radius;
170     }
171     constraintSize.SetSizeT(SizeF(minLength, minLength));
172     MinusPaddingToSize(padding, constraintSize);
173     return ConstrainSize(constraintSize, selfLayoutConstraint->minSize, selfLayoutConstraint->maxSize);
174 }
175 
HandleAdaptiveText(LayoutWrapper * layoutWrapper,LayoutConstraintF & layoutConstraint)176 void ButtonLayoutAlgorithm::HandleAdaptiveText(LayoutWrapper* layoutWrapper, LayoutConstraintF& layoutConstraint)
177 {
178     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
179     CHECK_NULL_VOID(buttonLayoutProperty);
180     auto host = layoutWrapper->GetHostNode();
181     CHECK_NULL_VOID(host);
182     auto* context = host->GetContextWithCheck();
183     CHECK_NULL_VOID(context);
184     auto buttonTheme = context->GetTheme<ButtonTheme>();
185     CHECK_NULL_VOID(buttonTheme);
186     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
187     CHECK_NULL_VOID(childWrapper);
188     if (buttonLayoutProperty->HasFontSize() || buttonLayoutProperty->HasControlSize()) {
189         auto childConstraint = layoutWrapper->GetLayoutProperty()->GetContentLayoutConstraint();
190         childWrapper->Measure(childConstraint);
191         auto textSize = childWrapper->GetGeometryNode()->GetContentSize();
192         // Fonsize is set. When the font height is larger than the button height, make the button fit the font
193         // height.
194         if (GreatOrEqual(textSize.Height(), layoutConstraint.maxSize.Height())) {
195             layoutConstraint.maxSize.SetHeight(textSize.Height());
196         }
197     } else {
198         // Fonsize is not set. When the font width is greater than the button width, dynamically change the font
199         // size to no less than 9sp.
200         auto textLayoutProperty = DynamicCast<TextLayoutProperty>(childWrapper->GetLayoutProperty());
201         CHECK_NULL_VOID(textLayoutProperty);
202         if (buttonTheme->GetIsApplyTextFontSize() && !buttonLayoutProperty->GetMaxFontSize().has_value() &&
203             !buttonLayoutProperty->GetMinFontSize().has_value()) {
204             textLayoutProperty->ResetAdaptMaxFontSize();
205             textLayoutProperty->ResetAdaptMinFontSize();
206         } else {
207             textLayoutProperty->UpdateAdaptMaxFontSize(
208                 buttonLayoutProperty->GetMaxFontSize().value_or(buttonTheme->GetMaxFontSize()));
209             textLayoutProperty->UpdateAdaptMinFontSize(
210                 buttonLayoutProperty->GetMinFontSize().value_or(buttonTheme->GetMinFontSize()));
211         }
212     }
213     childWrapper->Measure(layoutConstraint);
214     childSize_ = childWrapper->GetGeometryNode()->GetContentSize();
215 }
216 
HandleBorderRadius(LayoutWrapper * layoutWrapper)217 void ButtonLayoutAlgorithm::HandleBorderRadius(LayoutWrapper* layoutWrapper)
218 {
219     auto host = layoutWrapper->GetHostNode();
220     CHECK_NULL_VOID(host);
221     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
222     CHECK_NULL_VOID(buttonLayoutProperty);
223     auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
224     auto renderContext = host->GetRenderContext();
225     CHECK_NULL_VOID(renderContext);
226     auto buttonType = buttonLayoutProperty->GetType().value_or(ButtonType::CAPSULE);
227     if (buttonType == ButtonType::CIRCLE) {
228         auto minSize = std::min(frameSize.Height(), frameSize.Width());
229         auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
230         if (buttonLayoutProperty->HasBorderRadius() && layoutConstraint.parentIdealSize.IsNull()) {
231             auto borderRadius = buttonLayoutProperty->GetBorderRadius().value_or(NG::BorderRadiusProperty());
232             minSize = static_cast<float>(GetFirstValidRadius(borderRadius).ConvertToPx() * 2);
233         }
234         renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(minSize / 2)));
235         MeasureCircleButton(layoutWrapper);
236     } else if (buttonType == ButtonType::CAPSULE) {
237         renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(frameSize.Height() / 2)));
238     } else if (buttonType == ButtonType::NORMAL) {
239         auto normalRadius = buttonLayoutProperty->GetBorderRadiusValue(BorderRadiusProperty(Dimension()));
240         renderContext->UpdateBorderRadius(normalRadius);
241     } else if (buttonType == ButtonType::ROUNDED_RECTANGLE) {
242         auto defaultBorderRadius = GetDefaultBorderRadius(layoutWrapper);
243         auto roundedRectRadius =
244             buttonLayoutProperty->GetBorderRadiusValue(BorderRadiusProperty(Dimension(defaultBorderRadius)));
245         checkNegativeBorderRadius(roundedRectRadius.radiusTopLeft, defaultBorderRadius);
246         checkNegativeBorderRadius(roundedRectRadius.radiusTopRight, defaultBorderRadius);
247         checkNegativeBorderRadius(roundedRectRadius.radiusBottomLeft, defaultBorderRadius);
248         checkNegativeBorderRadius(roundedRectRadius.radiusBottomRight, defaultBorderRadius);
249         renderContext->UpdateBorderRadius(roundedRectRadius);
250     }
251 }
252 
IsMatchParentWidthOrHeight(LayoutConstraintF & layoutConstraint,std::optional<NG::LayoutPolicyProperty> layoutPolicy,LayoutWrapper * layoutWrapper)253 void IsMatchParentWidthOrHeight(LayoutConstraintF& layoutConstraint,
254     std::optional<NG::LayoutPolicyProperty> layoutPolicy, LayoutWrapper* layoutWrapper)
255 {
256     auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
257     if (layoutPolicy.has_value() && layoutPolicy->IsMatch()) {
258         if (layoutPolicy->IsWidthMatch()) {
259             layoutConstraint.parentIdealSize.SetWidth(frameSize.Width());
260         }
261         if (layoutPolicy->IsHeightMatch()) {
262             layoutConstraint.parentIdealSize.SetHeight(frameSize.Height());
263         }
264     }
265 }
266 
UpdateHeightIfMatchPolicy(std::optional<NG::LayoutPolicyProperty> layoutPolicy,SizeF & frameSize,float matchParentHeight)267 void UpdateHeightIfMatchPolicy(std::optional<NG::LayoutPolicyProperty> layoutPolicy, SizeF& frameSize,
268     float matchParentHeight)
269 {
270     if (layoutPolicy.has_value() && layoutPolicy->IsHeightMatch()) {
271         frameSize.SetHeight(matchParentHeight);
272     }
273 }
274 
275 // Called to perform measure current render node.
PerformMeasureSelf(LayoutWrapper * layoutWrapper)276 void ButtonLayoutAlgorithm::PerformMeasureSelf(LayoutWrapper* layoutWrapper)
277 {
278     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
279     CHECK_NULL_VOID(buttonLayoutProperty);
280     BoxLayoutAlgorithm::PerformMeasureSelf(layoutWrapper);
281     auto frameSize = layoutWrapper->GetGeometryNode()->GetFrameSize();
282     auto matchParentHeight = frameSize.Height();
283     if (NeedAgingMeasure(layoutWrapper)) {
284         return;
285     }
286     auto layoutPolicy = buttonLayoutProperty->GetLayoutPolicyProperty();
287     if (buttonLayoutProperty->HasLabel()) {
288         auto layoutConstraint = layoutWrapper->GetLayoutProperty()->CreateChildConstraint();
289         const auto& selfLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
290         auto padding = buttonLayoutProperty->CreatePaddingAndBorder();
291         auto topPadding = padding.top.value_or(0.0);
292         auto bottomPadding = padding.bottom.value_or(0.0);
293         auto host = layoutWrapper->GetHostNode();
294         CHECK_NULL_VOID(host);
295         auto* context = host->GetContextWithCheck();
296         CHECK_NULL_VOID(context);
297         auto buttonTheme = context->GetTheme<ButtonTheme>();
298         CHECK_NULL_VOID(buttonTheme);
299 
300         auto defaultHeight = GetDefaultHeight(layoutWrapper);
301         auto buttonType = buttonLayoutProperty->GetType().value_or(ButtonType::CAPSULE);
302         if (buttonType == ButtonType::CIRCLE) {
303             IsMatchParentWidthOrHeight(layoutConstraint, layoutPolicy, layoutWrapper);
304             HandleLabelCircleButtonFrameSize(layoutConstraint, frameSize, defaultHeight);
305         } else {
306             if (selfLayoutConstraint && !selfLayoutConstraint->selfIdealSize.Height().has_value()) {
307                 auto layoutContraint = buttonLayoutProperty->GetLayoutConstraint();
308                 CHECK_NULL_VOID(layoutContraint);
309                 auto maxHeight = layoutContraint->maxSize.Height();
310                 auto minHeight = layoutContraint->minSize.Height();
311                 auto actualHeight = static_cast<float>(childSize_.Height() + topPadding + bottomPadding);
312                 actualHeight = std::min(actualHeight, maxHeight);
313                 actualHeight = std::max(actualHeight, minHeight);
314                 frameSize.SetHeight(maxHeight > defaultHeight ? std::max(defaultHeight, actualHeight) : maxHeight);
315                 UpdateHeightIfMatchPolicy(layoutPolicy, frameSize, matchParentHeight);
316             }
317         }
318         // Determine if the button needs to fit the font size.
319         if (buttonLayoutProperty->HasFontSize()) {
320             if (GreatOrEqual(childSize_.Height() + topPadding + bottomPadding, frameSize.Height())) {
321                 frameSize = SizeF(frameSize.Width(), childSize_.Height() + topPadding + bottomPadding);
322             }
323         }
324         layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize);
325     }
326     HandleBorderRadius(layoutWrapper);
327 }
328 
HandleLabelCircleButtonFrameSize(const LayoutConstraintF & layoutConstraint,SizeF & frameSize,const float & defaultHeight)329 void ButtonLayoutAlgorithm::HandleLabelCircleButtonFrameSize(
330     const LayoutConstraintF& layoutConstraint, SizeF& frameSize, const float& defaultHeight)
331 {
332     float minLength = 0.0f;
333     if (layoutConstraint.parentIdealSize.IsNull()) {
334         minLength = static_cast<float>(defaultHeight);
335     } else if (layoutConstraint.parentIdealSize.Width().has_value() &&
336                !layoutConstraint.parentIdealSize.Height().has_value()) {
337         minLength = frameSize.Width();
338     } else if (layoutConstraint.parentIdealSize.Height().has_value() &&
339                !layoutConstraint.parentIdealSize.Width().has_value()) {
340         minLength = frameSize.Height();
341     } else {
342         minLength = std::min(frameSize.Width(), frameSize.Height());
343     }
344     frameSize.SetWidth(minLength);
345     frameSize.SetHeight(minLength);
346 }
347 
MeasureCircleButton(LayoutWrapper * layoutWrapper)348 void ButtonLayoutAlgorithm::MeasureCircleButton(LayoutWrapper* layoutWrapper)
349 {
350     auto frameNode = layoutWrapper->GetHostNode();
351     CHECK_NULL_VOID(frameNode);
352     auto context = frameNode->GetRenderContext();
353     CHECK_NULL_VOID(context);
354     const auto& radius = context->GetBorderRadius();
355     SizeF frameSize = { -1, -1 };
356     if (radius.has_value()) {
357         auto radiusTopMax = std::max(radius->radiusTopLeft, radius->radiusTopRight);
358         auto radiusBottomMax = std::max(radius->radiusBottomLeft, radius->radiusBottomRight);
359         auto radiusMax = std::max(radiusTopMax, radiusBottomMax);
360         auto rrectRadius = radiusMax.value_or(0.0_vp).ConvertToPx();
361         frameSize.SetSizeT(SizeF { static_cast<float>(rrectRadius * 2), static_cast<float>(rrectRadius * 2) });
362     }
363     frameSize.UpdateIllegalSizeWithCheck(SizeF { 0.0f, 0.0f });
364     layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize);
365 }
366 
GetFirstValidRadius(const BorderRadiusProperty & borderRadius)367 Dimension ButtonLayoutAlgorithm::GetFirstValidRadius(const BorderRadiusProperty& borderRadius)
368 {
369     if (borderRadius.radiusTopLeft.has_value()) {
370         return borderRadius.radiusTopLeft.value();
371     }
372     if (borderRadius.radiusTopRight.has_value()) {
373         return borderRadius.radiusTopRight.value();
374     }
375     if (borderRadius.radiusBottomLeft.has_value()) {
376         return borderRadius.radiusBottomLeft.value();
377     }
378     if (borderRadius.radiusBottomRight.has_value()) {
379         return borderRadius.radiusBottomRight.value();
380     }
381     return 0.0_vp;
382 }
383 
GetDefaultHeight(LayoutWrapper * layoutWrapper)384 float ButtonLayoutAlgorithm::GetDefaultHeight(LayoutWrapper* layoutWrapper)
385 {
386     auto layoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
387     CHECK_NULL_RETURN(layoutProperty, 0.0);
388     auto frameNode = layoutWrapper->GetHostNode();
389     CHECK_NULL_RETURN(frameNode, 0.0);
390     auto* context = frameNode->GetContext();
391     CHECK_NULL_RETURN(context, 0.0);
392     auto buttonTheme = context->GetTheme<ButtonTheme>();
393     CHECK_NULL_RETURN(buttonTheme, 0.0);
394     if (frameNode->GetTag() == V2::TOGGLE_ETS_TAG) {
395         auto toggleTheme = context->GetTheme<ToggleTheme>();
396         CHECK_NULL_RETURN(toggleTheme, 0.0);
397         return static_cast<float>(toggleTheme->GetButtonHeight().ConvertToPx());
398     }
399     ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
400     return static_cast<float>(buttonTheme->GetHeight(controlSize).ConvertToPx());
401 }
402 
GetDefaultBorderRadius(LayoutWrapper * layoutWrapper)403 float ButtonLayoutAlgorithm::GetDefaultBorderRadius(LayoutWrapper* layoutWrapper)
404 {
405     auto layoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
406     CHECK_NULL_RETURN(layoutProperty, 0.0f);
407     auto frameNode = layoutWrapper->GetHostNode();
408     CHECK_NULL_RETURN(frameNode, 0.0f);
409     auto* context = frameNode->GetContext();
410     CHECK_NULL_RETURN(context, 0.0f);
411     auto buttonTheme = context->GetTheme<ButtonTheme>();
412     CHECK_NULL_RETURN(buttonTheme, 0.0f);
413     ControlSize controlSize = layoutProperty->GetControlSize().value_or(ControlSize::NORMAL);
414     return static_cast<float>(buttonTheme->GetBorderRadius(controlSize).ConvertToPx());
415 }
416 
NeedAgingMeasure(LayoutWrapper * layoutWrapper)417 bool ButtonLayoutAlgorithm::NeedAgingMeasure(LayoutWrapper* layoutWrapper)
418 {
419     if (!IsAging(layoutWrapper)) {
420         return false;
421     }
422     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
423     CHECK_NULL_RETURN(buttonLayoutProperty, false);
424     auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
425     CHECK_NULL_RETURN(pipeline, false);
426     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
427     float agingPadding = buttonTheme->GetAgingNormalPadding().ConvertToPx() * 2.0f;
428     if (buttonLayoutProperty->HasControlSize() && buttonLayoutProperty->GetControlSize() == ControlSize::SMALL) {
429         agingPadding = buttonTheme->GetAgingSmallPadding().ConvertToPx() * 2.0f;
430     }
431     auto host = layoutWrapper->GetHostNode();
432     CHECK_NULL_RETURN(host, false);
433     auto pattern = host->GetPattern<ButtonPattern>();
434     CHECK_NULL_RETURN(pattern, false);
435     if (!pattern->GetHasCustomPadding()) {
436         auto geometryNode = layoutWrapper->GetGeometryNode();
437         CHECK_NULL_RETURN(geometryNode, false);
438         auto frameSize = geometryNode->GetFrameSize();
439         if (buttonLayoutProperty->HasLabel()) {
440             auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
441             CHECK_NULL_RETURN(childWrapper, false);
442             auto childGeometryNode = childWrapper->GetGeometryNode();
443             CHECK_NULL_RETURN(childGeometryNode, false);
444             auto childFrameSize = childGeometryNode->GetContentSize();
445             frameSize.SetHeight(childFrameSize.Height() + agingPadding);
446         } else {
447             frameSize.SetHeight(frameSize.Height() + agingPadding);
448         }
449         auto layoutContraint = buttonLayoutProperty->GetLayoutConstraint();
450         CHECK_NULL_RETURN(layoutContraint, false);
451         auto maxHeight = layoutContraint->maxSize.Height();
452         auto minHeight = layoutContraint->minSize.Height();
453         auto actualHeight = frameSize.Height();
454         actualHeight = std::min(actualHeight, maxHeight);
455         actualHeight = std::max(actualHeight, minHeight);
456         frameSize.SetHeight(actualHeight);
457         geometryNode->SetFrameSize(frameSize);
458     }
459     HandleBorderRadius(layoutWrapper);
460     return true;
461 }
462 
IsAging(LayoutWrapper * layoutWrapper)463 bool ButtonLayoutAlgorithm::IsAging(LayoutWrapper* layoutWrapper)
464 {
465     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(layoutWrapper->GetLayoutProperty());
466     CHECK_NULL_RETURN(buttonLayoutProperty, false);
467 
468     if (buttonLayoutProperty->HasType() && buttonLayoutProperty->GetType() == ButtonType::CIRCLE) {
469         return false;
470     }
471 
472     if (buttonLayoutProperty->HasLabel() && buttonLayoutProperty->GetLabel()->empty()) {
473         return false;
474     }
475 
476     if (buttonLayoutProperty->HasFontSize() && buttonLayoutProperty->GetFontSize()->Unit() != DimensionUnit::FP) {
477         return false;
478     }
479     const auto& calcConstraint = buttonLayoutProperty->GetCalcLayoutConstraint();
480     if (calcConstraint && calcConstraint->selfIdealSize->Height().has_value() &&
481         calcConstraint->selfIdealSize->Width().has_value()) {
482         return false;
483     }
484     auto pipeline = NG::PipelineContext::GetCurrentContextSafely();
485     CHECK_NULL_RETURN(pipeline, false);
486     auto buttonTheme = pipeline->GetTheme<ButtonTheme>();
487     CHECK_NULL_RETURN(buttonTheme, false);
488     auto fontScale = pipeline->GetFontScale();
489     if (!(NearEqual(fontScale, buttonTheme->GetBigFontSizeScale()) ||
490             NearEqual(fontScale, buttonTheme->GetLargeFontSizeScale()) ||
491             NearEqual(fontScale, buttonTheme->GetMaxFontSizeScale()))) {
492         return false;
493     }
494     return true;
495 }
496 } // namespace OHOS::Ace::NG
497