• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "convert.h"
22 #include "drawing_painter_impl.h"
23 #include "text_font_utils.h"
24 #include "include/core/SkMatrix.h"
25 #include "modules/skparagraph/include/Paragraph.h"
26 #include "modules/skparagraph/include/TextStyle.h"
27 #include "paragraph_builder_impl.h"
28 #include "skia_adapter/skia_convert_utils.h"
29 #include "symbol_engine/hm_symbol_run.h"
30 #include "text/font_metrics.h"
31 #include "text_line_impl.h"
32 #include "utils/text_log.h"
33 #include "utils/text_trace.h"
34 
35 namespace OHOS {
36 namespace Rosen {
37 namespace SPText {
38 using PaintID = skt::ParagraphPainter::PaintID;
39 
40 namespace {
GetTxtTextBoxes(const std::vector<skt::TextBox> & skiaBoxes)41 std::vector<TextBox> GetTxtTextBoxes(const std::vector<skt::TextBox>& skiaBoxes)
42 {
43     std::vector<TextBox> boxes;
44     for (const skt::TextBox& box : skiaBoxes) {
45         boxes.emplace_back(box.rect, static_cast<TextDirection>(box.direction));
46     }
47     return boxes;
48 }
49 } // anonymous namespace
50 
ParagraphImpl(std::unique_ptr<skt::Paragraph> paragraph,std::vector<PaintRecord> && paints)51 ParagraphImpl::ParagraphImpl(std::unique_ptr<skt::Paragraph> paragraph, std::vector<PaintRecord>&& paints)
52     : paragraph_(std::move(paragraph)), paints_(std::move(paints))
53 {
54     threadId_ = pthread_self();
55 }
56 
GetMaxWidth()57 double ParagraphImpl::GetMaxWidth()
58 {
59     RecordDifferentPthreadCall(__FUNCTION__);
60     return paragraph_->getMaxWidth();
61 }
62 
GetHeight()63 double ParagraphImpl::GetHeight()
64 {
65     RecordDifferentPthreadCall(__FUNCTION__);
66     return paragraph_->lineNumber() == 0 ? 0 : paragraph_->getHeight();
67 }
68 
GetLongestLine()69 double ParagraphImpl::GetLongestLine()
70 {
71     RecordDifferentPthreadCall(__FUNCTION__);
72     return paragraph_->getLongestLine();
73 }
74 
GetLongestLineWithIndent()75 double ParagraphImpl::GetLongestLineWithIndent()
76 {
77     RecordDifferentPthreadCall(__FUNCTION__);
78     return paragraph_->getLongestLineWithIndent();
79 }
80 
GetMinIntrinsicWidth()81 double ParagraphImpl::GetMinIntrinsicWidth()
82 {
83     RecordDifferentPthreadCall(__FUNCTION__);
84     return paragraph_->getMinIntrinsicWidth();
85 }
86 
GetMaxIntrinsicWidth()87 double ParagraphImpl::GetMaxIntrinsicWidth()
88 {
89     RecordDifferentPthreadCall(__FUNCTION__);
90     return paragraph_->getMaxIntrinsicWidth();
91 }
92 
GetAlphabeticBaseline()93 double ParagraphImpl::GetAlphabeticBaseline()
94 {
95     RecordDifferentPthreadCall(__FUNCTION__);
96     return paragraph_->getAlphabeticBaseline();
97 }
98 
GetIdeographicBaseline()99 double ParagraphImpl::GetIdeographicBaseline()
100 {
101     RecordDifferentPthreadCall(__FUNCTION__);
102     return paragraph_->getIdeographicBaseline();
103 }
104 
DidExceedMaxLines()105 bool ParagraphImpl::DidExceedMaxLines()
106 {
107     RecordDifferentPthreadCall(__FUNCTION__);
108     return paragraph_->didExceedMaxLines();
109 }
110 
GetLineCount() const111 size_t ParagraphImpl::GetLineCount() const
112 {
113     RecordDifferentPthreadCall(__FUNCTION__);
114     if (paragraph_ == nullptr || paragraph_->GetMaxLines() == 0) {
115         return 0;
116     }
117     return paragraph_->lineNumber();
118 }
119 
MarkDirty()120 void ParagraphImpl::MarkDirty()
121 {
122     RecordDifferentPthreadCall(__FUNCTION__);
123     if (paragraph_ == nullptr) {
124         return;
125     }
126     paragraph_->markDirty();
127 }
128 
GetUnresolvedGlyphsCount()129 int32_t ParagraphImpl::GetUnresolvedGlyphsCount()
130 {
131     RecordDifferentPthreadCall(__FUNCTION__);
132     if (paragraph_ == nullptr) {
133         return 0;
134     }
135     return paragraph_->unresolvedGlyphs();
136 }
137 
UpdateFontSize(size_t from,size_t to,float fontSize)138 void ParagraphImpl::UpdateFontSize(size_t from, size_t to, float fontSize)
139 {
140     RecordDifferentPthreadCall(__FUNCTION__);
141     if (paragraph_ == nullptr) {
142         return;
143     }
144     paragraph_->updateFontSize(from, to, fontSize);
145 }
146 
SetIndents(const std::vector<float> & indents)147 void ParagraphImpl::SetIndents(const std::vector<float>& indents)
148 {
149     RecordDifferentPthreadCall(__FUNCTION__);
150     paragraph_->setIndents(indents);
151 }
152 
DetectIndents(size_t index)153 float ParagraphImpl::DetectIndents(size_t index)
154 {
155     RecordDifferentPthreadCall(__FUNCTION__);
156     return paragraph_->detectIndents(index);
157 }
158 
InitSymbolRuns()159 void ParagraphImpl::InitSymbolRuns()
160 {
161     std::call_once(initSymbolRunsFlag_, [&paints_ = paints_, &hmSymbols_ = hmSymbols_,
162         &animationFunc_ = animationFunc_]() {
163         for (const PaintRecord& p : paints_) {
164             if (!p.isSymbolGlyph) {
165                 continue;
166             }
167 
168             std::shared_ptr<HMSymbolRun> hmSymbolRun = std::make_shared<HMSymbolRun>();
169             hmSymbolRun->SetAnimation(animationFunc_);
170             hmSymbolRun->SetSymbolUid(p.symbol.GetSymbolUid());
171             hmSymbolRun->SetSymbolTxt(p.symbol);
172             hmSymbols_.push_back(std::move(hmSymbolRun));
173         }
174     });
175 }
176 
Layout(double width)177 void ParagraphImpl::Layout(double width)
178 {
179     RecordDifferentPthreadCall(__FUNCTION__);
180     lineMetrics_.reset();
181     lineMetricsStyles_.clear();
182     InitSymbolRuns();
183     paragraph_->layout(width);
184 }
185 
GetGlyphsBoundsTop()186 double ParagraphImpl::GetGlyphsBoundsTop()
187 {
188     RecordDifferentPthreadCall(__FUNCTION__);
189     return paragraph_->getGlyphsBoundsTop();
190 }
191 
GetGlyphsBoundsBottom()192 double ParagraphImpl::GetGlyphsBoundsBottom()
193 {
194     RecordDifferentPthreadCall(__FUNCTION__);
195     return paragraph_->getGlyphsBoundsBottom();
196 }
197 
GetGlyphsBoundsLeft()198 double ParagraphImpl::GetGlyphsBoundsLeft()
199 {
200     RecordDifferentPthreadCall(__FUNCTION__);
201     return paragraph_->getGlyphsBoundsLeft();
202 }
203 
GetGlyphsBoundsRight()204 double ParagraphImpl::GetGlyphsBoundsRight()
205 {
206     RecordDifferentPthreadCall(__FUNCTION__);
207     return paragraph_->getGlyphsBoundsRight();
208 }
209 
MeasureText()210 OHOS::Rosen::Drawing::FontMetrics ParagraphImpl::MeasureText()
211 {
212     RecordDifferentPthreadCall(__FUNCTION__);
213     return paragraph_->measureText();
214 }
215 
Paint(SkCanvas * canvas,double x,double y)216 void ParagraphImpl::Paint(SkCanvas* canvas, double x, double y)
217 {
218     RecordDifferentPthreadCall(__FUNCTION__);
219     paragraph_->paint(canvas, x, y);
220 }
221 
Paint(Drawing::Canvas * canvas,double x,double y)222 void ParagraphImpl::Paint(Drawing::Canvas* canvas, double x, double y)
223 {
224     RecordDifferentPthreadCall(__FUNCTION__);
225     RSCanvasParagraphPainter painter(canvas, paints_);
226     painter.SetAnimation(animationFunc_);
227     painter.SetHmSymbols(hmSymbols_);
228     paragraph_->paint(&painter, x, y);
229 }
230 
Paint(Drawing::Canvas * canvas,Drawing::Path * path,double hOffset,double vOffset)231 void ParagraphImpl::Paint(Drawing::Canvas* canvas, Drawing::Path* path, double hOffset, double vOffset)
232 {
233     RecordDifferentPthreadCall(__FUNCTION__);
234     RSCanvasParagraphPainter painter(canvas, paints_);
235     painter.SetAnimation(animationFunc_);
236     paragraph_->paint(&painter, path, hOffset, vOffset);
237 }
238 
GetRectsForRange(size_t start,size_t end,RectHeightStyle rectHeightStyle,RectWidthStyle rectWidthStyle)239 std::vector<TextBox> ParagraphImpl::GetRectsForRange(size_t start, size_t end,
240     RectHeightStyle rectHeightStyle, RectWidthStyle rectWidthStyle)
241 {
242     RecordDifferentPthreadCall(__FUNCTION__);
243     std::vector<skt::TextBox> boxes =
244         paragraph_->getRectsForRange(start, end, static_cast<skt::RectHeightStyle>(rectHeightStyle),
245             static_cast<skt::RectWidthStyle>(rectWidthStyle));
246     return GetTxtTextBoxes(boxes);
247 }
248 
GetRectsForPlaceholders()249 std::vector<TextBox> ParagraphImpl::GetRectsForPlaceholders()
250 {
251     RecordDifferentPthreadCall(__FUNCTION__);
252     return GetTxtTextBoxes(paragraph_->getRectsForPlaceholders());
253 }
254 
GetGlyphPositionAtCoordinate(double dx,double dy)255 PositionWithAffinity ParagraphImpl::GetGlyphPositionAtCoordinate(double dx, double dy)
256 {
257     RecordDifferentPthreadCall(__FUNCTION__);
258     skt::PositionWithAffinity pos = paragraph_->getGlyphPositionAtCoordinate(dx, dy);
259     return PositionWithAffinity(pos.position, static_cast<Affinity>(pos.affinity));
260 }
261 
GetWordBoundary(size_t offset)262 Range<size_t> ParagraphImpl::GetWordBoundary(size_t offset)
263 {
264     RecordDifferentPthreadCall(__FUNCTION__);
265     skt::SkRange<size_t> range = paragraph_->getWordBoundary(offset);
266     return Range<size_t>(range.start, range.end);
267 }
268 
GetActualTextRange(int lineNumber,bool includeSpaces)269 Range<size_t> ParagraphImpl::GetActualTextRange(int lineNumber, bool includeSpaces)
270 {
271     RecordDifferentPthreadCall(__FUNCTION__);
272     if (lineNumber >= 0 && lineNumber < static_cast<int>(paragraph_->lineNumber())) {
273         skt::SkRange<size_t> range = paragraph_->getActualTextRange(lineNumber, includeSpaces);
274         if (range == skia::textlayout::EMPTY_TEXT) {
275             TEXT_LOGE_LIMIT3_MIN("Invalid line number %{public}d", lineNumber);
276             return Range<size_t>(0, 0);
277         } else {
278             return Range<size_t>(range.start, range.end);
279         }
280     } else {
281         TEXT_LOGE_LIMIT3_MIN("Invalid line number %{public}d", lineNumber);
282         return Range<size_t>(0, 0);
283     }
284 }
285 
GetEllipsisTextRange()286 Range<size_t> ParagraphImpl::GetEllipsisTextRange()
287 {
288     RecordDifferentPthreadCall(__FUNCTION__);
289     skt::SkRange<size_t> range = paragraph_->getEllipsisTextRange();
290     return Range<size_t>(range.start, range.end);
291 }
292 
GetLineMetrics()293 std::vector<skt::LineMetrics> ParagraphImpl::GetLineMetrics()
294 {
295     RecordDifferentPthreadCall(__FUNCTION__);
296     std::vector<skt::LineMetrics> metrics;
297     if (!lineMetrics_) {
298         paragraph_->getLineMetrics(metrics);
299     }
300     return metrics;
301 }
302 
GetLineMetricsAt(int lineNumber,skt::LineMetrics * lineMetrics) const303 bool ParagraphImpl::GetLineMetricsAt(int lineNumber, skt::LineMetrics* lineMetrics) const
304 {
305     RecordDifferentPthreadCall(__FUNCTION__);
306     return paragraph_->getLineMetricsAt(lineNumber, lineMetrics);
307 }
308 
GetExtraTextStyleAttributes(const skia::textlayout::TextStyle & skStyle,TextStyle & textstyle)309 void ParagraphImpl::GetExtraTextStyleAttributes(const skia::textlayout::TextStyle& skStyle, TextStyle& textstyle)
310 {
311     for (const auto& [tag, value] : skStyle.getFontFeatures()) {
312         textstyle.fontFeatures.SetFeature(tag.c_str(), value);
313     }
314     textstyle.textShadows.clear();
315     for (const skt::TextShadow& skShadow : skStyle.getShadows()) {
316         TextShadow shadow;
317         shadow.offset = skShadow.fOffset;
318         shadow.blurSigma = skShadow.fBlurSigma;
319         shadow.color = skShadow.fColor;
320         textstyle.textShadows.emplace_back(shadow);
321     }
322 }
323 
SkStyleToTextStyle(const skt::TextStyle & skStyle)324 TextStyle ParagraphImpl::SkStyleToTextStyle(const skt::TextStyle& skStyle)
325 {
326     RecordDifferentPthreadCall(__FUNCTION__);
327 
328     TextStyle txt;
329     txt.color = skStyle.getColor();
330     txt.decoration = static_cast<TextDecoration>(skStyle.getDecorationType());
331     txt.decorationColor = skStyle.getDecorationColor();
332     txt.decorationStyle = static_cast<TextDecorationStyle>(skStyle.getDecorationStyle());
333     txt.decorationThicknessMultiplier = SkScalarToDouble(skStyle.getDecorationThicknessMultiplier());
334     txt.fontWeight = TextFontUtils::GetTxtFontWeight(skStyle.getFontStyle().GetWeight());
335     txt.fontStyle = TextFontUtils::GetTxtFontStyle(skStyle.getFontStyle().GetSlant());
336 
337     txt.baseline = static_cast<TextBaseline>(skStyle.getTextBaseline());
338 
339     for (const SkString& fontFamily : skStyle.getFontFamilies()) {
340         txt.fontFamilies.emplace_back(fontFamily.c_str());
341     }
342 
343     txt.fontSize = SkScalarToDouble(skStyle.getFontSize());
344     txt.fontWidth = static_cast<FontWidth>(skStyle.getFontStyle().GetWidth());
345     txt.styleId = skStyle.getStyleId();
346     txt.letterSpacing = SkScalarToDouble(skStyle.getLetterSpacing());
347     txt.wordSpacing = SkScalarToDouble(skStyle.getWordSpacing());
348     txt.height = SkScalarToDouble(skStyle.getHeight());
349     txt.heightOverride = skStyle.getHeightOverride();
350     txt.halfLeading = skStyle.getHalfLeading();
351     txt.baseLineShift = SkScalarToDouble(skStyle.getBaselineShift());
352     txt.locale = skStyle.getLocale().c_str();
353     txt.backgroundRect = { skStyle.getBackgroundRect().color, skStyle.getBackgroundRect().leftTopRadius,
354         skStyle.getBackgroundRect().rightTopRadius, skStyle.getBackgroundRect().rightBottomRadius,
355         skStyle.getBackgroundRect().leftBottomRadius };
356     if (skStyle.hasBackground()) {
357         PaintID backgroundId = std::get<PaintID>(skStyle.getBackgroundPaintOrID());
358         if ((0 <= backgroundId) && (backgroundId < static_cast<int>(paints_.size()))) {
359             txt.background = paints_[backgroundId];
360         } else {
361             TEXT_LOGW("Invalid background id %{public}d", backgroundId);
362         }
363     }
364     if (skStyle.hasForeground()) {
365         PaintID foregroundId = std::get<PaintID>(skStyle.getForegroundPaintOrID());
366         if ((0 <= foregroundId) && (foregroundId < static_cast<int>(paints_.size()))) {
367             txt.foreground = paints_[foregroundId];
368         } else {
369             TEXT_LOGW("Invalid foreground id %{public}d", foregroundId);
370         }
371     }
372     GetExtraTextStyleAttributes(skStyle, txt);
373     return txt;
374 }
375 
GetFontMetricsResult(const SPText::TextStyle & textStyle)376 Drawing::FontMetrics ParagraphImpl::GetFontMetricsResult(const SPText::TextStyle& textStyle)
377 {
378     RecordDifferentPthreadCall(__FUNCTION__);
379 
380     auto skTextStyle = ParagraphBuilderImpl::ConvertTextStyleToSkStyle(textStyle);
381     OHOS::Rosen::Drawing::FontMetrics fontMetrics;
382     skTextStyle.getFontMetrics(&fontMetrics);
383     return fontMetrics;
384 }
385 
GetLineFontMetrics(const size_t lineNumber,size_t & charNumber,std::vector<Drawing::FontMetrics> & fontMetrics)386 bool ParagraphImpl::GetLineFontMetrics(const size_t lineNumber, size_t& charNumber,
387     std::vector<Drawing::FontMetrics>& fontMetrics)
388 {
389     if (!paragraph_) {
390         return false;
391     }
392     return paragraph_->GetLineFontMetrics(lineNumber, charNumber, fontMetrics);
393 }
394 
GetTextLines() const395 std::vector<std::unique_ptr<SPText::TextLineBase>> ParagraphImpl::GetTextLines() const
396 {
397     RecordDifferentPthreadCall(__FUNCTION__);
398     if (!paragraph_) {
399         return {};
400     }
401     std::vector<std::unique_ptr<skt::TextLineBase>> textLineBases = paragraph_->GetTextLines();
402     std::vector<std::unique_ptr<SPText::TextLineBase>> lines;
403     for (std::unique_ptr<skt::TextLineBase>& textLineBase : textLineBases) {
404         std::unique_ptr<SPText::TextLineImpl> textLinePtr =
405             std::make_unique<SPText::TextLineImpl>(std::move(textLineBase), paints_);
406         lines.emplace_back(std::move(textLinePtr));
407     }
408     return lines;
409 }
410 
CloneSelf()411 std::unique_ptr<Paragraph> ParagraphImpl::CloneSelf()
412 {
413     RecordDifferentPthreadCall(__FUNCTION__);
414     if (!paragraph_) {
415         return nullptr;
416     }
417     std::vector<PaintRecord> paints = paints_;
418     std::unique_ptr<skt::Paragraph> sktParagraph = paragraph_->CloneSelf();
419     std::unique_ptr<ParagraphImpl> paragraph = std::make_unique<ParagraphImpl>(std::move(sktParagraph),
420         std::move(paints));
421     return paragraph;
422 }
423 
UpdateColor(size_t from,size_t to,const RSColor & color,skia::textlayout::UtfEncodeType encodeType)424 void ParagraphImpl::UpdateColor(size_t from, size_t to, const RSColor& color,
425     skia::textlayout::UtfEncodeType encodeType)
426 {
427     RecordDifferentPthreadCall(__FUNCTION__);
428     if (!paragraph_) {
429         return;
430     }
431     auto unresolvedPaintID = paragraph_->updateColor(from, to,
432         SkColorSetARGB(color.GetAlpha(), color.GetRed(), color.GetGreen(), color.GetBlue()), encodeType);
433     for (auto paintID : unresolvedPaintID) {
434         paints_[paintID].SetColor(color);
435     }
436 }
437 
UpdatePaintsBySkiaBlock(skt::Block & skiaBlock,const std::optional<RSBrush> & brush)438 void ParagraphImpl::UpdatePaintsBySkiaBlock(skt::Block& skiaBlock, const std::optional<RSBrush>& brush)
439 {
440     PaintID foregroundId = std::get<PaintID>(skiaBlock.fStyle.getForegroundPaintOrID());
441     if ((foregroundId < 0) || (foregroundId >= static_cast<int>(paints_.size()))) {
442         return;
443     }
444     if (paints_[foregroundId].isSymbolGlyph) {
445         return;
446     }
447     paints_[foregroundId].brush = brush;
448 }
449 #ifdef USE_M133_SKIA
UpdateForegroundBrushWithValidData(skia_private::TArray<skt::Block,true> & skiaTextStyles,const std::optional<RSBrush> & brush)450 void ParagraphImpl::UpdateForegroundBrushWithValidData(skia_private::TArray<skt::Block, true>& skiaTextStyles,
451     const std::optional<RSBrush>& brush)
452 #else
453 void ParagraphImpl::UpdateForegroundBrushWithValidData(SkTArray<skt::Block, true>& skiaTextStyles,
454     const std::optional<RSBrush>& brush)
455 #endif
456 {
457     TEXT_TRACE_FUNC();
458     PaintID newId = static_cast<int>(paints_.size());
459     bool needAddNewBrush = true;
460 
461     for (size_t i = 0; i < skiaTextStyles.size(); i++) {
462         skt::Block& skiaBlock = skiaTextStyles[i];
463         if (skiaBlock.fStyle.hasForeground()) {
464             UpdatePaintsBySkiaBlock(skiaBlock, brush);
465         } else {
466             skiaBlock.fStyle.setForegroundPaintID(newId);
467             if (needAddNewBrush) {
468                 PaintRecord pr(brush, std::nullopt);
469                 paints_.push_back(pr);
470                 needAddNewBrush = false;
471             }
472         }
473     }
474 }
475 #ifdef USE_M133_SKIA
UpdateForegroundBrushWithNullopt(skia_private::TArray<skt::Block,true> & skiaTextStyles)476 void ParagraphImpl::UpdateForegroundBrushWithNullopt(skia_private::TArray<skt::Block, true>& skiaTextStyles)
477 #else
478 void ParagraphImpl::UpdateForegroundBrushWithNullopt(SkTArray<skt::Block, true>& skiaTextStyles)
479 #endif
480 {
481     TEXT_TRACE_FUNC();
482     for (size_t i = 0; i < skiaTextStyles.size(); i++) {
483         skt::Block& skiaBlock = skiaTextStyles[i];
484         if (!skiaBlock.fStyle.hasForeground()) {
485             continue;
486         }
487         UpdatePaintsBySkiaBlock(skiaBlock, std::nullopt);
488     }
489 }
490 
UpdateForegroundBrush(const TextStyle & spTextStyle)491 void ParagraphImpl::UpdateForegroundBrush(const TextStyle& spTextStyle)
492 {
493     RecordDifferentPthreadCall(__FUNCTION__);
494     if (paragraph_ == nullptr) {
495         return;
496     }
497 
498 #ifdef USE_M133_SKIA
499     skia_private::TArray<skt::Block, true>& skiaTextStyles = paragraph_->exportTextStyles();
500 #else
501     SkTArray<skt::Block, true>& skiaTextStyles = paragraph_->exportTextStyles();
502 #endif
503 
504     if (spTextStyle.foreground.has_value() && spTextStyle.foreground.value().brush.has_value()) {
505         UpdateForegroundBrushWithValidData(skiaTextStyles, spTextStyle.foreground.value().brush);
506     } else {
507         UpdateForegroundBrushWithNullopt(skiaTextStyles);
508     }
509 }
510 
GetTextBlobRecordInfo() const511 std::vector<TextBlobRecordInfo> ParagraphImpl::GetTextBlobRecordInfo() const
512 {
513     RecordDifferentPthreadCall(__FUNCTION__);
514     if (paragraph_ == nullptr) {
515         return {};
516     }
517     std::vector<TextBlobRecordInfo> textBlobRecordInfos;
518     std::vector<skt::TextBlobRecordInfo> infos = paragraph_->getTextBlobRecordInfo();
519     for (auto& info : infos) {
520         TextBlobRecordInfo recordInfo;
521         recordInfo.blob = info.fBlob;
522         recordInfo.offset = info.fOffset;
523         int index = std::get<int>(info.fPaint);
524         if (index >= 0 && index < static_cast<int>(paints_.size())) {
525             recordInfo.color = paints_[index].color;
526         }
527         textBlobRecordInfos.emplace_back(recordInfo);
528     }
529     return textBlobRecordInfos;
530 }
531 
HasSkipTextBlobDrawing() const532 bool ParagraphImpl::HasSkipTextBlobDrawing() const
533 {
534     RecordDifferentPthreadCall(__FUNCTION__);
535     if (paragraph_ == nullptr) {
536         return false;
537     }
538     return paragraph_->hasSkipTextBlobDrawing();
539 }
540 
SetSkipTextBlobDrawing(bool state)541 void ParagraphImpl::SetSkipTextBlobDrawing(bool state)
542 {
543     RecordDifferentPthreadCall(__FUNCTION__);
544     if (paragraph_ == nullptr) {
545         return;
546     }
547     paragraph_->setSkipTextBlobDrawing(state);
548 }
549 
CanPaintAllText() const550 bool ParagraphImpl::CanPaintAllText() const
551 {
552     RecordDifferentPthreadCall(__FUNCTION__);
553     if (paragraph_ == nullptr) {
554         return false;
555     }
556     return paragraph_->canPaintAllText();
557 }
558 
RecordDifferentPthreadCall(const char * caller) const559 void ParagraphImpl::RecordDifferentPthreadCall(const char* caller) const
560 {
561     pthread_t currenetThreadId = pthread_self();
562     if (threadId_ != currenetThreadId) {
563         TEXT_LOGE_LIMIT3_HOUR("New pthread access paragraph builder, old %{public}lu, caller %{public}s",
564             threadId_, caller);
565         threadId_ = currenetThreadId;
566     }
567 }
568 
GeneratePaintRegion(double x,double y)569 Drawing::RectI ParagraphImpl::GeneratePaintRegion(double x, double y)
570 {
571     RecordDifferentPthreadCall("GeneratePaintRegion");
572     if (!paragraph_) {
573         double left = std::floor(x);
574         double top = std::floor(y);
575         return Drawing::RectI(left, top, left, top);
576     }
577 
578     SkIRect skIRect = paragraph_->generatePaintRegion(SkDoubleToScalar(x), SkDoubleToScalar(y));
579     return Drawing::RectI(skIRect.left(), skIRect.top(), skIRect.right(), skIRect.bottom());
580 }
581 
IsLayoutDone()582 bool ParagraphImpl::IsLayoutDone()
583 {
584     RecordDifferentPthreadCall(__FUNCTION__);
585     return paragraph_->getState() >= skt::kFormatted ? true : false;
586 }
587 
SetLayoutState(size_t state)588 void ParagraphImpl::SetLayoutState(size_t state)
589 {
590     RecordDifferentPthreadCall(__FUNCTION__);
591     paragraph_->setState(static_cast<skt::InternalState>(state));
592 }
593 
GetDumpInfo() const594 std::string ParagraphImpl::GetDumpInfo() const
595 {
596     return paragraph_->GetDumpInfo();
597 }
598 } // namespace SPText
599 } // namespace Rosen
600 } // namespace OHOS
601