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 "skia_adapter/skia_canvas.h"
22 #include "skia_adapter/skia_convert_utils.h"
23 #include "impl/paragraph_impl.h"
24
25 #include "convert.h"
26 #include "text_line_base.h"
27
28 namespace OHOS {
29 namespace Rosen {
30 namespace skt = skia::textlayout;
31
TextRect(Drawing::RectF rec,TextDirection dir)32 TextRect::TextRect(Drawing::RectF rec, TextDirection dir)
33 {
34 rect = rec;
35 direction = dir;
36 }
37
IndexAndAffinity(size_t charIndex,Affinity charAffinity)38 IndexAndAffinity::IndexAndAffinity(size_t charIndex, Affinity charAffinity)
39 {
40 index = charIndex;
41 affinity = charAffinity;
42 }
43
44 namespace AdapterTxt {
Typography(std::unique_ptr<SPText::Paragraph> paragraph)45 Typography::Typography(std::unique_ptr<SPText::Paragraph> paragraph): paragraph_(std::move(paragraph))
46 {
47 }
48
GetMaxWidth() const49 double Typography::GetMaxWidth() const
50 {
51 std::shared_lock<std::shared_mutex> readLock(mutex_);
52 return paragraph_->GetMaxWidth();
53 }
54
GetHeight() const55 double Typography::GetHeight() const
56 {
57 std::shared_lock<std::shared_mutex> readLock(mutex_);
58 return paragraph_->GetHeight();
59 }
60
GetActualWidth() const61 double Typography::GetActualWidth() const
62 {
63 std::shared_lock<std::shared_mutex> readLock(mutex_);
64 return paragraph_->GetLongestLine();
65 }
66
GetLongestLineWithIndent() const67 double Typography::GetLongestLineWithIndent() const
68 {
69 std::shared_lock<std::shared_mutex> readLock(mutex_);
70 return paragraph_->GetLongestLineWithIndent();
71 }
72
GetMinIntrinsicWidth()73 double Typography::GetMinIntrinsicWidth()
74 {
75 std::shared_lock<std::shared_mutex> readLock(mutex_);
76 return paragraph_->GetMinIntrinsicWidth();
77 }
78
GetMaxIntrinsicWidth()79 double Typography::GetMaxIntrinsicWidth()
80 {
81 std::shared_lock<std::shared_mutex> readLock(mutex_);
82 return paragraph_->GetMaxIntrinsicWidth();
83 }
84
GetAlphabeticBaseline()85 double Typography::GetAlphabeticBaseline()
86 {
87 std::shared_lock<std::shared_mutex> readLock(mutex_);
88 return paragraph_->GetAlphabeticBaseline();
89 }
90
GetIdeographicBaseline()91 double Typography::GetIdeographicBaseline()
92 {
93 std::shared_lock<std::shared_mutex> readLock(mutex_);
94 return paragraph_->GetIdeographicBaseline();
95 }
96
DidExceedMaxLines() const97 bool Typography::DidExceedMaxLines() const
98 {
99 std::shared_lock<std::shared_mutex> readLock(mutex_);
100 return paragraph_->DidExceedMaxLines();
101 }
102
GetLineCount() const103 int Typography::GetLineCount() const
104 {
105 std::shared_lock<std::shared_mutex> readLock(mutex_);
106 return paragraph_->GetLineCount();
107 }
108
SetIndents(const std::vector<float> & indents)109 void Typography::SetIndents(const std::vector<float>& indents)
110 {
111 std::unique_lock<std::shared_mutex> writeLock(mutex_);
112 paragraph_->SetIndents(indents);
113 }
114
DetectIndents(size_t index)115 float Typography::DetectIndents(size_t index)
116 {
117 std::shared_lock<std::shared_mutex> readLock(mutex_);
118 return paragraph_->DetectIndents(index);
119 }
120
Layout(double width)121 void Typography::Layout(double width)
122 {
123 std::unique_lock<std::shared_mutex> writeLock(mutex_);
124 lineMetrics_.reset();
125 lineMetricsStyles_.clear();
126 return paragraph_->Layout(width);
127 }
128
GetGlyphsBoundsTop()129 double Typography::GetGlyphsBoundsTop()
130 {
131 std::shared_lock<std::shared_mutex> readLock(mutex_);
132 return paragraph_->GetGlyphsBoundsTop();
133 }
134
GetGlyphsBoundsBottom()135 double Typography::GetGlyphsBoundsBottom()
136 {
137 std::shared_lock<std::shared_mutex> readLock(mutex_);
138 return paragraph_->GetGlyphsBoundsBottom();
139 }
140
GetGlyphsBoundsLeft()141 double Typography::GetGlyphsBoundsLeft()
142 {
143 std::shared_lock<std::shared_mutex> readLock(mutex_);
144 return paragraph_->GetGlyphsBoundsLeft();
145 }
146
GetGlyphsBoundsRight()147 double Typography::GetGlyphsBoundsRight()
148 {
149 std::shared_lock<std::shared_mutex> readLock(mutex_);
150 return paragraph_->GetGlyphsBoundsRight();
151 }
152
MeasureText()153 Drawing::FontMetrics Typography::MeasureText()
154 {
155 std::unique_lock<std::shared_mutex> writeLock(mutex_);
156 return paragraph_->MeasureText();
157 }
158
MarkDirty()159 void Typography::MarkDirty()
160 {
161 std::unique_lock<std::shared_mutex> writeLock(mutex_);
162 if (paragraph_ == nullptr) {
163 return;
164 }
165 paragraph_->MarkDirty();
166 }
167
GetUnresolvedGlyphsCount()168 int32_t Typography::GetUnresolvedGlyphsCount()
169 {
170 std::shared_lock<std::shared_mutex> readLock(mutex_);
171 if (paragraph_ == nullptr) {
172 return 0;
173 }
174 return paragraph_->GetUnresolvedGlyphsCount();
175 }
176
UpdateFontSize(size_t from,size_t to,float fontSize)177 void Typography::UpdateFontSize(size_t from, size_t to, float fontSize)
178 {
179 std::unique_lock<std::shared_mutex> writeLock(mutex_);
180 if (paragraph_ == nullptr) {
181 return;
182 }
183 paragraph_->UpdateFontSize(from, to, fontSize);
184 }
185
Paint(SkCanvas * canvas,double x,double y)186 void Typography::Paint(SkCanvas *canvas, double x, double y)
187 {
188 std::unique_lock<std::shared_mutex> writeLock(mutex_);
189 return paragraph_->Paint(canvas, x, y);
190 }
191
Paint(Drawing::Canvas * drawCanvas,double x,double y)192 void Typography::Paint(Drawing::Canvas *drawCanvas, double x, double y)
193 {
194 std::unique_lock<std::shared_mutex> writeLock(mutex_);
195 paragraph_->Paint(drawCanvas, x, y);
196 }
197
Paint(Drawing::Canvas * drawCanvas,Drawing::Path * path,double hOffset,double vOffset)198 void Typography::Paint(Drawing::Canvas* drawCanvas, Drawing::Path* path, double hOffset, double vOffset)
199 {
200 std::unique_lock<std::shared_mutex> writeLock(mutex_);
201 paragraph_->Paint(drawCanvas, path, hOffset, vOffset);
202 }
203
GetTextRectsByBoundary(size_t left,size_t right,TextRectHeightStyle heightStyle,TextRectWidthStyle widthStyle)204 std::vector<TextRect> Typography::GetTextRectsByBoundary(size_t left, size_t right,
205 TextRectHeightStyle heightStyle, TextRectWidthStyle widthStyle)
206 {
207 std::shared_lock<std::shared_mutex> readLock(mutex_);
208 auto txtRectHeightStyle = Convert(heightStyle);
209 auto txtRectWidthStyle = Convert(widthStyle);
210 auto rects = paragraph_->GetRectsForRange(left, right, txtRectHeightStyle, txtRectWidthStyle);
211
212 std::vector<TextRect> boxes;
213 for (const auto &rect : rects) {
214 boxes.push_back(Convert(rect));
215 }
216 return boxes;
217 }
218
GetTextRectsOfPlaceholders()219 std::vector<TextRect> Typography::GetTextRectsOfPlaceholders()
220 {
221 std::shared_lock<std::shared_mutex> readLock(mutex_);
222 auto rects = paragraph_->GetRectsForPlaceholders();
223
224 std::vector<TextRect> boxes;
225 for (const auto &rect : rects) {
226 boxes.push_back(Convert(rect));
227 }
228 return boxes;
229 }
230
GetGlyphIndexByCoordinate(double x,double y)231 IndexAndAffinity Typography::GetGlyphIndexByCoordinate(double x, double y)
232 {
233 std::shared_lock<std::shared_mutex> readLock(mutex_);
234 auto pos = paragraph_->GetGlyphPositionAtCoordinate(x, y);
235 return Convert(pos);
236 }
237
GetWordBoundaryByIndex(size_t index)238 Boundary Typography::GetWordBoundaryByIndex(size_t index)
239 {
240 std::shared_lock<std::shared_mutex> readLock(mutex_);
241 auto range = paragraph_->GetWordBoundary(index);
242 return Convert(range);
243 }
244
GetActualTextRange(int lineNumber,bool includeSpaces)245 Boundary Typography::GetActualTextRange(int lineNumber, bool includeSpaces)
246 {
247 std::shared_lock<std::shared_mutex> readLock(mutex_);
248 auto range = paragraph_->GetActualTextRange(lineNumber, includeSpaces);
249 return Convert(range);
250 }
251
GetLineHeight(int lineNumber)252 double Typography::GetLineHeight(int lineNumber)
253 {
254 std::shared_lock<std::shared_mutex> readLock(mutex_);
255 const auto &lines = paragraph_->GetLineMetrics();
256 if ((0 <= lineNumber) && (lineNumber < static_cast<int>(lines.size()))) {
257 return lines[lineNumber].fHeight;
258 }
259 return 0.0;
260 }
261
GetLineWidth(int lineNumber)262 double Typography::GetLineWidth(int lineNumber)
263 {
264 std::shared_lock<std::shared_mutex> readLock(mutex_);
265 const auto &lines = paragraph_->GetLineMetrics();
266 if ((0 <= lineNumber) && (lineNumber < static_cast<int>(lines.size()))) {
267 return lines[lineNumber].fWidth;
268 }
269 return 0.0;
270 }
271
SetAnimation(std::function<bool (const std::shared_ptr<OHOS::Rosen::TextEngine::SymbolAnimationConfig> &)> & animationFunc)272 void Typography::SetAnimation(
273 std::function<bool(const std::shared_ptr<OHOS::Rosen::TextEngine::SymbolAnimationConfig>&)>& animationFunc
274 )
275 {
276 std::unique_lock<std::shared_mutex> writeLock(mutex_);
277 if (animationFunc != nullptr && paragraph_ != nullptr) {
278 paragraph_->SetAnimation(animationFunc);
279 }
280 }
281
SetParagraghId(uint32_t id)282 void Typography::SetParagraghId(uint32_t id)
283 {
284 std::unique_lock<std::shared_mutex> writeLock(mutex_);
285 if (paragraph_ != nullptr) {
286 paragraph_->SetParagraghId(id);
287 }
288 }
289
GetLineInfo(int lineNumber,bool oneLine,bool includeWhitespace,LineMetrics * lineMetrics)290 bool Typography::GetLineInfo(int lineNumber, bool oneLine, bool includeWhitespace, LineMetrics* lineMetrics)
291 {
292 std::shared_lock<std::shared_mutex> readLock(mutex_);
293 if (paragraph_ == nullptr) {
294 return false;
295 }
296 if (lineNumber < 0 || lineNumber >= static_cast<int>(paragraph_->GetLineCount()) || lineMetrics == nullptr) {
297 return false;
298 }
299
300 skia::textlayout::LineMetrics sklineMetrics;
301 if (!paragraph_->GetLineMetricsAt(lineNumber, &sklineMetrics)) {
302 return false;
303 }
304
305 if (!sklineMetrics.fLineMetrics.empty()) {
306 const auto &skFontMetrics = sklineMetrics.fLineMetrics.begin()->second.font_metrics;
307 lineMetrics->firstCharMetrics = skFontMetrics;
308 if (oneLine) {
309 lineMetrics->ascender = sklineMetrics.fAscent;
310 lineMetrics->descender = sklineMetrics.fDescent;
311 } else {
312 lineMetrics->ascender = skFontMetrics.fAscent;
313 lineMetrics->descender = skFontMetrics.fDescent;
314 }
315 lineMetrics->capHeight = skFontMetrics.fCapHeight;
316 lineMetrics->xHeight = skFontMetrics.fXHeight;
317 } else {
318 if (oneLine) {
319 lineMetrics->ascender = sklineMetrics.fAscent;
320 lineMetrics->descender = sklineMetrics.fDescent;
321 } else {
322 lineMetrics->ascender = 0.0;
323 lineMetrics->descender = 0.0;
324 }
325 lineMetrics->capHeight = 0.0;
326 lineMetrics->xHeight = 0.0;
327 }
328 if (includeWhitespace) {
329 lineMetrics->width = sklineMetrics.fWidthWithSpaces;
330 } else {
331 lineMetrics->width = sklineMetrics.fWidth;
332 }
333 lineMetrics->height = sklineMetrics.fHeight;
334 lineMetrics->x = sklineMetrics.fLeft;
335 lineMetrics->y = sklineMetrics.fTopHeight;
336 lineMetrics->startIndex = sklineMetrics.fStartIndex;
337 lineMetrics->endIndex = sklineMetrics.fEndIndex;
338
339 return true;
340 }
341
GetLineMetrics()342 std::vector<LineMetrics> Typography::GetLineMetrics()
343 {
344 std::unique_lock<std::shared_mutex> writeLock(mutex_);
345 if (lineMetrics_) {
346 return lineMetrics_.value();
347 }
348 lineMetrics_.emplace();
349 if (paragraph_ != nullptr) {
350 auto metrics = paragraph_->GetLineMetrics();
351 lineMetricsStyles_.reserve(std::accumulate(metrics.begin(), metrics.end(), 0,
352 [](const int a, const skia::textlayout::LineMetrics& b) { return a + b.fLineMetrics.size(); }));
353
354 for (const skt::LineMetrics& skLineMetrics : metrics) {
355 LineMetrics& line = lineMetrics_->emplace_back();
356 if (!skLineMetrics.fLineMetrics.empty()) {
357 const auto &skmFontMetrics = skLineMetrics.fLineMetrics.begin()->second.font_metrics;
358 line.firstCharMetrics = skmFontMetrics;
359 line.capHeight = skmFontMetrics.fCapHeight;
360 line.xHeight = skmFontMetrics.fXHeight;
361 } else {
362 line.capHeight = 0.0;
363 line.xHeight = 0.0;
364 }
365 line.lineNumber = skLineMetrics.fLineNumber;
366 line.baseline = skLineMetrics.fBaseline;
367 line.ascender = skLineMetrics.fAscent;
368 line.descender = skLineMetrics.fDescent;
369 line.width = skLineMetrics.fWidth;
370 line.height = skLineMetrics.fHeight;
371 line.x = skLineMetrics.fLeft;
372 line.y = skLineMetrics.fTopHeight;
373 line.startIndex = skLineMetrics.fStartIndex;
374 line.endIndex = skLineMetrics.fEndIndex;
375 for (const auto& [index, styleMtrics] : skLineMetrics.fLineMetrics) {
376 SPText::TextStyle spTextStyle = paragraph_->SkStyleToTextStyle(*styleMtrics.text_style);
377 lineMetricsStyles_.emplace_back(Convert(spTextStyle));
378
379 line.runMetrics.emplace(std::piecewise_construct, std::forward_as_tuple(index),
380 std::forward_as_tuple(&lineMetricsStyles_.back(), styleMtrics.font_metrics));
381 }
382 }
383 }
384 return lineMetrics_.value();
385 }
386
GetLineMetricsAt(int lineNumber,LineMetrics * lineMetrics)387 bool Typography::GetLineMetricsAt(int lineNumber, LineMetrics* lineMetrics)
388 {
389 if (paragraph_ == nullptr) {
390 return false;
391 }
392 if (lineNumber < 0 || lineNumber >= static_cast<int>(paragraph_->GetLineCount()) || lineMetrics == nullptr) {
393 return false;
394 }
395 std::vector<LineMetrics> vecLineMetrics = GetLineMetrics();
396
397 if (vecLineMetrics.empty()) {
398 return false;
399 }
400
401 *lineMetrics = vecLineMetrics[lineNumber];
402
403 return true;
404 }
405
GetFontMetrics(const OHOS::Rosen::TextStyle & textStyle)406 Drawing::FontMetrics Typography::GetFontMetrics(const OHOS::Rosen::TextStyle& textStyle)
407 {
408 std::shared_lock<std::shared_mutex> readLock(mutex_);
409 auto spTextStyle = Convert(textStyle);
410 return paragraph_->GetFontMetricsResult(spTextStyle);
411 }
412
GetLineFontMetrics(const size_t lineNumber,size_t & charNumber,std::vector<Drawing::FontMetrics> & fontMetrics)413 bool Typography::GetLineFontMetrics(const size_t lineNumber,
414 size_t& charNumber, std::vector<Drawing::FontMetrics>& fontMetrics)
415 {
416 std::shared_lock<std::shared_mutex> readLock(mutex_);
417 if (!paragraph_) {
418 return false;
419 }
420 return paragraph_->GetLineFontMetrics(lineNumber, charNumber, fontMetrics);
421 }
422
GetTextLines() const423 std::vector<std::unique_ptr<TextLineBase>> Typography::GetTextLines() const
424 {
425 std::shared_lock<std::shared_mutex> readLock(mutex_);
426 if (!paragraph_) {
427 return {};
428 }
429 std::vector<std::unique_ptr<SPText::TextLineBase>> textLines = paragraph_->GetTextLines();
430 std::vector<std::unique_ptr<TextLineBase>> lines;
431
432 for (std::unique_ptr<SPText::TextLineBase>& textLine : textLines) {
433 std::unique_ptr<TextLineBaseImpl> linePtr = std::make_unique<TextLineBaseImpl>(std::move(textLine));
434 lines.emplace_back(std::move(linePtr));
435 }
436 return lines;
437 }
438
CloneSelf()439 std::unique_ptr<OHOS::Rosen::Typography> Typography::CloneSelf()
440 {
441 std::shared_lock<std::shared_mutex> readLock(mutex_);
442 if (!paragraph_) {
443 return nullptr;
444 }
445 return std::make_unique<Typography>(paragraph_->CloneSelf());
446 }
447
UpdateColor(size_t from,size_t to,const Drawing::Color & color)448 void Typography::UpdateColor(size_t from, size_t to, const Drawing::Color& color)
449 {
450 std::unique_lock<std::shared_mutex> writeLock(mutex_);
451 if (!paragraph_) {
452 return;
453 }
454 paragraph_->UpdateColor(from, to, color);
455 }
456
GeneratePaintRegion(double x,double y) const457 Drawing::RectI Typography::GeneratePaintRegion(double x, double y) const
458 {
459 std::unique_lock<std::shared_mutex> writeLock(mutex_);
460 if (!paragraph_) {
461 double left = std::floor(x);
462 double top = std::floor(y);
463 return Drawing::RectI(left, top, left, top);
464 }
465
466 return paragraph_->GeneratePaintRegion(x, y);
467 }
468 } // namespace AdapterTxt
469 } // namespace Rosen
470 } // namespace OHOS
471