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