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