• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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/text_field/text_field_layout_algorithm.h"
17 
18 #include "base/geometry/axis.h"
19 #include "base/geometry/dimension.h"
20 #include "base/geometry/ng/rect_t.h"
21 #include "base/geometry/ng/size_t.h"
22 #include "base/i18n/localization.h"
23 #include "base/memory/referenced.h"
24 #include "base/utils/utils.h"
25 #include "core/common/font_manager.h"
26 #include "core/components/common/layout/constants.h"
27 #include "core/components/scroll/scroll_bar_theme.h"
28 #include "core/components_ng/base/frame_node.h"
29 #include "core/components_ng/pattern/text/text_layout_adapter.h"
30 #include "core/components_ng/pattern/text/text_layout_property.h"
31 #include "core/components_ng/pattern/text_field/text_field_content_modifier.h"
32 #include "core/components_ng/pattern/text_field/text_field_layout_property.h"
33 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
34 #include "core/components_ng/pattern/text_field/text_selector.h"
35 #include "core/components_ng/property/measure_utils.h"
36 #include "core/pipeline_ng/pipeline_context.h"
37 
38 namespace OHOS::Ace::NG {
39 namespace {
40 constexpr float PARAGRAPH_SAVE_BOUNDARY = 1.0f;
41 constexpr uint32_t INLINE_DEFAULT_VIEW_MAXLINE = 3;
42 constexpr uint32_t COUNTER_TEXT_MAXLINE = 1;
43 constexpr int32_t DEFAULT_MODE = -1;
44 constexpr int32_t SHOW_COUNTER_PERCENT = 100;
45 } // namespace
ConstructTextStyles(const RefPtr<FrameNode> & frameNode,TextStyle & textStyle,std::string & textContent,bool & showPlaceHolder)46 void TextFieldLayoutAlgorithm::ConstructTextStyles(
47     const RefPtr<FrameNode>& frameNode, TextStyle& textStyle, std::string& textContent, bool& showPlaceHolder)
48 {
49     CHECK_NULL_VOID(frameNode);
50     auto pipeline = frameNode->GetContext();
51     CHECK_NULL_VOID(pipeline);
52     auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
53     CHECK_NULL_VOID(textFieldTheme);
54     auto pattern = frameNode->GetPattern<TextFieldPattern>();
55     CHECK_NULL_VOID(pattern);
56     auto textFieldLayoutProperty = pattern->GetLayoutProperty<TextFieldLayoutProperty>();
57     CHECK_NULL_VOID(textFieldLayoutProperty);
58     auto isInlineStyle = pattern->IsNormalInlineState();
59 
60     if (!pattern->GetTextValue().empty()) {
61         UpdateTextStyle(frameNode, textFieldLayoutProperty, textFieldTheme, textStyle, pattern->IsDisabled());
62         textContent = pattern->GetTextValue();
63         if (!pattern->IsTextArea() && isInlineStyle) {
64             textStyle.SetTextOverflow(TextOverflow::ELLIPSIS);
65         } else {
66             textStyle.SetTextOverflow(TextOverflow::CLIP);
67         }
68     } else {
69         UpdatePlaceholderTextStyle(
70             frameNode, textFieldLayoutProperty, textFieldTheme, textStyle, pattern->IsDisabled());
71         textContent = textFieldLayoutProperty->GetPlaceholderValue("");
72         showPlaceHolder = true;
73     }
74 
75     // use for modifier.
76     auto contentModifier = pattern->GetContentModifier();
77     if (contentModifier) {
78         SetPropertyToModifier(textStyle, contentModifier);
79         contentModifier->ModifyTextStyle(textStyle);
80         contentModifier->SetFontReady(false);
81     }
82 }
83 
InlineMeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)84 std::optional<SizeF> TextFieldLayoutAlgorithm::InlineMeasureContent(
85     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
86 {
87     auto frameNode = layoutWrapper->GetHostNode();
88     CHECK_NULL_RETURN(frameNode, std::nullopt);
89     auto textFieldLayoutProperty = DynamicCast<TextFieldLayoutProperty>(layoutWrapper->GetLayoutProperty());
90     CHECK_NULL_RETURN(textFieldLayoutProperty, std::nullopt);
91     auto pattern = frameNode->GetPattern<TextFieldPattern>();
92     CHECK_NULL_RETURN(pattern, std::nullopt);
93     auto textFieldTheme = pattern->GetTheme();
94     CHECK_NULL_RETURN(textFieldTheme, std::nullopt);
95 
96     float contentWidth = 0.0f;
97     auto safeBoundary = textFieldTheme->GetInlineBorderWidth().ConvertToPx() * 2;
98     if (pattern->HasFocus()) {
99         paragraph_->Layout(
100             contentConstraint.maxSize.Width() - static_cast<float>(safeBoundary) - PARAGRAPH_SAVE_BOUNDARY);
101         auto longestLine = std::ceil(paragraph_->GetLongestLine());
102         paragraph_->Layout(std::min(static_cast<float>(longestLine), paragraph_->GetMaxWidth()));
103         contentWidth = ConstraintWithMinWidth(
104             contentConstraint, layoutWrapper, paragraph_, static_cast<float>(safeBoundary) + PARAGRAPH_SAVE_BOUNDARY);
105     } else {
106         paragraph_->Layout(contentConstraint.maxSize.Width());
107         contentWidth = ConstraintWithMinWidth(contentConstraint, layoutWrapper, paragraph_);
108         // calc inline status in advance
109         auto widthOffSet = contentConstraint.selfIdealSize.Width().has_value()?
110             pattern->GetPaddingLeft() + pattern->GetPaddingRight() - safeBoundary : 0.0f - safeBoundary;
111         inlineParagraph_->Layout(contentConstraint.maxSize.Width() + widthOffSet
112             - safeBoundary - PARAGRAPH_SAVE_BOUNDARY);
113         auto longestLine = std::ceil(inlineParagraph_->GetLongestLine());
114         inlineParagraph_->Layout(std::min(static_cast<float>(longestLine), inlineParagraph_->GetMaxWidth()));
115         auto inlineContentWidth = ConstraintWithMinWidth(contentConstraint, layoutWrapper, inlineParagraph_,
116             static_cast<float>(safeBoundary) + PARAGRAPH_SAVE_BOUNDARY);
117         inlineMeasureItem_.inlineScrollRectOffsetX = contentWidth
118             + pattern->GetHorizontalPaddingAndBorderSum() - inlineContentWidth - safeBoundary - PARAGRAPH_SAVE_BOUNDARY;
119     }
120 
121     textRect_.SetSize(SizeF(GetVisualTextWidth(), paragraph_->GetHeight()));
122 
123     auto inlineIdealHeight = contentConstraint.maxSize.Height();
124     GetInlineMeasureItem(contentConstraint, layoutWrapper, inlineIdealHeight);
125     auto contentHeight = GreatNotEqual(paragraph_->GetLongestLine(), 0.0)
126         ? paragraph_->GetHeight() : std::max(preferredHeight_, paragraph_->GetHeight());
127 
128     return SizeF(contentWidth, std::min(inlineIdealHeight, contentHeight));
129 }
130 
GetInlineMeasureItem(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper,float & inlineIdealHeight)131 void TextFieldLayoutAlgorithm::GetInlineMeasureItem(
132     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper, float& inlineIdealHeight)
133 {
134     auto frameNode = layoutWrapper->GetHostNode();
135     CHECK_NULL_VOID(frameNode);
136     auto textFieldLayoutProperty = DynamicCast<TextFieldLayoutProperty>(layoutWrapper->GetLayoutProperty());
137     CHECK_NULL_VOID(textFieldLayoutProperty);
138     auto pattern = frameNode->GetPattern<TextFieldPattern>();
139     CHECK_NULL_VOID(pattern);
140 
141     if (pattern->HasFocus() && paragraph_->GetLineCount() != 0) {
142         pattern->SetSingleLineHeight(paragraph_->GetHeight() / paragraph_->GetLineCount());
143         // The maximum height of the inline mode defaults to a maximum of three rows.
144         inlineIdealHeight =
145             pattern->GetSingleLineHeight() * textFieldLayoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE);
146         inlineMeasureItem_.inlineSizeHeight = inlineIdealHeight;
147     } else {
148         // calc inline status in advance
149         CalcInlineMeasureItem(layoutWrapper);
150     }
151 }
152 
CalcInlineMeasureItem(LayoutWrapper * layoutWrapper)153 void TextFieldLayoutAlgorithm::CalcInlineMeasureItem(LayoutWrapper* layoutWrapper)
154 {
155     auto textFieldLayoutProperty = DynamicCast<TextFieldLayoutProperty>(layoutWrapper->GetLayoutProperty());
156     CHECK_NULL_VOID(textFieldLayoutProperty);
157     auto lineCount = inlineParagraph_->GetLineCount() != 0 ? inlineParagraph_->GetLineCount() : 1;
158     inlineMeasureItem_.inlineSizeHeight = inlineParagraph_->GetHeight() / lineCount
159         * textFieldLayoutProperty->GetMaxViewLinesValue(INLINE_DEFAULT_VIEW_MAXLINE);
160     inlineMeasureItem_.inlineContentRectHeight = GreatNotEqual(inlineParagraph_->GetLongestLine(), 0.0)
161         ? inlineParagraph_->GetHeight() : std::max(preferredHeight_, inlineParagraph_->GetHeight());
162     inlineMeasureItem_.inlineLastOffsetY =
163         std::max(inlineMeasureItem_.inlineSizeHeight, inlineMeasureItem_.inlineContentRectHeight)
164         - std::min(inlineMeasureItem_.inlineSizeHeight, inlineMeasureItem_.inlineContentRectHeight);
165 }
166 
ConstraintWithMinWidth(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper,RefPtr<Paragraph> & paragraph,float removeValue)167 float TextFieldLayoutAlgorithm::ConstraintWithMinWidth(
168     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper,
169     RefPtr<Paragraph>& paragraph, float removeValue)
170 {
171     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
172         const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
173         if (calcLayoutConstraint && calcLayoutConstraint->minSize.has_value() &&
174             calcLayoutConstraint->minSize->Width().has_value() &&
175             !contentConstraint.selfIdealSize.Width().has_value()) {
176             auto width = std::max(contentConstraint.minSize.Width() - removeValue, paragraph->GetLongestLine());
177             if (width != paragraph->GetLongestLine()) {
178                 paragraph->Layout(width);
179             } else {
180                 if (LessNotEqual(paragraph->GetLongestLine(), paragraph->GetMaxWidth())) {
181                     paragraph->Layout(std::ceil(paragraph->GetLongestLine()));
182                 }
183                 return contentConstraint.selfIdealSize.Width().has_value() ? paragraph->GetMaxWidth()
184                                                                            : GetVisualTextWidth();
185             }
186         }
187     }
188     return std::max(paragraph->GetMaxWidth(), 0.0f);
189 }
190 
PlaceHolderMeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper,float imageWidth)191 SizeF TextFieldLayoutAlgorithm::PlaceHolderMeasureContent(
192     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper, float imageWidth)
193 {
194     paragraph_->Layout(contentConstraint.maxSize.Width() - imageWidth);
195 
196     // Adapts to auto width.
197     if (autoWidth_) {
198         paragraph_->Layout(std::max(0.0f, std::ceil(paragraph_->GetLongestLine())));
199     }
200 
201     auto contentWidth = ConstraintWithMinWidth(contentConstraint, layoutWrapper, paragraph_, imageWidth);
202     auto counterNodeHeight = CounterNodeMeasure(contentWidth, layoutWrapper);
203 
204     auto height = GreatNotEqual(paragraph_->GetLongestLine(), 0.0)
205                       ? paragraph_->GetHeight()
206                       : std::max(preferredHeight_, paragraph_->GetHeight());
207 
208     auto contentHeight = std::min(contentConstraint.maxSize.Height() - counterNodeHeight, height);
209 
210     textRect_.SetSize(SizeF(GetVisualTextWidth(), paragraph_->GetHeight()));
211 
212     return SizeF(contentWidth, contentHeight);
213 }
214 
TextAreaMeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)215 SizeF TextFieldLayoutAlgorithm::TextAreaMeasureContent(
216     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
217 {
218     paragraph_->Layout(contentConstraint.maxSize.Width());
219 
220     auto contentWidth = ConstraintWithMinWidth(contentConstraint, layoutWrapper, paragraph_);
221 
222     if (autoWidth_) {
223         contentWidth = std::min(contentWidth, paragraph_->GetLongestLine());
224         paragraph_->Layout(std::ceil(contentWidth));
225     }
226 
227     auto counterNodeHeight = CounterNodeMeasure(contentWidth, layoutWrapper);
228 
229     auto height = GreatNotEqual(paragraph_->GetLongestLine(), 0.0)
230                       ? paragraph_->GetHeight()
231                       : std::max(preferredHeight_, paragraph_->GetHeight());
232 
233     auto contentHeight = std::min(contentConstraint.maxSize.Height() - counterNodeHeight, height);
234 
235     textRect_.SetSize(SizeF(GetVisualTextWidth(), paragraph_->GetHeight()));
236     return SizeF(contentWidth, contentHeight);
237 }
238 
TextInputMeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper,float imageWidth)239 SizeF TextFieldLayoutAlgorithm::TextInputMeasureContent(
240     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper, float imageWidth)
241 {
242     paragraph_->Layout(std::numeric_limits<double>::infinity());
243     paragraph_->Layout(std::ceil(paragraph_->GetLongestLine()));
244 
245     auto contentWidth = contentConstraint.maxSize.Width() - imageWidth;
246     CounterNodeMeasure(contentWidth, layoutWrapper);
247     if (autoWidth_) {
248         contentWidth = std::min(contentWidth, paragraph_->GetLongestLine());
249     }
250 
251     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
252         const auto& calcLayoutConstraint = layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint();
253         if (calcLayoutConstraint && calcLayoutConstraint->minSize.has_value() &&
254             calcLayoutConstraint->minSize->Width().has_value() &&
255             !contentConstraint.selfIdealSize.Width().has_value()) {
256             contentWidth = std::min(contentConstraint.maxSize.Width() - imageWidth,
257                 std::max(paragraph_->GetLongestLine(), contentConstraint.minSize.Width() - imageWidth));
258         }
259     }
260 
261     auto height = GreatNotEqual(paragraph_->GetLongestLine(), 0.0)
262                       ? paragraph_->GetHeight()
263                       : std::max(preferredHeight_, paragraph_->GetHeight());
264 
265     auto contentHeight = std::min(contentConstraint.maxSize.Height(), height);
266 
267     textRect_.SetSize(SizeF(std::max(0.0f, paragraph_->GetLongestLine()), paragraph_->GetHeight()));
268     return SizeF(contentWidth, contentHeight);
269 }
270 
UpdateCounterNode(uint32_t textLength,uint32_t maxLength,const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)271 void TextFieldLayoutAlgorithm::UpdateCounterNode(
272     uint32_t textLength, uint32_t maxLength, const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
273 {
274     auto pipeline = PipelineBase::GetCurrentContext();
275     CHECK_NULL_VOID(pipeline);
276     auto theme = pipeline->GetTheme<TextFieldTheme>();
277     CHECK_NULL_VOID(theme);
278     auto frameNode = layoutWrapper->GetHostNode();
279     CHECK_NULL_VOID(frameNode);
280     auto pattern = frameNode->GetPattern<TextFieldPattern>();
281     CHECK_NULL_VOID(pattern);
282     auto counterNode = pattern->GetCounterNode().Upgrade();
283     CHECK_NULL_VOID(counterNode);
284     auto textLayoutProperty = DynamicCast<TextLayoutProperty>(counterNode->GetLayoutProperty());
285     CHECK_NULL_VOID(textLayoutProperty);
286     auto textFieldLayoutProperty = pattern->GetLayoutProperty<TextFieldLayoutProperty>();
287     CHECK_NULL_VOID(textFieldLayoutProperty);
288 
289     std::string counterText = "";
290     TextStyle countTextStyle = (textLength != maxLength) ? theme->GetCountTextStyle() : theme->GetOverCountTextStyle();
291     auto counterType = textFieldLayoutProperty->GetSetCounterValue(DEFAULT_MODE);
292     uint32_t limitsize = static_cast<uint32_t>(static_cast<int32_t>(maxLength) * counterType / SHOW_COUNTER_PERCENT);
293     if ((pattern->GetCounterState() == true) && textLength == maxLength && (counterType != DEFAULT_MODE)) {
294         countTextStyle = theme->GetOverCountTextStyle();
295         counterText = std::to_string(textLength) + "/" + std::to_string(maxLength);
296         countTextStyle.SetTextColor(theme->GetOverCounterColor());
297         pattern->SetCounterState(false);
298     } else if ((textLength >= limitsize) && (counterType != DEFAULT_MODE)) {
299         countTextStyle = theme->GetCountTextStyle();
300         counterText = std::to_string(textLength) + "/" + std::to_string(maxLength);
301         countTextStyle.SetTextColor(theme->GetDefaultCounterColor());
302     } else if (textFieldLayoutProperty->GetShowCounterValue(false) && counterType == DEFAULT_MODE) {
303         counterText = std::to_string(textLength) + "/" + std::to_string(maxLength);
304     }
305     textLayoutProperty->UpdateContent(counterText);
306     textLayoutProperty->UpdateFontSize(countTextStyle.GetFontSize());
307     textLayoutProperty->UpdateTextColor(countTextStyle.GetTextColor());
308     textLayoutProperty->UpdateFontWeight(countTextStyle.GetFontWeight());
309     textLayoutProperty->UpdateTextAlign(TextAlign::END);
310     textLayoutProperty->UpdateMaxLines(COUNTER_TEXT_MAXLINE);
311     auto host = counterNode->GetHostNode();
312     CHECK_NULL_VOID(host);
313     auto context = host->GetRenderContext();
314     CHECK_NULL_VOID(context);
315     context->UpdateForegroundColor(countTextStyle.GetTextColor());
316     host->Measure(contentConstraint);
317 }
318 
CounterLayout(LayoutWrapper * layoutWrapper)319 void TextFieldLayoutAlgorithm::CounterLayout(LayoutWrapper* layoutWrapper)
320 {
321     auto frameNode = layoutWrapper->GetHostNode();
322     CHECK_NULL_VOID(frameNode);
323     auto pattern = frameNode->GetPattern<TextFieldPattern>();
324     auto counterNode = pattern->GetCounterNode().Upgrade();
325     auto isInlineStyle = pattern->IsNormalInlineState();
326     auto isShowPassword = pattern->IsShowPasswordIcon();
327     if (counterNode && !isShowPassword && !isInlineStyle) {
328         auto frameNode = layoutWrapper->GetHostNode();
329         CHECK_NULL_VOID(frameNode);
330         auto pattern = frameNode->GetPattern<TextFieldPattern>();
331         CHECK_NULL_VOID(pattern);
332         auto frameRect = layoutWrapper->GetGeometryNode()->GetFrameRect();
333         auto textGeometryNode = counterNode->GetGeometryNode();
334         CHECK_NULL_VOID(textGeometryNode);
335         const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
336         CHECK_NULL_VOID(content);
337         if (!pattern->IsTextArea()) {
338             auto contentRect = layoutWrapper->GetGeometryNode()->GetContentRect();
339             auto counterWidth = counterNode->GetGeometryNode()->GetFrameSize().Width();
340             auto textGeometryNode = counterNode->GetGeometryNode();
341             CHECK_NULL_VOID(textGeometryNode);
342             textGeometryNode->SetFrameOffset(OffsetF(
343                 contentRect.Width() - counterWidth, frameRect.Height() + textGeometryNode->GetFrameRect().Height()));
344             counterNode->Layout();
345         } else {
346             textGeometryNode->SetFrameOffset(OffsetF(content->GetRect().GetX(),
347                 frameRect.Height() - pattern->GetPaddingBottom() - textGeometryNode->GetFrameRect().Height()));
348             counterNode->Layout();
349         }
350     }
351 }
352 
CounterNodeMeasure(float contentWidth,LayoutWrapper * layoutWrapper)353 float TextFieldLayoutAlgorithm::CounterNodeMeasure(float contentWidth, LayoutWrapper* layoutWrapper)
354 {
355     auto frameNode = layoutWrapper->GetHostNode();
356     CHECK_NULL_RETURN(frameNode, 0.0f);
357     auto pattern = frameNode->GetPattern<TextFieldPattern>();
358     CHECK_NULL_RETURN(pattern, 0.0f);
359     auto textFieldLayoutProperty = pattern->GetLayoutProperty<TextFieldLayoutProperty>();
360     CHECK_NULL_RETURN(textFieldLayoutProperty, 0.0f);
361     auto isInlineStyle = pattern->IsNormalInlineState();
362     auto isShowPassword = pattern->IsShowPasswordIcon();
363     if (textFieldLayoutProperty->GetShowCounterValue(false) && textFieldLayoutProperty->HasMaxLength() &&
364         !isInlineStyle && !isShowPassword) {
365         auto counterNode = DynamicCast<UINode>(pattern->GetCounterNode().Upgrade());
366         CHECK_NULL_RETURN(counterNode, 0.0f);
367         auto counterNodeLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(frameNode->GetChildIndex(counterNode));
368         if (counterNodeLayoutWrapper) {
369             auto textLength =
370                 static_cast<uint32_t>(showPlaceHolder_ ? 0 : StringUtils::ToWstring(textContent_).length());
371             auto maxLength = static_cast<uint32_t>(textFieldLayoutProperty->GetMaxLength().value());
372             LayoutConstraintF textContentConstraint;
373             textContentConstraint.UpdateIllegalSelfIdealSizeWithCheck(OptionalSizeF(contentWidth, std::nullopt));
374             UpdateCounterNode(textLength, maxLength, textContentConstraint, layoutWrapper);
375             return counterNodeLayoutWrapper->GetGeometryNode()->GetFrameSize().Height();
376         }
377     }
378     return 0.0f;
379 }
380 
GetVisualTextWidth() const381 float TextFieldLayoutAlgorithm::GetVisualTextWidth() const
382 {
383     return std::min(paragraph_->GetMaxWidth(), std::max(0.0f, paragraph_->GetLongestLine()));
384 }
385 
UpdateTextStyle(const RefPtr<FrameNode> & frameNode,const RefPtr<TextFieldLayoutProperty> & layoutProperty,const RefPtr<TextFieldTheme> & theme,TextStyle & textStyle,bool isDisabled)386 void TextFieldLayoutAlgorithm::UpdateTextStyle(const RefPtr<FrameNode>& frameNode,
387     const RefPtr<TextFieldLayoutProperty>& layoutProperty, const RefPtr<TextFieldTheme>& theme, TextStyle& textStyle,
388     bool isDisabled)
389 {
390     const std::vector<std::string> defaultFontFamily = { "sans-serif" };
391     textStyle.SetFontFamilies(layoutProperty->GetFontFamilyValue(defaultFontFamily));
392     FontRegisterCallback(frameNode, textStyle.GetFontFamilies());
393 
394     Dimension fontSize;
395     if (layoutProperty->HasFontSize() && layoutProperty->GetFontSize().value_or(Dimension()).IsNonNegative()) {
396         fontSize = layoutProperty->GetFontSizeValue(Dimension());
397     } else {
398         fontSize = theme ? theme->GetFontSize() : textStyle.GetFontSize();
399     }
400     textStyle.SetFontSize(fontSize);
401     textStyle.SetTextAlign(layoutProperty->GetTextAlignValue(TextAlign::START));
402     textStyle.SetFontWeight(
403         layoutProperty->GetFontWeightValue(theme ? theme->GetFontWeight() : textStyle.GetFontWeight()));
404     if (isDisabled) {
405         textStyle.SetTextColor(theme ? theme->GetDisableTextColor() : textStyle.GetTextColor());
406         if (layoutProperty->GetShowUnderlineValue(false) &&
407             layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
408             textStyle.SetTextColor(theme ? theme->GetTextColorDisable() : textStyle.GetTextColor());
409         }
410     } else {
411         auto renderContext = frameNode->GetRenderContext();
412         if (renderContext->HasForegroundColor()) {
413             textStyle.SetTextColor(renderContext->GetForegroundColor().value());
414         } else if (renderContext->HasForegroundColorStrategy()) {
415             textStyle.SetTextColor(Color::BLACK);
416         } else {
417             textStyle.SetTextColor(
418                 layoutProperty->GetTextColorValue(theme ? theme->GetTextColor() : textStyle.GetTextColor()));
419         }
420     }
421     if (layoutProperty->GetMaxLines()) {
422         textStyle.SetMaxLines(layoutProperty->GetMaxLines().value());
423     }
424     if (layoutProperty->HasItalicFontStyle()) {
425         textStyle.SetFontStyle(layoutProperty->GetItalicFontStyle().value());
426     }
427     if (layoutProperty->HasTextAlign()) {
428         textStyle.SetTextAlign(layoutProperty->GetTextAlign().value());
429     }
430 }
431 
UpdatePlaceholderTextStyle(const RefPtr<FrameNode> & frameNode,const RefPtr<TextFieldLayoutProperty> & layoutProperty,const RefPtr<TextFieldTheme> & theme,TextStyle & textStyle,bool isDisabled)432 void TextFieldLayoutAlgorithm::UpdatePlaceholderTextStyle(const RefPtr<FrameNode>& frameNode,
433     const RefPtr<TextFieldLayoutProperty>& layoutProperty, const RefPtr<TextFieldTheme>& theme, TextStyle& textStyle,
434     bool isDisabled)
435 {
436     const std::vector<std::string> defaultFontFamily = { "sans-serif" };
437     textStyle.SetFontFamilies(layoutProperty->GetPlaceholderFontFamilyValue(defaultFontFamily));
438     FontRegisterCallback(frameNode, textStyle.GetFontFamilies());
439 
440     Dimension fontSize;
441     if (layoutProperty->GetPlaceholderValue("").empty()) {
442         if (layoutProperty->HasFontSize() && layoutProperty->GetFontSize().value_or(Dimension()).IsNonNegative()) {
443             fontSize = layoutProperty->GetFontSizeValue(Dimension());
444         } else {
445             fontSize = theme ? theme->GetFontSize() : textStyle.GetFontSize();
446         }
447     } else {
448         if (layoutProperty->HasPlaceholderFontSize() &&
449             layoutProperty->GetPlaceholderFontSize().value_or(Dimension()).IsNonNegative()) {
450             fontSize = layoutProperty->GetPlaceholderFontSizeValue(Dimension());
451         } else {
452             fontSize = theme ? theme->GetFontSize() : textStyle.GetFontSize();
453         }
454     }
455 
456     textStyle.SetFontSize(fontSize);
457     textStyle.SetFontWeight(
458         layoutProperty->GetPlaceholderFontWeightValue(theme ? theme->GetFontWeight() : textStyle.GetFontWeight()));
459     if (isDisabled) {
460         textStyle.SetTextColor(theme ? theme->GetDisableTextColor() : textStyle.GetTextColor());
461         if (layoutProperty->GetShowUnderlineValue(false) &&
462             layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
463             textStyle.SetTextColor(theme ? theme->GetTextColorDisable() : textStyle.GetTextColor());
464         }
465     } else {
466         textStyle.SetTextColor(layoutProperty->GetPlaceholderTextColorValue(
467             theme ? theme->GetPlaceholderColor() : textStyle.GetTextColor()));
468     }
469     if (layoutProperty->HasPlaceholderMaxLines()) {
470         textStyle.SetMaxLines(layoutProperty->GetPlaceholderMaxLines().value());
471     }
472     if (layoutProperty->HasPlaceholderItalicFontStyle()) {
473         textStyle.SetFontStyle(layoutProperty->GetPlaceholderItalicFontStyle().value());
474     }
475     if (layoutProperty->HasPlaceholderTextAlign()) {
476         textStyle.SetTextAlign(layoutProperty->GetPlaceholderTextAlign().value());
477     }
478     textStyle.SetTextOverflow(TextOverflow::ELLIPSIS);
479     textStyle.SetTextAlign(layoutProperty->GetTextAlignValue(TextAlign::START));
480 }
481 
CalculateContentMaxSizeWithCalculateConstraint(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)482 LayoutConstraintF TextFieldLayoutAlgorithm::CalculateContentMaxSizeWithCalculateConstraint(
483     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
484 {
485     auto textFieldContentConstraint = contentConstraint;
486     auto frameNode = layoutWrapper->GetHostNode();
487     CHECK_NULL_RETURN(frameNode, textFieldContentConstraint);
488     auto pattern = frameNode->GetPattern<TextFieldPattern>();
489     CHECK_NULL_RETURN(pattern, textFieldContentConstraint);
490     auto idealWidth = contentConstraint.selfIdealSize.Width().value_or(contentConstraint.maxSize.Width());
491     auto idealHeight = contentConstraint.selfIdealSize.Height().value_or(contentConstraint.maxSize.Height());
492     auto maxIdealSize = SizeF { idealWidth, idealHeight };
493     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
494         auto frameIdealSize = maxIdealSize + SizeF(pattern->GetHorizontalPaddingAndBorderSum(),
495                                                  pattern->GetVerticalPaddingAndBorderSum());
496         auto finalSize = UpdateOptionSizeByCalcLayoutConstraint(static_cast<OptionalSize<float>>(frameIdealSize),
497             layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint(),
498             layoutWrapper->GetLayoutProperty()->GetLayoutConstraint()->percentReference);
499         finalSize.SetWidth(
500             finalSize.Width().value_or(frameIdealSize.Width()) - pattern->GetHorizontalPaddingAndBorderSum());
501         finalSize.SetHeight(
502             finalSize.Height().value_or(frameIdealSize.Height()) - pattern->GetVerticalPaddingAndBorderSum());
503         maxIdealSize.UpdateSizeWhenSmaller(finalSize.ConvertToSizeT());
504     }
505     textFieldContentConstraint.maxSize = maxIdealSize;
506     return textFieldContentConstraint;
507 }
508 
FontRegisterCallback(const RefPtr<FrameNode> & frameNode,const std::vector<std::string> & fontFamilies)509 void TextFieldLayoutAlgorithm::FontRegisterCallback(
510     const RefPtr<FrameNode>& frameNode, const std::vector<std::string>& fontFamilies)
511 {
512     auto callback = [weakNode = WeakPtr<FrameNode>(frameNode)] {
513         auto frameNode = weakNode.Upgrade();
514         CHECK_NULL_VOID(frameNode);
515         frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
516         auto pattern = frameNode->GetPattern<TextFieldPattern>();
517         CHECK_NULL_VOID(pattern);
518         auto modifier = DynamicCast<TextFieldContentModifier>(pattern->GetContentModifier());
519         CHECK_NULL_VOID(modifier);
520         modifier->SetFontReady(true);
521     };
522     auto pipeline = frameNode->GetContext();
523     CHECK_NULL_VOID(pipeline);
524     auto fontManager = pipeline->GetFontManager();
525     if (fontManager) {
526         bool isCustomFont = false;
527         for (const auto& familyName : fontFamilies) {
528             bool customFont = fontManager->RegisterCallbackNG(frameNode, familyName, callback);
529             if (customFont) {
530                 isCustomFont = true;
531             }
532         }
533         fontManager->AddVariationNodeNG(frameNode);
534         if (isCustomFont || fontManager->IsDefaultFontChanged()) {
535             auto pattern = frameNode->GetPattern<TextFieldPattern>();
536             CHECK_NULL_VOID(pattern);
537             pattern->SetIsCustomFont(true);
538             auto modifier = DynamicCast<TextFieldContentModifier>(pattern->GetContentModifier());
539             CHECK_NULL_VOID(modifier);
540             modifier->SetIsCustomFont(true);
541         }
542     }
543 }
544 
GetParagraphStyle(const TextStyle & textStyle,const std::string & content) const545 ParagraphStyle TextFieldLayoutAlgorithm::GetParagraphStyle(const TextStyle& textStyle, const std::string& content) const
546 {
547     return { .direction = GetTextDirection(content, direction_),
548         .maxLines = textStyle.GetMaxLines(),
549         .fontLocale = Localization::GetInstance()->GetFontLocale(),
550         .wordBreak = textStyle.GetWordBreak(),
551         .textOverflow = textStyle.GetTextOverflow(),
552         .fontSize = textStyle.GetFontSize().ConvertToPx() };
553 }
554 
CreateParagraph(const TextStyle & textStyle,std::string content,bool needObscureText,int32_t nakedCharPosition,bool disableTextAlign)555 void TextFieldLayoutAlgorithm::CreateParagraph(const TextStyle& textStyle, std::string content, bool needObscureText,
556     int32_t nakedCharPosition, bool disableTextAlign)
557 {
558     auto paraStyle = GetParagraphStyle(textStyle, content);
559     if (!disableTextAlign) {
560         paraStyle.align = textStyle.GetTextAlign();
561     }
562     paragraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
563     CHECK_NULL_VOID(paragraph_);
564     paragraph_->PushStyle(textStyle);
565     StringUtils::TransformStrCase(content, static_cast<int32_t>(textStyle.GetTextCase()));
566     auto displayText = TextFieldPattern::CreateDisplayText(content, nakedCharPosition, needObscureText);
567     paragraph_->AddText(displayText);
568     paragraph_->Build();
569 }
570 
CreateParagraph(const TextStyle & textStyle,const std::vector<std::string> & contents,const std::string & content,bool needObscureText,bool disableTextAlign)571 void TextFieldLayoutAlgorithm::CreateParagraph(const TextStyle& textStyle, const std::vector<std::string>& contents,
572     const std::string& content, bool needObscureText, bool disableTextAlign)
573 {
574     TextStyle dragTextStyle = textStyle;
575     Color color = textStyle.GetTextColor().ChangeAlpha(DRAGGED_TEXT_TRANSPARENCY);
576     dragTextStyle.SetTextColor(color);
577     std::vector<TextStyle> textStyles { textStyle, dragTextStyle, textStyle };
578 
579     auto style = textStyles.begin();
580     ParagraphStyle paraStyle { .direction = GetTextDirection(content, direction_),
581         .maxLines = style->GetMaxLines(),
582         .fontLocale = Localization::GetInstance()->GetFontLocale(),
583         .wordBreak = style->GetWordBreak(),
584         .textOverflow = style->GetTextOverflow(),
585         .fontSize = style->GetFontSize().ConvertToPx() };
586     if (!disableTextAlign) {
587         paraStyle.align = style->GetTextAlign();
588     }
589     paragraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
590     CHECK_NULL_VOID(paragraph_);
591     for (size_t i = 0; i < contents.size(); i++) {
592         std::string splitStr = contents[i];
593         if (splitStr.empty()) {
594             continue;
595         }
596         auto& style = textStyles[i];
597         paragraph_->PushStyle(style);
598         StringUtils::TransformStrCase(splitStr, static_cast<int32_t>(style.GetTextCase()));
599         if (needObscureText) {
600             paragraph_->AddText(
601                 TextFieldPattern::CreateObscuredText(static_cast<int32_t>(StringUtils::ToWstring(splitStr).length())));
602         } else {
603             paragraph_->AddText(StringUtils::Str8ToStr16(splitStr));
604         }
605         paragraph_->PopStyle();
606     }
607     paragraph_->Build();
608 }
609 
CreateInlineParagraph(const TextStyle & textStyle,std::string content,bool needObscureText,int32_t nakedCharPosition,bool disableTextAlign)610 void TextFieldLayoutAlgorithm::CreateInlineParagraph(const TextStyle& textStyle, std::string content,
611     bool needObscureText, int32_t nakedCharPosition, bool disableTextAlign)
612 {
613     auto paraStyle = GetParagraphStyle(textStyle, content);
614     if (!disableTextAlign) {
615         paraStyle.align = textStyle.GetTextAlign();
616     }
617     paraStyle.maxLines = -1;
618     inlineParagraph_ = Paragraph::Create(paraStyle, FontCollection::Current());
619     CHECK_NULL_VOID(paragraph_);
620     inlineParagraph_->PushStyle(textStyle);
621     StringUtils::TransformStrCase(content, static_cast<int32_t>(textStyle.GetTextCase()));
622     auto displayText = TextFieldPattern::CreateDisplayText(content, nakedCharPosition, needObscureText);
623     inlineParagraph_->AddText(displayText);
624     inlineParagraph_->Build();
625 }
626 
GetTextDirection(const std::string & content,TextDirection direction)627 TextDirection TextFieldLayoutAlgorithm::GetTextDirection(const std::string& content, TextDirection direction)
628 {
629     if (direction == TextDirection::LTR || direction == TextDirection::RTL) {
630         return direction;
631     }
632 
633     TextDirection textDirection = TextDirection::LTR;
634     auto showingTextForWString = StringUtils::ToWstring(content);
635     for (const auto& charOfShowingText : showingTextForWString) {
636         if (TextLayoutadapter::IsLeftToRight(charOfShowingText)) {
637             return TextDirection::LTR;
638         }
639         if (TextLayoutadapter::IsRightToLeft(charOfShowingText) ||
640             TextLayoutadapter::IsRightTOLeftArabic(charOfShowingText)) {
641             return TextDirection::RTL;
642         }
643     }
644     return textDirection;
645 }
646 
GetParagraph() const647 const RefPtr<Paragraph>& TextFieldLayoutAlgorithm::GetParagraph() const
648 {
649     return paragraph_;
650 }
651 
GetTextFieldDefaultHeight()652 float TextFieldLayoutAlgorithm::GetTextFieldDefaultHeight()
653 {
654     auto pipeline = PipelineContext::GetCurrentContext();
655     CHECK_NULL_RETURN(pipeline, 0.0f);
656     auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
657     CHECK_NULL_RETURN(textFieldTheme, 0.0f);
658     auto height = textFieldTheme->GetHeight();
659     return static_cast<float>(height.ConvertToPx());
660 }
661 
SetPropertyToModifier(const TextStyle & textStyle,RefPtr<TextFieldContentModifier> modifier)662 void TextFieldLayoutAlgorithm::SetPropertyToModifier(
663     const TextStyle& textStyle, RefPtr<TextFieldContentModifier> modifier)
664 {
665     CHECK_NULL_VOID(modifier);
666     modifier->SetFontFamilies(textStyle.GetFontFamilies());
667     modifier->SetFontSize(textStyle.GetFontSize());
668     modifier->SetFontWeight(textStyle.GetFontWeight());
669     modifier->SetTextColor(textStyle.GetTextColor());
670     modifier->SetFontStyle(textStyle.GetFontStyle());
671     modifier->SetTextOverflow(textStyle.GetTextOverflow());
672 }
673 
UpdateUnitLayout(LayoutWrapper * layoutWrapper)674 void TextFieldLayoutAlgorithm::UpdateUnitLayout(LayoutWrapper* layoutWrapper)
675 {
676     auto frameNode = layoutWrapper->GetHostNode();
677     CHECK_NULL_VOID(frameNode);
678     auto pattern = frameNode->GetPattern<TextFieldPattern>();
679     CHECK_NULL_VOID(pattern);
680     auto children = frameNode->GetChildren();
681     const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
682     CHECK_NULL_VOID(content);
683     auto contentSize = content->GetRect().GetSize();
684     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize();
685     auto layoutProperty = AceType::DynamicCast<TextFieldLayoutProperty>(layoutWrapper->GetLayoutProperty());
686     CHECK_NULL_VOID(layoutProperty);
687     if (!children.empty() && layoutProperty->GetShowUnderlineValue(false) &&
688         layoutProperty->GetTextInputTypeValue(TextInputType::UNSPECIFIED) == TextInputType::UNSPECIFIED) {
689         auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
690         CHECK_NULL_VOID(childWrapper);
691         auto textGeometryNode = childWrapper->GetGeometryNode();
692         CHECK_NULL_VOID(textGeometryNode);
693         auto childFrameSize = textGeometryNode->GetFrameSize();
694         unitWidth_ = childFrameSize.Width();
695         textGeometryNode->SetFrameOffset(
696             OffsetF({ content->GetRect().GetX() + contentSize.Width() - childFrameSize.Width(), 0.0 }));
697         if (childFrameSize.Height() < size.Height()) {
698             childWrapper->GetGeometryNode()->SetFrameSize(SizeF({ unitWidth_, size.Height() }));
699         }
700         childWrapper->Layout();
701     }
702 }
703 } // namespace OHOS::Ace::NG
704