1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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 "typography.h"
17
18 #include <mutex>
19 #include <numeric>
20
21 #include "convert.h"
22 #include "impl/paragraph_impl.h"
23 #include "modules/skparagraph/include/TextStyle.h"
24 #include "skia_adapter/skia_canvas.h"
25 #include "skia_adapter/skia_convert_utils.h"
26 #include "text_line_base.h"
27 #include "text_style.h"
28 #include "txt/paragraph_style.h"
29 #include "txt/text_style.h"
30 #include "typography_style.h"
31 #include "utils/text_log.h"
32 #include "utils/text_trace.h"
33
34 namespace OHOS {
35 namespace Rosen {
36 namespace skt = skia::textlayout;
37
TextRect(Drawing::RectF rec,TextDirection dir)38 TextRect::TextRect(Drawing::RectF rec, TextDirection dir)
39 {
40 rect = rec;
41 direction = dir;
42 }
43
IndexAndAffinity(size_t charIndex,Affinity charAffinity)44 IndexAndAffinity::IndexAndAffinity(size_t charIndex, Affinity charAffinity)
45 {
46 index = charIndex;
47 affinity = charAffinity;
48 }
49
50 namespace AdapterTxt {
Typography(std::unique_ptr<SPText::Paragraph> paragraph)51 Typography::Typography(std::unique_ptr<SPText::Paragraph> paragraph): paragraph_(std::move(paragraph))
52 {
53 }
54
GetMaxWidth() const55 double Typography::GetMaxWidth() const
56 {
57 std::shared_lock<std::shared_mutex> readLock(mutex_);
58 return paragraph_->GetMaxWidth();
59 }
60
GetHeight() const61 double Typography::GetHeight() const
62 {
63 std::shared_lock<std::shared_mutex> readLock(mutex_);
64 return paragraph_->GetHeight();
65 }
66
GetActualWidth() const67 double Typography::GetActualWidth() const
68 {
69 std::shared_lock<std::shared_mutex> readLock(mutex_);
70 return paragraph_->GetLongestLine();
71 }
72
GetLongestLineWithIndent() const73 double Typography::GetLongestLineWithIndent() const
74 {
75 std::shared_lock<std::shared_mutex> readLock(mutex_);
76 return paragraph_->GetLongestLineWithIndent();
77 }
78
GetMinIntrinsicWidth()79 double Typography::GetMinIntrinsicWidth()
80 {
81 std::shared_lock<std::shared_mutex> readLock(mutex_);
82 return paragraph_->GetMinIntrinsicWidth();
83 }
84
GetMaxIntrinsicWidth()85 double Typography::GetMaxIntrinsicWidth()
86 {
87 std::shared_lock<std::shared_mutex> readLock(mutex_);
88 return paragraph_->GetMaxIntrinsicWidth();
89 }
90
GetAlphabeticBaseline()91 double Typography::GetAlphabeticBaseline()
92 {
93 std::shared_lock<std::shared_mutex> readLock(mutex_);
94 return paragraph_->GetAlphabeticBaseline();
95 }
96
GetIdeographicBaseline()97 double Typography::GetIdeographicBaseline()
98 {
99 std::shared_lock<std::shared_mutex> readLock(mutex_);
100 return paragraph_->GetIdeographicBaseline();
101 }
102
DidExceedMaxLines() const103 bool Typography::DidExceedMaxLines() const
104 {
105 std::shared_lock<std::shared_mutex> readLock(mutex_);
106 return paragraph_->DidExceedMaxLines();
107 }
108
GetLineCount() const109 int Typography::GetLineCount() const
110 {
111 std::shared_lock<std::shared_mutex> readLock(mutex_);
112 return paragraph_->GetLineCount();
113 }
114
SetIndents(const std::vector<float> & indents)115 void Typography::SetIndents(const std::vector<float>& indents)
116 {
117 std::unique_lock<std::shared_mutex> writeLock(mutex_);
118 paragraph_->SetIndents(indents);
119 }
120
DetectIndents(size_t index)121 float Typography::DetectIndents(size_t index)
122 {
123 std::shared_lock<std::shared_mutex> readLock(mutex_);
124 return paragraph_->DetectIndents(index);
125 }
126
Relayout(double width,const TypographyStyle & typograhyStyle,const std::vector<TextStyle> & textStyles)127 void Typography::Relayout(double width, const TypographyStyle &typograhyStyle, const std::vector<TextStyle> &textStyles)
128 {
129 std::unique_lock<std::shared_mutex> writeLock(mutex_);
130
131 if (!paragraph_->IsLayoutDone()) {
132 TEXT_LOGI_LIMIT3_MIN("Need to layout first");
133 return;
134 }
135
136 bool isTextStyleChange = std::any_of(textStyles.begin(), textStyles.end(), [](const TextStyle& style) {
137 return style.relayoutChangeBitmap.any() || style.symbol.GetSymbolBitmap().any();
138 });
139 if (!typograhyStyle.relayoutChangeBitmap.any() && !isTextStyleChange) {
140 if (skt::nearlyEqual(paragraph_->GetMaxWidth(), width)) {
141 TEXT_LOGI_LIMIT3_MIN("No relayout required");
142 return;
143 }
144 paragraph_->SetLayoutState(skt::InternalState::kShaped);
145
146 paragraph_->Layout(width);
147 } else {
148 SPText::ParagraphStyle paragraphStyle = Convert(typograhyStyle);
149 std::vector<SPText::TextStyle> spTextStyles;
150 for (const TextStyle& style : textStyles) {
151 spTextStyles.push_back(Convert(style));
152 }
153
154 paragraph_->Relayout(width, paragraphStyle, spTextStyles);
155 }
156 lineMetrics_.reset();
157 lineMetricsStyles_.clear();
158 }
159
Layout(double width)160 void Typography::Layout(double width)
161 {
162 TEXT_TRACE_FUNC();
163 std::unique_lock<std::shared_mutex> writeLock(mutex_);
164 lineMetrics_.reset();
165 lineMetricsStyles_.clear();
166 return paragraph_->Layout(width);
167 }
168
GetGlyphsBoundsTop()169 double Typography::GetGlyphsBoundsTop()
170 {
171 std::shared_lock<std::shared_mutex> readLock(mutex_);
172 return paragraph_->GetGlyphsBoundsTop();
173 }
174
GetGlyphsBoundsBottom()175 double Typography::GetGlyphsBoundsBottom()
176 {
177 std::shared_lock<std::shared_mutex> readLock(mutex_);
178 return paragraph_->GetGlyphsBoundsBottom();
179 }
180
GetGlyphsBoundsLeft()181 double Typography::GetGlyphsBoundsLeft()
182 {
183 std::shared_lock<std::shared_mutex> readLock(mutex_);
184 return paragraph_->GetGlyphsBoundsLeft();
185 }
186
GetGlyphsBoundsRight()187 double Typography::GetGlyphsBoundsRight()
188 {
189 std::shared_lock<std::shared_mutex> readLock(mutex_);
190 return paragraph_->GetGlyphsBoundsRight();
191 }
192
MeasureText()193 Drawing::FontMetrics Typography::MeasureText()
194 {
195 std::unique_lock<std::shared_mutex> writeLock(mutex_);
196 return paragraph_->MeasureText();
197 }
198
MarkDirty()199 void Typography::MarkDirty()
200 {
201 std::unique_lock<std::shared_mutex> writeLock(mutex_);
202 if (paragraph_ == nullptr) {
203 return;
204 }
205 paragraph_->MarkDirty();
206 }
207
GetUnresolvedGlyphsCount()208 int32_t Typography::GetUnresolvedGlyphsCount()
209 {
210 std::shared_lock<std::shared_mutex> readLock(mutex_);
211 if (paragraph_ == nullptr) {
212 return 0;
213 }
214 return paragraph_->GetUnresolvedGlyphsCount();
215 }
216
UpdateFontSize(size_t from,size_t to,float fontSize)217 void Typography::UpdateFontSize(size_t from, size_t to, float fontSize)
218 {
219 std::unique_lock<std::shared_mutex> writeLock(mutex_);
220 if (paragraph_ == nullptr) {
221 return;
222 }
223 paragraph_->UpdateFontSize(from, to, fontSize);
224 }
225
Paint(SkCanvas * canvas,double x,double y)226 void Typography::Paint(SkCanvas *canvas, double x, double y)
227 {
228 std::unique_lock<std::shared_mutex> writeLock(mutex_);
229 return paragraph_->Paint(canvas, x, y);
230 }
231
Paint(Drawing::Canvas * drawCanvas,double x,double y)232 void Typography::Paint(Drawing::Canvas *drawCanvas, double x, double y)
233 {
234 std::unique_lock<std::shared_mutex> writeLock(mutex_);
235 paragraph_->Paint(drawCanvas, x, y);
236 }
237
Paint(Drawing::Canvas * drawCanvas,Drawing::Path * path,double hOffset,double vOffset)238 void Typography::Paint(Drawing::Canvas* drawCanvas, Drawing::Path* path, double hOffset, double vOffset)
239 {
240 std::unique_lock<std::shared_mutex> writeLock(mutex_);
241 paragraph_->Paint(drawCanvas, path, hOffset, vOffset);
242 }
243
GetTextRectsByBoundary(size_t left,size_t right,TextRectHeightStyle heightStyle,TextRectWidthStyle widthStyle)244 std::vector<TextRect> Typography::GetTextRectsByBoundary(size_t left, size_t right,
245 TextRectHeightStyle heightStyle, TextRectWidthStyle widthStyle)
246 {
247 std::shared_lock<std::shared_mutex> readLock(mutex_);
248 auto txtRectHeightStyle = Convert(heightStyle);
249 auto txtRectWidthStyle = Convert(widthStyle);
250 auto rects = paragraph_->GetRectsForRange(left, right, txtRectHeightStyle, txtRectWidthStyle);
251
252 std::vector<TextRect> boxes;
253 for (const auto &rect : rects) {
254 boxes.push_back(Convert(rect));
255 }
256 return boxes;
257 }
258
GetTextRectsOfPlaceholders()259 std::vector<TextRect> Typography::GetTextRectsOfPlaceholders()
260 {
261 std::shared_lock<std::shared_mutex> readLock(mutex_);
262 auto rects = paragraph_->GetRectsForPlaceholders();
263
264 std::vector<TextRect> boxes;
265 for (const auto &rect : rects) {
266 boxes.push_back(Convert(rect));
267 }
268 return boxes;
269 }
270
GetGlyphIndexByCoordinate(double x,double y)271 IndexAndAffinity Typography::GetGlyphIndexByCoordinate(double x, double y)
272 {
273 std::shared_lock<std::shared_mutex> readLock(mutex_);
274 auto pos = paragraph_->GetGlyphPositionAtCoordinate(x, y);
275 return Convert(pos);
276 }
277
GetWordBoundaryByIndex(size_t index)278 Boundary Typography::GetWordBoundaryByIndex(size_t index)
279 {
280 std::shared_lock<std::shared_mutex> readLock(mutex_);
281 auto range = paragraph_->GetWordBoundary(index);
282 return Convert(range);
283 }
284
GetActualTextRange(int lineNumber,bool includeSpaces)285 Boundary Typography::GetActualTextRange(int lineNumber, bool includeSpaces)
286 {
287 std::shared_lock<std::shared_mutex> readLock(mutex_);
288 auto range = paragraph_->GetActualTextRange(lineNumber, includeSpaces);
289 return Convert(range);
290 }
291
GetEllipsisTextRange()292 Boundary Typography::GetEllipsisTextRange()
293 {
294 std::shared_lock<std::shared_mutex> readLock(mutex_);
295 auto range = paragraph_->GetEllipsisTextRange();
296 return Convert(range);
297 }
298
GetLineHeight(int lineNumber)299 double Typography::GetLineHeight(int lineNumber)
300 {
301 std::shared_lock<std::shared_mutex> readLock(mutex_);
302 const auto &lines = paragraph_->GetLineMetrics();
303 if ((0 <= lineNumber) && (lineNumber < static_cast<int>(lines.size()))) {
304 return lines[lineNumber].fHeight;
305 }
306 return 0.0;
307 }
308
GetLineWidth(int lineNumber)309 double Typography::GetLineWidth(int lineNumber)
310 {
311 std::shared_lock<std::shared_mutex> readLock(mutex_);
312 const auto &lines = paragraph_->GetLineMetrics();
313 if ((0 <= lineNumber) && (lineNumber < static_cast<int>(lines.size()))) {
314 return lines[lineNumber].fWidth;
315 }
316 return 0.0;
317 }
318
SetAnimation(std::function<bool (const std::shared_ptr<OHOS::Rosen::TextEngine::SymbolAnimationConfig> &)> & animationFunc)319 void Typography::SetAnimation(
320 std::function<bool(const std::shared_ptr<OHOS::Rosen::TextEngine::SymbolAnimationConfig>&)>& animationFunc
321 )
322 {
323 std::unique_lock<std::shared_mutex> writeLock(mutex_);
324 if (animationFunc != nullptr && paragraph_ != nullptr) {
325 paragraph_->SetAnimation(animationFunc);
326 }
327 }
328
GetAnimation()329 std::function<bool(const std::shared_ptr<TextEngine::SymbolAnimationConfig>&)> Typography::GetAnimation()
330 {
331 std::shared_lock<std::shared_mutex> readLock(mutex_);
332 if (paragraph_ == nullptr) {
333 return nullptr;
334 }
335 return paragraph_->GetAnimation();
336 }
337
SetParagraghId(uint32_t id)338 void Typography::SetParagraghId(uint32_t id)
339 {
340 std::unique_lock<std::shared_mutex> writeLock(mutex_);
341 if (paragraph_ != nullptr) {
342 paragraph_->SetParagraghId(id);
343 }
344 }
345
GetLineInfo(int lineNumber,bool oneLine,bool includeWhitespace,LineMetrics * lineMetrics)346 bool Typography::GetLineInfo(int lineNumber, bool oneLine, bool includeWhitespace, LineMetrics* lineMetrics)
347 {
348 std::shared_lock<std::shared_mutex> readLock(mutex_);
349 if (paragraph_ == nullptr) {
350 return false;
351 }
352 if (lineNumber < 0 || lineNumber >= static_cast<int>(paragraph_->GetLineCount()) || lineMetrics == nullptr) {
353 return false;
354 }
355
356 skia::textlayout::LineMetrics sklineMetrics;
357 if (!paragraph_->GetLineMetricsAt(lineNumber, &sklineMetrics)) {
358 return false;
359 }
360
361 if (!sklineMetrics.fLineMetrics.empty()) {
362 const auto &skFontMetrics = sklineMetrics.fLineMetrics.begin()->second.font_metrics;
363 lineMetrics->firstCharMetrics = skFontMetrics;
364 if (oneLine) {
365 lineMetrics->ascender = sklineMetrics.fAscent;
366 lineMetrics->descender = sklineMetrics.fDescent;
367 } else {
368 lineMetrics->ascender = skFontMetrics.fAscent;
369 lineMetrics->descender = skFontMetrics.fDescent;
370 }
371 lineMetrics->capHeight = skFontMetrics.fCapHeight;
372 lineMetrics->xHeight = skFontMetrics.fXHeight;
373 } else {
374 if (oneLine) {
375 lineMetrics->ascender = sklineMetrics.fAscent;
376 lineMetrics->descender = sklineMetrics.fDescent;
377 } else {
378 lineMetrics->ascender = 0.0;
379 lineMetrics->descender = 0.0;
380 }
381 lineMetrics->capHeight = 0.0;
382 lineMetrics->xHeight = 0.0;
383 }
384 if (includeWhitespace) {
385 lineMetrics->width = sklineMetrics.fWidthWithSpaces;
386 } else {
387 lineMetrics->width = sklineMetrics.fWidth;
388 }
389 lineMetrics->height = sklineMetrics.fHeight;
390 lineMetrics->x = sklineMetrics.fLeft;
391 lineMetrics->y = sklineMetrics.fTopHeight;
392 lineMetrics->startIndex = sklineMetrics.fStartIndex;
393 lineMetrics->endIndex = sklineMetrics.fEndIndex;
394
395 return true;
396 }
397
GetLineMetrics()398 std::vector<LineMetrics> Typography::GetLineMetrics()
399 {
400 std::unique_lock<std::shared_mutex> writeLock(mutex_);
401 if (lineMetrics_) {
402 return lineMetrics_.value();
403 }
404 lineMetrics_.emplace();
405 if (paragraph_ != nullptr) {
406 auto metrics = paragraph_->GetLineMetrics();
407 lineMetricsStyles_.reserve(std::accumulate(metrics.begin(), metrics.end(), 0,
408 [](const int a, const skia::textlayout::LineMetrics& b) { return a + b.fLineMetrics.size(); }));
409
410 for (const skt::LineMetrics& skLineMetrics : metrics) {
411 LineMetrics& line = lineMetrics_->emplace_back();
412 if (!skLineMetrics.fLineMetrics.empty()) {
413 const auto &skmFontMetrics = skLineMetrics.fLineMetrics.begin()->second.font_metrics;
414 line.firstCharMetrics = skmFontMetrics;
415 line.capHeight = skmFontMetrics.fCapHeight;
416 line.xHeight = skmFontMetrics.fXHeight;
417 } else {
418 line.capHeight = 0.0;
419 line.xHeight = 0.0;
420 }
421 line.lineNumber = skLineMetrics.fLineNumber;
422 line.baseline = skLineMetrics.fBaseline;
423 line.ascender = skLineMetrics.fAscent;
424 line.descender = skLineMetrics.fDescent;
425 line.width = skLineMetrics.fWidth;
426 line.height = skLineMetrics.fHeight;
427 line.x = skLineMetrics.fLeft;
428 line.y = skLineMetrics.fTopHeight;
429 line.startIndex = skLineMetrics.fStartIndex;
430 line.endIndex = skLineMetrics.fEndIndex;
431 for (const auto& [index, styleMtrics] : skLineMetrics.fLineMetrics) {
432 SPText::TextStyle spTextStyle = paragraph_->SkStyleToTextStyle(*styleMtrics.text_style);
433 lineMetricsStyles_.emplace_back(Convert(spTextStyle));
434
435 line.runMetrics.emplace(std::piecewise_construct, std::forward_as_tuple(index),
436 std::forward_as_tuple(&lineMetricsStyles_.back(), styleMtrics.font_metrics));
437 }
438 }
439 }
440 return lineMetrics_.value();
441 }
442
GetLineMetricsAt(int lineNumber,LineMetrics * lineMetrics)443 bool Typography::GetLineMetricsAt(int lineNumber, LineMetrics* lineMetrics)
444 {
445 if (paragraph_ == nullptr) {
446 return false;
447 }
448 if (lineNumber < 0 || lineNumber >= static_cast<int>(paragraph_->GetLineCount()) || lineMetrics == nullptr) {
449 return false;
450 }
451 std::vector<LineMetrics> vecLineMetrics = GetLineMetrics();
452
453 if (vecLineMetrics.empty()) {
454 return false;
455 }
456
457 *lineMetrics = vecLineMetrics[lineNumber];
458
459 return true;
460 }
461
GetFontMetrics(const OHOS::Rosen::TextStyle & textStyle)462 Drawing::FontMetrics Typography::GetFontMetrics(const OHOS::Rosen::TextStyle& textStyle)
463 {
464 std::shared_lock<std::shared_mutex> readLock(mutex_);
465 auto spTextStyle = Convert(textStyle);
466 return paragraph_->GetFontMetricsResult(spTextStyle);
467 }
468
GetLineFontMetrics(const size_t lineNumber,size_t & charNumber,std::vector<Drawing::FontMetrics> & fontMetrics)469 bool Typography::GetLineFontMetrics(const size_t lineNumber,
470 size_t& charNumber, std::vector<Drawing::FontMetrics>& fontMetrics)
471 {
472 std::shared_lock<std::shared_mutex> readLock(mutex_);
473 if (!paragraph_) {
474 return false;
475 }
476 return paragraph_->GetLineFontMetrics(lineNumber, charNumber, fontMetrics);
477 }
478
GetTextLines() const479 std::vector<std::unique_ptr<TextLineBase>> Typography::GetTextLines() const
480 {
481 std::shared_lock<std::shared_mutex> readLock(mutex_);
482 if (!paragraph_) {
483 return {};
484 }
485 std::vector<std::unique_ptr<SPText::TextLineBase>> textLines = paragraph_->GetTextLines();
486 std::vector<std::unique_ptr<TextLineBase>> lines;
487
488 for (std::unique_ptr<SPText::TextLineBase>& textLine : textLines) {
489 std::unique_ptr<TextLineBaseImpl> linePtr = std::make_unique<TextLineBaseImpl>(std::move(textLine));
490 lines.emplace_back(std::move(linePtr));
491 }
492 return lines;
493 }
494
CloneSelf()495 std::unique_ptr<OHOS::Rosen::Typography> Typography::CloneSelf()
496 {
497 std::shared_lock<std::shared_mutex> readLock(mutex_);
498 if (!paragraph_) {
499 return nullptr;
500 }
501 return std::make_unique<Typography>(paragraph_->CloneSelf());
502 }
503
UpdateColor(size_t from,size_t to,const Drawing::Color & color)504 void Typography::UpdateColor(size_t from, size_t to, const Drawing::Color& color)
505 {
506 std::unique_lock<std::shared_mutex> writeLock(mutex_);
507 if (!paragraph_) {
508 return;
509 }
510 paragraph_->UpdateColor(from, to, color);
511 }
512
UpdateAllTextStyles(const TextStyle & textStyleTemplate)513 void Typography::UpdateAllTextStyles(const TextStyle& textStyleTemplate)
514 {
515 std::unique_lock<std::shared_mutex> writeLock(mutex_);
516 if (!paragraph_) {
517 return;
518 }
519 std::vector<SPText::TextStyle> spTextStyles;
520 spTextStyles.push_back(Convert(textStyleTemplate));
521 paragraph_->ApplyTextStyleChanges(spTextStyles);
522 }
523
GeneratePaintRegion(double x,double y) const524 Drawing::RectI Typography::GeneratePaintRegion(double x, double y) const
525 {
526 std::unique_lock<std::shared_mutex> writeLock(mutex_);
527 if (!paragraph_) {
528 double left = std::floor(x);
529 double top = std::floor(y);
530 return Drawing::RectI(left, top, left, top);
531 }
532
533 return paragraph_->GeneratePaintRegion(x, y);
534 }
535
GetTextBlobRecordInfo() const536 std::vector<TextBlobRecordInfo> Typography::GetTextBlobRecordInfo() const
537 {
538 std::shared_lock<std::shared_mutex> readLock(mutex_);
539 if (paragraph_ == nullptr) {
540 return {};
541 }
542 return paragraph_->GetTextBlobRecordInfo();
543 }
544
HasSkipTextBlobDrawing() const545 bool Typography::HasSkipTextBlobDrawing() const
546 {
547 std::shared_lock<std::shared_mutex> readLock(mutex_);
548 if (paragraph_ == nullptr) {
549 return false;
550 }
551 return paragraph_->HasSkipTextBlobDrawing();
552 }
553
SetSkipTextBlobDrawing(bool state)554 void Typography::SetSkipTextBlobDrawing(bool state)
555 {
556 std::unique_lock<std::shared_mutex> writeLock(mutex_);
557 if (paragraph_ == nullptr) {
558 return;
559 }
560 paragraph_->SetSkipTextBlobDrawing(state);
561 }
562
CanPaintAllText() const563 bool Typography::CanPaintAllText() const
564 {
565 std::shared_lock<std::shared_mutex> readLock(mutex_);
566 if (paragraph_ == nullptr) {
567 TEXT_LOGI_LIMIT3_MIN("Failed to get paragraph");
568 return false;
569 }
570 return paragraph_->CanPaintAllText();
571 }
572
GetDumpInfo() const573 std::string Typography::GetDumpInfo() const
574 {
575 std::shared_lock<std::shared_mutex> readLock(mutex_);
576 if (paragraph_ == nullptr) {
577 return {};
578 }
579 return paragraph_->GetDumpInfo();
580 }
581
582 } // namespace AdapterTxt
583 } // namespace Rosen
584 } // namespace OHOS
585