• 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 #include "ui/base/ace_type.h"
16 #include "ui/base/utils/utils.h"
17 #include "base/geometry/dimension.h"
18 #include "base/utils/utf_helper.h"
19 #include "core/components/common/layout/constants.h"
20 #include "core/components_ng/pattern/security_component/security_component_common.h"
21 #include "core/components_ng/pattern/security_component/security_component_layout_element.h"
22 #include "core/components_ng/pattern/security_component/security_component_layout_property.h"
23 #include "core/components_ng/pattern/security_component/security_component_theme.h"
24 #include "core/components_ng/pattern/text/text_layout_algorithm.h"
25 #include "core/components_ng/pattern/text/text_layout_property.h"
26 #include "core/components_ng/pattern/text/text_pattern.h"
27 #include "core/components_ng/property/measure_property.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 #ifdef ENABLE_ROSEN_BACKEND
30 #include "core/components/custom_paint/rosen_render_custom_paint.h"
31 #endif
32 
33 namespace OHOS::Ace::NG {
34 
35 constexpr double DEFAULT_SIZE_24 = 24;
36 
Init(const RefPtr<SecurityComponentLayoutProperty> & property,RefPtr<LayoutWrapper> & iconWrap)37 void IconLayoutElement::Init(const RefPtr<SecurityComponentLayoutProperty>& property,
38     RefPtr<LayoutWrapper>& iconWrap)
39 {
40     CHECK_NULL_VOID(property);
41     CHECK_NULL_VOID(iconWrap);
42     secCompProperty_ = property;
43     iconWrap_ = iconWrap;
44     bool isSymbolIcon = iconWrap->GetHostTag() == V2::SYMBOL_ETS_TAG;
45     if (isSymbolIcon &&
46         static_cast<int32_t>(property->GetSymbolIconStyle().value_or(-1)) ==
47         static_cast<int32_t>(SecurityComponentIconStyle::ICON_NULL)) {
48         return;
49     } else if (!isSymbolIcon && property->GetIconStyle().value_or(-1) ==
50         static_cast<int32_t>(SecurityComponentIconStyle::ICON_NULL)) {
51         return;
52     }
53     isExist_ = true;
54 
55     auto pipeline = PipelineContext::GetCurrentContextSafely();
56     CHECK_NULL_VOID(pipeline);
57     auto theme = pipeline->GetTheme<SecurityComponentTheme>();
58     CHECK_NULL_VOID(theme);
59     minIconSize_ = theme->GetMinIconSize().ConvertToPx();
60     auto iconNode = iconWrap_->GetHostNode();
61     CHECK_NULL_VOID(iconNode);
62 
63     width_ = isSymbolIcon ? Dimension(DEFAULT_SIZE_24, DimensionUnit::VP).ConvertToPx() :
64         theme->GetIconSize().ConvertToPx();
65     height_ = width_ * alpha_;
66 
67     UpdateUserSetSize(property);
68 
69     std::optional<NG::CalcLength> propWidth;
70     propWidth.emplace(Dimension(Dimension(width_).ConvertToVp(), DimensionUnit::VP));
71     std::optional<NG::CalcLength> propHeight;
72     propHeight.emplace(Dimension(Dimension(height_).ConvertToVp(), DimensionUnit::VP));
73     auto iconLayoutProperty = iconNode->GetLayoutProperty<ImageLayoutProperty>();
74     CHECK_NULL_VOID(iconLayoutProperty);
75     iconLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(propWidth, propHeight));
76 }
77 
UpdateUserSetSize(const RefPtr<SecurityComponentLayoutProperty> & property)78 void IconLayoutElement::UpdateUserSetSize(const RefPtr<SecurityComponentLayoutProperty>& property)
79 {
80     if (property->GetIconCalcSize()->Width().has_value() && property->GetIconCalcSize()->Height().has_value()) {
81         isSetSize_ = true;
82         width_ = property->GetIconCalcSize()->Width()->GetDimension().ConvertToPx();
83         height_ = property->GetIconCalcSize()->Height()->GetDimension().ConvertToPx();
84         if (!property->GetImageSourceInfo().has_value()) {
85             double tmp = GreatNotEqual(width_, height_) ? height_ : width_;
86             width_ = height_ = tmp;
87         }
88     } else if (property->GetIconCalcSize()->Width().has_value()) {
89         isSetSize_ = true;
90         width_ = property->GetIconCalcSize()->Width()->GetDimension().ConvertToPx();
91         height_ = width_ * alpha_;
92     } else if (property->GetIconCalcSize()->Height().has_value()) {
93         isSetSize_ = true;
94         height_ = property->GetIconCalcSize()->Height()->GetDimension().ConvertToPx();
95         width_ = (NearEqual(alpha_, 0.0)) ? 0.0 : (height_ / alpha_);
96     } else if (property->GetIconSize().has_value()) {
97         isSetSize_ = true;
98         width_ = height_ = property->GetIconSize().value().ConvertToPx();
99     }
100 }
101 
DoMeasure()102 void IconLayoutElement::DoMeasure()
103 {
104     if (!isExist_) {
105         return;
106     }
107     auto iconConstraint = secCompProperty_->CreateChildConstraint();
108     iconConstraint.selfIdealSize.SetWidth(width_);
109     iconConstraint.selfIdealSize.SetHeight(height_);
110     iconWrap_->Measure(iconConstraint);
111 }
112 
ShrinkWidth(double reduceSize)113 double IconLayoutElement::ShrinkWidth(double reduceSize)
114 {
115     if (!isExist_ || isSetSize_) {
116         return reduceSize;
117     }
118     if (NearEqual(alpha_, 0.0)) {
119         return reduceSize;
120     }
121 
122     if (GreatOrEqual(height_, width_)) {
123         if (GreatNotEqual(minIconSize_, (width_ - reduceSize))) {
124             int remain = reduceSize - (width_ - minIconSize_);
125             width_ = minIconSize_;
126             height_ = width_ * alpha_;
127             return remain;
128         }
129 
130         width_ -= reduceSize;
131         height_ = width_ * alpha_;
132         return 0.0;
133     } else {
134         if (GreatNotEqual(minIconSize_, (height_ - reduceSize * alpha_))) {
135             int remain = reduceSize - (height_ - minIconSize_) / alpha_;
136             height_ = minIconSize_;
137             width_ = height_ / alpha_;
138             return remain;
139         }
140 
141         width_ -= reduceSize;
142         height_ = width_ * alpha_;
143         return 0.0;
144     }
145 }
146 
ShrinkHeight(double reduceSize)147 double IconLayoutElement::ShrinkHeight(double reduceSize)
148 {
149     if (!isExist_ || isSetSize_) {
150         return reduceSize;
151     }
152     if (NearEqual(alpha_, 0.0)) {
153         return reduceSize;
154     }
155 
156     if (GreatOrEqual(height_, width_)) {
157         if (GreatNotEqual(minIconSize_, (width_ - reduceSize / alpha_))) {
158             int remain = reduceSize - (width_ - minIconSize_) * alpha_;
159             width_ = minIconSize_;
160             height_ = width_ * alpha_;
161             return remain;
162         }
163 
164         height_ -= reduceSize;
165         width_ = height_ / alpha_;
166         return 0.0;
167     } else {
168         if (GreatNotEqual(minIconSize_, (height_ - reduceSize))) {
169             int remain = reduceSize - (height_ - minIconSize_);
170             height_ = minIconSize_;
171             width_ = height_ / alpha_;
172             return remain;
173         }
174 
175         height_ -= reduceSize;
176         width_ = height_ / alpha_;
177         return 0.0;
178     }
179 }
180 
UpdateFontSize()181 void TextLayoutElement::UpdateFontSize()
182 {
183     auto layoutAlgorithmWrap = textWrap_->GetLayoutAlgorithm();
184     CHECK_NULL_VOID(layoutAlgorithmWrap);
185     auto layoutAlgorithm = AceType::DynamicCast<TextLayoutAlgorithm>(layoutAlgorithmWrap->GetLayoutAlgorithm());
186     CHECK_NULL_VOID(layoutAlgorithm);
187     auto textStyle = layoutAlgorithm->GetTextStyle();
188     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
189     CHECK_NULL_VOID(textProp);
190     if (isAdaptive_ && !NearEqual(textStyle.GetFontSize().Value(), 0.0f)) {
191         Dimension fontSize(textStyle.GetFontSize().ConvertToFp(), DimensionUnit::FP);
192         textProp->UpdateFontSize(fontSize);
193     }
194 }
195 
GetHeightConstraint(const RefPtr<SecurityComponentLayoutProperty> & property,float height)196 float TextLayoutElement::GetHeightConstraint(const RefPtr<SecurityComponentLayoutProperty>& property, float height)
197 {
198     CHECK_NULL_RETURN(property, 0.0f);
199     auto isVertical = (property->GetTextIconLayoutDirection().value_or(
200         SecurityComponentLayoutDirection::HORIZONTAL) == SecurityComponentLayoutDirection::VERTICAL);
201 
202     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
203     CHECK_NULL_RETURN(textProp, 0.0f);
204     auto context = PipelineContext::GetCurrentContextSafely();
205     CHECK_NULL_RETURN(context, 0.0f);
206     auto theme = context->GetTheme<SecurityComponentTheme>();
207     CHECK_NULL_RETURN(theme, 0.0f);
208     auto topPadding = property->GetBackgroundTopPadding().value_or(theme->GetBackgroundTopPadding());
209     auto bottomPadding = property->GetBackgroundBottomPadding().value_or(theme->GetBackgroundBottomPadding());
210     if (isVertical) {
211         auto iconSize = (property->GetIconSize().value_or(theme->GetIconSize()));
212         auto textIconSpace = (property->GetTextIconSpace().value_or(theme->GetTextIconSpace()));
213         return height - topPadding.Value() - bottomPadding.Value() - iconSize.Value() - textIconSpace.Value();
214     }
215 
216     return height - topPadding.Value() - bottomPadding.Value();
217 }
218 
Init(const RefPtr<SecurityComponentLayoutProperty> & property,RefPtr<LayoutWrapper> & textWrap)219 void TextLayoutElement::Init(const RefPtr<SecurityComponentLayoutProperty>& property,
220     RefPtr<LayoutWrapper>& textWrap)
221 {
222     secCompProperty_ = property;
223     textWrap_ = textWrap;
224     CHECK_NULL_VOID(property);
225     CHECK_NULL_VOID(textWrap);
226     if (property->GetSecurityComponentDescription().value_or(-1) ==
227             static_cast<int32_t>(SecurityComponentDescription::TEXT_NULL)) {
228         return;
229     }
230     isExist_ = true;
231 
232     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
233     CHECK_NULL_VOID(textProp);
234     auto context = PipelineContext::GetCurrentContextSafely();
235     CHECK_NULL_VOID(context);
236     auto theme = context->GetTheme<SecurityComponentTheme>();
237     CHECK_NULL_VOID(theme);
238     minFontSize_ = theme->GetMinFontSize();
239     if (property->GetAdaptMaxFontSize().has_value() && property->GetAdaptMinFontSize().has_value()) {
240         if (GreatOrEqual(property->GetAdaptMaxFontSize()->ConvertToFp(),
241             property->GetAdaptMinFontSize()->ConvertToFp())) {
242             textProp->UpdateFontSize(property->GetAdaptMaxFontSize().value());
243             isAdaptive_ = true;
244         }
245         isSetSize_ = true;
246     } else if (property->GetFontSize().has_value()) {
247         isSetSize_ = true;
248     } else {
249         defaultFontSize_ = theme->GetFontSize();
250         textProp->UpdateFontSize(defaultFontSize_);
251     }
252 
253     auto textConstraint = property->CreateChildConstraint();
254     SizeT<float> maxSize { textConstraint.maxSize.Width(), Infinity<float>() };
255     if (isAdaptive_ && property->GetHeightAdaptivePolicy().has_value() &&
256         property->GetHeightAdaptivePolicy() == TextHeightAdaptivePolicy::LAYOUT_CONSTRAINT_FIRST) {
257         SC_LOG_DEBUG("Component height constrained.");
258         auto heightConstraint = GetHeightConstraint(property, textConstraint.maxSize.Height());
259         if (LessOrEqual(heightConstraint, 0.0f)) {
260             heightConstraint = 0.0f;
261         }
262         maxSize.SetHeight(heightConstraint);
263     }
264     textConstraint.maxSize = maxSize;
265     textWrap_->Measure(std::optional<LayoutConstraintF>(textConstraint));
266     UpdateFontSize();
267     auto geometryNode = textWrap->GetGeometryNode();
268     CHECK_NULL_VOID(geometryNode);
269     auto textSizeF = geometryNode->GetFrameSize();
270     width_ = textSizeF.Width();
271     height_ = textSizeF.Height();
272 }
273 
MeasureForWidth(float width)274 void TextLayoutElement::MeasureForWidth(float width)
275 {
276     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
277     CHECK_NULL_VOID(textProp);
278     auto textConstraint = textProp->GetContentLayoutConstraint();
279     CHECK_NULL_VOID(textConstraint);
280     textConstraint->selfIdealSize.SetWidth(width);
281     textWrap_->Measure(textConstraint);
282     UpdateFontSize();
283     auto textSizeF = textWrap_->GetGeometryNode()->GetFrameSize();
284     width_ = textSizeF.Width();
285     height_ = textSizeF.Height();
286 }
287 
DoMeasure(bool isVertical,float minWidth,float leftSpace)288 void TextLayoutElement::DoMeasure(bool isVertical, float minWidth, float leftSpace)
289 {
290     if (!isExist_) {
291         return;
292     }
293 
294     float textMaxWidth;
295     if (isVertical) {
296         textMaxWidth = minWidth > leftSpace ? minWidth : leftSpace;
297     } else {
298         textMaxWidth = minWidth > leftSpace ? minWidth - leftSpace : 0.0;
299     }
300     auto textNode = textWrap_->GetHostNode();
301     CHECK_NULL_VOID(textNode);
302     auto textPattern = textNode->GetPattern<TextPattern>();
303     CHECK_NULL_VOID(textPattern);
304 
305     if (GreatNotEqual(width_, textMaxWidth)) {
306         MeasureForWidth(textMaxWidth);
307         auto realWidth = textPattern->GetLineMetrics(0).width;
308         if (LessNotEqual(width_, realWidth)) {
309             MeasureForWidth(realWidth);
310         }
311     }
312 }
313 
ChooseExactFontSize(RefPtr<TextLayoutProperty> & property,bool isWidth)314 void TextLayoutElement::ChooseExactFontSize(RefPtr<TextLayoutProperty>& property, bool isWidth)
315 {
316     if (!minTextSize_.has_value()) {
317         property->UpdateFontSize(minFontSize_);
318         return;
319     }
320     constexpr Dimension ADAPT_UNIT = 1.0_fp;
321     Dimension step = ADAPT_UNIT;
322     Dimension fontSize = (property->GetFontSize().has_value()) ? property->GetFontSize().value() : defaultFontSize_;
323     while (fontSize > minFontSize_) {
324         auto tempSize = GetMeasureTextSize(UtfUtils::Str16ToStr8(property->GetContent().value_or(u"")),
325             fontSize,
326             property->GetFontWeight().value_or(FontWeight::NORMAL), 0.0);
327         if (!tempSize.has_value()) {
328             fontSize = minFontSize_;
329             break;
330         }
331         if (isWidth) {
332             if (GreatOrEqual(width_, tempSize.value().Width())) {
333                 break;
334             }
335         } else {
336             if (GreatOrEqual(height_, tempSize.value().Height())) {
337                 break;
338             }
339         }
340         fontSize -= step;
341     }
342     property->UpdateFontSize(fontSize);
343 }
344 
UpdateSize(bool isWidth)345 void TextLayoutElement::UpdateSize(bool isWidth)
346 {
347     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
348     CHECK_NULL_VOID(textProp);
349     ChooseExactFontSize(textProp, isWidth);
350     auto textConstraint = textProp->GetContentLayoutConstraint();
351     CHECK_NULL_VOID(textConstraint);
352     if (isWidth) {
353         textConstraint->selfIdealSize.SetWidth(width_);
354     } else {
355         textConstraint->selfIdealSize.SetHeight(height_);
356     }
357 
358     textWrap_->Measure(textConstraint);
359     UpdateFontSize();
360     auto geometryNode = textWrap_->GetGeometryNode();
361     CHECK_NULL_VOID(geometryNode);
362     auto textSizeF = geometryNode->GetFrameSize();
363     width_ = textSizeF.Width();
364     height_ = textSizeF.Height();
365 }
366 
DidExceedMaxLines(std::optional<SizeF> & currentTextSize)367 bool TextLayoutElement::DidExceedMaxLines(std::optional<SizeF>& currentTextSize)
368 {
369     if (!isExist_) {
370         return false;
371     }
372 
373     auto textNode = textWrap_->GetHostNode();
374     CHECK_NULL_RETURN(textNode, false);
375     auto textPattern = textNode->GetPattern<TextPattern>();
376     CHECK_NULL_RETURN(textPattern, false);
377     if (textPattern->DidExceedMaxLines()) {
378         return true;
379     }
380 
381     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
382     CHECK_NULL_RETURN(textProp, false);
383     auto textConstraint = textProp->GetContentLayoutConstraint();
384     CHECK_NULL_RETURN(textConstraint, false);
385 
386     if (currentTextSize.has_value() && GreatNotEqual(currentTextSize->Height(), textConstraint->maxSize.Height())) {
387         return true;
388     }
389     return false;
390 }
391 
GetCurrentTextSize(std::optional<SizeF> & currentTextSize,Dimension & currentFontSize)392 bool TextLayoutElement::GetCurrentTextSize(std::optional<SizeF>& currentTextSize, Dimension& currentFontSize)
393 {
394     if (!isExist_) {
395         return false;
396     }
397 
398     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
399     CHECK_NULL_RETURN(textProp, false);
400     if (!textProp->GetFontSize().has_value()) {
401         return false;
402     }
403     if (!textProp->GetContent().has_value()) {
404         return false;
405     }
406     currentTextSize = GetMeasureTextSize(UtfUtils::Str16ToStr8(textProp->GetContent().value()),
407         textProp->GetFontSize().value(), textProp->GetFontWeight().value_or(FontWeight::NORMAL), width_);
408     if (!currentTextSize.has_value()) {
409         return false;
410     }
411     currentFontSize = textProp->GetFontSize().value();
412     return true;
413 }
414 
TryShrinkTextWidth(SizeF & point,SizeF & circlePoint,bool maxSpaceToShrink,float maxDistance,float threshold)415 bool TextLayoutElement::TryShrinkTextWidth(SizeF& point, SizeF& circlePoint, bool maxSpaceToShrink, float maxDistance,
416     float threshold)
417 {
418 #ifdef ENABLE_ROSEN_BACKEND
419     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
420     CHECK_NULL_RETURN(textProp, false);
421 
422     auto stepPx = Dimension(1.0, DimensionUnit::VP).ConvertToPx();
423     auto currentHeight = height_;
424     auto tempWidth = width_;
425     auto currentRectWidth = point.Width();
426     while (NearEqual(currentHeight, height_)) {
427         if (LessOrEqual(tempWidth, threshold)) {
428             MeasureForWidth(tempWidth + stepPx);
429             return false;
430         }
431         auto newWidth = tempWidth - stepPx;
432         currentRectWidth -= stepPx;
433         MeasureForWidth(newWidth);
434         if (!NearEqual(currentHeight, height_)) {
435             MeasureForWidth(tempWidth);
436             return false;
437         }
438         auto distance = pow(currentRectWidth - circlePoint.Width()) + pow(point.Height() - circlePoint.Height());
439         tempWidth = newWidth;
440         if (!GreatNotEqual(distance, maxDistance)) {
441             break;
442         }
443     }
444     return true;
445 #else
446     return false;
447 #endif
448 }
449 
GetMeasureTextSize(const std::string & data,const Dimension & fontSize,FontWeight fontWeight,float constraintWidth)450 std::optional<SizeF> TextLayoutElement::GetMeasureTextSize(const std::string& data,
451     const Dimension& fontSize, FontWeight fontWeight, float constraintWidth)
452 {
453 #ifdef ENABLE_ROSEN_BACKEND
454     MeasureContext content;
455     if (!NearEqual(constraintWidth, 0.0)) {
456         content.constraintWidth = Dimension(constraintWidth);
457     }
458     content.textContent = data;
459     content.fontSize = fontSize;
460     auto fontweight = StringUtils::FontWeightToString(fontWeight);
461     content.fontWeight = fontweight;
462     auto size = RosenRenderCustomPaint::MeasureTextSizeInner(content);
463     return SizeF(size.Width(), size.Height());
464 #else
465     return std::nullopt;
466 #endif
467 }
468 
MeasureMinTextSize()469 void TextLayoutElement::MeasureMinTextSize()
470 {
471     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
472     CHECK_NULL_VOID(textProp);
473     minTextSize_ = GetMeasureTextSize(UtfUtils::Str16ToStr8(textProp->GetContent().value_or(u"")),
474         minFontSize_,
475         textProp->GetFontWeight().value_or(FontWeight::NORMAL), 0.0);
476 }
477 
ShrinkWidth(double reduceSize)478 double TextLayoutElement::ShrinkWidth(double reduceSize)
479 {
480     if (!isExist_ || isSetSize_) {
481         return reduceSize;
482     }
483     if (!minTextSize_.has_value()) {
484         MeasureMinTextSize();
485     }
486     double minTextWidth = minTextSize_.value_or(SizeT(0.0F, 0.0F)).Width();
487     if (GreatNotEqual(minTextWidth, (width_ - reduceSize))) {
488         int remain = reduceSize - (width_ - minTextWidth);
489         width_ = minTextWidth;
490         UpdateSize(true);
491         return remain;
492     }
493 
494     width_ -= reduceSize;
495     UpdateSize(true);
496     return 0.0;
497 }
498 
ShrinkHeight(double reduceSize)499 double TextLayoutElement::ShrinkHeight(double reduceSize)
500 {
501     if (!isExist_ || isSetSize_) {
502         return reduceSize;
503     }
504     if (!minTextSize_.has_value()) {
505         MeasureMinTextSize();
506     }
507 
508     double minTextHeight = minTextSize_.value_or(SizeT(0.0F, 0.0F)).Height();
509     if (GreatNotEqual(minTextHeight, (height_ - reduceSize))) {
510         double remain = reduceSize - (height_ - minTextHeight);
511         height_ = minTextHeight;
512         UpdateSize(false);
513         return remain;
514     }
515     height_ -= reduceSize;
516     UpdateSize(false);
517     return 0.0;
518 }
519 };
520