1 /*
2 * Copyright (c) 2024 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/text_adapt_font_sizer.h"
17
18 #include <limits>
19
20 #include "base/geometry/dimension.h"
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/common/font_manager.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25
26 namespace OHOS::Ace::NG {
AdaptMaxFontSize(TextStyle & textStyle,const std::string & content,const Dimension & stepUnit,const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)27 bool TextAdaptFontSizer::AdaptMaxFontSize(TextStyle& textStyle, const std::string& content,
28 const Dimension& stepUnit, const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
29 {
30 double maxFontSize = 0.0;
31 double minFontSize = 0.0;
32 GetAdaptMaxMinFontSize(textStyle, maxFontSize, minFontSize, contentConstraint);
33 if (LessNotEqual(maxFontSize, minFontSize) || LessOrEqual(minFontSize, 0.0)) {
34 // minFontSize or maxFontSize is invalid
35 return CreateParagraphAndLayout(textStyle, content, contentConstraint, layoutWrapper, false);
36 }
37 double stepSize = 0.0;
38 GetAdaptFontSizeStep(textStyle, stepSize, stepUnit, contentConstraint);
39 auto maxSize = GetMaxMeasureSize(contentConstraint);
40 GetSuitableSize(maxSize, layoutWrapper);
41 // Use the minFontSize to layout the paragraph. While using the minFontSize, if the paragraph could be layout in 1
42 // line, then increase the font size and try to layout using the maximum available fontsize.
43 textStyle.SetFontSize(Dimension(minFontSize));
44 CreateParagraphAndLayout(textStyle, content, contentConstraint, layoutWrapper);
45 if (IsAdaptExceedLimit(maxSize)) {
46 return true;
47 }
48 auto tag = static_cast<int32_t>((maxFontSize - minFontSize) / stepSize);
49 auto length = tag + 1 + (GreatNotEqual(maxFontSize, minFontSize + stepSize * tag) ? 1 : 0);
50 int32_t left = 0;
51 int32_t right = length - 1;
52 float fontSize = 0.0f;
53 while (left <= right) {
54 int32_t mid = left + (right - left) / 2;
55 fontSize = static_cast<float>((mid == length - 1) ? (maxFontSize) : (minFontSize + stepSize * mid));
56 textStyle.SetFontSize(Dimension(fontSize));
57 if (!CreateParagraphAndLayout(textStyle, content, contentConstraint, layoutWrapper)) {
58 return false;
59 }
60 if (!IsAdaptExceedLimit(maxSize)) {
61 left = mid + 1;
62 } else {
63 right = mid - 1;
64 }
65 }
66 fontSize = static_cast<float>((left - 1 == length - 1) ? (maxFontSize) : (minFontSize + stepSize * (left - 1)));
67 fontSize = LessNotEqual(fontSize, minFontSize) ? minFontSize : fontSize;
68 fontSize = GreatNotEqual(fontSize, maxFontSize) ? maxFontSize : fontSize;
69 textStyle.SetFontSize(Dimension(fontSize));
70 return CreateParagraphAndLayout(textStyle, content, contentConstraint, layoutWrapper);
71 }
72
AdaptMinFontSize(TextStyle & textStyle,const std::string & content,const Dimension & stepUnit,const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)73 bool TextAdaptFontSizer::AdaptMinFontSize(TextStyle& textStyle, const std::string& content,
74 const Dimension& stepUnit, const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
75 {
76 double maxFontSize = 0.0;
77 double minFontSize = 0.0;
78 GetAdaptMaxMinFontSize(textStyle, maxFontSize, minFontSize, contentConstraint);
79 if (LessNotEqual(maxFontSize, minFontSize) || LessOrEqual(minFontSize, 0.0)) {
80 return CreateParagraphAndLayout(textStyle, content, contentConstraint, layoutWrapper, false);
81 }
82 double stepSize = 0.0;
83 GetAdaptFontSizeStep(textStyle, stepSize, stepUnit, contentConstraint);
84 auto maxSize = GetMaxMeasureSize(contentConstraint);
85 GetSuitableSize(maxSize, layoutWrapper);
86 while (GreatOrEqual(maxFontSize, minFontSize)) {
87 textStyle.SetFontSize(Dimension(maxFontSize));
88 if (!CreateParagraphAndLayout(textStyle, content, contentConstraint, layoutWrapper)) {
89 return false;
90 }
91 if (!DidExceedMaxLines(maxSize)) {
92 break;
93 }
94 maxFontSize -= stepSize;
95 }
96 return true;
97 }
98
GetAdaptMaxMinFontSize(const TextStyle & textStyle,double & maxFontSize,double & minFontSize,const LayoutConstraintF & contentConstraint)99 void TextAdaptFontSizer::GetAdaptMaxMinFontSize(const TextStyle& textStyle, double& maxFontSize, double& minFontSize,
100 const LayoutConstraintF& contentConstraint)
101 {
102 maxFontSize = textStyle.GetAdaptMaxFontSize().ConvertToPxDistribute(
103 textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
104 minFontSize = textStyle.GetAdaptMinFontSize().ConvertToPxDistribute(
105 textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
106 }
107
GetAdaptFontSizeStep(const TextStyle & textStyle,double & stepSize,const Dimension & stepUnit,const LayoutConstraintF & contentConstraint)108 void TextAdaptFontSizer::GetAdaptFontSizeStep(const TextStyle& textStyle, double& stepSize, const Dimension& stepUnit,
109 const LayoutConstraintF& contentConstraint)
110 {
111 Dimension step = stepUnit;
112 if (GreatNotEqual(textStyle.GetAdaptFontSizeStep().Value(), 0.0)) {
113 step = textStyle.GetAdaptFontSizeStep();
114 }
115 stepSize =
116 step.ConvertToPxDistribute(textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
117 }
118
GetMaxMeasureSize(const LayoutConstraintF & contentConstraint)119 SizeF TextAdaptFontSizer::GetMaxMeasureSize(const LayoutConstraintF& contentConstraint)
120 {
121 auto maxSize = contentConstraint.selfIdealSize;
122 maxSize.UpdateIllegalSizeWithCheck(contentConstraint.maxSize);
123 return maxSize.ConvertToSizeT();
124 }
125
DidExceedMaxLines(const SizeF & maxSize)126 bool TextAdaptFontSizer::DidExceedMaxLines(const SizeF& maxSize)
127 {
128 auto paragraph = GetParagraph();
129 CHECK_NULL_RETURN(paragraph, false);
130 bool didExceedMaxLines = paragraph->DidExceedMaxLines();
131 didExceedMaxLines = didExceedMaxLines || GreatNotEqual(paragraph->GetHeight(), maxSize.Height());
132 didExceedMaxLines = didExceedMaxLines || GreatNotEqual(paragraph->GetLongestLine(), maxSize.Width());
133 return didExceedMaxLines;
134 }
135
IsAdaptExceedLimit(const SizeF & maxSize)136 bool TextAdaptFontSizer::IsAdaptExceedLimit(const SizeF& maxSize)
137 {
138 auto paragraph = GetParagraph();
139 CHECK_NULL_RETURN(paragraph, false);
140 return (paragraph->GetLineCount() > 1) || paragraph->DidExceedMaxLines() ||
141 GreatNotEqual(paragraph->GetLongestLine(), maxSize.Width());
142 }
143
IsNeedAdaptFontSize(const double & maxFontSize,const double & minFontSize)144 bool TextAdaptFontSizer::IsNeedAdaptFontSize(const double& maxFontSize, const double& minFontSize)
145 {
146 if (LessNotEqual(maxFontSize, minFontSize) || LessOrEqual(minFontSize, 0.0)) {
147 return false;
148 }
149 return true;
150 }
151
IsNeedAdaptFontSize(const TextStyle & textStyle,const LayoutConstraintF & contentConstraint)152 bool TextAdaptFontSizer::IsNeedAdaptFontSize(const TextStyle& textStyle, const LayoutConstraintF& contentConstraint)
153 {
154 double maxFontSize = 0.0;
155 double minFontSize = 0.0;
156 GetAdaptMaxMinFontSize(textStyle, maxFontSize, minFontSize, contentConstraint);
157 return IsNeedAdaptFontSize(maxFontSize, minFontSize);
158 }
159
SetAdaptFontSizeLineHeight(const Dimension & lineHeight,const TextStyle & textStyle)160 void TextAdaptFontSizer::SetAdaptFontSizeLineHeight(const Dimension& lineHeight, const TextStyle& textStyle)
161 {
162 lineHeight_ = lineHeight.ConvertToPxDistribute(
163 textStyle.GetMinFontScale(), textStyle.GetMaxFontScale(), textStyle.IsAllowScale());
164 }
165
IsAdaptFontSizeExceedLineHeight(const RefPtr<Paragraph> & paragraph)166 bool TextAdaptFontSizer::IsAdaptFontSizeExceedLineHeight(const RefPtr<Paragraph>& paragraph)
167 {
168 if (LessOrEqual(lineHeight_, 0.0)) {
169 return false;
170 }
171 auto lineMetrics = paragraph->GetLineMetrics(0);
172 return GreatNotEqual(lineMetrics.height, lineHeight_);
173 }
174 } // namespace OHOS::Ace::NG
175