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_field/text_field_content_modifier.h"
17
18 #include "base/utils/utils.h"
19 #include "core/components_ng/base/modifier.h"
20 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
21 #include "core/components_ng/property/calc_length.h"
22 #include "core/components_ng/render/drawing.h"
23 #include "core/components_ng/render/drawing_prop_convertor.h"
24 #include "core/components_ng/render/image_painter.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26
27 namespace OHOS::Ace::NG {
28 namespace {
29 const FontWeight FONT_WEIGHT_CONVERT_MAP[] = {
30 FontWeight::W100,
31 FontWeight::W200,
32 FontWeight::W300,
33 FontWeight::W400,
34 FontWeight::W500,
35 FontWeight::W600,
36 FontWeight::W700,
37 FontWeight::W800,
38 FontWeight::W900,
39 FontWeight::W700,
40 FontWeight::W400,
41 FontWeight::W900,
42 FontWeight::W100,
43 FontWeight::W500,
44 FontWeight::W400,
45 };
46 constexpr Dimension ERROR_TEXT_UNDERLINE_MARGIN = 8.0_vp;
47 constexpr Dimension ERROR_TEXT_CAPSULE_MARGIN = 8.0_vp;
48
ConvertFontWeight(FontWeight fontWeight)49 inline FontWeight ConvertFontWeight(FontWeight fontWeight)
50 {
51 return FONT_WEIGHT_CONVERT_MAP[(int)fontWeight];
52 }
53 } // namespace
54
TextFieldContentModifier(const WeakPtr<OHOS::Ace::NG::Pattern> & pattern)55 TextFieldContentModifier::TextFieldContentModifier(const WeakPtr<OHOS::Ace::NG::Pattern>& pattern) : pattern_(pattern)
56 {
57 SetDefaultAnimatablePropertyValue();
58 SetDefaultPropertyValue();
59 }
60
onDraw(DrawingContext & context)61 void TextFieldContentModifier::onDraw(DrawingContext& context)
62 {
63 auto& canvas = context.canvas;
64 auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
65 CHECK_NULL_VOID(textFieldPattern);
66 auto paragraph = textFieldPattern->GetParagraph();
67 CHECK_NULL_VOID(paragraph);
68 auto contentOffset = contentOffset_->Get();
69 auto contentRect = textFieldPattern->GetContentRect();
70 auto clipRectHeight = 0.0f;
71 auto errorMargin = 0.0f;
72 auto errorViewHeight = 0.0f;
73 auto errorParagraph = textFieldPattern->GetErrorParagraph();
74 auto textFrameRect = textFieldPattern->GetFrameRect();
75 auto frameNode = textFieldPattern->GetHost();
76 CHECK_NULL_VOID(frameNode);
77 auto layoutProperty = frameNode->GetLayoutProperty<TextFieldLayoutProperty>();
78 CHECK_NULL_VOID(layoutProperty);
79 if (layoutProperty->GetShowUnderlineValue(false) && showErrorState_->Get()) {
80 errorMargin = ERROR_TEXT_UNDERLINE_MARGIN.ConvertToPx();
81 } else if (textFieldPattern->NeedShowPasswordIcon() && showErrorState_->Get()) {
82 errorMargin = ERROR_TEXT_CAPSULE_MARGIN.ConvertToPx();
83 } else if (showErrorState_->Get()) {
84 errorMargin = ERROR_TEXT_CAPSULE_MARGIN.ConvertToPx();
85 } else {
86 errorMargin = 0;
87 }
88 ProcessErrorParagraph(context, errorMargin);
89 if (errorParagraph && showErrorState_->Get()) {
90 errorViewHeight = textFrameRect.Bottom() - textFrameRect.Top() + errorMargin;
91 }
92 clipRectHeight = contentRect.GetY() + contentRect.Height() + errorViewHeight;
93 canvas.Save();
94 RSRect clipInnerRect = RSRect(contentRect.GetX(), contentRect.GetY(),
95 contentRect.Width() + contentRect.GetX() + textFieldPattern->GetInlinePadding(), clipRectHeight);
96 canvas.ClipRect(clipInnerRect, RSClipOp::INTERSECT);
97 if (paragraph) {
98 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
99 canvas.Save();
100 RSRect clipRect;
101 std::vector<RSPoint> clipRadius;
102 GetFrameRectClip(clipRect, clipRadius);
103 canvas.ClipRoundRect(clipRect, clipRadius, true);
104 paragraph->Paint(canvas, textFieldPattern->GetTextRect().GetX(),
105 textFieldPattern->IsTextArea() ? textFieldPattern->GetTextRect().GetY() : contentOffset.GetY());
106 canvas.Restore();
107 } else {
108 paragraph->Paint(canvas, textFieldPattern->GetTextRect().GetX(),
109 textFieldPattern->IsTextArea() ? textFieldPattern->GetTextRect().GetY() : contentOffset.GetY());
110 }
111 }
112 canvas.Restore();
113 }
114
GetFrameRectClip(RSRect & clipRect,std::vector<RSPoint> & clipRadius)115 void TextFieldContentModifier::GetFrameRectClip(RSRect& clipRect, std::vector<RSPoint>& clipRadius)
116 {
117 auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
118 CHECK_NULL_VOID(textFieldPattern);
119 auto host = textFieldPattern->GetHost();
120 CHECK_NULL_VOID(host);
121 auto renderContext = host->GetRenderContext();
122 CHECK_NULL_VOID(renderContext);
123 auto textFrameRect = textFieldPattern->GetFrameRect();
124 clipRect = RSRect(0.0f, 0.0f, textFrameRect.Width(), textFrameRect.Height());
125 auto radius = renderContext->GetBorderRadius().value_or(BorderRadiusProperty());
126 auto radiusTopLeft = RSPoint(static_cast<float>(radius.radiusTopLeft.value_or(0.0_vp).ConvertToPx()),
127 static_cast<float>(radius.radiusTopLeft.value_or(0.0_vp).ConvertToPx()));
128 clipRadius.emplace_back(radiusTopLeft);
129 auto radiusTopRight = RSPoint(static_cast<float>(radius.radiusTopRight.value_or(0.0_vp).ConvertToPx()),
130 static_cast<float>(radius.radiusTopRight.value_or(0.0_vp).ConvertToPx()));
131 clipRadius.emplace_back(radiusTopRight);
132 auto radiusBottomRight = RSPoint(static_cast<float>(radius.radiusBottomRight.value_or(0.0_vp).ConvertToPx()),
133 static_cast<float>(radius.radiusBottomRight.value_or(0.0_vp).ConvertToPx()));
134 clipRadius.emplace_back(radiusBottomRight);
135 auto radiusBottomLeft = RSPoint(static_cast<float>(radius.radiusBottomLeft.value_or(0.0_vp).ConvertToPx()),
136 static_cast<float>(radius.radiusBottomLeft.value_or(0.0_vp).ConvertToPx()));
137 clipRadius.emplace_back(radiusBottomLeft);
138 }
139
SetDefaultAnimatablePropertyValue()140 void TextFieldContentModifier::SetDefaultAnimatablePropertyValue()
141 {
142 RefPtr<TextTheme> theme;
143 RefPtr<TextFieldLayoutProperty> textFieldLayoutProperty;
144 RefPtr<PipelineContext> pipelineContext;
145 auto textPartten = pattern_.Upgrade();
146 CHECK_NULL_VOID(textPartten);
147 auto frameNode = textPartten->GetHost();
148 CHECK_NULL_VOID(frameNode);
149 pipelineContext = frameNode->GetContext();
150 CHECK_NULL_VOID(pipelineContext);
151 theme = pipelineContext->GetTheme<TextTheme>();
152 textFieldLayoutProperty = frameNode->GetLayoutProperty<TextFieldLayoutProperty>();
153 auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
154 CHECK_NULL_VOID(textFieldPattern);
155 TextStyle textStyle;
156 if (!textFieldPattern->GetTextValue().empty()) {
157 textStyle = CreateTextStyleUsingTheme(
158 textFieldLayoutProperty->GetFontStyle(), textFieldLayoutProperty->GetTextLineStyle(), theme);
159 } else {
160 textStyle = CreateTextStyleUsingTheme(textFieldLayoutProperty->GetPlaceholderFontStyle(),
161 textFieldLayoutProperty->GetPlaceholderTextLineStyle(), theme);
162 }
163 SetDefaultFontSize(textStyle);
164 SetDefaultFontWeight(textStyle);
165 SetDefaultTextColor(textStyle);
166 SetDefaultFontStyle(textStyle);
167 SetDefaultTextOverflow(textStyle);
168 }
169
SetDefaultPropertyValue()170 void TextFieldContentModifier::SetDefaultPropertyValue()
171 {
172 RefPtr<TextFieldTheme> theme;
173 RefPtr<PipelineContext> pipelineContext;
174 auto textPattern = pattern_.Upgrade();
175 CHECK_NULL_VOID(textPattern);
176 auto frameNode = textPattern->GetHost();
177 CHECK_NULL_VOID(frameNode);
178 pipelineContext = frameNode->GetContext();
179 CHECK_NULL_VOID(pipelineContext);
180 theme = pipelineContext->GetTheme<TextFieldTheme>();
181 auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
182
183 textObscured_ = AceType::MakeRefPtr<PropertyBool>(textFieldPattern->GetTextObscured());
184 dragStatus_ = AceType::MakeRefPtr<PropertyBool>(false);
185 contentOffset_ = AceType::MakeRefPtr<PropertyOffsetF>(
186 OffsetF(textFieldPattern->GetTextRect().GetX(), textFieldPattern->GetTextRect().GetY()));
187 contentSize_ = AceType::MakeRefPtr<PropertySizeF>(SizeF());
188 textValue_ = AceType::MakeRefPtr<PropertyString>("");
189 errorTextValue_ = AceType::MakeRefPtr<PropertyString>("");
190 placeholderValue_ = AceType::MakeRefPtr<PropertyString>("");
191 textRectY_ = AceType::MakeRefPtr<PropertyFloat>(textFieldPattern->GetTextRect().GetY());
192 textRectX_ = AceType::MakeRefPtr<PropertyFloat>(textFieldPattern->GetTextRect().GetX());
193 textAlign_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(TextAlign::START));
194 showErrorState_ = AceType::MakeRefPtr<PropertyBool>(false);
195 fontFamilyString_ = AceType::MakeRefPtr<PropertyString>("");
196 fontReady_ = AceType::MakeRefPtr<PropertyBool>(false);
197 contentChange_ = AceType::MakeRefPtr<PropertyBool>(false);
198 AttachProperty(contentOffset_);
199 AttachProperty(contentSize_);
200 AttachProperty(textValue_);
201 AttachProperty(errorTextValue_);
202 AttachProperty(placeholderValue_);
203 AttachProperty(textRectY_);
204 AttachProperty(textObscured_);
205 AttachProperty(dragStatus_);
206 AttachProperty(textRectX_);
207 AttachProperty(textAlign_);
208 AttachProperty(showErrorState_);
209 AttachProperty(showUnderline_);
210 AttachProperty(fontFamilyString_);
211 AttachProperty(fontReady_);
212 AttachProperty(contentChange_);
213 }
214
SetDefaultFontSize(const TextStyle & textStyle)215 void TextFieldContentModifier::SetDefaultFontSize(const TextStyle& textStyle)
216 {
217 float fontSizeValue;
218 auto pipelineContext = PipelineContext::GetCurrentContext();
219 if (pipelineContext) {
220 fontSizeValue = pipelineContext->NormalizeToPx(textStyle.GetFontSize());
221 if (textStyle.IsAllowScale() || textStyle.GetFontSize().Unit() == DimensionUnit::FP) {
222 fontSizeValue = pipelineContext->NormalizeToPx(textStyle.GetFontSize() * pipelineContext->GetFontScale());
223 }
224 } else {
225 fontSizeValue = textStyle.GetFontSize().ConvertToPx();
226 }
227
228 fontSizeFloat_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(fontSizeValue);
229 AttachProperty(fontSizeFloat_);
230 }
231
SetDefaultFontWeight(const TextStyle & textStyle)232 void TextFieldContentModifier::SetDefaultFontWeight(const TextStyle& textStyle)
233 {
234 fontWeightFloat_ =
235 AceType::MakeRefPtr<AnimatablePropertyFloat>(static_cast<float>(ConvertFontWeight(textStyle.GetFontWeight())));
236 AttachProperty(fontWeightFloat_);
237 }
238
SetDefaultTextColor(const TextStyle & textStyle)239 void TextFieldContentModifier::SetDefaultTextColor(const TextStyle& textStyle)
240 {
241 animatableTextColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(textStyle.GetTextColor()));
242 AttachProperty(animatableTextColor_);
243 }
244
SetDefaultFontStyle(const TextStyle & textStyle)245 void TextFieldContentModifier::SetDefaultFontStyle(const TextStyle& textStyle)
246 {
247 fontStyle_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(textStyle.GetFontStyle()));
248 AttachProperty(fontStyle_);
249 }
250
SetDefaultTextOverflow(const TextStyle & textStyle)251 void TextFieldContentModifier::SetDefaultTextOverflow(const TextStyle& textStyle)
252 {
253 textOverflow_ = AceType::MakeRefPtr<PropertyInt>(static_cast<int32_t>(textStyle.GetTextOverflow()));
254 AttachProperty(textOverflow_);
255 }
256
ModifyTextStyle(TextStyle & textStyle)257 void TextFieldContentModifier::ModifyTextStyle(TextStyle& textStyle)
258 {
259 if (fontSize_.has_value() && fontSizeFloat_) {
260 textStyle.SetFontSize(Dimension(fontSizeFloat_->Get(), DimensionUnit::PX));
261 }
262 if (fontWeight_.has_value() && fontWeightFloat_) {
263 textStyle.SetFontWeight(static_cast<FontWeight>(std::floor(fontWeightFloat_->Get() + 0.5f)));
264 }
265 if (textColor_.has_value() && animatableTextColor_) {
266 textStyle.SetTextColor(Color(animatableTextColor_->Get().GetValue()));
267 }
268 }
269
SetFontFamilies(const std::vector<std::string> & value)270 void TextFieldContentModifier::SetFontFamilies(const std::vector<std::string>& value)
271 {
272 CHECK_NULL_VOID(fontFamilyString_);
273 fontFamilyString_->Set(V2::ConvertFontFamily(value));
274 }
275
SetFontSize(const Dimension & value)276 void TextFieldContentModifier::SetFontSize(const Dimension& value)
277 {
278 auto valPx = static_cast<float>(value.ConvertToPx());
279 fontSize_ = Dimension(valPx);
280 CHECK_NULL_VOID(fontSizeFloat_);
281 fontSizeFloat_->Set(valPx);
282 }
283
SetFontWeight(const FontWeight & value)284 void TextFieldContentModifier::SetFontWeight(const FontWeight& value)
285 {
286 fontWeight_ = ConvertFontWeight(value);
287 CHECK_NULL_VOID(fontWeightFloat_);
288 fontWeightFloat_->Set(static_cast<int>(ConvertFontWeight(value)));
289 }
290
SetTextColor(const Color & value)291 void TextFieldContentModifier::SetTextColor(const Color& value)
292 {
293 textColor_ = value;
294 CHECK_NULL_VOID(animatableTextColor_);
295 animatableTextColor_->Set(LinearColor(value));
296 }
297
SetTextOverflow(const TextOverflow value)298 void TextFieldContentModifier::SetTextOverflow(const TextOverflow value)
299 {
300 if (textOverflow_->Get() != static_cast<int32_t>(value)) {
301 textOverflow_->Set(static_cast<int32_t>(value));
302 }
303 }
304
SetFontStyle(const OHOS::Ace::FontStyle & value)305 void TextFieldContentModifier::SetFontStyle(const OHOS::Ace::FontStyle& value)
306 {
307 if (fontStyle_->Get() != static_cast<int32_t>(value)) {
308 fontStyle_->Set(static_cast<int32_t>(value));
309 }
310 }
311
SetContentOffset(OffsetF & value)312 void TextFieldContentModifier::SetContentOffset(OffsetF& value)
313 {
314 if (contentOffset_) {
315 contentOffset_->Set(value);
316 }
317 }
318
GetContentOffsetY()319 float TextFieldContentModifier::GetContentOffsetY()
320 {
321 return contentOffset_->Get().GetY();
322 }
323
SetContentSize(SizeF & value)324 void TextFieldContentModifier::SetContentSize(SizeF& value)
325 {
326 if (contentSize_) {
327 contentSize_->Set(value);
328 }
329 }
330
SetTextValue(std::string & value)331 void TextFieldContentModifier::SetTextValue(std::string& value)
332 {
333 if (textValue_->Get() != value) {
334 textValue_->Set(value);
335 }
336 }
337
SetErrorTextValue(const std::string & value)338 void TextFieldContentModifier::SetErrorTextValue(const std::string& value)
339 {
340 if (errorTextValue_->Get() != value) {
341 errorTextValue_->Set(value);
342 }
343 }
344
SetPlaceholderValue(std::string && value)345 void TextFieldContentModifier::SetPlaceholderValue(std::string&& value)
346 {
347 if (placeholderValue_->Get() != value) {
348 placeholderValue_->Set(value);
349 }
350 }
351
SetTextRectY(const float value)352 void TextFieldContentModifier::SetTextRectY(const float value)
353 {
354 if (textRectY_->Get() != value) {
355 textRectY_->Set(value);
356 }
357 }
358
GetTextRectY()359 float TextFieldContentModifier::GetTextRectY()
360 {
361 return textRectY_->Get();
362 }
363
SetTextObscured(bool value)364 void TextFieldContentModifier::SetTextObscured(bool value)
365 {
366 if (textObscured_) {
367 textObscured_->Set(value);
368 }
369 }
370
ChangeDragStatus()371 void TextFieldContentModifier::ChangeDragStatus()
372 {
373 dragStatus_->Set(!dragStatus_->Get());
374 }
375
SetTextRectX(const float value)376 void TextFieldContentModifier::SetTextRectX(const float value)
377 {
378 if (textRectX_->Get() != value) {
379 textRectX_->Set(value);
380 }
381 }
382
GetTextRectX()383 float TextFieldContentModifier::GetTextRectX()
384 {
385 return textRectX_->Get();
386 }
387
SetTextAlign(const TextAlign value)388 void TextFieldContentModifier::SetTextAlign(const TextAlign value)
389 {
390 if (textAlign_->Get() != static_cast<int32_t>(value)) {
391 textAlign_->Set(static_cast<int32_t>(value));
392 }
393 }
394
SetShowErrorState(bool value)395 void TextFieldContentModifier::SetShowErrorState(bool value)
396 {
397 if (showErrorState_) {
398 showErrorState_->Set(value);
399 }
400 }
401
SetShowUnderlineState(bool value)402 void TextFieldContentModifier::SetShowUnderlineState(bool value)
403 {
404 if (showUnderline_) {
405 showUnderline_->Set(value);
406 }
407 }
408
SetFontReady(bool value)409 void TextFieldContentModifier::SetFontReady(bool value)
410 {
411 if (fontReady_) {
412 fontReady_->Set(value);
413 }
414 }
415
ContentChange()416 void TextFieldContentModifier::ContentChange()
417 {
418 CHECK_NULL_VOID(contentChange_);
419 contentChange_->Set(!contentChange_->Get());
420 }
421
NeedMeasureUpdate(PropertyChangeFlag & flag)422 bool TextFieldContentModifier::NeedMeasureUpdate(PropertyChangeFlag& flag)
423 {
424 flag = 0;
425 if (fontSize_.has_value() && fontSizeFloat_ && !NearEqual(fontSize_.value().Value(), fontSizeFloat_->Get())) {
426 flag |= PROPERTY_UPDATE_MEASURE;
427 }
428 if (fontWeight_.has_value() && fontWeightFloat_ &&
429 !NearEqual(static_cast<float>(fontWeight_.value()), fontWeightFloat_->Get())) {
430 flag |= PROPERTY_UPDATE_MEASURE;
431 }
432 if (textColor_.has_value() && animatableTextColor_ &&
433 textColor_->GetValue() != animatableTextColor_->Get().GetValue()) {
434 flag |= PROPERTY_UPDATE_MEASURE_SELF;
435 }
436 flag &= (PROPERTY_UPDATE_MEASURE | PROPERTY_UPDATE_MEASURE_SELF | PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
437 return flag;
438 }
439
ProcessErrorParagraph(DrawingContext & context,float errorMargin)440 void TextFieldContentModifier::ProcessErrorParagraph(DrawingContext& context, float errorMargin)
441 {
442 auto textFieldPattern = DynamicCast<TextFieldPattern>(pattern_.Upgrade());
443 CHECK_NULL_VOID(textFieldPattern);
444 auto offset = contentOffset_->Get();
445 auto textFrameRect = textFieldPattern->GetFrameRect();
446 auto errorParagraph = textFieldPattern->GetErrorParagraph();
447 auto errorValue = textFieldPattern->GetErrorTextString();
448 auto frameNode = textFieldPattern->GetHost();
449 auto& canvas = context.canvas;
450 if (showErrorState_->Get() && errorParagraph && !textFieldPattern->IsDisabled() && !errorValue.empty()) {
451 auto property = frameNode->GetLayoutProperty();
452 float padding = 0.0f;
453 if (property && property->GetPaddingProperty()) {
454 const auto& paddingProperty = property->GetPaddingProperty();
455 padding = paddingProperty->left.value_or(CalcLength(0.0)).GetDimension().ConvertToPx() +
456 paddingProperty->right.value_or(CalcLength(0.0)).GetDimension().ConvertToPx();
457 }
458 errorParagraph->Layout(textFrameRect.Width() - padding);
459 errorParagraph->Paint(canvas, offset.GetX(), textFrameRect.Bottom() - textFrameRect.Top() + errorMargin);
460 }
461 }
462 } // namespace OHOS::Ace::NG
463