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