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 "core/components_ng/pattern/security_component/security_component_layout_element.h"
16 
17 #include "base/log/ace_scoring_log.h"
18 #include "base/memory/ace_type.h"
19 #include "core/components_ng/pattern/image/image_layout_property.h"
20 #include "core/components_ng/pattern/security_component/security_component_layout_property.h"
21 #include "core/components_ng/pattern/security_component/security_component_theme.h"
22 #include "core/components_ng/pattern/text/text_layout_property.h"
23 #include "core/components_ng/pattern/text/text_pattern.h"
24 #include "core/components_ng/property/measure_property.h"
25 #include "core/pipeline_ng/pipeline_context.h"
26 #ifdef ENABLE_ROSEN_BACKEND
27 #include "core/components/custom_paint/rosen_render_custom_paint.h"
28 #endif
29 
30 namespace OHOS::Ace::NG {
Init(RefPtr<SecurityComponentLayoutProperty> & property,RefPtr<LayoutWrapper> & iconWrap)31 void IconLayoutElement::Init(RefPtr<SecurityComponentLayoutProperty>& property,
32     RefPtr<LayoutWrapper>& iconWrap)
33 {
34     CHECK_NULL_VOID(property);
35     CHECK_NULL_VOID(iconWrap);
36     secCompProperty_ = property;
37     iconWrap_ = iconWrap;
38     if (property->GetIconStyle().value_or(-1) ==
39         static_cast<int32_t>(SecurityComponentIconStyle::ICON_NULL)) {
40         return;
41     }
42     isExist_ = true;
43 
44     auto pipeline = PipelineContext::GetCurrentContextSafely();
45     CHECK_NULL_VOID(pipeline);
46     auto theme = pipeline->GetTheme<SecurityComponentTheme>();
47     CHECK_NULL_VOID(theme);
48     minIconSize_ = theme->GetMinIconSize().ConvertToPx();
49 
50     if (property->GetIconSize().has_value()) {
51         isSetSize_ = true;
52         width_ = height_ = property->GetIconSize().value().ConvertToPx();
53     } else {
54         width_ = height_ = theme->GetIconSize().ConvertToPx();
55     }
56 }
57 
DoMeasure()58 void IconLayoutElement::DoMeasure()
59 {
60     if (!isExist_) {
61         return;
62     }
63     auto iconConstraint = secCompProperty_->CreateChildConstraint();
64     iconConstraint.selfIdealSize.SetWidth(width_);
65     iconConstraint.selfIdealSize.SetHeight(height_);
66     iconWrap_->Measure(iconConstraint);
67 }
68 
ShrinkWidth(double reduceSize)69 double IconLayoutElement::ShrinkWidth(double reduceSize)
70 {
71     if (!isExist_ || isSetSize_) {
72         return reduceSize;
73     }
74     if (GreatNotEqual(minIconSize_, (width_ - reduceSize))) {
75         int remain = reduceSize - (width_ - minIconSize_);
76         height_ = width_ = minIconSize_;
77         return remain;
78     }
79 
80     width_ -= reduceSize;
81     height_ = width_;
82     return 0.0;
83 }
84 
ShrinkHeight(double reduceSize)85 double IconLayoutElement::ShrinkHeight(double reduceSize)
86 {
87     if (!isExist_ || isSetSize_) {
88         return reduceSize;
89     }
90     if (GreatNotEqual(minIconSize_, (height_ - reduceSize))) {
91         double remain = reduceSize - (height_ - minIconSize_);
92         width_ = height_ = minIconSize_;
93         return remain;
94     }
95     height_ -= reduceSize;
96     width_ = height_;
97     return 0.0;
98 }
99 
Init(RefPtr<SecurityComponentLayoutProperty> & property,RefPtr<LayoutWrapper> & textWrap)100 void TextLayoutElement::Init(RefPtr<SecurityComponentLayoutProperty>& property,
101     RefPtr<LayoutWrapper>& textWrap)
102 {
103     secCompProperty_ = property;
104     textWrap_ = textWrap;
105     CHECK_NULL_VOID(property);
106     CHECK_NULL_VOID(textWrap);
107     if (property->GetSecurityComponentDescription().value_or(-1) ==
108             static_cast<int32_t>(SecurityComponentDescription::TEXT_NULL)) {
109         return;
110     }
111     isExist_ = true;
112 
113     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
114     CHECK_NULL_VOID(textProp);
115     auto context = PipelineContext::GetCurrentContextSafely();
116     CHECK_NULL_VOID(context);
117     auto theme = context->GetTheme<SecurityComponentTheme>();
118     CHECK_NULL_VOID(theme);
119     minFontSize_ = theme->GetMinFontSize();
120     if (property->GetFontSize().has_value()) {
121         isSetSize_ = true;
122     } else {
123         defaultFontSize_ = theme->GetFontSize();
124         textProp->UpdateFontSize(defaultFontSize_);
125     }
126 
127     auto textConstraint = property->CreateChildConstraint();
128     SizeT<float> maxSize { textConstraint.maxSize.Width(), Infinity<float>() };
129     textConstraint.maxSize = maxSize;
130     textWrap_->Measure(std::optional<LayoutConstraintF>(textConstraint));
131     auto geometryNode = textWrap->GetGeometryNode();
132     CHECK_NULL_VOID(geometryNode);
133     auto textSizeF = geometryNode->GetFrameSize();
134     width_ = textSizeF.Width();
135     height_ = textSizeF.Height();
136 }
137 
MeasureForWidth(float width)138 void TextLayoutElement::MeasureForWidth(float width)
139 {
140     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
141     CHECK_NULL_VOID(textProp);
142     auto textConstraint = textProp->GetContentLayoutConstraint();
143     CHECK_NULL_VOID(textConstraint);
144     textConstraint->selfIdealSize.SetWidth(width);
145     textWrap_->Measure(textConstraint);
146     auto textSizeF = textWrap_->GetGeometryNode()->GetFrameSize();
147     width_ = textSizeF.Width();
148     height_ = textSizeF.Height();
149 }
150 
DoMeasure(bool isVertical,float minWidth,float leftSpace)151 void TextLayoutElement::DoMeasure(bool isVertical, float minWidth, float leftSpace)
152 {
153     if (!isExist_) {
154         return;
155     }
156 
157     float textMaxWidth;
158     if (isVertical) {
159         textMaxWidth = minWidth > leftSpace ? minWidth : leftSpace;
160     } else {
161         textMaxWidth = minWidth > leftSpace ? minWidth - leftSpace : 0.0;
162     }
163     auto textNode = textWrap_->GetHostNode();
164     CHECK_NULL_VOID(textNode);
165     auto textPattern = textNode->GetPattern<TextPattern>();
166     CHECK_NULL_VOID(textPattern);
167 
168     if (GreatNotEqual(width_, textMaxWidth)) {
169         MeasureForWidth(textMaxWidth);
170         auto realWidth = textPattern->GetLineMetrics(0).width;
171         if (LessNotEqual(width_, realWidth)) {
172             MeasureForWidth(realWidth);
173         }
174     }
175 }
176 
ChooseExactFontSize(RefPtr<TextLayoutProperty> & property,bool isWidth)177 void TextLayoutElement::ChooseExactFontSize(RefPtr<TextLayoutProperty>& property, bool isWidth)
178 {
179     if (!minTextSize_.has_value()) {
180         property->UpdateFontSize(minFontSize_);
181         return;
182     }
183     constexpr Dimension ADAPT_UNIT = 1.0_fp;
184     Dimension step = ADAPT_UNIT;
185     Dimension fontSize = (property->GetFontSize().has_value()) ? property->GetFontSize().value() : defaultFontSize_;
186     while (fontSize > minFontSize_) {
187         auto tempSize = GetMeasureTextSize(property->GetContent().value_or(""),
188             fontSize,
189             property->GetFontWeight().value_or(FontWeight::NORMAL), 0.0);
190         if (!tempSize.has_value()) {
191             fontSize = minFontSize_;
192             break;
193         }
194         if (isWidth) {
195             if (GreatOrEqual(width_, tempSize.value().Width())) {
196                 break;
197             }
198         } else {
199             if (GreatOrEqual(height_, tempSize.value().Height())) {
200                 break;
201             }
202         }
203         fontSize -= step;
204     }
205     property->UpdateFontSize(fontSize);
206 }
207 
UpdateSize(bool isWidth)208 void TextLayoutElement::UpdateSize(bool isWidth)
209 {
210     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
211     CHECK_NULL_VOID(textProp);
212     ChooseExactFontSize(textProp, isWidth);
213     auto textConstraint = textProp->GetContentLayoutConstraint();
214     CHECK_NULL_VOID(textConstraint);
215     if (isWidth) {
216         textConstraint->selfIdealSize.SetWidth(width_);
217     } else {
218         textConstraint->selfIdealSize.SetHeight(height_);
219     }
220 
221     textWrap_->Measure(textConstraint);
222     auto geometryNode = textWrap_->GetGeometryNode();
223     CHECK_NULL_VOID(geometryNode);
224     auto textSizeF = geometryNode->GetFrameSize();
225     width_ = textSizeF.Width();
226     height_ = textSizeF.Height();
227 }
228 
GetCurrentTextSize(std::optional<SizeF> & currentTextSize,Dimension & currentFontSize)229 bool TextLayoutElement::GetCurrentTextSize(std::optional<SizeF>& currentTextSize, Dimension& currentFontSize)
230 {
231     if (!isExist_) {
232         return false;
233     }
234 
235     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
236     CHECK_NULL_RETURN(textProp, false);
237     if (!textProp->GetFontSize().has_value()) {
238         return false;
239     }
240     if (!textProp->GetContent().has_value()) {
241         return false;
242     }
243     currentTextSize = GetMeasureTextSize(textProp->GetContent().value(), textProp->GetFontSize().value(),
244         textProp->GetFontWeight().value_or(FontWeight::NORMAL), width_);
245     if (!currentTextSize.has_value()) {
246         return false;
247     }
248     currentFontSize = textProp->GetFontSize().value();
249     return true;
250 }
251 
TryShrinkTextWidth(SizeF & point,SizeF & circlePoint,bool maxSpaceToShrink,float maxDistance,float threshold)252 bool TextLayoutElement::TryShrinkTextWidth(SizeF& point, SizeF& circlePoint, bool maxSpaceToShrink, float maxDistance,
253     float threshold)
254 {
255     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
256     CHECK_NULL_RETURN(textProp, false);
257 
258     auto stepPx = Dimension(1.0, DimensionUnit::VP).ConvertToPx();
259     auto tempHeight = height_;
260     auto tempWidth = width_;
261     auto currentRectWidth = point.Width();
262     while (NearEqual(tempHeight, height_)) {
263         if (LessOrEqual(tempWidth, threshold)) {
264             return false;
265         }
266         tempWidth -= stepPx;
267         currentRectWidth -= stepPx;
268         auto tempSize = GetMeasureTextSize(textProp->GetContent().value(), textProp->GetFontSize().value(),
269             textProp->GetFontWeight().value_or(FontWeight::NORMAL), tempWidth);
270         if (!tempSize.has_value()) {
271             return false;
272         }
273         tempHeight = tempSize.value().Height();
274         if (!NearEqual(tempHeight, height_)) {
275             return false;
276         }
277         auto distance = pow(currentRectWidth - circlePoint.Width()) + pow(point.Height() - circlePoint.Height());
278         if (!GreatNotEqual(distance, maxDistance)) {
279             break;
280         }
281     }
282 
283     MeasureForWidth(tempWidth);
284     return true;
285 }
286 
GetMeasureTextSize(const std::string & data,const Dimension & fontSize,FontWeight fontWeight,float constraintWidth)287 std::optional<SizeF> TextLayoutElement::GetMeasureTextSize(const std::string& data,
288     const Dimension& fontSize, FontWeight fontWeight, float constraintWidth)
289 {
290 #ifdef ENABLE_ROSEN_BACKEND
291     MeasureContext content;
292     if (!NearEqual(constraintWidth, 0.0)) {
293         content.constraintWidth = Dimension(constraintWidth);
294     }
295     content.textContent = data;
296     content.fontSize = fontSize;
297     auto fontweight = StringUtils::FontWeightToString(fontWeight);
298     content.fontWeight = fontweight;
299     auto size = RosenRenderCustomPaint::MeasureTextSizeInner(content);
300     return SizeF(size.Width(), size.Height());
301 #else
302     return std::nullopt;
303 #endif
304 }
305 
MeasureMinTextSize()306 void TextLayoutElement::MeasureMinTextSize()
307 {
308     auto textProp = AceType::DynamicCast<TextLayoutProperty>(textWrap_->GetLayoutProperty());
309     CHECK_NULL_VOID(textProp);
310     minTextSize_ = GetMeasureTextSize(textProp->GetContent().value_or(""),
311         minFontSize_,
312         textProp->GetFontWeight().value_or(FontWeight::NORMAL), 0.0);
313 }
314 
ShrinkWidth(double reduceSize)315 double TextLayoutElement::ShrinkWidth(double reduceSize)
316 {
317     if (!isExist_ || isSetSize_) {
318         return reduceSize;
319     }
320     if (!minTextSize_.has_value()) {
321         MeasureMinTextSize();
322     }
323     double minTextWidth = minTextSize_.value_or(SizeT(0.0F, 0.0F)).Width();
324     if (GreatNotEqual(minTextWidth, (width_ - reduceSize))) {
325         int remain = reduceSize - (width_ - minTextWidth);
326         width_ = minTextWidth;
327         UpdateSize(true);
328         return remain;
329     }
330 
331     width_ -= reduceSize;
332     UpdateSize(true);
333     return 0.0;
334 }
335 
ShrinkHeight(double reduceSize)336 double TextLayoutElement::ShrinkHeight(double reduceSize)
337 {
338     if (!isExist_ || isSetSize_) {
339         return reduceSize;
340     }
341     if (!minTextSize_.has_value()) {
342         MeasureMinTextSize();
343     }
344 
345     double minTextHeight = minTextSize_.value_or(SizeT(0.0F, 0.0F)).Height();
346     if (GreatNotEqual(minTextHeight, (height_ - reduceSize))) {
347         double remain = reduceSize - (height_ - minTextHeight);
348         height_ = minTextHeight;
349         UpdateSize(false);
350         return remain;
351     }
352     height_ -= reduceSize;
353     UpdateSize(false);
354     return 0.0;
355 }
356 };
357