• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/utils/measure_util.h"
17 #include "core/components/common/properties/text_style.h"
18 #include "frameworks/core/components/font/constants_converter.h"
19 #include "frameworks/core/components/font/rosen_font_collection.h"
20 #include "frameworks/core/components/text/text_theme.h"
21 #include "rosen_text/text_style.h"
22 #include "rosen_text/typography.h"
23 #include "rosen_text/typography_create.h"
24 #include "ui/base/utils/utils.h"
25 
26 namespace OHOS::Ace {
27 namespace {
28 const std::u16string ELLIPSIS = u"\u2026";
29 const std::string FONTWEIGHT = "wght";
30 
ApplyLineHeightInNumUnit(const MeasureContext & context,Rosen::TextStyle & txtStyle)31 void ApplyLineHeightInNumUnit(const MeasureContext& context, Rosen::TextStyle& txtStyle)
32 {
33     auto lineHeight = context.lineHeight.value().ConvertToPx();
34     txtStyle.heightOnly = true;
35     if (!NearEqual(lineHeight, txtStyle.fontSize) && (lineHeight > 0.0) && (!NearZero(txtStyle.fontSize))) {
36         txtStyle.heightScale = lineHeight / txtStyle.fontSize;
37     } else {
38         txtStyle.heightScale = 1;
39         static const int32_t BEGIN_VERSION = 6;
40         auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
41         auto isBeginVersion = pipelineContext && pipelineContext->GetMinPlatformVersion() >= BEGIN_VERSION;
42         if (NearZero(lineHeight) || (!isBeginVersion && NearEqual(lineHeight, txtStyle.fontSize))) {
43             txtStyle.heightOnly = false;
44         }
45     }
46 }
47 
IsApplyIndent(const MeasureContext & context,double & indent)48 bool IsApplyIndent(const MeasureContext& context, double& indent)
49 {
50     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
51     CHECK_NULL_RETURN(pipeline, false);
52     if (context.textIndent.value().Unit() != DimensionUnit::PERCENT) {
53         indent = context.textIndent.value().ConvertToPx();
54         return true;
55     } else {
56         if (context.constraintWidth.has_value()) {
57             indent = context.constraintWidth.value().ConvertToPx() * context.textIndent.value().Value();
58             return true;
59         }
60     }
61     return false;
62 }
63 
prepareTextStyleForMeasure(const MeasureContext & context)64 Rosen::TextStyle prepareTextStyleForMeasure(const MeasureContext& context)
65 {
66     using namespace Constants;
67     Rosen::TextStyle txtStyle;
68     std::vector<std::string> fontFamilies;
69     if (context.fontSize.has_value()) {
70         txtStyle.fontSize = context.fontSize.value().ConvertToPx();
71     } else {
72         auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
73         CHECK_NULL_RETURN(pipelineContext, txtStyle);
74         auto textTheme = pipelineContext->GetTheme<TextTheme>();
75         txtStyle.fontSize = textTheme->GetTextStyle().GetFontSize().ConvertToPx();
76     }
77     txtStyle.fontStyle = ConvertTxtFontStyle(context.fontStyle);
78     FontWeight fontWeightStr = StringUtils::StringToFontWeight(context.fontWeight);
79     txtStyle.fontWeight = ConvertTxtFontWeight(fontWeightStr);
80     auto fontWeightValue = (static_cast<int32_t>(
81             ConvertTxtFontWeight(fontWeightStr)) + 1) * 100; // 100: coefficient for transformation
82     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
83     if (pipelineContext) {
84         fontWeightValue = fontWeightValue * pipelineContext->GetFontWeightScale();
85     }
86     txtStyle.fontVariations.SetAxisValue(FONTWEIGHT, fontWeightValue);
87     StringUtils::StringSplitter(context.fontFamily, ',', fontFamilies);
88     txtStyle.fontFamilies = fontFamilies;
89     if (context.letterSpacing.has_value()) {
90         txtStyle.letterSpacing = context.letterSpacing.value().ConvertToPx();
91     }
92     if (context.lineHeight.has_value()) {
93         if (context.lineHeight->Unit() == DimensionUnit::PERCENT) {
94             txtStyle.heightOnly = true;
95             txtStyle.heightScale = context.lineHeight->Value();
96         } else {
97             ApplyLineHeightInNumUnit(context, txtStyle);
98         }
99     }
100     return txtStyle;
101 }
102 
prepareParagraphForMeasure(const MeasureContext & context,std::unique_ptr<Rosen::Typography> & paragraph)103 void prepareParagraphForMeasure(const MeasureContext& context, std::unique_ptr<Rosen::Typography>& paragraph)
104 {
105     if (context.textIndent.has_value() && !LessOrEqual(context.textIndent.value().Value(), 0.0)) {
106         double indent = 0.0;
107         // first line indent
108         if (IsApplyIndent(context, indent)) {
109             std::vector<float> indents;
110             // only indent first line
111             indents.emplace_back(static_cast<float>(indent));
112             indents.emplace_back(0.0);
113             paragraph->SetIndents(indents);
114         }
115     }
116     if (context.constraintWidth.has_value()) {
117         paragraph->Layout(context.constraintWidth.value().ConvertToPx());
118     } else {
119         paragraph->Layout(Size::INFINITE_SIZE);
120     }
121 }
122 
MeasureTextInner(const MeasureContext & context)123 double MeasureTextInner(const MeasureContext& context)
124 {
125     using namespace Constants;
126     Rosen::TypographyStyle style;
127     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
128     if (!fontCollection) {
129         LOGW("fontCollection is null");
130         return 0.0;
131     }
132     std::unique_ptr<Rosen::TypographyCreate> builder = Rosen::TypographyCreate::Create(style, fontCollection);
133     Rosen::TextStyle txtStyle;
134     std::vector<std::string> fontFamilies;
135     if (context.fontSize) {
136         txtStyle.fontSize = context.fontSize.value().ConvertToPx();
137     } else {
138         auto pipelineContext = PipelineBase::GetCurrentContext();
139         CHECK_NULL_RETURN(pipelineContext, 0.0);
140         auto textTheme = pipelineContext->GetTheme<TextTheme>();
141         txtStyle.fontSize = textTheme->GetTextStyle().GetFontSize().ConvertToPx();
142     }
143     txtStyle.fontStyle = ConvertTxtFontStyle(context.fontStyle);
144     FontWeight fontWeightStr = StringUtils::StringToFontWeight(context.fontWeight);
145     txtStyle.fontWeight = ConvertTxtFontWeight(fontWeightStr);
146     auto fontWeightValue = (static_cast<int32_t>(
147             ConvertTxtFontWeight(fontWeightStr)) + 1) * 100; // 100: coefficient for transformation
148     auto pipelineContext = PipelineBase::GetCurrentContextSafely();
149     if (pipelineContext) {
150         fontWeightValue = fontWeightValue * pipelineContext->GetFontWeightScale();
151     }
152     txtStyle.fontVariations.SetAxisValue(FONTWEIGHT, fontWeightValue);
153     StringUtils::StringSplitter(context.fontFamily, ',', fontFamilies);
154     txtStyle.fontFamilies = fontFamilies;
155     if (context.letterSpacing.has_value()) {
156         txtStyle.letterSpacing = context.letterSpacing.value().ConvertToPx();
157     }
158 
159     builder->PushStyle(txtStyle);
160     builder->AppendText(StringUtils::Str8ToStr16(context.textContent));
161     auto paragraph = builder->CreateTypography();
162     if (!paragraph) {
163         return 0.0;
164     }
165     paragraph->Layout(Size::INFINITE_SIZE);
166     return std::ceil(paragraph->GetActualWidth());
167 }
168 
MeasureTextSizeInner(const MeasureContext & context)169 Size MeasureTextSizeInner(const MeasureContext& context)
170 {
171     using namespace Constants;
172     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
173     if (!fontCollection) {
174         TAG_LOGW(AceLogTag::ACE_FONT, "fontCollection is null");
175         return Size(0.0, 0.0);
176     }
177     ACE_TEXT_SCOPED_TRACE("MeasureTextSizeInner");
178     Rosen::TypographyStyle style;
179     style.textAlign = ConvertTxtTextAlign(context.textAlign);
180     if (context.textOverlayFlow == TextOverflow::ELLIPSIS) {
181         style.ellipsis = ELLIPSIS;
182     }
183     if (GreatNotEqual(context.maxlines, 0.0)) {
184         style.maxLines = context.maxlines;
185     }
186     style.wordBreakType = static_cast<Rosen::WordBreakType>(context.wordBreak);
187     std::unique_ptr<Rosen::TypographyCreate> builder = Rosen::TypographyCreate::Create(style, fontCollection);
188 
189     Rosen::TextStyle txtStyle = prepareTextStyleForMeasure(context);
190     builder->PushStyle(txtStyle);
191     std::string content = context.textContent;
192     StringUtils::TransformStrCase(content, static_cast<int32_t>(context.textCase));
193     builder->AppendText(StringUtils::Str8ToStr16(content));
194 
195     auto paragraph = builder->CreateTypography();
196     CHECK_NULL_RETURN(paragraph, Size(0.0, 0.0));
197 
198     prepareParagraphForMeasure(context, paragraph);
199     double textWidth = 0.0;
200     auto* paragraphTxt = static_cast<Rosen::Typography*>(paragraph.get());
201     if (paragraphTxt->GetLineCount() == 1 && !context.isReturnActualWidth) {
202         textWidth = std::max(paragraph->GetActualWidth(), paragraph->GetMaxIntrinsicWidth());
203     } else {
204         textWidth = paragraph->GetActualWidth();
205     }
206     auto sizeWidth = std::min(paragraph->GetMaxWidth(), textWidth);
207     sizeWidth =
208         context.constraintWidth.has_value() ? context.constraintWidth.value().ConvertToPx() : std::ceil(sizeWidth);
209 
210     float baselineOffset = 0.0;
211     if (context.baselineOffset.has_value()) {
212         baselineOffset = static_cast<float>(context.baselineOffset.value().ConvertToPx());
213     }
214     float heightFinal = static_cast<float>(paragraph->GetHeight()) + std::fabs(baselineOffset);
215     if (SystemProperties::GetDebugEnabled()) {
216         TAG_LOGI(AceLogTag::ACE_FONT, "MeasureTextSize [maxW:%{public}f, H:%{public}f],[w:%{public}f, h:%{public}f]",
217             paragraph->GetMaxWidth(), paragraph->GetHeight(), sizeWidth, heightFinal);
218     }
219 
220     return Size(sizeWidth, heightFinal);
221 }
222 }
223 
MeasureText(const MeasureContext & context)224 double MeasureUtil::MeasureText(const MeasureContext& context)
225 {
226     if (SystemProperties::GetRosenBackendEnabled()) {
227 #ifdef ENABLE_ROSEN_BACKEND
228         return MeasureTextInner(context);
229 #else
230         return 0.0;
231 #endif
232     } else {
233         return 0.0;
234     }
235 }
236 
MeasureTextSize(const MeasureContext & context)237 Size MeasureUtil::MeasureTextSize(const MeasureContext& context)
238 {
239     if (SystemProperties::GetRosenBackendEnabled()) {
240 #ifdef ENABLE_ROSEN_BACKEND
241         return MeasureTextSizeInner(context);
242 #else
243         return Size(0.0, 0.0);
244 #endif
245     } else {
246         return Size(0.0, 0.0);
247     }
248 }
249 
MeasureTextSize(const TextStyle & textStyle,const std::string & text)250 Size MeasureUtil::MeasureTextSize(const TextStyle& textStyle, const std::string& text)
251 {
252 #ifdef ENABLE_ROSEN_BACKEND
253     MeasureContext content;
254     content.textContent = text;
255     content.fontSize = textStyle.GetFontSize();
256     auto fontweight = StringUtils::FontWeightToString(textStyle.GetFontWeight());
257     content.fontWeight = fontweight;
258     content.isReturnActualWidth = true;
259     content.maxlines = 1;
260     return MeasureTextSizeInner(content);
261 #else
262     return 0.0f;
263 #endif
264 }
265 
MeasureTextWidth(const TextStyle & textStyle,const std::string & text)266 double MeasureUtil::MeasureTextWidth(const TextStyle& textStyle, const std::string& text)
267 {
268     auto width = MeasureTextSize(textStyle, text).Width();
269     return std::max(width, 0.0);
270 }
271 } // namespace OHOS::Ace
272