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