• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/security_component/security_component_layout_algorithm.h"
17 
18 #include "base/log/ace_scoring_log.h"
19 #include "core/components_ng/base/frame_node.h"
20 #include "core/components_ng/pattern/button/button_layout_property.h"
21 #include "core/components_ng/pattern/image/image_layout_property.h"
22 #include "core/components_ng/pattern/image/image_render_property.h"
23 #include "core/components_ng/pattern/text/text_layout_property.h"
24 #include "core/components_v2/inspector/inspector_constants.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26 
27 namespace {
28 constexpr float HALF = 2.0f;
29 }
30 
31 namespace OHOS::Ace::NG {
GetChildWrapper(LayoutWrapper * layoutWrapper,const std::string & tag)32 RefPtr<LayoutWrapper> SecurityComponentLayoutAlgorithm::GetChildWrapper(LayoutWrapper* layoutWrapper,
33     const std::string& tag)
34 {
35     int32_t count = layoutWrapper->GetTotalChildCount();
36     for (int32_t i = 0; i < count; i++) {
37         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(i);
38         if (childWrapper == nullptr) {
39             continue;
40         }
41         if (childWrapper->GetHostTag() == tag) {
42             return childWrapper;
43         }
44     }
45     return nullptr;
46 }
47 
UpdateChildPosition(LayoutWrapper * layoutWrapper,const std::string & tag,OffsetF & offset)48 void SecurityComponentLayoutAlgorithm::UpdateChildPosition(LayoutWrapper* layoutWrapper, const std::string& tag,
49     OffsetF& offset)
50 {
51     auto childWrapper = GetChildWrapper(layoutWrapper, tag);
52     CHECK_NULL_VOID(childWrapper);
53     auto childNode = childWrapper->GetHostNode();
54     CHECK_NULL_VOID(childNode);
55     childNode->GetGeometryNode()->SetMarginFrameOffset(
56         OffsetF(std::round(offset.GetX()), std::round(offset.GetY())));
57 }
58 
CreateDefaultChildConstraint(RefPtr<SecurityComponentLayoutProperty> & securityComponentProperty)59 static LayoutConstraintF CreateDefaultChildConstraint(
60     RefPtr<SecurityComponentLayoutProperty>& securityComponentProperty)
61 {
62     auto constraint = securityComponentProperty->CreateChildConstraint();
63     SizeT<float> maxSize { Infinity<float>(), Infinity<float>() };
64     constraint.maxSize = maxSize;
65     return constraint;
66 }
67 
MeasureButton(LayoutWrapper * layoutWrapper,RefPtr<SecurityComponentLayoutProperty> & securityComponentProperty)68 void SecurityComponentLayoutAlgorithm::MeasureButton(LayoutWrapper* layoutWrapper,
69     RefPtr<SecurityComponentLayoutProperty>& securityComponentProperty)
70 {
71     auto buttonWrapper = GetChildWrapper(layoutWrapper, V2::BUTTON_ETS_TAG);
72     CHECK_NULL_VOID(buttonWrapper);
73     auto buttonLayoutProperty = DynamicCast<ButtonLayoutProperty>(buttonWrapper->GetLayoutProperty());
74     CHECK_NULL_VOID(buttonLayoutProperty);
75     auto buttonConstraint = CreateDefaultChildConstraint(securityComponentProperty);
76     if (securityComponentProperty->GetBackgroundType() == static_cast<int32_t>(ButtonType::CIRCLE)) {
77         buttonConstraint.selfIdealSize.SetSize(SizeF(std::max(componentWidth_, componentHeight_),
78             std::max(componentWidth_, componentHeight_)));
79         if (GreatNotEqual(componentWidth_, componentHeight_)) {
80             top_.EnlargeHeight((componentWidth_ / HALF) - (componentHeight_ / HALF));
81         } else if (GreatNotEqual(componentHeight_, componentWidth_)) {
82             left_.EnlargeWidth((componentHeight_ / HALF) - (componentWidth_ / HALF));
83         }
84         componentWidth_ = componentHeight_ = std::max(componentWidth_, componentHeight_);
85     } else {
86         buttonConstraint.selfIdealSize.SetSize(SizeF(componentWidth_, componentHeight_));
87     }
88 
89     buttonWrapper->Measure(std::optional<LayoutConstraintF>(buttonConstraint));
90 }
91 
InitPadding(RefPtr<SecurityComponentLayoutProperty> & property)92 void SecurityComponentLayoutAlgorithm::InitPadding(RefPtr<SecurityComponentLayoutProperty>& property)
93 {
94     auto theme = PipelineContext::GetCurrentContext()->GetTheme<SecurityComponentTheme>();
95     CHECK_NULL_VOID(theme);
96 
97     double borderWidth = property->GetBackgroundBorderWidth().value_or(Dimension(0.0)).ConvertToPx();
98     double size = property->GetBackgroundLeftPadding().value_or(theme->GetBackgroundLeftPadding()).ConvertToPx() +
99         borderWidth;
100     left_.Init(false,
101         property->GetBackgroundLeftPadding().has_value(), size, borderWidth);
102 
103     size = property->GetBackgroundTopPadding().value_or(theme->GetBackgroundTopPadding()).ConvertToPx() +
104         borderWidth;
105     top_.Init(true,
106         property->GetBackgroundTopPadding().has_value(), size, borderWidth);
107 
108     size = property->GetBackgroundRightPadding().value_or(theme->GetBackgroundRightPadding()).ConvertToPx() +
109         borderWidth;
110     right_.Init(false,
111         property->GetBackgroundRightPadding().has_value(), size, borderWidth);
112 
113     size = property->GetBackgroundBottomPadding().value_or(theme->GetBackgroundBottomPadding()).ConvertToPx() +
114         borderWidth;
115     bottom_.Init(true,
116         property->GetBackgroundBottomPadding().has_value(), size, borderWidth);
117 
118     size = property->GetTextIconSpace().value_or(theme->GetTextIconSpace()).ConvertToPx();
119     middle_.Init(isVertical_, property->GetTextIconSpace().has_value(), size, 0.0);
120 }
121 
ShrinkWidth(double diff)122 double SecurityComponentLayoutAlgorithm::ShrinkWidth(double diff)
123 {
124     // first shrink left and right padding
125     double remain = left_.ShrinkWidth(diff / HALF);
126     remain = right_.ShrinkWidth(remain + (diff / HALF));
127     remain = left_.ShrinkWidth(remain);
128     if (NearEqual(remain, 0.0)) {
129         MeasureIntegralSize();
130         return componentWidth_;
131     }
132 
133     // if horizontal shrink IconTextSpace
134     remain = middle_.ShrinkWidth(remain);
135     if (NearEqual(remain, 0.0)) {
136         MeasureIntegralSize();
137         return componentWidth_;
138     }
139 
140     double iconWidth = icon_.width_;
141     double textWidth = text_.width_;
142     if (isVertical_) {
143         // Shrink max width, then shrink another proportionally if vertical
144         if (GreatNotEqual(textWidth, iconWidth)) {
145             double textRemain = text_.ShrinkWidth(remain);
146             double iconRemain = (remain - textRemain) * iconWidth / textWidth;
147             icon_.ShrinkWidth(iconRemain);
148         } else {
149             double iconRemain = icon_.ShrinkWidth(remain);
150             double textRemain = (remain - iconRemain) * textWidth / iconWidth;
151             text_.ShrinkWidth(textRemain);
152         }
153     } else {
154         // Shrink proportional text and icon if horizontal
155         double iconRemain = iconWidth * remain / (iconWidth + textWidth);
156         double textRemain = textWidth * remain / (iconWidth + textWidth);
157         double resIcon = icon_.ShrinkWidth(iconRemain);
158         double resText = text_.ShrinkWidth(textRemain);
159         if (!NearEqual(resIcon, 0.0)) {
160             text_.ShrinkWidth(resIcon);
161         } else if (!NearEqual(resText, 0.0)) {
162             icon_.ShrinkWidth(resText);
163         }
164     }
165     MeasureIntegralSize();
166     return componentWidth_;
167 }
168 
EnlargeWidth(double diff)169 double SecurityComponentLayoutAlgorithm::EnlargeWidth(double diff)
170 {
171     double remain = left_.EnlargeWidth(diff / HALF);
172     remain = right_.EnlargeWidth(remain + (diff / HALF));
173     remain = left_.EnlargeWidth(remain);
174     if (GreatNotEqual(remain, 0.0) && !isVertical_) {
175         middle_.EnlargeWidth(remain);
176     }
177     MeasureIntegralSize();
178     return componentWidth_;
179 }
180 
ShrinkHeight(double diff)181 double SecurityComponentLayoutAlgorithm::ShrinkHeight(double diff)
182 {
183     // first shrink left and right padding
184     double remain = top_.ShrinkHeight(diff / HALF);
185     remain = bottom_.ShrinkHeight(remain + (diff / HALF));
186     remain = top_.ShrinkHeight(remain);
187     if (NearEqual(remain, 0.0)) {
188         MeasureIntegralSize();
189         return componentHeight_;
190     }
191 
192     // if vertical shrink IconTextSpace
193     remain = middle_.ShrinkHeight(remain);
194     if (NearEqual(remain, 0.0)) {
195         MeasureIntegralSize();
196         return componentHeight_;
197     }
198 
199     double iconHeight = icon_.height_;
200     double textHeight = text_.height_;
201     if (!isVertical_) {
202          // Shrink max width, then shrink another proportionally if horizontal
203         if (GreatNotEqual(textHeight, iconHeight)) {
204             double textRemain = text_.ShrinkHeight(remain);
205             double iconRemain = (remain - textRemain) * iconHeight / textHeight;
206             icon_.ShrinkHeight(iconRemain);
207         } else {
208             double iconRemain = icon_.ShrinkHeight(remain);
209             double textRemain = (remain - iconRemain) * textHeight / iconHeight;
210             text_.ShrinkHeight(textRemain);
211         }
212     } else {
213         double iconRemain = iconHeight * remain / (iconHeight + textHeight);
214         double textRemain = textHeight * remain / (iconHeight + textHeight);
215         double resIcon = icon_.ShrinkHeight(iconRemain);
216         double resText = text_.ShrinkHeight(textRemain);
217         if (!NearEqual(resIcon, 0.0)) {
218             text_.ShrinkHeight(resIcon);
219         } else if (!NearEqual(resText, 0.0)) {
220             icon_.ShrinkHeight(resText);
221         }
222     }
223     isNeedReadaptWidth_ = true;
224     MeasureIntegralSize();
225     return componentWidth_;
226 }
227 
EnlargeHeight(double diff)228 double SecurityComponentLayoutAlgorithm::EnlargeHeight(double diff)
229 {
230     double remain = top_.EnlargeHeight(diff / HALF);
231     remain = bottom_.EnlargeHeight(remain + (diff / HALF));
232     remain = top_.EnlargeHeight(remain);
233     if (GreatNotEqual(remain, 0.0) && isVertical_) {
234         middle_.EnlargeHeight(remain);
235     }
236     MeasureIntegralSize();
237     return componentWidth_;
238 }
239 
AdaptWidth()240 void SecurityComponentLayoutAlgorithm::AdaptWidth()
241 {
242     if (idealWidth_ != 0.0) {
243         if (componentWidth_ > idealWidth_) {
244             ShrinkWidth(componentWidth_ - idealWidth_);
245         } else if (componentWidth_ < idealWidth_) {
246             EnlargeWidth(idealWidth_ - componentWidth_);
247         }
248         return;
249     }
250 
251     if (componentWidth_ > maxWidth_) {
252         ShrinkWidth(componentWidth_ - maxWidth_);
253     } else if (componentWidth_ < minWidth_) {
254         EnlargeWidth(minWidth_ - componentWidth_);
255     }
256 }
257 
AdaptHeight()258 void SecurityComponentLayoutAlgorithm::AdaptHeight()
259 {
260     if (idealHeight_ != 0.0) {
261         if (componentHeight_ > idealHeight_) {
262             ShrinkHeight(componentHeight_ - idealHeight_);
263         } else if (componentHeight_ < idealHeight_) {
264             EnlargeHeight(idealHeight_ - componentHeight_);
265         }
266         return;
267     }
268     if (componentHeight_ > maxHeight_) {
269         ShrinkHeight(componentHeight_ - maxHeight_);
270     } else if (componentHeight_ < minHeight_) {
271         EnlargeHeight(minHeight_ - componentHeight_);
272     }
273 }
274 
MeasureIntegralSize()275 void SecurityComponentLayoutAlgorithm::MeasureIntegralSize()
276 {
277     if (isVertical_) {
278         double contextWidth = std::max(text_.width_, icon_.width_);
279         componentHeight_ = top_.height_ + text_.height_ +
280             middle_.height_ + icon_.height_ + bottom_.height_;
281         componentWidth_ = left_.width_ + contextWidth + right_.width_;
282     } else {
283         double contextHeight = std::max(text_.height_, icon_.height_);
284         componentHeight_ = top_.height_ + contextHeight + bottom_.height_;
285         componentWidth_ = left_.width_ + icon_.width_ +
286             middle_.width_ + text_.width_ + right_.width_;
287     }
288 }
289 
UpdateVerticalOffset(OffsetF & offsetIcon,OffsetF & offsetText)290 void SecurityComponentLayoutAlgorithm::UpdateVerticalOffset(OffsetF& offsetIcon,
291     OffsetF& offsetText)
292 {
293     offsetText = offsetIcon + OffsetF(0.0, icon_.height_ + middle_.height_);
294     if (icon_.width_ > text_.width_) {
295         offsetText += OffsetF((icon_.width_ - text_.width_) / HALF, 0.0);
296     } else {
297         offsetIcon += OffsetF((text_.width_ - icon_.width_) / HALF, 0.0);
298     }
299 }
300 
UpdateHorizontalOffset(OffsetF & offsetIcon,OffsetF & offsetText)301 void SecurityComponentLayoutAlgorithm::UpdateHorizontalOffset(OffsetF& offsetIcon,
302     OffsetF& offsetText)
303 {
304     offsetText = offsetIcon +
305         OffsetF(icon_.width_ + middle_.width_, 0.0);
306     if (icon_.height_ > text_.height_) {
307         offsetText +=
308             OffsetF(0.0, (icon_.height_ - text_.height_) / HALF);
309     } else {
310         offsetIcon +=
311             OffsetF(0.0, (text_.height_ - icon_.height_) / HALF);
312     }
313 }
314 
Layout(LayoutWrapper * layoutWrapper)315 void SecurityComponentLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
316 {
317     CHECK_NULL_VOID(layoutWrapper);
318     OffsetF offsetIcon = OffsetF(left_.width_, top_.height_);
319     OffsetF offsetText = OffsetF(left_.width_, top_.height_);
320     if (isVertical_) {
321         UpdateVerticalOffset(offsetIcon, offsetText);
322     } else {
323         UpdateHorizontalOffset(offsetIcon, offsetText);
324     }
325 
326     UpdateChildPosition(layoutWrapper, V2::IMAGE_ETS_TAG, offsetIcon);
327     UpdateChildPosition(layoutWrapper, V2::TEXT_ETS_TAG, offsetText);
328 
329     for (auto&& child : layoutWrapper->GetAllChildrenWithBuild()) {
330         child->Layout();
331     }
332 }
333 
UpdateCircleButtonConstraint()334 void SecurityComponentLayoutAlgorithm::UpdateCircleButtonConstraint()
335 {
336     double circleIdealSize = std::max(componentWidth_, componentHeight_);
337     if ((idealWidth_ != 0.0) && (idealHeight_ != 0.0)) {
338         circleIdealSize = std::min(idealWidth_, idealHeight_);
339     } else if (idealWidth_ != 0.0) {
340         circleIdealSize = idealWidth_;
341     } else if (idealHeight_ != 0.0) {
342         circleIdealSize = idealHeight_;
343     } else {
344         if ((componentWidth_ < minWidth_) || (componentHeight_ < minHeight_)) {
345             circleIdealSize = std::max(minWidth_, minHeight_);
346         } else if ((componentWidth_ > maxWidth_) || (componentHeight_ > maxHeight_)) {
347             circleIdealSize = std::min(maxWidth_, maxHeight_);
348         }
349     }
350     idealWidth_ = idealHeight_ = circleIdealSize;
351 }
352 
FillBlank()353 void SecurityComponentLayoutAlgorithm::FillBlank()
354 {
355     if (isNobg_) {
356         return;
357     }
358     if (GreatNotEqual(idealWidth_, componentWidth_)) {
359         left_.width_ += ((idealWidth_ - componentWidth_) / HALF);
360         right_.width_ += ((idealWidth_ - componentWidth_) / HALF);
361     } else if (GreatNotEqual(minWidth_, componentWidth_)) {
362         left_.width_ += ((minWidth_ - componentWidth_) / HALF);
363         right_.width_ += ((minWidth_ - componentWidth_) / HALF);
364     }
365     if (GreatNotEqual(idealHeight_, componentHeight_)) {
366         top_.height_ += ((idealHeight_ - componentHeight_) / HALF);
367         bottom_.height_ += ((idealHeight_ - componentHeight_) / HALF);
368     } else if (GreatNotEqual(minHeight_, componentHeight_)) {
369         top_.height_ += ((minHeight_ - componentHeight_) / HALF);
370         bottom_.height_ += ((minHeight_ - componentHeight_) / HALF);
371     }
372     MeasureIntegralSize();
373 }
374 
Measure(LayoutWrapper * layoutWrapper)375 void SecurityComponentLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
376 {
377     CHECK_NULL_VOID(layoutWrapper);
378     auto securityComponentLayoutProperty =
379         AceType::DynamicCast<SecurityComponentLayoutProperty>(layoutWrapper->GetLayoutProperty());
380     CHECK_NULL_VOID(securityComponentLayoutProperty);
381 
382     auto iconWrapper = GetChildWrapper(layoutWrapper, V2::IMAGE_ETS_TAG);
383     icon_.Init(securityComponentLayoutProperty, iconWrapper);
384 
385     auto textWrapper = GetChildWrapper(layoutWrapper, V2::TEXT_ETS_TAG);
386     text_.Init(securityComponentLayoutProperty, textWrapper);
387 
388     constraint_ = securityComponentLayoutProperty->GetContentLayoutConstraint();
389     CHECK_NULL_VOID(constraint_);
390     isVertical_ = (securityComponentLayoutProperty->GetTextIconLayoutDirection().value() ==
391         SecurityComponentLayoutDirection::VERTICAL);
392     isNobg_ = (securityComponentLayoutProperty->GetBackgroundType().value() == BUTTON_TYPE_NULL);
393     idealWidth_ = constraint_->selfIdealSize.Width().value_or(0.0);
394     idealHeight_ = constraint_->selfIdealSize.Height().value_or(0.0);
395     minWidth_ = constraint_->minSize.Width();
396     minHeight_ = constraint_->minSize.Height();
397     maxWidth_ = constraint_->maxSize.Width();
398     maxHeight_ = constraint_->maxSize.Height();
399     InitPadding(securityComponentLayoutProperty);
400 
401     MeasureIntegralSize();
402 
403     if (securityComponentLayoutProperty->GetBackgroundType() == static_cast<int32_t>(ButtonType::CIRCLE)) {
404         UpdateCircleButtonConstraint();
405     }
406     AdaptWidth();
407     AdaptHeight();
408     if (isNeedReadaptWidth_) {
409         AdaptWidth();
410     }
411     // fill blank when all paddings can not be enlarged because it has been set
412     FillBlank();
413 
414     icon_.DoMeasure();
415     MeasureButton(layoutWrapper, securityComponentLayoutProperty);
416     layoutWrapper->GetGeometryNode()->SetFrameSize(SizeF(componentWidth_, componentHeight_));
417 }
418 } // namespace OHOS::Ace::NG
419