• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #include "include/core/SkPaint.h"
3 #include "modules/skparagraph/include/ParagraphStyle.h"
4 #include "modules/skparagraph/src/ParagraphBuilderImpl.h"
5 #include "modules/skparagraph/src/ParagraphImpl.h"
6 #include "src/core/SkMakeUnique.h"
7 #include "src/core/SkSpan.h"
8 #include "unicode/unistr.h"
9 
10 namespace skia {
11 namespace textlayout {
12 
make(const ParagraphStyle & style,sk_sp<FontCollection> fontCollection)13 std::unique_ptr<ParagraphBuilder> ParagraphBuilder::make(
14         const ParagraphStyle& style, sk_sp<FontCollection> fontCollection) {
15     return skstd::make_unique<ParagraphBuilderImpl>(style, fontCollection);
16 }
17 
ParagraphBuilderImpl(const ParagraphStyle & style,sk_sp<FontCollection> fontCollection)18 ParagraphBuilderImpl::ParagraphBuilderImpl(
19         const ParagraphStyle& style, sk_sp<FontCollection> fontCollection)
20         : ParagraphBuilder(style, fontCollection), fUtf8(), fFontCollection(std::move(fontCollection)) {
21     this->setParagraphStyle(style);
22 }
23 
24 ParagraphBuilderImpl::~ParagraphBuilderImpl() = default;
25 
setParagraphStyle(const ParagraphStyle & style)26 void ParagraphBuilderImpl::setParagraphStyle(const ParagraphStyle& style) {
27     fParagraphStyle = style;
28     fTextStyles.push(fParagraphStyle.getTextStyle());
29     fStyledBlocks.emplace_back(fUtf8.size(), fUtf8.size(), fParagraphStyle.getTextStyle());
30 }
31 
pushStyle(const TextStyle & style)32 void ParagraphBuilderImpl::pushStyle(const TextStyle& style) {
33     this->endRunIfNeeded();
34 
35     fTextStyles.push(style);
36     if (!fStyledBlocks.empty() && fStyledBlocks.back().fRange.end == fUtf8.size() &&
37         fStyledBlocks.back().fStyle == style) {
38         // Just continue with the same style
39     } else {
40         // Go with the new style
41         fStyledBlocks.emplace_back(fUtf8.size(), fUtf8.size(), fTextStyles.top());
42     }
43 }
44 
pop()45 void ParagraphBuilderImpl::pop() {
46     this->endRunIfNeeded();
47 
48     if (fTextStyles.size() > 1) {
49         fTextStyles.pop();
50     } else {
51         // In this case we use paragraph style and skip Pop operation
52         SkDebugf("SkParagraphBuilder.Pop() called too many times.\n");
53     }
54 
55     auto top = fTextStyles.top();
56     fStyledBlocks.emplace_back(fUtf8.size(), fUtf8.size(), top);
57 }
58 
peekStyle()59 TextStyle ParagraphBuilderImpl::peekStyle() {
60     this->endRunIfNeeded();
61 
62     if (!fTextStyles.empty()) {
63         return fTextStyles.top();
64     } else {
65         SkDebugf("SkParagraphBuilder._styles is empty.\n");
66         return fParagraphStyle.getTextStyle();
67     }
68 }
69 
addText(const std::u16string & text)70 void ParagraphBuilderImpl::addText(const std::u16string& text) {
71     icu::UnicodeString unicode;
72     unicode.setTo((UChar*)text.data());
73     std::string str;
74     unicode.toUTF8String(str);
75     // SkDebugf("Layout text16: '%s'\n", str.c_str());
76     fUtf8.insert(fUtf8.size(), str.c_str());
77 }
78 
addText(const char * text)79 void ParagraphBuilderImpl::addText(const char* text) {
80     // SkDebugf("Layout text8: '%s'\n", text);
81     fUtf8.insert(fUtf8.size(), text);
82 }
83 
endRunIfNeeded()84 void ParagraphBuilderImpl::endRunIfNeeded() {
85     if (fStyledBlocks.empty()) {
86         return;
87     }
88 
89     auto& last = fStyledBlocks.back();
90     if (last.fRange.start == fUtf8.size()) {
91         fStyledBlocks.pop_back();
92     } else {
93         last.fRange.end = fUtf8.size();
94     }
95 }
96 
Build()97 std::unique_ptr<Paragraph> ParagraphBuilderImpl::Build() {
98     if (!fUtf8.isEmpty()) {
99         this->endRunIfNeeded();
100     }
101     return skstd::make_unique<ParagraphImpl>(
102             fUtf8, fParagraphStyle, fStyledBlocks, fFontCollection);
103 }
104 
105 }  // namespace textlayout
106 }  // namespace skia
107