• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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/search/search_layout_algorithm.h"
17 #include "core/components_ng/pattern/search/search_pattern.h"
18 
19 #include "core/components_ng/pattern/button/button_pattern.h"
20 #include "core/components_ng/pattern/image/image_pattern.h"
21 #include "core/components_ng/pattern/text/text_base.h"
22 #include "core/components_ng/pattern/text_field/text_field_layout_algorithm.h"
23 
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t TEXTFIELD_INDEX = 0;
27 constexpr int32_t IMAGE_INDEX = 1;
28 constexpr int32_t CANCEL_IMAGE_INDEX = 2;
29 constexpr int32_t CANCEL_BUTTON_INDEX = 3;
30 constexpr int32_t BUTTON_INDEX = 4;
31 constexpr int32_t DIVIDER_INDEX = 5;
32 constexpr int32_t MULTIPLE_2 = 2;
33 constexpr float MAX_SEARCH_BUTTON_RATE = 0.4f;
34 constexpr float AGING_MIN_SCALE = 1.75f;
35 constexpr float MAX_FONT_SCALE = 2.0f;
36 constexpr int TWO = 2;
37 constexpr Dimension DEFAULT_DIVIDER_HEIGHT = 12.0_vp;
38 } // namespace
39 
IsFixedHeightMode(LayoutWrapper * layoutWrapper)40 bool SearchLayoutAlgorithm::IsFixedHeightMode(LayoutWrapper* layoutWrapper)
41 {
42     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
43     CHECK_NULL_RETURN(layoutProperty, false);
44 
45     auto constraint = layoutProperty->GetLayoutConstraint();
46     return constraint->selfIdealSize.Height().has_value();
47 }
48 
CalculateMaxFontScale(LayoutWrapper * layoutWrapper)49 float SearchLayoutAlgorithm::CalculateMaxFontScale(LayoutWrapper* layoutWrapper)
50 {
51     auto searchHost = layoutWrapper->GetHostNode();
52     CHECK_NULL_RETURN(searchHost, MAX_FONT_SCALE);
53     auto pipeline = searchHost->GetContext();
54     CHECK_NULL_RETURN(pipeline, MAX_FONT_SCALE);
55     auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
56     CHECK_NULL_RETURN(textFieldWrapper, MAX_FONT_SCALE);
57     auto textFieldLayoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
58     CHECK_NULL_RETURN(textFieldLayoutProperty, MAX_FONT_SCALE);
59     auto maxScale = MAX_FONT_SCALE;
60     if (textFieldLayoutProperty->HasMaxFontScale()) {
61         maxScale = std::min(textFieldLayoutProperty->GetMaxFontScale().value(), maxScale);
62     } else {
63         maxScale = std::min(pipeline->GetMaxAppFontScale(), maxScale);
64     }
65     return maxScale;
66 }
67 
CalculateMinFontScale(LayoutWrapper * layoutWrapper)68 float SearchLayoutAlgorithm::CalculateMinFontScale(LayoutWrapper* layoutWrapper)
69 {
70     auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
71     CHECK_NULL_RETURN(textFieldWrapper, 0.0f);
72     auto textFieldLayoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
73     CHECK_NULL_RETURN(textFieldLayoutProperty, 0.0f);
74     auto minScale = 0.0f;
75     if (textFieldLayoutProperty->HasMinFontScale()) {
76         minScale = textFieldLayoutProperty->GetMinFontScale().value();
77     }
78     return minScale;
79 }
80 
CancelImageMeasure(LayoutWrapper * layoutWrapper)81 void SearchLayoutAlgorithm::CancelImageMeasure(LayoutWrapper* layoutWrapper)
82 {
83     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
84     CHECK_NULL_VOID(layoutProperty);
85     auto cancelImageWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_IMAGE_INDEX);
86     CHECK_NULL_VOID(cancelImageWrapper);
87     auto cancelImageGeometryNode = cancelImageWrapper->GetGeometryNode();
88     CHECK_NULL_VOID(cancelImageGeometryNode);
89     auto imageLayoutProperty = cancelImageWrapper->GetLayoutProperty();
90     CHECK_NULL_VOID(imageLayoutProperty);
91     auto searchHost = layoutWrapper->GetHostNode();
92     CHECK_NULL_VOID(searchHost);
93     auto pipeline = searchHost->GetContext();
94     CHECK_NULL_VOID(pipeline);
95     auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
96     CHECK_NULL_VOID(searchTheme);
97     auto defaultImageHeight = static_cast<float>(searchTheme->GetIconSize().ConvertToPxDistribute(
98         minFontScale_, maxFontScale_));
99     auto imageHeight = static_cast<float>(std::min(layoutProperty->HasCancelButtonUDSize() ?
100         layoutProperty->GetCancelButtonUDSizeValue().ConvertToPxDistribute(
101             minFontScale_, maxFontScale_) : defaultImageHeight,
102         searchHeight_));
103     if (cancelImageWrapper->GetHostTag() == V2::SYMBOL_ETS_TAG) {
104         imageHeight = CalcSymbolIconHeight(layoutWrapper, CANCEL_IMAGE_INDEX, defaultImageHeight);
105     }
106     CalcSize imageCalcSize;
107     imageCalcSize.SetWidth(CalcLength(imageHeight));
108     imageCalcSize.SetHeight(CalcLength(imageHeight));
109     imageLayoutProperty->UpdateUserDefinedIdealSize(imageCalcSize);
110     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
111     cancelImageWrapper->Measure(childLayoutConstraint);
112     cancelIconSizeMeasure_ = cancelImageGeometryNode->GetFrameSize();
113 }
114 
CancelButtonMeasure(LayoutWrapper * layoutWrapper)115 void SearchLayoutAlgorithm::CancelButtonMeasure(LayoutWrapper* layoutWrapper)
116 {
117     auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
118     CHECK_NULL_VOID(cancelButtonWrapper);
119     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
120     CHECK_NULL_VOID(layoutProperty);
121     auto cancelButtonLayoutProperty =
122         AceType::DynamicCast<ButtonLayoutProperty>(cancelButtonWrapper->GetLayoutProperty());
123     CHECK_NULL_VOID(cancelButtonLayoutProperty);
124     auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
125     CHECK_NULL_VOID(cancelButtonGeometryNode);
126     auto searchHost = layoutWrapper->GetHostNode();
127     CHECK_NULL_VOID(searchHost);
128     auto pipeline = searchHost->GetContext();
129     CHECK_NULL_VOID(pipeline);
130     auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
131     CHECK_NULL_VOID(searchTheme);
132 
133     // calculate theme space from cancel button to cancel image
134     auto spaceHeight = searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx() -
135                        searchTheme->GetIconHeight().ConvertToPx();
136 
137     // calculate cancel button height
138     auto cancelButtonHeight =
139         layoutProperty->GetCancelButtonUDSizeValue(Dimension(cancelIconSizeMeasure_.Height())).ConvertToPx() +
140         spaceHeight;
141 
142     // cancel button height should be less than searchHeight
143     cancelButtonHeight = std::min(cancelButtonHeight, searchHeight_);
144 
145     CalcSize cancelButtonCalcSize((CalcLength(cancelButtonHeight)), CalcLength(cancelButtonHeight));
146     cancelButtonLayoutProperty->UpdateUserDefinedIdealSize(cancelButtonCalcSize);
147 
148     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
149     cancelButtonWrapper->Measure(childLayoutConstraint);
150     cancelBtnSizeMeasure_ = cancelButtonGeometryNode->GetFrameSize();
151 }
152 
TextFieldMeasure(LayoutWrapper * layoutWrapper)153 void SearchLayoutAlgorithm::TextFieldMeasure(LayoutWrapper* layoutWrapper)
154 {
155     auto searchHost = layoutWrapper->GetHostNode();
156     CHECK_NULL_VOID(searchHost);
157     auto pipeline = searchHost->GetContext();
158     CHECK_NULL_VOID(pipeline);
159     auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
160     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
161     CHECK_NULL_VOID(layoutProperty);
162     auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
163     CHECK_NULL_VOID(textFieldWrapper);
164     auto textFieldLayoutProperty = textFieldWrapper->GetLayoutProperty();
165 
166     UpdateFontFeature(layoutWrapper);
167     auto constraint = layoutProperty->GetLayoutConstraint();
168     CHECK_NULL_VOID(constraint);
169     auto searchWidthMax = CalcSearchWidth(constraint.value(), layoutWrapper);
170 
171     auto textFieldWidth = CalculateTextFieldWidth(layoutWrapper, searchWidthMax, searchTheme);
172     auto textFieldHeight = searchHeight_;
173     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
174     auto widthPolicy = TextBase::GetLayoutCalPolicy(layoutWrapper, true);
175     if (widthPolicy == LayoutCalPolicy::WRAP_CONTENT || widthPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
176         textFieldLayoutProperty->UpdateLayoutPolicyProperty(LayoutCalPolicy::WRAP_CONTENT, true);
177         childLayoutConstraint.maxSize.SetWidth(GetTextFieldMaxWidth(layoutWrapper, widthPolicy, textFieldWidth));
178         childLayoutConstraint.minSize.SetWidth(GetTextFieldMinWidth(layoutWrapper, searchTheme));
179     } else {
180         textFieldLayoutProperty->UpdateLayoutPolicyProperty(LayoutCalPolicy::NO_MATCH, true);
181         childLayoutConstraint.selfIdealSize.SetWidth(textFieldWidth);
182     }
183     if (LessNotEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
184         SetTextFieldLayoutConstraintHeight(childLayoutConstraint, textFieldHeight, layoutWrapper);
185     }
186     textFieldWrapper->Measure(childLayoutConstraint);
187     UpdateTextFieldSize(layoutWrapper);
188     searchWidthReducedLength_ = textFieldWidth - textFieldSizeMeasure_.Width();
189 }
190 
CalculateTextFieldWidth(LayoutWrapper * layoutWrapper,float searchWidthMax,const RefPtr<SearchTheme> & searchTheme)191 float SearchLayoutAlgorithm::CalculateTextFieldWidth(
192     LayoutWrapper* layoutWrapper, float searchWidthMax, const RefPtr<SearchTheme>& searchTheme)
193 {
194     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
195     CHECK_NULL_RETURN(layoutProperty, 0.0f);
196     auto buttonWidth = searchButtonSizeMeasure_.Width();
197     auto cancelButtonWidth = cancelBtnSizeMeasure_.Width();
198     auto iconRenderWidth =
199         layoutProperty->GetSearchIconUDSizeValue(Dimension(searchIconSizeMeasure_.Width())).ConvertToPx();
200     auto padding = layoutProperty->CreatePaddingAndBorder();
201     float leftPadding = padding.left.value_or(0.0f);
202     float rightPadding = padding.right.value_or(0.0f);
203     auto textFieldWidth = searchWidthMax - searchTheme->GetSearchIconLeftSpace().ConvertToPx() - iconRenderWidth -
204                           searchTheme->GetSearchIconRightSpace().ConvertToPx() - leftPadding - rightPadding;
205     if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TEN)) {
206         textFieldWidth = searchWidthMax - searchTheme->GetSearchIconLeftSpace().ConvertToPx() - iconRenderWidth -
207                          searchTheme->GetSearchIconRightSpace().ConvertToPx();
208     }
209 
210     auto searchWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
211     auto searchButtonNode = searchWrapper->GetHostNode();
212     auto searchButtonEvent = searchButtonNode->GetOrCreateEventHub<ButtonEventHub>();
213     auto searchButtonLayoutProperty = searchButtonNode->GetLayoutProperty<ButtonLayoutProperty>();
214     CHECK_NULL_RETURN(searchButtonLayoutProperty, 0.0f);
215     auto needToDisable = searchButtonLayoutProperty->GetAutoDisable().value_or(false);
216     if (searchButtonEvent->IsEnabled() || needToDisable) {
217         textFieldWidth = textFieldWidth - buttonWidth - searchTheme->GetSearchDividerWidth().ConvertToPx() -
218                          MULTIPLE_2 * searchTheme->GetDividerSideSpace().ConvertToPx();
219     }
220 
221     auto style = layoutProperty->GetCancelButtonStyle().value_or(CancelButtonStyle::INPUT);
222     if (style != CancelButtonStyle::INVISIBLE) {
223         textFieldWidth = textFieldWidth - cancelButtonWidth;
224     }
225     if (style == CancelButtonStyle::INVISIBLE && !searchButtonEvent->IsEnabled()) {
226         // right padding without cancel button and search button
227         auto rightPadding = searchTheme->GetRightPaddingWithoutButton();
228         textFieldWidth = textFieldWidth - rightPadding.ConvertToPx();
229     }
230 
231     return textFieldWidth;
232 }
233 
UpdateFontFeature(LayoutWrapper * layoutWrapper)234 void SearchLayoutAlgorithm::UpdateFontFeature(LayoutWrapper* layoutWrapper)
235 {
236     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
237     CHECK_NULL_VOID(layoutProperty);
238     auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
239     CHECK_NULL_VOID(textFieldWrapper);
240 
241     auto textFieldLayoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
242     CHECK_NULL_VOID(textFieldLayoutProperty);
243     if (layoutProperty->HasFontFeature()) {
244         textFieldLayoutProperty->UpdateFontFeature(layoutProperty->GetFontFeature().value());
245     }
246     if (layoutProperty->HasStrokeWidth()) {
247         textFieldLayoutProperty->UpdateStrokeWidth(layoutProperty->GetStrokeWidth().value());
248     }
249     if (layoutProperty->HasStrokeColor()) {
250         textFieldLayoutProperty->UpdateStrokeColor(layoutProperty->GetStrokeColor().value());
251     } else {
252         if (textFieldLayoutProperty->HasTextColor()) {
253             textFieldLayoutProperty->UpdateStrokeColor(textFieldLayoutProperty->GetTextColor().value());
254         } else {
255             textFieldLayoutProperty->ResetStrokeColor();
256         }
257     }
258 }
259 
UpdateTextFieldSize(LayoutWrapper * layoutWrapper)260 void SearchLayoutAlgorithm::UpdateTextFieldSize(LayoutWrapper* layoutWrapper)
261 {
262     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
263     CHECK_NULL_VOID(layoutProperty);
264     auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
265     CHECK_NULL_VOID(textFieldWrapper);
266 
267     auto textFieldGeometryNode = textFieldWrapper->GetGeometryNode();
268     CHECK_NULL_VOID(textFieldGeometryNode);
269     textFieldSizeMeasure_ = textFieldGeometryNode->GetFrameSize();
270 }
271 
SetTextFieldLayoutConstraintHeight(LayoutConstraintF & contentConstraint,double textFieldHeight,LayoutWrapper * layoutWrapper)272 void SearchLayoutAlgorithm::SetTextFieldLayoutConstraintHeight(LayoutConstraintF& contentConstraint,
273     double textFieldHeight, LayoutWrapper* layoutWrapper)
274 {
275     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
276         auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
277         auto textFieldLayoutProperty =
278             AceType::DynamicCast<TextFieldLayoutProperty>(textFieldWrapper->GetLayoutProperty());
279         if ((textFieldLayoutProperty == nullptr) || (!textFieldLayoutProperty->HasLineHeight())) {
280             contentConstraint.selfIdealSize.SetHeight(textFieldHeight);
281         }
282         return;
283     }
284     contentConstraint.selfIdealSize.SetHeight(textFieldHeight);
285 }
286 
ImageMeasure(LayoutWrapper * layoutWrapper)287 void SearchLayoutAlgorithm::ImageMeasure(LayoutWrapper* layoutWrapper)
288 {
289     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
290     CHECK_NULL_VOID(layoutProperty);
291     auto imageWrapper = layoutWrapper->GetOrCreateChildByIndex(IMAGE_INDEX);
292     CHECK_NULL_VOID(imageWrapper);
293     auto imageGeometryNode = imageWrapper->GetGeometryNode();
294     CHECK_NULL_VOID(imageGeometryNode);
295     auto imageLayoutProperty = imageWrapper->GetLayoutProperty();
296     CHECK_NULL_VOID(imageLayoutProperty);
297     auto searchHost = layoutWrapper->GetHostNode();
298     CHECK_NULL_VOID(searchHost);
299     auto pipeline = searchHost->GetContext();
300     CHECK_NULL_VOID(pipeline);
301     auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
302     CHECK_NULL_VOID(searchTheme);
303     auto defaultImageHeight = searchTheme->GetIconSize().ConvertToPx();
304     auto imageHeight = static_cast<float>(std::min(layoutProperty->HasSearchIconUDSize() ?
305         layoutProperty->GetSearchIconUDSizeValue().ConvertToPx() : defaultImageHeight,
306         searchHeight_));
307     if (imageWrapper->GetHostTag() == V2::SYMBOL_ETS_TAG) {
308         imageHeight = CalcSymbolIconHeight(layoutWrapper, IMAGE_INDEX, defaultImageHeight);
309     }
310     CalcSize imageCalcSize;
311     imageCalcSize.SetWidth(CalcLength(imageHeight));
312     imageCalcSize.SetHeight(CalcLength(imageHeight));
313     imageLayoutProperty->UpdateUserDefinedIdealSize(imageCalcSize);
314 
315     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
316     imageWrapper->Measure(childLayoutConstraint);
317     searchIconSizeMeasure_ = imageGeometryNode->GetFrameSize();
318 }
319 
searchButtonCalcSize(const RefPtr<SearchTheme> & searchTheme,RefPtr<SearchLayoutProperty> layoutProperty,LayoutWrapper * layoutWrapper,float maxFontScale,float minFontScale)320 CalcSize SearchLayoutAlgorithm::searchButtonCalcSize(const RefPtr<SearchTheme>& searchTheme,
321     RefPtr<SearchLayoutProperty> layoutProperty, LayoutWrapper* layoutWrapper, float maxFontScale, float minFontScale)
322 {
323     // calculate theme space from search button to font
324     auto spaceHeight = searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx() -
325                        searchTheme->GetButtonFontSize().ConvertToPxDistribute(minFontScale, maxFontScale);
326     // calculate search button height
327     auto defaultButtonHeight =
328         searchTheme->GetHeight().ConvertToPx() - 2 * searchTheme->GetSearchButtonSpace().ConvertToPx();
329     auto searchButtonHeight = std::max(defaultButtonHeight,
330         layoutProperty->GetSearchButtonFontSizeValue(searchTheme->GetButtonFontSize()).ConvertToPxDistribute(
331             minFontScale, maxFontScale) + spaceHeight);
332     searchButtonHeight = std::min(searchButtonHeight, searchHeight_);
333     CalcSize searchButtonCalcSize;
334     searchButtonCalcSize.SetHeight(CalcLength(searchButtonHeight));
335     return searchButtonCalcSize;
336 }
337 
SearchButtonMeasure(LayoutWrapper * layoutWrapper)338 void SearchLayoutAlgorithm::SearchButtonMeasure(LayoutWrapper* layoutWrapper)
339 {
340     auto buttonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
341     CHECK_NULL_VOID(buttonWrapper);
342     auto buttonLayoutProperty = AceType::DynamicCast<ButtonLayoutProperty>(buttonWrapper->GetLayoutProperty());
343     CHECK_NULL_VOID(buttonLayoutProperty);
344     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
345     CHECK_NULL_VOID(layoutProperty);
346     auto buttonGeometryNode = buttonWrapper->GetGeometryNode();
347     CHECK_NULL_VOID(buttonGeometryNode);
348     auto searchHost = layoutWrapper->GetHostNode();
349     CHECK_NULL_VOID(searchHost);
350     auto pipeline = searchHost->GetContext();
351     CHECK_NULL_VOID(pipeline);
352     auto searchTheme = pipeline->GetTheme<SearchTheme>(searchHost->GetThemeScopeId());
353     CHECK_NULL_VOID(searchTheme);
354     buttonLayoutProperty->UpdateUserDefinedIdealSize(searchButtonCalcSize(searchTheme, layoutProperty, layoutWrapper,
355         maxFontScale_, minFontScale_));
356     auto textWrapper = buttonWrapper->GetChildByIndex(0);
357     if (textWrapper) {
358         auto textLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(textWrapper->GetLayoutProperty());
359         CHECK_NULL_VOID(textLayoutProperty);
360         textLayoutProperty->UpdateMaxFontScale(maxFontScale_);
361         textLayoutProperty->UpdateMinFontScale(minFontScale_);
362     }
363     if (GreatOrEqual(pipeline->GetFontScale(), AGING_MIN_SCALE)) {
364         buttonLayoutProperty->ClearUserDefinedIdealSize(false, true);
365     }
366 
367     // searchButton Measure
368     auto buttonLayoutConstraint = layoutProperty->CreateChildConstraint();
369     buttonWrapper->Measure(buttonLayoutConstraint);
370 
371     // deal with pixel round
372     auto pixelRound = static_cast<uint16_t>(PixelRoundPolicy::FORCE_FLOOR_TOP) |
373                         static_cast<uint16_t>(PixelRoundPolicy::FORCE_CEIL_BOTTOM);
374     buttonLayoutProperty->UpdatePixelRound(pixelRound);
375 
376     // compute searchButton width
377     CHECK_NULL_VOID(layoutProperty->GetLayoutConstraint());
378     auto searchWidthMax = CalcSearchWidth(layoutProperty->GetLayoutConstraint().value(), layoutWrapper);
379     double searchButtonWidth = searchWidthMax * MAX_SEARCH_BUTTON_RATE;
380     double curSearchButtonWidth = buttonGeometryNode->GetFrameSize().Width();
381     searchButtonWidth = std::min(searchButtonWidth, curSearchButtonWidth);
382     buttonLayoutConstraint.selfIdealSize.SetWidth(searchButtonWidth);
383     buttonWrapper->Measure(buttonLayoutConstraint);
384     searchButtonSizeMeasure_ = buttonGeometryNode->GetFrameSize();
385 }
386 
DividerMeasure(LayoutWrapper * layoutWrapper)387 void SearchLayoutAlgorithm::DividerMeasure(LayoutWrapper* layoutWrapper)
388 {
389     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
390     CHECK_NULL_VOID(layoutProperty);
391     auto dividerWrapper = layoutWrapper->GetOrCreateChildByIndex(DIVIDER_INDEX);
392     CHECK_NULL_VOID(dividerWrapper);
393     auto dividerGeometryNode = dividerWrapper->GetGeometryNode();
394     CHECK_NULL_VOID(dividerGeometryNode);
395     auto dividerLayoutProperty = dividerWrapper->GetLayoutProperty();
396     CHECK_NULL_VOID(dividerLayoutProperty);
397     auto host = layoutWrapper->GetHostNode();
398     CHECK_NULL_VOID(host);
399     auto pipeline = host->GetContext();
400     CHECK_NULL_VOID(pipeline);
401     auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
402     CHECK_NULL_VOID(searchTheme);
403 
404     auto iconHeight = searchTheme->GetIconHeight().ConvertToPx();
405     auto dividerHeight = std::min(static_cast<float>(searchHeight_), static_cast<float>(iconHeight));
406     if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
407         auto defaultDividerHeight = DEFAULT_DIVIDER_HEIGHT.ConvertToPx();
408         dividerHeight = std::min(static_cast<float>(searchHeight_), static_cast<float>(defaultDividerHeight));
409     }
410     auto dividerWidth = searchTheme->GetSearchDividerWidth();
411 
412     CalcSize dividerSize;
413     dividerSize.SetWidth(CalcLength(dividerWidth));
414     dividerSize.SetHeight(CalcLength(dividerHeight));
415     dividerLayoutProperty->UpdateUserDefinedIdealSize(dividerSize);
416 
417     auto childLayoutConstraint = layoutProperty->CreateChildConstraint();
418     dividerWrapper->Measure(childLayoutConstraint);
419     dividerSizeMeasure_ = dividerGeometryNode->GetFrameSize();
420 }
421 
CalcSearchAdaptHeight(LayoutWrapper * layoutWrapper)422 double SearchLayoutAlgorithm::CalcSearchAdaptHeight(LayoutWrapper* layoutWrapper)
423 {
424     double searchHeightAdapt = 0;
425     auto host = layoutWrapper->GetHostNode();
426     CHECK_NULL_RETURN(host, 0);
427     auto pipeline = host->GetContext();
428     CHECK_NULL_RETURN(pipeline, 0);
429     auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
430     CHECK_NULL_RETURN(searchTheme, 0);
431     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
432     CHECK_NULL_RETURN(layoutProperty, 0);
433     auto searchBtnWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
434     CHECK_NULL_RETURN(searchBtnWrapper, 0);
435     auto cancelBtnLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
436     CHECK_NULL_RETURN(cancelBtnLayoutWrapper, 0);
437     // search button height
438     auto buttonNode = searchBtnWrapper->GetHostNode();
439     CHECK_NULL_RETURN(buttonNode, true);
440     auto searchButtonEvent = buttonNode->GetOrCreateEventHub<ButtonEventHub>();
441     CHECK_NULL_RETURN(searchButtonEvent, true);
442     auto searchButtonHeight = searchButtonSizeMeasure_.Height() + 2 *
443         searchTheme->GetSearchButtonSpace().ConvertToPxDistribute(minFontScale_, maxFontScale_);
444     auto searchButtonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
445     CHECK_NULL_RETURN(searchButtonLayoutProperty, true);
446     auto needToDisable = searchButtonLayoutProperty->GetAutoDisable().value_or(false);
447     searchButtonHeight = (!searchButtonEvent->IsEnabled() && !needToDisable) ? 0.0f : searchButtonHeight;
448     // search icon height
449     auto searchIconFrameHight = searchIconSizeMeasure_.Height();
450     auto searchIconHeight = layoutProperty->GetSearchIconUDSizeValue(
451         Dimension(searchIconFrameHight)).ConvertToPxDistribute(minFontScale_, maxFontScale_);
452     searchIconHeight += searchTheme->GetHeight().ConvertToPxDistribute(minFontScale_, maxFontScale_) -
453     searchTheme->GetIconHeight().ConvertToPxDistribute(minFontScale_, maxFontScale_);
454     // cancel button height
455     auto cancelButtonNode = cancelBtnLayoutWrapper->GetHostNode();
456     CHECK_NULL_RETURN(cancelButtonNode, 0);
457     auto cancelButtonEvent = cancelButtonNode->GetOrCreateEventHub<ButtonEventHub>();
458     CHECK_NULL_RETURN(cancelButtonEvent, 0);
459     auto cancelBtnHight = cancelBtnSizeMeasure_.Height() + 2 *
460         searchTheme->GetSearchButtonSpace().ConvertToPxDistribute(minFontScale_, maxFontScale_);
461     cancelBtnHight = (!cancelButtonEvent->IsEnabled()) ? 0.0f : cancelBtnHight;
462     // textfield height
463     auto padding = layoutProperty->CreatePaddingAndBorder();
464     auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
465     auto textfieldHeight = textFieldSizeMeasure_.Height() + verticalPadding;
466     // calculate the highest
467     searchHeightAdapt = std::max(searchIconHeight, searchButtonHeight);
468     searchHeightAdapt = std::max(searchHeightAdapt, cancelBtnHight);
469     searchHeightAdapt = std::max(searchHeightAdapt, static_cast<double>(textfieldHeight));
470     return searchHeightAdapt;
471 }
472 
SelfMeasure(LayoutWrapper * layoutWrapper)473 void SearchLayoutAlgorithm::SelfMeasure(LayoutWrapper* layoutWrapper)
474 {
475     auto geometryNode = layoutWrapper->GetGeometryNode();
476     CHECK_NULL_VOID(geometryNode);
477     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
478     CHECK_NULL_VOID(layoutProperty);
479     auto constraint = layoutProperty->GetLayoutConstraint();
480     CHECK_NULL_VOID(constraint);
481     auto searchHeight = CalcSearchHeight(constraint.value(), layoutWrapper);
482     UpdateClipBounds(layoutWrapper, searchHeight);
483     // update search height
484     constraint->selfIdealSize.SetHeight(searchHeight);
485     auto searchWidth = CalcSearchWidth(constraint.value(), layoutWrapper);
486     auto layoutPolicy = TextBase::GetLayoutCalPolicy(layoutWrapper, true);
487     if ((layoutPolicy == LayoutCalPolicy::WRAP_CONTENT && Positive(searchWidthReducedLength_)) ||
488         layoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
489         searchWidth -= searchWidthReducedLength_;
490     }
491     SizeF idealSize(searchWidth, searchHeight);
492     if (GreaterOrEqualToInfinity(idealSize.Width()) || GreaterOrEqualToInfinity(idealSize.Height())) {
493         geometryNode->SetFrameSize(SizeF());
494         return;
495     }
496 
497     // update search height
498     geometryNode->SetFrameSize(idealSize);
499     geometryNode->SetContentSize(idealSize);
500 }
501 
CalcSearchWidth(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)502 double SearchLayoutAlgorithm::CalcSearchWidth(
503     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
504 {
505     auto fixIdealMaxWidth = GetSearchFixAtIdealMaxWidth(layoutWrapper);
506     if (fixIdealMaxWidth) {
507         return fixIdealMaxWidth.value();
508     }
509     auto searchConstraint = contentConstraint;
510     auto maxWidth = TextBase::GetConstraintMaxLength(layoutWrapper, contentConstraint, true);
511     auto idealWidth = contentConstraint.selfIdealSize.Width().value_or(maxWidth);
512     auto maxHeight = TextBase::GetConstraintMaxLength(layoutWrapper, contentConstraint, false);
513     auto idealHeight = contentConstraint.selfIdealSize.Height().value_or(maxHeight);
514     auto maxIdealSize = SizeF { idealWidth, idealHeight };
515     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
516         auto frameIdealSize = maxIdealSize;
517         auto finalSize = UpdateOptionSizeByCalcLayoutConstraint(static_cast<OptionalSize<float>>(frameIdealSize),
518             layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint(),
519             layoutWrapper->GetLayoutProperty()->GetLayoutConstraint()->percentReference);
520         finalSize.SetWidth(finalSize.Width().value_or(frameIdealSize.Width()));
521         finalSize.SetHeight(finalSize.Height().value_or(frameIdealSize.Height()));
522         maxIdealSize.UpdateSizeWhenSmaller(finalSize.ConvertToSizeT());
523     }
524     searchConstraint.maxSize = maxIdealSize;
525     auto searchWidth = (searchConstraint.selfIdealSize.Width().has_value())
526                 ? std::min(searchConstraint.selfIdealSize.Width().value(), searchConstraint.maxSize.Width())
527                 : std::min(searchConstraint.percentReference.Width(), searchConstraint.maxSize.Width());
528 
529     const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
530     CHECK_NULL_RETURN(calcLayoutConstraint, searchWidth);
531     auto hasMinSize = calcLayoutConstraint->minSize->Width().has_value();
532     auto hasMaxSize = calcLayoutConstraint->maxSize->Width().has_value();
533     auto hasWidth = calcLayoutConstraint->selfIdealSize->Width().has_value();
534     if (hasMinSize && ((hasMaxSize && searchConstraint.minSize.Width() >= searchConstraint.maxSize.Width())
535         || (!hasMaxSize && !hasWidth))) {
536         return searchConstraint.minSize.Width();
537     }
538     if (hasMinSize) {
539         searchWidth = std::max(searchConstraint.minSize.Width(), static_cast<float>(searchWidth));
540     }
541     if (hasMaxSize) {
542         searchWidth = std::min(searchConstraint.maxSize.Width(), static_cast<float>(searchWidth));
543     }
544     return searchWidth;
545 }
546 
CalcSearchHeight(const LayoutConstraintF & constraint,LayoutWrapper * layoutWrapper)547 double SearchLayoutAlgorithm::CalcSearchHeight(
548     const LayoutConstraintF& constraint, LayoutWrapper* layoutWrapper)
549 {
550     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
551     CHECK_NULL_RETURN(layoutProperty, 0.0);
552     auto host = layoutWrapper->GetHostNode();
553     CHECK_NULL_RETURN(host, 0.0);
554     auto pipeline = host->GetContext();
555     CHECK_NULL_RETURN(pipeline, 0.0);
556     auto renderContext = host->GetRenderContext();
557     CHECK_NULL_RETURN(renderContext, 0.0);
558     auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
559     CHECK_NULL_RETURN(searchTheme, 0.0);
560     auto themeHeight = searchTheme->GetHeight().ConvertToPx();
561     auto searchHeight =
562         (constraint.selfIdealSize.Height().has_value()) ? constraint.selfIdealSize.Height().value() : themeHeight;
563     auto layoutPolicy = TextBase::GetLayoutCalPolicy(layoutWrapper, false);
564     auto shouldMatchParent =
565         layoutPolicy == LayoutCalPolicy::MATCH_PARENT && constraint.parentIdealSize.Height().has_value();
566     searchHeight = shouldMatchParent ? constraint.parentIdealSize.Height().value() : searchHeight;
567     auto padding = layoutProperty->CreatePaddingAndBorder();
568     auto verticalPadding = padding.top.value_or(0.0f) + padding.bottom.value_or(0.0f);
569     searchHeight = std::max(verticalPadding, static_cast<float>(searchHeight));
570     auto searchHeightAdapt = searchHeight;
571     if (!IsFixedHeightMode(layoutWrapper) && !shouldMatchParent) {
572         searchHeightAdapt = std::max(searchHeightAdapt, CalcSearchAdaptHeight(layoutWrapper));
573         renderContext->SetClipToBounds(false);
574     } else {
575         renderContext->SetClipToBounds(true);
576     }
577 
578     const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
579     CHECK_NULL_RETURN(calcLayoutConstraint, searchHeightAdapt);
580     auto hasMinSize = calcLayoutConstraint->minSize.has_value() &&
581         calcLayoutConstraint->minSize->Height().has_value();
582     auto hasMaxSize = calcLayoutConstraint->maxSize.has_value() &&
583         calcLayoutConstraint->maxSize->Height().has_value();
584     auto hasHeight = calcLayoutConstraint->selfIdealSize.has_value() &&
585         calcLayoutConstraint->selfIdealSize->Height().has_value();
586     if (hasMinSize && ((hasMaxSize && constraint.minSize.Height() >= constraint.maxSize.Height())
587         || (!hasMaxSize && !hasHeight && !shouldMatchParent))) {
588         return constraint.minSize.Height();
589     }
590     if (hasMinSize) {
591         searchHeightAdapt = std::max(constraint.minSize.Height(),
592             static_cast<float>(searchHeightAdapt));
593     }
594     if (hasMaxSize) {
595         searchHeightAdapt = std::min(constraint.maxSize.Height(),
596             static_cast<float>(searchHeightAdapt));
597     }
598     return searchHeightAdapt;
599 }
600 
Measure(LayoutWrapper * layoutWrapper)601 void SearchLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
602 {
603     auto host = layoutWrapper->GetHostNode();
604     CHECK_NULL_VOID(host);
605     auto children = host->GetChildren();
606     if (children.empty()) {
607         return;
608     }
609 
610     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
611     CHECK_NULL_VOID(layoutProperty);
612     auto constraint = layoutProperty->GetLayoutConstraint();
613     CHECK_NULL_VOID(constraint);
614     ResetChildrenMeasureSize();
615     searchHeight_ = CalcSearchHeight(constraint.value(), layoutWrapper);
616     maxFontScale_ = CalculateMaxFontScale(layoutWrapper);
617     minFontScale_ = CalculateMinFontScale(layoutWrapper);
618 
619     SearchButtonMeasure(layoutWrapper);
620     DividerMeasure(layoutWrapper);
621     ImageMeasure(layoutWrapper);
622     CancelImageMeasure(layoutWrapper);
623     CancelButtonMeasure(layoutWrapper);
624     TextFieldMeasure(layoutWrapper);
625     SelfMeasure(layoutWrapper);
626 }
627 
CalcChildrenHotZone(LayoutWrapper * layoutWrapper)628 void SearchLayoutAlgorithm::CalcChildrenHotZone(LayoutWrapper* layoutWrapper)
629 {
630     // search info
631     auto searchGeometryNode = layoutWrapper->GetGeometryNode();
632     CHECK_NULL_VOID(searchGeometryNode);
633     auto searchHeight = searchGeometryNode->GetFrameSize().Height();
634 
635     // cancel button info
636     auto cancelButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
637     CHECK_NULL_VOID(cancelButtonWrapper);
638     auto cancelButtonFrameNode = cancelButtonWrapper->GetHostNode();
639     CHECK_NULL_VOID(cancelButtonFrameNode);
640     auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
641     CHECK_NULL_VOID(cancelButtonGeometryNode);
642     auto cancelButtonFrameSize = cancelButtonGeometryNode->GetFrameSize();
643     auto cancelButtonWidth = cancelButtonFrameSize.Width();
644     auto cancelButtonHeight = cancelButtonFrameSize.Height();
645 
646     // search button info
647     auto searchButtonWrapper = layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
648     CHECK_NULL_VOID(searchButtonWrapper);
649     auto searchButtonFrameNode = searchButtonWrapper->GetHostNode();
650     CHECK_NULL_VOID(searchButtonFrameNode);
651     auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
652     CHECK_NULL_VOID(searchButtonGeometryNode);
653     auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
654     auto searchButtonWidth = searchButtonFrameSize.Width();
655     auto searchButtonHeight = searchButtonFrameSize.Height();
656 
657     auto pipeline = searchButtonFrameNode->GetContext();
658     CHECK_NULL_VOID(pipeline);
659     auto searchTheme = pipeline->GetTheme<SearchTheme>(searchButtonFrameNode->GetThemeScopeId());
660     auto buttonSpace = searchTheme->GetSearchButtonSpace().ConvertToPx();
661     // calculate cancel button hot zone
662     cancelButtonFrameNode->RemoveLastHotZoneRect();
663     DimensionRect cancelButtonHotZone;
664     if (cancelButtonHeight > searchHeight) {
665         cancelButtonHotZone.SetSize(DimensionSize(Dimension(cancelButtonWidth), Dimension(searchHeight)));
666         double hotZoneOffsetY = (cancelButtonHeight - searchHeight) / 2;
667         cancelButtonHotZone.SetOffset(DimensionOffset(Dimension(0), Dimension(hotZoneOffsetY)));
668     } else {
669         cancelButtonHotZone.SetSize(DimensionSize(
670             Dimension(cancelButtonWidth + 2 * buttonSpace), Dimension(cancelButtonHeight + 2 * buttonSpace)));
671         cancelButtonHotZone.SetOffset(
672             DimensionOffset(Offset(static_cast<float>(-buttonSpace), static_cast<float>(-buttonSpace))));
673     }
674     cancelButtonFrameNode->AddHotZoneRect(cancelButtonHotZone);
675 
676     // calculate search button hot zone
677     searchButtonFrameNode->RemoveLastHotZoneRect();
678     DimensionRect searchButtonHotZone;
679     if (searchButtonHeight > searchHeight) {
680         searchButtonHotZone.SetSize(DimensionSize(Dimension(searchButtonWidth), Dimension(searchHeight)));
681         double hotZoneOffsetY = (searchButtonHeight - searchHeight) / 2;
682         searchButtonHotZone.SetOffset(DimensionOffset(Dimension(0), Dimension(hotZoneOffsetY)));
683     } else {
684         searchButtonHotZone.SetSize(DimensionSize(
685             Dimension(searchButtonWidth + 2 * buttonSpace), Dimension(searchButtonHeight + 2 * buttonSpace)));
686         searchButtonHotZone.SetOffset(
687             DimensionOffset(Offset(static_cast<float>(-buttonSpace), static_cast<float>(-buttonSpace))));
688     }
689     searchButtonFrameNode->AddHotZoneRect(searchButtonHotZone);
690 }
691 
Layout(LayoutWrapper * layoutWrapper)692 void SearchLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
693 {
694     auto host = layoutWrapper->GetHostNode();
695     CHECK_NULL_VOID(host);
696     auto children = host->GetChildren();
697     if (children.empty()) {
698         return;
699     }
700 
701     auto layoutProperty = DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
702     CHECK_NULL_VOID(layoutProperty);
703     auto isRTL = layoutProperty->GetNonAutoLayoutDirection() == TextDirection::RTL;
704 
705 
706     auto pipeline = host->GetContext();
707     CHECK_NULL_VOID(pipeline);
708     auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
709 
710     auto geometryNode = layoutWrapper->GetGeometryNode();
711     CHECK_NULL_VOID(geometryNode);
712     auto searchSize = geometryNode->GetFrameSize();
713     auto searchFrameWidth = searchSize.Width();
714     auto searchFrameHeight = searchSize.Height();
715     if (NearZero(searchFrameWidth) || NearZero(searchFrameHeight)) {
716         return;
717     }
718 
719     LayoutSearchParams params = {
720         .layoutWrapper = layoutWrapper,
721         .layoutProperty = layoutProperty,
722         .searchTheme = searchTheme,
723         .searchFrameWidth = searchFrameWidth,
724         .searchFrameHeight = searchFrameHeight,
725         .isRTL = isRTL
726     };
727 
728     LayoutSearchIcon(params);
729     LayoutSearchButton(params);
730     LayoutDivider(params);
731     LayoutCancelButton(params);
732     LayoutCancelImage(params);
733     LayoutTextField(params);
734 
735     CalcChildrenHotZone(layoutWrapper);
736 }
737 
LayoutSearchIcon(const LayoutSearchParams & params)738 void SearchLayoutAlgorithm::LayoutSearchIcon(const LayoutSearchParams& params)
739 {
740     auto searchIconLeftSpace = params.searchTheme->GetSearchIconLeftSpace().ConvertToPx();
741     auto imageWrapper = params.layoutWrapper->GetOrCreateChildByIndex(IMAGE_INDEX);
742     CHECK_NULL_VOID(imageWrapper);
743     auto imageGeometryNode = imageWrapper->GetGeometryNode();
744     CHECK_NULL_VOID(imageGeometryNode);
745     auto iconFrameWidth = searchIconSizeMeasure_.Width();
746     auto iconFrameHeight = searchIconSizeMeasure_.Height();
747     auto layoutProperty = params.layoutProperty;
748     auto iconRenderWidth = layoutProperty->GetSearchIconUDSizeValue(Dimension(iconFrameWidth)).ConvertToPx();
749 
750     auto padding = layoutProperty->CreatePaddingAndBorder();
751     float topPadding = padding.top.value_or(0.0f);
752     auto bottomPadding = padding.bottom.value_or(0.0f);
753     auto leftOffset = padding.left.value_or(0.0f);
754     auto rightOffset = padding.right.value_or(0.0f);
755     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
756         leftOffset = 0.0f;
757     }
758     float iconHorizontalOffset = params.isRTL ?
759         params.searchFrameWidth - searchIconLeftSpace - iconRenderWidth - rightOffset :
760         leftOffset + searchIconLeftSpace + (iconRenderWidth - iconFrameWidth) / 2.0f;
761 
762     auto searchIconConstraint = imageWrapper->GetLayoutProperty()->GetLayoutConstraint();
763     auto iconUserHeight =
764         searchIconConstraint->selfIdealSize.Height().value_or(params.searchTheme->GetIconHeight().ConvertToPx());
765     float imageVerticalOffset = topPadding;
766     auto host = params.layoutWrapper->GetHostNode();
767     if (host) {
768         auto pipeline = host->GetContext();
769         if (pipeline && pipeline->GetPixelRoundMode() == PixelRoundMode::PIXEL_ROUND_AFTER_MEASURE) {
770             // height is rounded in framenode's measure function, iconFrameHeight has no fractional part
771             iconUserHeight = std::floor(iconUserHeight + 0.5f);
772         }
773     }
774     if (NearEqual(iconUserHeight, iconFrameHeight)) {
775         float iconInterval = (params.searchFrameHeight - iconUserHeight) / 2;
776         if (topPadding <= iconInterval && bottomPadding <= iconInterval) {
777             imageVerticalOffset = iconInterval;
778         } else if (topPadding <= iconInterval && bottomPadding > iconInterval) {
779             imageVerticalOffset = params.searchFrameHeight - (bottomPadding + iconFrameHeight);
780         }
781     }
782     OffsetF imageOffset(iconHorizontalOffset, imageVerticalOffset);
783     imageGeometryNode->SetMarginFrameOffset(imageOffset);
784     imageWrapper->Layout();
785 }
786 
LayoutSearchButton(const LayoutSearchParams & params)787 void SearchLayoutAlgorithm::LayoutSearchButton(const LayoutSearchParams& params)
788 {
789     auto searchButtonSpace = params.searchTheme->GetSearchButtonSpace().ConvertToPx();
790 
791     auto searchButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
792     CHECK_NULL_VOID(searchButtonWrapper);
793     auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
794     CHECK_NULL_VOID(searchButtonGeometryNode);
795     auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
796     float searchButtonVerticalOffset = (params.searchFrameHeight - searchButtonFrameSize.Height()) / TWO;
797 
798     auto padding = params.layoutProperty->CreatePaddingAndBorder();
799     auto leftOffset = padding.left.value_or(0.0f);
800     auto rightOffset = padding.right.value_or(0.0f);
801     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
802         rightOffset = 0.0f;
803     }
804     float searchButtonHorizontalOffset = 0.0f;
805     if (params.isRTL) {
806         searchButtonHorizontalOffset = leftOffset + searchButtonSpace;
807     } else {
808         searchButtonHorizontalOffset =
809             params.searchFrameWidth - searchButtonFrameSize.Width() - searchButtonSpace - rightOffset;
810         searchButtonHorizontalOffset = std::max(searchButtonHorizontalOffset, 0.0f);
811     }
812     auto searchButtonOffset = OffsetF(searchButtonHorizontalOffset, searchButtonVerticalOffset);
813     searchButtonGeometryNode->SetMarginFrameOffset(searchButtonOffset);
814     searchButtonWrapper->Layout();
815 }
816 
LayoutDivider(const LayoutSearchParams & params)817 void SearchLayoutAlgorithm::LayoutDivider(const LayoutSearchParams& params)
818 {
819     auto searchButtonSpace = params.searchTheme->GetSearchButtonSpace().ConvertToPx();
820     auto dividerSpace = params.searchTheme->GetDividerSideSpace().ConvertToPx();
821 
822     auto dividerWrapper = params.layoutWrapper->GetOrCreateChildByIndex(DIVIDER_INDEX);
823     CHECK_NULL_VOID(dividerWrapper);
824     auto dividerGeometryNode = dividerWrapper->GetGeometryNode();
825     CHECK_NULL_VOID(dividerGeometryNode);
826     auto dividerFrameSize = dividerGeometryNode->GetFrameSize();
827 
828     auto padding = params.layoutProperty->CreatePaddingAndBorder();
829     auto leftOffset = padding.left.value_or(0.0f);
830     auto rightOffset = padding.right.value_or(0.0f);
831     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
832         rightOffset = 0.0f;
833     }
834     auto buttonWidth = searchButtonSizeMeasure_.Width();
835 
836     float dividerHorizontalOffset = 0.0f;
837     if (params.isRTL) {
838         dividerHorizontalOffset =
839             leftOffset + buttonWidth + dividerSpace + searchButtonSpace + dividerFrameSize.Width() / 2.0f;
840     } else {
841         dividerHorizontalOffset = params.searchFrameWidth - buttonWidth - dividerSpace - searchButtonSpace -
842                                   dividerFrameSize.Width() / 2.0f - rightOffset;
843     }
844     dividerHorizontalOffset = std::max(dividerHorizontalOffset, 0.0f);
845     auto dividerVerticalOffset = (params.searchFrameHeight - dividerFrameSize.Height()) / 2.0f;
846     auto dividerOffset = OffsetF(dividerHorizontalOffset, dividerVerticalOffset);
847     dividerGeometryNode->SetMarginFrameOffset(dividerOffset);
848     dividerWrapper->Layout();
849 }
850 
851 
LayoutCancelButton(const LayoutSearchParams & params)852 void SearchLayoutAlgorithm::LayoutCancelButton(const LayoutSearchParams& params)
853 {
854     auto searchTheme = params.searchTheme;
855     CHECK_NULL_VOID(searchTheme);
856     auto dividerSideSpace = searchTheme->GetDividerSideSpace().ConvertToPx();
857     auto dividerWidth = searchTheme->GetSearchDividerWidth().ConvertToPx();
858     auto borderWidth = searchTheme->GetBorderWidth().ConvertToPx();
859 
860     auto cancelButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
861     CHECK_NULL_VOID(cancelButtonWrapper);
862     auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
863     CHECK_NULL_VOID(cancelButtonGeometryNode);
864     auto cancelButtonFrameSize = cancelButtonGeometryNode->GetFrameSize();
865     auto cancelButtonFrameWidth = cancelButtonFrameSize.Width();
866     auto cancelButtonFrameHeight = cancelButtonFrameSize.Height();
867 
868     auto searchButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(BUTTON_INDEX);
869     CHECK_NULL_VOID(searchButtonWrapper);
870     auto searchButtonGeometryNode = searchButtonWrapper->GetGeometryNode();
871     CHECK_NULL_VOID(searchButtonGeometryNode);
872     auto searchButtonFrameSize = searchButtonGeometryNode->GetFrameSize();
873     auto searchButtonHorizontalOffset = searchButtonGeometryNode->GetMarginFrameOffset().GetX();
874 
875     auto cancelButtonHorizontalOffset = 0;
876     auto cancelButtonVerticalOffset = (params.searchFrameHeight - cancelButtonFrameHeight) / 2;
877     auto searchButtonNode = searchButtonWrapper->GetHostNode();
878     auto searchButtonEvent = searchButtonNode->GetOrCreateEventHub<ButtonEventHub>();
879     auto buttonSpace = params.searchTheme->GetSearchButtonSpace().ConvertToPx();
880     auto searchButtonLayoutProperty = searchButtonNode->GetLayoutProperty<ButtonLayoutProperty>();
881     CHECK_NULL_VOID(searchButtonLayoutProperty);
882     auto needToDisable = searchButtonLayoutProperty->GetAutoDisable().value_or(false);
883     if (params.isRTL) {
884         if (searchButtonEvent->IsEnabled() || needToDisable) {
885             cancelButtonHorizontalOffset =
886                 searchButtonHorizontalOffset + (searchButtonFrameSize.Width() + TWO * dividerSideSpace + dividerWidth);
887         } else {
888             cancelButtonHorizontalOffset = searchButtonHorizontalOffset;
889         }
890     } else {
891         if (searchButtonEvent->IsEnabled() || needToDisable) {
892             auto cancelButtonOffsetToSearchButton = cancelButtonFrameWidth + 2 * dividerSideSpace + dividerWidth;
893             cancelButtonHorizontalOffset =
894                 std::max(searchButtonHorizontalOffset - cancelButtonOffsetToSearchButton, 0.0);
895         } else {
896             cancelButtonHorizontalOffset = params.searchFrameWidth - cancelButtonFrameWidth - buttonSpace - borderWidth;
897         }
898     }
899     auto cancelButtonOffset = OffsetF(cancelButtonHorizontalOffset, cancelButtonVerticalOffset);
900     cancelButtonGeometryNode->SetMarginFrameOffset(cancelButtonOffset);
901     cancelButtonWrapper->Layout();
902 }
903 
LayoutCancelImage(const LayoutSearchParams & params)904 void SearchLayoutAlgorithm::LayoutCancelImage(const LayoutSearchParams& params)
905 {
906     auto cancelImageWrapper = params.layoutWrapper->GetOrCreateChildByIndex(CANCEL_IMAGE_INDEX);
907     CHECK_NULL_VOID(cancelImageWrapper);
908     auto cancelImageGeometryNode = cancelImageWrapper->GetGeometryNode();
909     CHECK_NULL_VOID(cancelImageGeometryNode);
910     auto cancelImageFrameSize = cancelImageGeometryNode->GetFrameSize();
911     auto cancelImageFrameWidth = cancelImageFrameSize.Width();
912     auto cancelImageFrameHeight = cancelImageFrameSize.Height();
913 
914     auto cancelButtonWrapper = params.layoutWrapper->GetOrCreateChildByIndex(CANCEL_BUTTON_INDEX);
915     CHECK_NULL_VOID(cancelButtonWrapper);
916     auto cancelButtonGeometryNode = cancelButtonWrapper->GetGeometryNode();
917     CHECK_NULL_VOID(cancelButtonGeometryNode);
918     auto cancelButtonHorizontalOffset = cancelButtonGeometryNode->GetMarginFrameOffset().GetX();
919     auto cancelButtonFrameWidth = cancelButtonGeometryNode->GetFrameSize().Width();
920 
921     auto cancelImageVerticalOffset = (params.searchFrameHeight - cancelImageFrameHeight) / 2;
922     auto cancelButtonImageCenterOffset = (cancelButtonFrameWidth - cancelImageFrameWidth) / 2;
923     auto cancelImageHorizontalOffset = cancelButtonHorizontalOffset + cancelButtonImageCenterOffset;
924     auto cancelImageOffset = OffsetF(cancelImageHorizontalOffset, cancelImageVerticalOffset);
925     cancelImageGeometryNode->SetMarginFrameOffset(cancelImageOffset);
926     cancelImageWrapper->Layout();
927 }
928 
LayoutTextField(const LayoutSearchParams & params)929 void SearchLayoutAlgorithm::LayoutTextField(const LayoutSearchParams& params)
930 {
931     auto searchIconLeftSpace = params.searchTheme->GetSearchIconLeftSpace().ConvertToPx();
932     auto searchIconRightSpace = params.searchTheme->GetSearchIconRightSpace().ConvertToPx();
933     auto searchIconWidth = searchIconSizeMeasure_.Width();
934     auto layoutProperty = DynamicCast<SearchLayoutProperty>(params.layoutWrapper->GetLayoutProperty());
935     CHECK_NULL_VOID(layoutProperty);
936     auto padding = layoutProperty->CreatePaddingAndBorder();
937 
938     auto textFieldWrapper = params.layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
939     CHECK_NULL_VOID(textFieldWrapper);
940     auto textFieldGeometryNode = textFieldWrapper->GetGeometryNode();
941     CHECK_NULL_VOID(textFieldGeometryNode);
942 
943     auto hostGeometryNode = params.layoutWrapper->GetGeometryNode();
944     CHECK_NULL_VOID(hostGeometryNode);
945 
946     auto textFieldHorizontalOffset = 0;
947     if (params.isRTL) {
948         auto rightOffset = searchIconWidth + searchIconLeftSpace
949             + searchIconRightSpace + padding.right.value_or(0.0f);
950         textFieldHorizontalOffset = hostGeometryNode->GetFrameSize().Width()
951             - rightOffset - textFieldGeometryNode->GetFrameSize().Width();
952     } else {
953         textFieldHorizontalOffset = searchIconWidth + searchIconLeftSpace
954             + searchIconRightSpace + padding.left.value_or(0.0f);
955     }
956 
957     auto textFieldVerticalOffset = (params.searchFrameHeight - textFieldGeometryNode->GetFrameSize().Height()) / 2;
958     textFieldGeometryNode->SetMarginFrameOffset(OffsetF(textFieldHorizontalOffset, textFieldVerticalOffset));
959     textFieldWrapper->Layout();
960 }
961 
UpdateClipBounds(LayoutWrapper * layoutWrapper,float height)962 void SearchLayoutAlgorithm::UpdateClipBounds(LayoutWrapper* layoutWrapper, float height)
963 {
964     if (!IsFixedHeightMode(layoutWrapper)) {
965         return;
966     }
967     auto host = layoutWrapper->GetHostNode();
968     CHECK_NULL_VOID(host);
969     auto renderContext = host->GetRenderContext();
970     CHECK_NULL_VOID(renderContext);
971     auto layoutProperty = AceType::DynamicCast<SearchLayoutProperty>(layoutWrapper->GetLayoutProperty());
972     CHECK_NULL_VOID(layoutProperty);
973     if (!layoutProperty->HasSearchIconUDSize() && !layoutProperty->HasCancelButtonUDSize()) {
974         auto pipeline = host->GetContext();
975         CHECK_NULL_VOID(pipeline);
976         auto searchTheme = pipeline->GetTheme<SearchTheme>(host->GetThemeScopeId());
977         CHECK_NULL_VOID(searchTheme);
978         auto defaultImageHeight = searchTheme->GetIconSize().ConvertToPx();
979         auto isClip = LessNotEqual(height, defaultImageHeight);
980         renderContext->SetClipToBounds(isClip);
981         return;
982     }
983     auto isClip = false;
984     if (layoutProperty->HasSearchIconUDSize()) {
985         isClip = isClip || LessNotEqual(height, layoutProperty->GetSearchIconUDSizeValue().ConvertToPx());
986     }
987     if (layoutProperty->HasCancelButtonUDSize()) {
988         isClip = isClip || LessNotEqual(height, layoutProperty->GetCancelButtonUDSizeValue().ConvertToPx());
989     }
990     renderContext->SetClipToBounds(isClip);
991 }
CalcSymbolIconHeight(LayoutWrapper * layoutWrapper,int32_t index,double defaultImageHeight)992 double SearchLayoutAlgorithm::CalcSymbolIconHeight(
993     LayoutWrapper* layoutWrapper, int32_t index, double defaultImageHeight)
994 {
995     auto hostNode = layoutWrapper->GetHostNode();
996     CHECK_NULL_RETURN(hostNode, defaultImageHeight);
997     auto pipeline = hostNode->GetContext();
998     CHECK_NULL_RETURN(pipeline, defaultImageHeight);
999     auto searchPattern = hostNode->GetPattern<SearchPattern>();
1000     CHECK_NULL_RETURN(searchPattern, defaultImageHeight);
1001     auto searchNode = searchPattern->GetSearchNode();
1002     CHECK_NULL_RETURN(searchNode, defaultImageHeight);
1003 
1004     auto iconNode = AceType::DynamicCast<FrameNode>(hostNode->GetChildAtIndex(index));
1005     CHECK_NULL_RETURN(iconNode, defaultImageHeight);
1006     auto symbolLayoutProperty = iconNode->GetLayoutProperty<TextLayoutProperty>();
1007     CHECK_NULL_RETURN(symbolLayoutProperty, defaultImageHeight);
1008     symbolLayoutProperty->UpdateMaxFontScale(maxFontScale_);
1009     symbolLayoutProperty->UpdateMinFontScale(minFontScale_);
1010     auto defaultSymbolIconSize =
1011         (index == IMAGE_INDEX ? searchNode->GetSearchSymbolIconSize() : searchNode->GetCancelSymbolIconSize());
1012     auto iconSize = symbolLayoutProperty->GetFontSize().value_or(defaultSymbolIconSize);
1013 
1014     return iconSize.ConvertToPxDistribute(minFontScale_, maxFontScale_);
1015 }
1016 
GetSearchFieldMinWidth(LayoutWrapper * layoutWrapper)1017 float SearchLayoutAlgorithm::GetSearchFieldMinWidth(LayoutWrapper* layoutWrapper)
1018 {
1019     CHECK_NULL_RETURN(layoutWrapper, 0.0f);
1020     auto textFieldWrapper = layoutWrapper->GetOrCreateChildByIndex(TEXTFIELD_INDEX);
1021     CHECK_NULL_RETURN(textFieldWrapper, 0.0f);
1022     auto textFieldNode = textFieldWrapper->GetHostNode();
1023     CHECK_NULL_RETURN(textFieldNode, 0.0f);
1024     auto textFieldPattern = textFieldNode->GetPattern<TextFieldPattern>();
1025     CHECK_NULL_RETURN(textFieldPattern, 0.0f);
1026     return textFieldPattern->GetCaretRect().Width();
1027 }
1028 
GetSearchFixAtIdealMaxWidth(LayoutWrapper * layoutWrapper)1029 std::optional<float> SearchLayoutAlgorithm::GetSearchFixAtIdealMaxWidth(LayoutWrapper* layoutWrapper)
1030 {
1031     auto widthPolicy = TextBase::GetLayoutCalPolicy(layoutWrapper, true);
1032     if (widthPolicy != LayoutCalPolicy::FIX_AT_IDEAL_SIZE) {
1033         return std::nullopt;
1034     }
1035     return TextBase::GetCalcLayoutConstraintLength(layoutWrapper, true, true);
1036 }
1037 
GetTextFieldMinWidth(LayoutWrapper * layoutWrapper,const RefPtr<SearchTheme> & searchTheme)1038 float SearchLayoutAlgorithm::GetTextFieldMinWidth(LayoutWrapper* layoutWrapper, const RefPtr<SearchTheme>& searchTheme)
1039 {
1040     auto minCalcWidth = TextBase::GetCalcLayoutConstraintLength(layoutWrapper, false, true);
1041     if (minCalcWidth.has_value()) {
1042         return CalculateTextFieldWidth(layoutWrapper, minCalcWidth.value(), searchTheme);
1043     }
1044     return GetSearchFieldMinWidth(layoutWrapper);
1045 }
1046 
GetTextFieldMaxWidth(LayoutWrapper * layoutWrapper,LayoutCalPolicy layoutPolicy,float maxWidth)1047 float SearchLayoutAlgorithm::GetTextFieldMaxWidth(
1048     LayoutWrapper* layoutWrapper, LayoutCalPolicy layoutPolicy, float maxWidth)
1049 {
1050     auto maxCalcWidth = TextBase::GetCalcLayoutConstraintLength(layoutWrapper, true, true);
1051     if (layoutPolicy == LayoutCalPolicy::FIX_AT_IDEAL_SIZE && !maxCalcWidth.has_value()) {
1052         return std::numeric_limits<double>::infinity();
1053     }
1054     return maxWidth;
1055 }
1056 
ResetChildrenMeasureSize()1057 void SearchLayoutAlgorithm::ResetChildrenMeasureSize()
1058 {
1059     searchIconSizeMeasure_.Reset();
1060     cancelIconSizeMeasure_.Reset();
1061     searchButtonSizeMeasure_.Reset();
1062     cancelBtnSizeMeasure_.Reset();
1063     textFieldSizeMeasure_.Reset();
1064     dividerSizeMeasure_.Reset();
1065 }
1066 } // namespace OHOS::Ace::NG
1067