• 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/SkSpan.h"
7 #include "unicode/unistr.h"
8 
9 namespace skia {
10 namespace textlayout {
11 
make(const ParagraphStyle & style,sk_sp<FontCollection> fontCollection)12 std::unique_ptr<ParagraphBuilder> ParagraphBuilder::make(
13         const ParagraphStyle& style, sk_sp<FontCollection> fontCollection) {
14     return std::make_unique<ParagraphBuilderImpl>(style, fontCollection);
15 }
16 
ParagraphBuilderImpl(const ParagraphStyle & style,sk_sp<FontCollection> fontCollection)17 ParagraphBuilderImpl::ParagraphBuilderImpl(
18         const ParagraphStyle& style, sk_sp<FontCollection> fontCollection)
19         : ParagraphBuilder(style, fontCollection), fUtf8(), fFontCollection(std::move(fontCollection)) {
20     this->setParagraphStyle(style);
21 }
22 
23 ParagraphBuilderImpl::~ParagraphBuilderImpl() = default;
24 
setParagraphStyle(const ParagraphStyle & style)25 void ParagraphBuilderImpl::setParagraphStyle(const ParagraphStyle& style) {
26     fParagraphStyle = style;
27     fTextStyles.push(fParagraphStyle.getTextStyle());
28     fStyledBlocks.emplace_back(fUtf8.size(), fUtf8.size(), fParagraphStyle.getTextStyle());
29 }
30 
pushStyle(const TextStyle & style)31 void ParagraphBuilderImpl::pushStyle(const TextStyle& style) {
32     this->endRunIfNeeded();
33 
34     fTextStyles.push(style);
35     if (!fStyledBlocks.empty() && fStyledBlocks.back().fRange.end == fUtf8.size() &&
36         fStyledBlocks.back().fStyle == style) {
37         // Just continue with the same style
38     } else {
39         // Go with the new style
40         fStyledBlocks.emplace_back(fUtf8.size(), fUtf8.size(), fTextStyles.top());
41     }
42 }
43 
pop()44 void ParagraphBuilderImpl::pop() {
45     this->endRunIfNeeded();
46 
47     if (fTextStyles.size() > 1) {
48         fTextStyles.pop();
49     } else {
50         // In this case we use paragraph style and skip Pop operation
51         SkDEBUGF("SkParagraphBuilder.Pop() called too many times.\n");
52     }
53 
54     auto top = fTextStyles.top();
55     fStyledBlocks.emplace_back(fUtf8.size(), fUtf8.size(), top);
56 }
57 
peekStyle()58 TextStyle ParagraphBuilderImpl::peekStyle() {
59     this->endRunIfNeeded();
60 
61     if (!fTextStyles.empty()) {
62         return fTextStyles.top();
63     } else {
64         SkDebugf("SkParagraphBuilder._styles is empty.\n");
65         return fParagraphStyle.getTextStyle();
66     }
67 }
68 
addText(const std::u16string & text)69 void ParagraphBuilderImpl::addText(const std::u16string& text) {
70     icu::UnicodeString unicode;
71     unicode.setTo((UChar*)text.data());
72     std::string str;
73     unicode.toUTF8String(str);
74     fUtf8.insert(fUtf8.size(), str.c_str());
75 }
76 
addText(const char * text)77 void ParagraphBuilderImpl::addText(const char* text) {
78     fUtf8.insert(fUtf8.size(), text);
79 }
80 
addText(const char * text,size_t len)81 void ParagraphBuilderImpl::addText(const char* text, size_t len) {
82     fUtf8.insert(fUtf8.size(), text, len);
83 }
84 
addPlaceholder(const PlaceholderStyle & placeholderStyle)85 void ParagraphBuilderImpl::addPlaceholder(const PlaceholderStyle& placeholderStyle) {
86     addPlaceholder(placeholderStyle, false);
87 }
88 
addPlaceholder(const PlaceholderStyle & placeholderStyle,bool lastOne)89 void ParagraphBuilderImpl::addPlaceholder(const PlaceholderStyle& placeholderStyle, bool lastOne) {
90     this->endRunIfNeeded();
91 
92     BlockRange stylesBefore(fPlaceholders.empty() ? 0 : fPlaceholders.back().fBlocksBefore.end + 1,
93                             fStyledBlocks.size());
94     TextRange textBefore(fPlaceholders.empty() ? 0 : fPlaceholders.back().fRange.end,
95                             fUtf8.size());
96     auto start = fUtf8.size();
97     auto topStyle = fTextStyles.top();
98     if (!lastOne) {
99         pushStyle(TextStyle(topStyle, true));
100         addText(std::u16string(1ull, 0xFFFC));
101         pop();
102     }
103     auto end = fUtf8.size();
104     fPlaceholders.emplace_back(start, end, placeholderStyle, topStyle, stylesBefore, textBefore);
105 }
106 
endRunIfNeeded()107 void ParagraphBuilderImpl::endRunIfNeeded() {
108     if (fStyledBlocks.empty()) {
109         return;
110     }
111 
112     auto& last = fStyledBlocks.back();
113     if (last.fRange.start == fUtf8.size()) {
114         fStyledBlocks.pop_back();
115     } else {
116         last.fRange.end = fUtf8.size();
117     }
118 }
119 
Build()120 std::unique_ptr<Paragraph> ParagraphBuilderImpl::Build() {
121     if (!fUtf8.isEmpty()) {
122         this->endRunIfNeeded();
123     }
124 
125     // Add one fake placeholder with the rest of the text
126     addPlaceholder(PlaceholderStyle(), true);
127     return std::make_unique<ParagraphImpl>(
128             fUtf8, fParagraphStyle, fStyledBlocks, fPlaceholders, fFontCollection);
129 }
130 
131 }  // namespace textlayout
132 }  // namespace skia
133