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