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