1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved.
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 "paragraph_builder_impl.h"
17
18 #include "modules/skparagraph/include/ParagraphStyle.h"
19 #include "modules/skparagraph/include/TextStyle.h"
20 #include "paragraph_impl.h"
21 #include "txt/paragraph_style.h"
22 #include "utils/text_log.h"
23
24 namespace skt = skia::textlayout;
25
26 namespace OHOS {
27 namespace Rosen {
28 namespace SPText {
29 namespace {
ConvertToSkFontWeight(FontWeight fontWeight)30 int ConvertToSkFontWeight(FontWeight fontWeight)
31 {
32 constexpr int weightBase = 100;
33 return static_cast<int>(fontWeight) * weightBase + weightBase;
34 }
35
ConvertToRSFontSlant(FontStyle fontStyle)36 RSFontStyle::Slant ConvertToRSFontSlant(FontStyle fontStyle)
37 {
38 RSFontStyle::Slant slant;
39 switch (fontStyle) {
40 case FontStyle::NORMAL: {
41 slant = RSFontStyle::Slant::UPRIGHT_SLANT;
42 break;
43 }
44 case FontStyle::ITALIC: {
45 slant = RSFontStyle::Slant::ITALIC_SLANT;
46 break;
47 }
48 case FontStyle::OBLIQUE: {
49 slant = RSFontStyle::Slant::OBLIQUE_SLANT;
50 break;
51 }
52 default: {
53 slant = RSFontStyle::Slant::UPRIGHT_SLANT;
54 }
55 }
56 return slant;
57 }
58
MakeFontStyle(FontWeight fontWeight,FontWidth fontWidth,FontStyle fontStyle)59 RSFontStyle MakeFontStyle(FontWeight fontWeight, FontWidth fontWidth, FontStyle fontStyle)
60 {
61 auto weight = ConvertToSkFontWeight(fontWeight);
62 auto width = static_cast<RSFontStyle::Width>(fontWidth);
63 auto slant = ConvertToRSFontSlant(fontStyle);
64 return RSFontStyle(weight, width, slant);
65 }
66
MakeFontArguments(skt::TextStyle & skStyle,const FontVariations & fontVariations)67 void MakeFontArguments(skt::TextStyle& skStyle, const FontVariations& fontVariations)
68 {
69 constexpr size_t axisLen = 4;
70
71 std::vector<SkFontArguments::VariationPosition::Coordinate> coordinates;
72 for (const auto& [axis, value] : fontVariations.GetAxisValues()) {
73 if (axis.length() == axisLen) {
74 coordinates.push_back({
75 SkSetFourByteTag(axis[0], axis[1], axis[2], axis[3]),
76 value,
77 });
78 }
79 }
80 SkFontArguments::VariationPosition position = { coordinates.data(), static_cast<int>(coordinates.size()) };
81
82 SkFontArguments arguments;
83 arguments.setVariationDesignPosition(position);
84 skStyle.setFontArguments(arguments);
85 }
86
MakeTextShadow(const TextShadow & txtShadow)87 skt::TextShadow MakeTextShadow(const TextShadow& txtShadow)
88 {
89 skt::TextShadow shadow;
90 shadow.fOffset = txtShadow.offset;
91 shadow.fBlurSigma = txtShadow.blurSigma;
92 shadow.fColor = txtShadow.color;
93 return shadow;
94 }
95
DefaultLocale()96 const char* DefaultLocale()
97 {
98 static const char* LOCALE_ZH = "zh-Hans";
99 return LOCALE_ZH;
100 }
101 } // anonymous namespace
102
ParagraphBuilderImpl(const ParagraphStyle & style,std::shared_ptr<txt::FontCollection> fontCollection)103 ParagraphBuilderImpl::ParagraphBuilderImpl(
104 const ParagraphStyle& style, std::shared_ptr<txt::FontCollection> fontCollection)
105 : baseStyle_(style.ConvertToTextStyle())
106 {
107 threadId_ = pthread_self();
108 builder_ = skt::ParagraphBuilder::make(TextStyleToSkStyle(style), fontCollection->CreateSktFontCollection());
109 }
110
111 ParagraphBuilderImpl::~ParagraphBuilderImpl() = default;
112
PushStyle(const TextStyle & style)113 void ParagraphBuilderImpl::PushStyle(const TextStyle& style)
114 {
115 RecordDifferentPthreadCall(__FUNCTION__);
116 builder_->pushStyle(TextStyleToSkStyle(style));
117 }
118
Pop()119 void ParagraphBuilderImpl::Pop()
120 {
121 RecordDifferentPthreadCall(__FUNCTION__);
122 builder_->pop();
123 }
124
AddText(const std::u16string & text)125 void ParagraphBuilderImpl::AddText(const std::u16string& text)
126 {
127 RecordDifferentPthreadCall(__FUNCTION__);
128 builder_->addText(text);
129 }
130
AddPlaceholder(PlaceholderRun & run)131 void ParagraphBuilderImpl::AddPlaceholder(PlaceholderRun& run)
132 {
133 RecordDifferentPthreadCall(__FUNCTION__);
134 skt::PlaceholderStyle placeholderStyle;
135 placeholderStyle.fHeight = run.height;
136 placeholderStyle.fWidth = run.width;
137 placeholderStyle.fBaseline = static_cast<skt::TextBaseline>(run.baseline);
138 placeholderStyle.fBaselineOffset = run.baselineOffset;
139 placeholderStyle.fAlignment = static_cast<skt::PlaceholderAlignment>(run.alignment);
140
141 builder_->addPlaceholder(placeholderStyle);
142 }
143
Build()144 std::unique_ptr<Paragraph> ParagraphBuilderImpl::Build()
145 {
146 RecordDifferentPthreadCall(__FUNCTION__);
147 auto ret = std::make_unique<ParagraphImpl>(builder_->Build(), std::move(paints_));
148 builder_->Reset();
149 return ret;
150 }
151
AllocPaintID(const PaintRecord & paint)152 skt::ParagraphPainter::PaintID ParagraphBuilderImpl::AllocPaintID(const PaintRecord& paint)
153 {
154 paints_.push_back(paint);
155 return static_cast<int>(paints_.size()) - 1;
156 }
157
TextStyleToSkStyle(const ParagraphStyle & txt)158 skt::ParagraphStyle ParagraphBuilderImpl::TextStyleToSkStyle(const ParagraphStyle& txt)
159 {
160 skt::ParagraphStyle skStyle;
161 skt::TextStyle textStyle;
162
163 PaintRecord paint;
164 paint.SetColor(textStyle.getColor());
165 if (txt.customSpTextStyle) {
166 textStyle = this->TextStyleToSkStyle(txt.spTextStyle);
167 } else {
168 textStyle.setForegroundPaintID(AllocPaintID(paint));
169 textStyle.setFontStyle(MakeFontStyle(txt.fontWeight, txt.fontWidth, txt.fontStyle));
170 textStyle.setFontSize(SkDoubleToScalar(txt.fontSize));
171 textStyle.setHeight(SkDoubleToScalar(txt.height));
172 textStyle.setHeightOverride(txt.heightOverride);
173 textStyle.setFontFamilies({ SkString(txt.fontFamily.c_str()) });
174 textStyle.setLocale(SkString(txt.locale.empty() ? DefaultLocale() : txt.locale.c_str()));
175 }
176
177 skStyle.setTextStyle(textStyle);
178 skStyle.setTextOverflower(txt.textOverflower);
179 skt::StrutStyle strutStyle;
180 strutStyle.setFontStyle(MakeFontStyle(txt.strutFontWeight, txt.strutFontWidth, txt.strutFontStyle));
181 strutStyle.setFontSize(SkDoubleToScalar(txt.strutFontSize));
182 strutStyle.setHeight(SkDoubleToScalar(txt.strutHeight));
183 strutStyle.setHeightOverride(txt.strutHeightOverride);
184
185 std::vector<SkString> strutFonts;
186 std::transform(txt.strutFontFamilies.begin(), txt.strutFontFamilies.end(), std::back_inserter(strutFonts),
187 [](const std::string& f) { return SkString(f.c_str()); });
188 strutStyle.setFontFamilies(strutFonts);
189 strutStyle.setLeading(txt.strutLeading);
190 strutStyle.setForceStrutHeight(txt.forceStrutHeight);
191 strutStyle.setStrutEnabled(txt.strutEnabled);
192 strutStyle.setWordBreakType(static_cast<skt::WordBreakType>(txt.wordBreakType));
193 strutStyle.setLineBreakStrategy(static_cast<skt::LineBreakStrategy>(txt.breakStrategy));
194 skStyle.setStrutStyle(strutStyle);
195
196 skStyle.setTextAlign(static_cast<skt::TextAlign>(txt.textAlign));
197 skStyle.setTextDirection(static_cast<skt::TextDirection>(txt.textDirection));
198 skStyle.setEllipsisMod(static_cast<skt::EllipsisModal>(txt.ellipsisModal));
199 if (txt.ellipsisModal != EllipsisModal::TAIL) {
200 skStyle.setEllipsis(txt.ellipsis);
201 }
202 skStyle.setMaxLines(txt.maxLines);
203 skStyle.setEllipsis(txt.ellipsis);
204 skStyle.setTextHeightBehavior(static_cast<skt::TextHeightBehavior>(txt.textHeightBehavior));
205 if (!txt.hintingIsOn) {
206 skStyle.turnHintingOff();
207 }
208 skStyle.setReplaceTabCharacters(true);
209 skStyle.setTextSplitRatio(txt.textSplitRatio);
210 skStyle.setTextHeightBehavior(static_cast<skt::TextHeightBehavior>(txt.textHeightBehavior));
211
212 return skStyle;
213 }
214
TextStyleToSkStyle(const TextStyle & txt)215 skt::TextStyle ParagraphBuilderImpl::TextStyleToSkStyle(const TextStyle& txt)
216 {
217 auto skStyle = ConvertTextStyleToSkStyle(txt);
218 CopyTextStylePaint(txt, skStyle);
219 return skStyle;
220 }
221
ConvertTextStyleToSkStyle(const TextStyle & txt)222 skt::TextStyle ParagraphBuilderImpl::ConvertTextStyleToSkStyle(const TextStyle& txt)
223 {
224 skt::TextStyle skStyle;
225
226 skStyle.setColor(txt.color);
227 skStyle.setDecoration(static_cast<skt::TextDecoration>(txt.decoration));
228 skStyle.setDecorationColor(txt.decorationColor);
229 skStyle.setDecorationStyle(static_cast<skt::TextDecorationStyle>(txt.decorationStyle));
230 skStyle.setDecorationThicknessMultiplier(SkDoubleToScalar(txt.decorationThicknessMultiplier));
231 skStyle.setFontStyle(MakeFontStyle(txt.fontWeight, txt.fontWidth, txt.fontStyle));
232 skStyle.setTextBaseline(static_cast<skt::TextBaseline>(txt.baseline));
233
234 std::vector<SkString> fonts;
235 std::transform(txt.fontFamilies.begin(), txt.fontFamilies.end(), std::back_inserter(fonts),
236 [](const std::string& f) { return SkString(f.c_str()); });
237 skStyle.setFontFamilies(fonts);
238
239 skStyle.setFontSize(SkDoubleToScalar(txt.fontSize));
240 skStyle.setLetterSpacing(SkDoubleToScalar(txt.letterSpacing));
241 skStyle.setWordSpacing(SkDoubleToScalar(txt.wordSpacing));
242 skStyle.setHeight(SkDoubleToScalar(txt.height));
243 skStyle.setHeightOverride(txt.heightOverride);
244 skStyle.setHalfLeading(txt.halfLeading);
245 skStyle.setBaselineShift(txt.baseLineShift);
246
247 skStyle.setLocale(SkString(txt.locale.empty() ? DefaultLocale() : txt.locale.c_str()));
248 skStyle.setStyleId(txt.styleId);
249 skStyle.setBackgroundRect({ txt.backgroundRect.color, txt.backgroundRect.leftTopRadius,
250 txt.backgroundRect.rightTopRadius, txt.backgroundRect.rightBottomRadius,
251 txt.backgroundRect.leftBottomRadius });
252
253 skStyle.resetFontFeatures();
254 for (const auto& ff : txt.fontFeatures.GetFontFeatures()) {
255 skStyle.addFontFeature(SkString(ff.first.c_str()), ff.second);
256 }
257
258 if (!txt.fontVariations.GetAxisValues().empty()) {
259 MakeFontArguments(skStyle, txt.fontVariations);
260 }
261
262 skStyle.resetShadows();
263 for (const TextShadow& txtShadow : txt.textShadows) {
264 skStyle.addShadow(MakeTextShadow(txtShadow));
265 }
266
267 if (txt.isPlaceholder) {
268 skStyle.setPlaceholder();
269 }
270
271 return skStyle;
272 }
273
CopyTextStylePaint(const TextStyle & txt,skia::textlayout::TextStyle & skStyle)274 void ParagraphBuilderImpl::CopyTextStylePaint(const TextStyle& txt, skia::textlayout::TextStyle& skStyle)
275 {
276 if (txt.background.has_value()) {
277 skStyle.setBackgroundPaintID(AllocPaintID(txt.background.value()));
278 }
279 if (txt.foreground.has_value()) {
280 skStyle.setForegroundPaintID(AllocPaintID(txt.foreground.value()));
281 } else {
282 PaintRecord paint;
283 paint.SetColor(txt.color);
284 paint.isSymbolGlyph = txt.isSymbolGlyph;
285 paint.symbol.SetRenderColor(txt.symbol.GetRenderColor());
286 paint.symbol.SetRenderMode(txt.symbol.GetRenderMode());
287 paint.symbol.SetSymbolEffect(txt.symbol.GetEffectStrategy());
288 paint.symbol.SetAnimationMode(txt.symbol.GetAnimationMode());
289 paint.symbol.SetRepeatCount(txt.symbol.GetRepeatCount());
290 paint.symbol.SetAnimationStart(txt.symbol.GetAnimationStart());
291 paint.symbol.SetCommonSubType(txt.symbol.GetCommonSubType());
292 skStyle.setForegroundPaintID(AllocPaintID(paint));
293 }
294 }
295
RecordDifferentPthreadCall(const char * caller) const296 void ParagraphBuilderImpl::RecordDifferentPthreadCall(const char* caller) const
297 {
298 pthread_t currenetThreadId = pthread_self();
299 if (threadId_ != currenetThreadId) {
300 TEXT_LOGE_LIMIT3_HOUR("New pthread access paragraph builder, old %{public}lu, caller %{public}s",
301 threadId_, caller);
302 threadId_ = currenetThreadId;
303 }
304 }
305 } // namespace SPText
306 } // namespace Rosen
307 } // namespace OHOS
308