• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/text_area/text_area_layout_algorithm.h"
17 
18 #include <optional>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
24 #include "core/pipeline/pipeline_base.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26 
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr float PARAGRAPH_SAVE_BOUNDARY = 1.0f;
30 } // namespace
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)31 std::optional<SizeF> TextAreaLayoutAlgorithm::MeasureContent(
32     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
33 {
34     auto frameNode = layoutWrapper->GetHostNode();
35     CHECK_NULL_RETURN(frameNode, std::nullopt);
36     auto textFieldLayoutProperty = DynamicCast<TextFieldLayoutProperty>(layoutWrapper->GetLayoutProperty());
37     auto pattern = frameNode->GetPattern<TextFieldPattern>();
38     CHECK_NULL_RETURN(pattern, std::nullopt);
39 
40     // Construct text style.
41     TextStyle textStyle;
42     ConstructTextStyles(frameNode, textStyle, textContent_, showPlaceHolder_);
43 
44     auto isInlineStyle = pattern->IsNormalInlineState();
45     if (!isInlineStyle && textFieldLayoutProperty->HasNormalMaxViewLines()) {
46         textStyle.SetMaxLines(textFieldLayoutProperty->GetNormalMaxViewLines().value());
47     }
48 
49     if (isInlineStyle && textFieldLayoutProperty->HasTextOverflow()) {
50         if (textFieldLayoutProperty->HasTextOverflowMaxLines()) {
51             textStyle.SetMaxLines(textFieldLayoutProperty->GetTextOverflowMaxLinesValue());
52         } else if (textFieldLayoutProperty->HasNormalMaxViewLines()) {
53             textStyle.SetMaxLines(textFieldLayoutProperty->GetNormalMaxViewLines().value());
54         }
55     }
56 
57     direction_ = textFieldLayoutProperty->GetLayoutDirection();
58 
59     // Create paragraph.
60     pattern->SetAdaptFontSize(std::nullopt);
61     auto textFieldContentConstraint = CalculateContentMaxSizeWithCalculateConstraint(contentConstraint, layoutWrapper);
62     if (IsNeedAdaptFontSize(textStyle, textFieldLayoutProperty, textFieldContentConstraint)) {
63         if (!AddAdaptFontSizeAndAnimations(textStyle, textFieldLayoutProperty, textFieldContentConstraint,
64             layoutWrapper)) {
65             return std::nullopt;
66         }
67         pattern->SetAdaptFontSize(textStyle.GetFontSize());
68     } else {
69         CreateParagraphEx(textStyle, textContent_, contentConstraint, layoutWrapper);
70     }
71 
72     autoWidth_ = textFieldLayoutProperty->GetWidthAutoValue(false);
73 
74     if (textContent_.empty()) {
75         // Used for empty text.
76         preferredHeight_ = pattern->PreferredLineHeight(true);
77     }
78 
79     // Paragraph layout.}
80     if (isInlineStyle) {
81         auto fontSize = pattern->FontSizeConvertToPx(textStyle.GetFontSize());
82         auto paragraphData = CreateParagraphData { false, fontSize };
83         CreateInlineParagraph(textStyle, textContent_, false, pattern->GetNakedCharPosition(), paragraphData);
84         return InlineMeasureContent(textFieldContentConstraint, layoutWrapper);
85     } else if (showPlaceHolder_) {
86         return PlaceHolderMeasureContent(textFieldContentConstraint, layoutWrapper);
87     } else {
88         return TextAreaMeasureContent(textFieldContentConstraint, layoutWrapper);
89     }
90 }
91 
Measure(LayoutWrapper * layoutWrapper)92 void TextAreaLayoutAlgorithm::Measure(LayoutWrapper* layoutWrapper)
93 {
94     OptionalSizeF frameSize;
95     const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
96     auto frameNode = layoutWrapper->GetHostNode();
97     CHECK_NULL_VOID(frameNode);
98     auto pattern = frameNode->GetPattern<TextFieldPattern>();
99     CHECK_NULL_VOID(pattern);
100     float contentWidth = 0.0f;
101     float contentHeight = 0.0f;
102     if (content) {
103         auto contentSize = content->GetRect().GetSize();
104         contentWidth = contentSize.Width();
105         contentHeight = contentSize.Height();
106     }
107     // Add children height;
108     auto counterNode = pattern->GetCounterNode().Upgrade();
109     if (counterNode && !pattern->IsNormalInlineState()) {
110         auto counterSize = counterNode->GetGeometryNode()->GetFrameSize();
111         contentHeight += counterSize.Height();
112     }
113 
114     auto finalWidth = 0;
115     if (pattern->IsNormalInlineState() && pattern->HasFocus()) {
116         finalWidth = LessOrEqual(contentWidth, 0) ? 0 :
117             contentWidth + pattern->GetHorizontalPaddingAndBorderSum() + PARAGRAPH_SAVE_BOUNDARY;
118         frameSize.SetWidth(finalWidth);
119         frameSize.SetHeight(contentHeight + pattern->GetVerticalPaddingAndBorderSum() + PARAGRAPH_SAVE_BOUNDARY);
120     } else {
121         // The width after MeasureContent is already optimal, but the height needs to be constrained in Measure.
122         finalWidth = LessOrEqual(contentWidth, 0) ? 0 : contentWidth + pattern->GetHorizontalPaddingAndBorderSum();
123         frameSize.SetWidth(finalWidth);
124         ConstraintHeight(layoutWrapper, frameSize, contentHeight);
125     }
126     layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize.ConvertToSizeT());
127 }
128 
ConstraintHeight(LayoutWrapper * layoutWrapper,OptionalSizeF & frameSize,float contentHeight)129 void TextAreaLayoutAlgorithm::ConstraintHeight(LayoutWrapper* layoutWrapper, OptionalSizeF& frameSize,
130     float contentHeight)
131 {
132     auto frameNode = layoutWrapper->GetHostNode();
133     CHECK_NULL_VOID(frameNode);
134     auto pattern = frameNode->GetPattern<TextFieldPattern>();
135     CHECK_NULL_VOID(pattern);
136     auto textFieldLayoutProperty = pattern->GetLayoutProperty<TextFieldLayoutProperty>();
137     CHECK_NULL_VOID(textFieldLayoutProperty);
138     auto contentConstraint = layoutWrapper->GetLayoutProperty()->CreateContentConstraint();
139     auto textFieldContentConstraint =
140         CalculateContentMaxSizeWithCalculateConstraint(contentConstraint, layoutWrapper);
141     if (textFieldContentConstraint.selfIdealSize.Height().has_value()) {
142         if (LessOrEqual(textFieldContentConstraint.maxSize.Height(), 0)) {
143             frameSize.SetHeight(textFieldContentConstraint.maxSize.Height());
144         } else {
145             frameSize.SetHeight(
146                 textFieldContentConstraint.maxSize.Height() + pattern->GetVerticalPaddingAndBorderSum());
147         }
148     } else {
149         frameSize.SetHeight(contentHeight + pattern->GetVerticalPaddingAndBorderSum());
150     }
151 
152     // Height is constrained by the CalcLayoutConstraint.
153     const auto& layoutConstraint = layoutWrapper->GetLayoutProperty()->GetLayoutConstraint();
154     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
155         frameSize.Constrain(layoutConstraint->minSize, layoutConstraint->maxSize);
156     } else if (!layoutWrapper->GetLayoutProperty()->GetLayoutRect()) {
157         auto finalSize = UpdateOptionSizeByCalcLayoutConstraint(frameSize,
158             layoutWrapper->GetLayoutProperty()->GetCalcLayoutConstraint(),
159             layoutWrapper->GetLayoutProperty()->GetLayoutConstraint()->percentReference);
160         frameSize.SetHeight(finalSize.Height());
161     }
162 }
163 
Layout(LayoutWrapper * layoutWrapper)164 void TextAreaLayoutAlgorithm::Layout(LayoutWrapper* layoutWrapper)
165 {
166     // update child position.
167     auto frameNode = layoutWrapper->GetHostNode();
168     CHECK_NULL_VOID(frameNode);
169     auto pattern = frameNode->GetPattern<TextFieldPattern>();
170     CHECK_NULL_VOID(pattern);
171     auto size = layoutWrapper->GetGeometryNode()->GetFrameSize() -
172                 SizeF(pattern->GetHorizontalPaddingAndBorderSum(), pattern->GetVerticalPaddingAndBorderSum());
173 
174     // Remove counterNode height.
175     auto counterNodeLayoutWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
176     if (counterNodeLayoutWrapper && !pattern->IsNormalInlineState()) {
177         auto counterHeight = counterNodeLayoutWrapper->GetGeometryNode()->GetFrameSize().Height();
178         size.SetHeight(size.Height() - counterHeight);
179     }
180 
181     const auto& content = layoutWrapper->GetGeometryNode()->GetContent();
182     CHECK_NULL_VOID(content);
183     auto layoutProperty = DynamicCast<TextFieldLayoutProperty>(layoutWrapper->GetLayoutProperty());
184     CHECK_NULL_VOID(layoutProperty);
185     auto context = layoutWrapper->GetHostNode()->GetContext();
186     CHECK_NULL_VOID(context);
187     parentGlobalOffset_ = layoutWrapper->GetHostNode()->GetPaintRectOffset() - context->GetRootRect().GetOffset();
188     auto align = Alignment::TOP_CENTER;
189 
190     auto border = pattern->GetBorderWidthProperty();
191     auto offsetBase = OffsetF(pattern->GetPaddingLeft() + pattern->GetBorderLeft(border),
192         pattern->GetPaddingTop() + pattern->GetBorderTop(border));
193     if (layoutWrapper->GetLayoutProperty()->GetPositionProperty()) {
194         align = layoutWrapper->GetLayoutProperty()->GetPositionProperty()->GetAlignment().value_or(align);
195     }
196     // Update text position.
197     if (LessOrEqual(textRect_.Height(), content->GetRect().Height())) {
198         auto textRect = textRect_.GetSize();
199         if (LessOrEqual(textRect.Height(), 0.0)) {
200             textRect.SetHeight(content->GetRect().Height());
201         }
202         OffsetF textRectOffSet = Alignment::GetAlignPosition(size, textRect, align);
203         textRect_.SetOffset(OffsetF(0.0f, textRectOffSet.GetY()) + offsetBase);
204         content->SetOffset(OffsetF(0.0f, textRectOffSet.GetY()) + offsetBase);
205     } else {
206         textRect_.SetOffset(
207             showPlaceHolder_ ? offsetBase : OffsetF(offsetBase.GetX(), pattern->GetTextRect().GetOffset().GetY()));
208         content->SetOffset(offsetBase);
209     }
210     // CounterNode Layout.
211     auto isInlineStyle = pattern->IsNormalInlineState();
212     if (layoutProperty->GetShowCounterValue(false) && layoutProperty->HasMaxLength() && !isInlineStyle) {
213         TextFieldLayoutAlgorithm::CounterLayout(layoutWrapper);
214     }
215 }
216 
CreateParagraphEx(const TextStyle & textStyle,const std::string & content,const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)217 bool TextAreaLayoutAlgorithm::CreateParagraphEx(const TextStyle& textStyle, const std::string& content,
218     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
219 {
220     // update child position.
221     auto frameNode = layoutWrapper->GetHostNode();
222     CHECK_NULL_RETURN(frameNode, false);
223     auto pattern = frameNode->GetPattern<TextFieldPattern>();
224     CHECK_NULL_RETURN(pattern, false);
225     auto isInlineStyle = pattern->IsNormalInlineState();
226     auto fontSize = pattern->FontSizeConvertToPx(textStyle.GetFontSize());
227     auto paragraphData = CreateParagraphData { false, fontSize };
228     if (pattern->IsDragging() && !showPlaceHolder_ && !isInlineStyle) {
229         CreateParagraph(textStyle, pattern->GetDragContents(), content, false, paragraphData);
230     } else {
231         CreateParagraph(textStyle, content, false, pattern->GetNakedCharPosition(), paragraphData);
232     }
233     return true;
234 }
235 } // namespace OHOS::Ace::NG
236