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_impl.h"
17
18 #include <algorithm>
19 #include <numeric>
20
21 #include "include/core/SkMatrix.h"
22 #include "drawing_painter_impl.h"
23 #include "paragraph_builder_impl.h"
24 #include "skia_adapter/skia_convert_utils.h"
25 #include "text/font_metrics.h"
26 #include "text_line_impl.h"
27 #include "utils/text_log.h"
28 #include "utils/text_trace.h"
29
30 namespace OHOS {
31 namespace Rosen {
32 namespace SPText {
33 namespace skt = skia::textlayout;
34 using PaintID = skt::ParagraphPainter::PaintID;
35
36 namespace {
GetTxtFontWeight(int fontWeight)37 FontWeight GetTxtFontWeight(int fontWeight)
38 {
39 constexpr int minWeight = static_cast<int>(FontWeight::W100);
40 constexpr int maxWeight = static_cast<int>(FontWeight::W900);
41
42 int weight = std::clamp((fontWeight - 100) / 100, minWeight, maxWeight);
43 return static_cast<FontWeight>(weight);
44 }
45
GetTxtFontStyle(RSFontStyle::Slant slant)46 FontStyle GetTxtFontStyle(RSFontStyle::Slant slant)
47 {
48 return slant == RSFontStyle::Slant::UPRIGHT_SLANT ?
49 FontStyle::NORMAL : FontStyle::ITALIC;
50 }
51
GetTxtTextBoxes(const std::vector<skt::TextBox> & skiaBoxes)52 std::vector<TextBox> GetTxtTextBoxes(const std::vector<skt::TextBox>& skiaBoxes)
53 {
54 std::vector<TextBox> boxes;
55 for (const skt::TextBox& box : skiaBoxes) {
56 boxes.emplace_back(box.rect, static_cast<TextDirection>(box.direction));
57 }
58 return boxes;
59 }
60 } // anonymous namespace
61
ParagraphImpl(std::unique_ptr<skt::Paragraph> paragraph,std::vector<PaintRecord> && paints)62 ParagraphImpl::ParagraphImpl(std::unique_ptr<skt::Paragraph> paragraph, std::vector<PaintRecord>&& paints)
63 : paragraph_(std::move(paragraph)), paints_(std::move(paints))
64 {
65 threadId_ = pthread_self();
66 }
67
GetMaxWidth()68 double ParagraphImpl::GetMaxWidth()
69 {
70 RecordDifferentPthreadCall(__FUNCTION__);
71 return paragraph_->getMaxWidth();
72 }
73
GetHeight()74 double ParagraphImpl::GetHeight()
75 {
76 RecordDifferentPthreadCall(__FUNCTION__);
77 return paragraph_->lineNumber() == 0 ? 0 : paragraph_->getHeight();
78 }
79
GetLongestLine()80 double ParagraphImpl::GetLongestLine()
81 {
82 RecordDifferentPthreadCall(__FUNCTION__);
83 return paragraph_->getLongestLine();
84 }
85
GetLongestLineWithIndent()86 double ParagraphImpl::GetLongestLineWithIndent()
87 {
88 RecordDifferentPthreadCall(__FUNCTION__);
89 return paragraph_->getLongestLineWithIndent();
90 }
91
GetMinIntrinsicWidth()92 double ParagraphImpl::GetMinIntrinsicWidth()
93 {
94 RecordDifferentPthreadCall(__FUNCTION__);
95 return paragraph_->getMinIntrinsicWidth();
96 }
97
GetMaxIntrinsicWidth()98 double ParagraphImpl::GetMaxIntrinsicWidth()
99 {
100 RecordDifferentPthreadCall(__FUNCTION__);
101 return paragraph_->getMaxIntrinsicWidth();
102 }
103
GetAlphabeticBaseline()104 double ParagraphImpl::GetAlphabeticBaseline()
105 {
106 RecordDifferentPthreadCall(__FUNCTION__);
107 return paragraph_->getAlphabeticBaseline();
108 }
109
GetIdeographicBaseline()110 double ParagraphImpl::GetIdeographicBaseline()
111 {
112 RecordDifferentPthreadCall(__FUNCTION__);
113 return paragraph_->getIdeographicBaseline();
114 }
115
DidExceedMaxLines()116 bool ParagraphImpl::DidExceedMaxLines()
117 {
118 RecordDifferentPthreadCall(__FUNCTION__);
119 return paragraph_->didExceedMaxLines();
120 }
121
GetLineCount() const122 size_t ParagraphImpl::GetLineCount() const
123 {
124 RecordDifferentPthreadCall(__FUNCTION__);
125 if (paragraph_ == nullptr || paragraph_->GetMaxLines() == 0) {
126 return 0;
127 }
128 return paragraph_->lineNumber();
129 }
130
MarkDirty()131 void ParagraphImpl::MarkDirty()
132 {
133 RecordDifferentPthreadCall(__FUNCTION__);
134 if (paragraph_ == nullptr) {
135 return;
136 }
137 paragraph_->markDirty();
138 }
139
GetUnresolvedGlyphsCount()140 int32_t ParagraphImpl::GetUnresolvedGlyphsCount()
141 {
142 RecordDifferentPthreadCall(__FUNCTION__);
143 if (paragraph_ == nullptr) {
144 return 0;
145 }
146 return paragraph_->unresolvedGlyphs();
147 }
148
UpdateFontSize(size_t from,size_t to,float fontSize)149 void ParagraphImpl::UpdateFontSize(size_t from, size_t to, float fontSize)
150 {
151 RecordDifferentPthreadCall(__FUNCTION__);
152 if (paragraph_ == nullptr) {
153 return;
154 }
155 paragraph_->updateFontSize(from, to, fontSize);
156 }
157
SetIndents(const std::vector<float> & indents)158 void ParagraphImpl::SetIndents(const std::vector<float>& indents)
159 {
160 RecordDifferentPthreadCall(__FUNCTION__);
161 paragraph_->setIndents(indents);
162 }
163
DetectIndents(size_t index)164 float ParagraphImpl::DetectIndents(size_t index)
165 {
166 RecordDifferentPthreadCall(__FUNCTION__);
167 return paragraph_->detectIndents(index);
168 }
169
Layout(double width)170 void ParagraphImpl::Layout(double width)
171 {
172 TEXT_TRACE_FUNC();
173 RecordDifferentPthreadCall(__FUNCTION__);
174 lineMetrics_.reset();
175 lineMetricsStyles_.clear();
176 paragraph_->layout(width);
177 }
178
GetGlyphsBoundsTop()179 double ParagraphImpl::GetGlyphsBoundsTop()
180 {
181 RecordDifferentPthreadCall(__FUNCTION__);
182 return paragraph_->getGlyphsBoundsTop();
183 }
184
GetGlyphsBoundsBottom()185 double ParagraphImpl::GetGlyphsBoundsBottom()
186 {
187 RecordDifferentPthreadCall(__FUNCTION__);
188 return paragraph_->getGlyphsBoundsBottom();
189 }
190
GetGlyphsBoundsLeft()191 double ParagraphImpl::GetGlyphsBoundsLeft()
192 {
193 RecordDifferentPthreadCall(__FUNCTION__);
194 return paragraph_->getGlyphsBoundsLeft();
195 }
196
GetGlyphsBoundsRight()197 double ParagraphImpl::GetGlyphsBoundsRight()
198 {
199 RecordDifferentPthreadCall(__FUNCTION__);
200 return paragraph_->getGlyphsBoundsRight();
201 }
202
MeasureText()203 OHOS::Rosen::Drawing::FontMetrics ParagraphImpl::MeasureText()
204 {
205 RecordDifferentPthreadCall(__FUNCTION__);
206 return paragraph_->measureText();
207 }
208
Paint(SkCanvas * canvas,double x,double y)209 void ParagraphImpl::Paint(SkCanvas* canvas, double x, double y)
210 {
211 RecordDifferentPthreadCall(__FUNCTION__);
212 paragraph_->paint(canvas, x, y);
213 }
214
Paint(Drawing::Canvas * canvas,double x,double y)215 void ParagraphImpl::Paint(Drawing::Canvas* canvas, double x, double y)
216 {
217 RecordDifferentPthreadCall(__FUNCTION__);
218 RSCanvasParagraphPainter painter(canvas, paints_);
219 painter.SetAnimation(animationFunc_);
220 painter.SetParagraphId(id_);
221 paragraph_->paint(&painter, x, y);
222 }
223
Paint(Drawing::Canvas * canvas,Drawing::Path * path,double hOffset,double vOffset)224 void ParagraphImpl::Paint(Drawing::Canvas* canvas, Drawing::Path* path, double hOffset, double vOffset)
225 {
226 RecordDifferentPthreadCall(__FUNCTION__);
227 RSCanvasParagraphPainter painter(canvas, paints_);
228 painter.SetAnimation(animationFunc_);
229 painter.SetParagraphId(id_);
230 paragraph_->paint(&painter, path, hOffset, vOffset);
231 }
232
GetRectsForRange(size_t start,size_t end,RectHeightStyle rectHeightStyle,RectWidthStyle rectWidthStyle)233 std::vector<TextBox> ParagraphImpl::GetRectsForRange(size_t start, size_t end,
234 RectHeightStyle rectHeightStyle, RectWidthStyle rectWidthStyle)
235 {
236 RecordDifferentPthreadCall(__FUNCTION__);
237 std::vector<skt::TextBox> boxes =
238 paragraph_->getRectsForRange(start, end, static_cast<skt::RectHeightStyle>(rectHeightStyle),
239 static_cast<skt::RectWidthStyle>(rectWidthStyle));
240 return GetTxtTextBoxes(boxes);
241 }
242
GetRectsForPlaceholders()243 std::vector<TextBox> ParagraphImpl::GetRectsForPlaceholders()
244 {
245 RecordDifferentPthreadCall(__FUNCTION__);
246 return GetTxtTextBoxes(paragraph_->getRectsForPlaceholders());
247 }
248
GetGlyphPositionAtCoordinate(double dx,double dy)249 PositionWithAffinity ParagraphImpl::GetGlyphPositionAtCoordinate(double dx, double dy)
250 {
251 RecordDifferentPthreadCall(__FUNCTION__);
252 skt::PositionWithAffinity pos = paragraph_->getGlyphPositionAtCoordinate(dx, dy);
253 return PositionWithAffinity(pos.position, static_cast<Affinity>(pos.affinity));
254 }
255
GetWordBoundary(size_t offset)256 Range<size_t> ParagraphImpl::GetWordBoundary(size_t offset)
257 {
258 RecordDifferentPthreadCall(__FUNCTION__);
259 skt::SkRange<size_t> range = paragraph_->getWordBoundary(offset);
260 return Range<size_t>(range.start, range.end);
261 }
262
GetActualTextRange(int lineNumber,bool includeSpaces)263 Range<size_t> ParagraphImpl::GetActualTextRange(int lineNumber, bool includeSpaces)
264 {
265 RecordDifferentPthreadCall(__FUNCTION__);
266 if (lineNumber >=0 && lineNumber <= static_cast<int>(paragraph_->lineNumber())) {
267 skt::SkRange<size_t> range = paragraph_->getActualTextRange(lineNumber, includeSpaces);
268 return Range<size_t>(range.start, range.end);
269 } else {
270 return Range<size_t>(0, 0);
271 }
272 }
273
GetLineMetrics()274 std::vector<skia::textlayout::LineMetrics> ParagraphImpl::GetLineMetrics()
275 {
276 RecordDifferentPthreadCall(__FUNCTION__);
277 std::vector<skt::LineMetrics> metrics;
278 if (!lineMetrics_) {
279 paragraph_->getLineMetrics(metrics);
280 }
281 return metrics;
282 }
283
GetLineMetricsAt(int lineNumber,skt::LineMetrics * lineMetrics) const284 bool ParagraphImpl::GetLineMetricsAt(int lineNumber, skt::LineMetrics* lineMetrics) const
285 {
286 RecordDifferentPthreadCall(__FUNCTION__);
287 return paragraph_->getLineMetricsAt(lineNumber, lineMetrics);
288 }
289
SkStyleToTextStyle(const skt::TextStyle & skStyle)290 TextStyle ParagraphImpl::SkStyleToTextStyle(const skt::TextStyle& skStyle)
291 {
292 RecordDifferentPthreadCall(__FUNCTION__);
293
294 TextStyle txt;
295 txt.color = skStyle.getColor();
296 txt.decoration = static_cast<TextDecoration>(skStyle.getDecorationType());
297 txt.decorationColor = skStyle.getDecorationColor();
298 txt.decorationStyle = static_cast<TextDecorationStyle>(skStyle.getDecorationStyle());
299 txt.decorationThicknessMultiplier = SkScalarToDouble(skStyle.getDecorationThicknessMultiplier());
300 txt.fontWeight = GetTxtFontWeight(skStyle.getFontStyle().GetWeight());
301 txt.fontStyle = GetTxtFontStyle(skStyle.getFontStyle().GetSlant());
302
303 txt.baseline = static_cast<TextBaseline>(skStyle.getTextBaseline());
304
305 for (const SkString& fontFamily : skStyle.getFontFamilies()) {
306 txt.fontFamilies.emplace_back(fontFamily.c_str());
307 }
308
309 txt.fontSize = SkScalarToDouble(skStyle.getFontSize());
310 txt.letterSpacing = SkScalarToDouble(skStyle.getLetterSpacing());
311 txt.wordSpacing = SkScalarToDouble(skStyle.getWordSpacing());
312 txt.height = SkScalarToDouble(skStyle.getHeight());
313
314 txt.locale = skStyle.getLocale().c_str();
315 if (skStyle.hasBackground()) {
316 PaintID backgroundId = std::get<PaintID>(skStyle.getBackgroundPaintOrID());
317 if ((0 <= backgroundId) && (backgroundId < static_cast<int>(paints_.size()))) {
318 txt.background = paints_[backgroundId];
319 } else {
320 TEXT_LOGW("Invalid background Id:%{public}d", backgroundId);
321 }
322 }
323 if (skStyle.hasForeground()) {
324 PaintID foregroundId = std::get<PaintID>(skStyle.getForegroundPaintOrID());
325 if ((0 <= foregroundId) && (foregroundId < static_cast<int>(paints_.size()))) {
326 txt.foreground = paints_[foregroundId];
327 } else {
328 TEXT_LOGW("Invalid foreground Id:%{public}d", foregroundId);
329 }
330 }
331
332 txt.textShadows.clear();
333 for (const skt::TextShadow& skShadow : skStyle.getShadows()) {
334 TextShadow shadow;
335 shadow.offset = skShadow.fOffset;
336 shadow.blurSigma = skShadow.fBlurSigma;
337 shadow.color = skShadow.fColor;
338 txt.textShadows.emplace_back(shadow);
339 }
340
341 return txt;
342 }
343
GetFontMetricsResult(const SPText::TextStyle & textStyle)344 Drawing::FontMetrics ParagraphImpl::GetFontMetricsResult(const SPText::TextStyle& textStyle)
345 {
346 RecordDifferentPthreadCall(__FUNCTION__);
347
348 auto skTextStyle = ParagraphBuilderImpl::ConvertTextStyleToSkStyle(textStyle);
349 OHOS::Rosen::Drawing::FontMetrics fontMetrics;
350 skTextStyle.getFontMetrics(&fontMetrics);
351 return fontMetrics;
352 }
353
GetLineFontMetrics(const size_t lineNumber,size_t & charNumber,std::vector<Drawing::FontMetrics> & fontMetrics)354 bool ParagraphImpl::GetLineFontMetrics(const size_t lineNumber, size_t& charNumber,
355 std::vector<Drawing::FontMetrics>& fontMetrics)
356 {
357 if (!paragraph_) {
358 return false;
359 }
360 return paragraph_->GetLineFontMetrics(lineNumber, charNumber, fontMetrics);
361 }
362
GetTextLines() const363 std::vector<std::unique_ptr<SPText::TextLineBase>> ParagraphImpl::GetTextLines() const
364 {
365 RecordDifferentPthreadCall(__FUNCTION__);
366 if (!paragraph_) {
367 return {};
368 }
369 std::vector<std::unique_ptr<skt::TextLineBase>> textLineBases = paragraph_->GetTextLines();
370 std::vector<std::unique_ptr<SPText::TextLineBase>> lines;
371 for (std::unique_ptr<skt::TextLineBase>& textLineBase : textLineBases) {
372 std::unique_ptr<SPText::TextLineImpl> textLinePtr =
373 std::make_unique<SPText::TextLineImpl>(std::move(textLineBase), paints_);
374 lines.emplace_back(std::move(textLinePtr));
375 }
376 return lines;
377 }
378
CloneSelf()379 std::unique_ptr<Paragraph> ParagraphImpl::CloneSelf()
380 {
381 RecordDifferentPthreadCall(__FUNCTION__);
382 if (!paragraph_) {
383 return nullptr;
384 }
385 std::vector<PaintRecord> paints = paints_;
386 std::unique_ptr<skt::Paragraph> sktParagraph = paragraph_->CloneSelf();
387 std::unique_ptr<ParagraphImpl> paragraph = std::make_unique<ParagraphImpl>(std::move(sktParagraph),
388 std::move(paints));
389 return paragraph;
390 }
391
UpdateColor(size_t from,size_t to,const RSColor & color)392 void ParagraphImpl::UpdateColor(size_t from, size_t to, const RSColor& color)
393 {
394 RecordDifferentPthreadCall(__FUNCTION__);
395 if (!paragraph_) {
396 return;
397 }
398 auto unresolvedPaintID = paragraph_->updateColor(from, to,
399 SkColorSetARGB(color.GetAlpha(), color.GetRed(), color.GetGreen(), color.GetBlue()));
400 for (auto paintID : unresolvedPaintID) {
401 paints_[paintID].SetColor(color);
402 }
403 }
404
RecordDifferentPthreadCall(const char * caller) const405 void ParagraphImpl::RecordDifferentPthreadCall(const char* caller) const
406 {
407 pthread_t currenetThreadId = pthread_self();
408 if (threadId_ != currenetThreadId) {
409 TEXT_LOGE_LIMIT3_HOUR("New pthread access paragraph builder, old %{public}lu, caller %{public}s",
410 threadId_, caller);
411 threadId_ = currenetThreadId;
412 }
413 }
414
GeneratePaintRegion(double x,double y)415 Drawing::RectI ParagraphImpl::GeneratePaintRegion(double x, double y)
416 {
417 RecordDifferentPthreadCall("GeneratePaintRegion");
418 if (!paragraph_) {
419 double left = std::floor(x);
420 double top = std::floor(y);
421 return Drawing::RectI(left, top, left, top);
422 }
423
424 SkIRect skIRect = paragraph_->generatePaintRegion(SkDoubleToScalar(x), SkDoubleToScalar(y));
425 return Drawing::RectI(skIRect.left(), skIRect.top(), skIRect.right(), skIRect.bottom());
426 }
427 } // namespace SPText
428 } // namespace Rosen
429 } // namespace OHOS
430