1 | /* |
2 | * Copyright 2016 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #include "include/core/SkFontMetrics.h" |
9 | #include "include/core/SkStream.h" |
10 | #include "include/core/SkTypeface.h" |
11 | #include "include/private/SkTo.h" |
12 | #include "modules/skshaper/include/SkShaper.h" |
13 | #include "src/utils/SkUTF.h" |
14 | |
15 | class SkShaperPrimitive : public SkShaper { |
16 | public: |
17 | SkShaperPrimitive() {} |
18 | private: |
19 | void shape(const char* utf8, size_t utf8Bytes, |
20 | const SkFont& srcFont, |
21 | bool leftToRight, |
22 | SkScalar width, |
23 | RunHandler*) const override; |
24 | |
25 | void shape(const char* utf8, size_t utf8Bytes, |
26 | FontRunIterator&, |
27 | BiDiRunIterator&, |
28 | ScriptRunIterator&, |
29 | LanguageRunIterator&, |
30 | SkScalar width, |
31 | RunHandler*) const override; |
32 | |
33 | void shape(const char* utf8, size_t utf8Bytes, |
34 | FontRunIterator&, |
35 | BiDiRunIterator&, |
36 | ScriptRunIterator&, |
37 | LanguageRunIterator&, |
38 | const Feature*, size_t featureSize, |
39 | SkScalar width, |
40 | RunHandler*) const override; |
41 | }; |
42 | |
43 | std::unique_ptr<SkShaper> SkShaper::MakePrimitive() { |
44 | return std::make_unique<SkShaperPrimitive>(); |
45 | } |
46 | |
47 | static inline bool is_breaking_whitespace(SkUnichar c) { |
48 | switch (c) { |
49 | case 0x0020: // SPACE |
50 | //case 0x00A0: // NO-BREAK SPACE |
51 | case 0x1680: // OGHAM SPACE MARK |
52 | case 0x180E: // MONGOLIAN VOWEL SEPARATOR |
53 | case 0x2000: // EN QUAD |
54 | case 0x2001: // EM QUAD |
55 | case 0x2002: // EN SPACE (nut) |
56 | case 0x2003: // EM SPACE (mutton) |
57 | case 0x2004: // THREE-PER-EM SPACE (thick space) |
58 | case 0x2005: // FOUR-PER-EM SPACE (mid space) |
59 | case 0x2006: // SIX-PER-EM SPACE |
60 | case 0x2007: // FIGURE SPACE |
61 | case 0x2008: // PUNCTUATION SPACE |
62 | case 0x2009: // THIN SPACE |
63 | case 0x200A: // HAIR SPACE |
64 | case 0x200B: // ZERO WIDTH SPACE |
65 | case 0x202F: // NARROW NO-BREAK SPACE |
66 | case 0x205F: // MEDIUM MATHEMATICAL SPACE |
67 | case 0x3000: // IDEOGRAPHIC SPACE |
68 | //case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE |
69 | return true; |
70 | default: |
71 | return false; |
72 | } |
73 | } |
74 | |
75 | static size_t linebreak(const char text[], const char stop[], |
76 | const SkFont& font, SkScalar width, |
77 | SkScalar* advance, |
78 | size_t* trailing) |
79 | { |
80 | SkScalar accumulatedWidth = 0; |
81 | int glyphIndex = 0; |
82 | const char* start = text; |
83 | const char* word_start = text; |
84 | bool prevWS = true; |
85 | *trailing = 0; |
86 | |
87 | while (text < stop) { |
88 | const char* prevText = text; |
89 | SkUnichar uni = SkUTF::NextUTF8(&text, stop); |
90 | accumulatedWidth += advance[glyphIndex++]; |
91 | bool currWS = is_breaking_whitespace(uni); |
92 | |
93 | if (!currWS && prevWS) { |
94 | word_start = prevText; |
95 | } |
96 | prevWS = currWS; |
97 | |
98 | if (width < accumulatedWidth) { |
99 | if (currWS) { |
100 | // eat the rest of the whitespace |
101 | const char* next = text; |
102 | while (next < stop && is_breaking_whitespace(SkUTF::NextUTF8(&next, stop))) { |
103 | text = next; |
104 | } |
105 | if (trailing) { |
106 | *trailing = text - prevText; |
107 | } |
108 | } else { |
109 | // backup until a whitespace (or 1 char) |
110 | if (word_start == start) { |
111 | if (prevText > start) { |
112 | text = prevText; |
113 | } |
114 | } else { |
115 | text = word_start; |
116 | } |
117 | } |
118 | break; |
119 | } |
120 | } |
121 | |
122 | return text - start; |
123 | } |
124 | |
125 | void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes, |
126 | FontRunIterator& font, |
127 | BiDiRunIterator& bidi, |
128 | ScriptRunIterator&, |
129 | LanguageRunIterator&, |
130 | SkScalar width, |
131 | RunHandler* handler) const |
132 | { |
133 | SkFont skfont; |
134 | if (!font.atEnd()) { |
135 | font.consume(); |
136 | skfont = font.currentFont(); |
137 | } else { |
138 | skfont.setTypeface(sk_ref_sp(skfont.getTypefaceOrDefault())); |
139 | } |
140 | SkASSERT(skfont.getTypeface()); |
141 | bool skbidi = 0; |
142 | if (!bidi.atEnd()) { |
143 | bidi.consume(); |
144 | skbidi = (bidi.currentLevel() % 2) == 0; |
145 | } |
146 | return this->shape(utf8, utf8Bytes, skfont, skbidi, width, handler); |
147 | } |
148 | |
149 | void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes, |
150 | FontRunIterator& font, |
151 | BiDiRunIterator& bidi, |
152 | ScriptRunIterator&, |
153 | LanguageRunIterator&, |
154 | const Feature*, size_t, |
155 | SkScalar width, |
156 | RunHandler* handler) const { |
157 | font.consume(); |
158 | SkASSERT(font.currentFont().getTypeface()); |
159 | bidi.consume(); |
160 | return this->shape(utf8, utf8Bytes, font.currentFont(), (bidi.currentLevel() % 2) == 0, |
161 | width, handler); |
162 | } |
163 | |
164 | void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes, |
165 | const SkFont& font, |
166 | bool leftToRight, |
167 | SkScalar width, |
168 | RunHandler* handler) const { |
169 | sk_ignore_unused_variable(leftToRight); |
170 | |
171 | int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8); |
172 | if (glyphCount <= 0) { |
173 | return; |
174 | } |
175 | |
176 | std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]); |
177 | font.textToGlyphs(utf8, utf8Bytes, SkTextEncoding::kUTF8, glyphs.get(), glyphCount); |
178 | |
179 | std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]); |
180 | font.getWidthsBounds(glyphs.get(), glyphCount, advances.get(), nullptr, nullptr); |
181 | |
182 | size_t glyphOffset = 0; |
183 | size_t utf8Offset = 0; |
184 | while (0 < utf8Bytes) { |
185 | size_t bytesCollapsed; |
186 | size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width, |
187 | advances.get() + glyphOffset, &bytesCollapsed); |
188 | size_t bytesVisible = bytesConsumed - bytesCollapsed; |
189 | |
190 | size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible); |
191 | const RunHandler::RunInfo info = { |
192 | font, |
193 | 0, |
194 | { font.measureText(utf8, bytesVisible, SkTextEncoding::kUTF8), 0 }, |
195 | numGlyphs, |
196 | RunHandler::Range(utf8Offset, bytesVisible) |
197 | }; |
198 | handler->beginLine(); |
199 | handler->runInfo(info); |
200 | handler->commitRunInfo(); |
201 | const auto buffer = handler->runBuffer(info); |
202 | |
203 | memcpy(buffer.glyphs, glyphs.get() + glyphOffset, numGlyphs * sizeof(SkGlyphID)); |
204 | SkPoint position = buffer.point; |
205 | for (size_t i = 0; i < numGlyphs; ++i) { |
206 | buffer.positions[i] = position; |
207 | position.fX += advances[i + glyphOffset]; |
208 | } |
209 | if (buffer.clusters) { |
210 | const char* txtPtr = utf8; |
211 | for (size_t i = 0; i < numGlyphs; ++i) { |
212 | // Each character maps to exactly one glyph. |
213 | buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset); |
214 | SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes); |
215 | } |
216 | } |
217 | handler->commitRunBuffer(info); |
218 | handler->commitLine(); |
219 | |
220 | glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed); |
221 | utf8Offset += bytesConsumed; |
222 | utf8 += bytesConsumed; |
223 | utf8Bytes -= bytesConsumed; |
224 | } |
225 | |
226 | return; |
227 | } |
228 | |