• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "include/core/SkFont.h"
8 #include "include/core/SkFontTypes.h"
9 #include "include/core/SkPoint.h"
10 #include "include/core/SkScalar.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/base/SkTo.h"
13 #include "modules/skshaper/include/SkShaper.h"
14 #include "src/base/SkUTF.h"
15 
16 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
17 #include "include/core/SkFontMgr.h"
18 #endif
19 
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23 
24 #ifdef ENABLE_DRAWING_ADAPTER
25 namespace SkiaRsText {
26 #endif
27 class SkShaperPrimitive : public SkShaper {
28 public:
SkShaperPrimitive()29     SkShaperPrimitive() {}
30 private:
31 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
32     void shape(const char* utf8, size_t utf8Bytes,
33 #ifdef ENABLE_TEXT_ENHANCE
34                const RSFont& srcFont,
35 #else
36                const SkFont& srcFont,
37 #endif
38                bool leftToRight,
39                SkScalar width,
40                RunHandler*) const override;
41 
42     void shape(const char* utf8, size_t utf8Bytes,
43                FontRunIterator&,
44                BiDiRunIterator&,
45                ScriptRunIterator&,
46                LanguageRunIterator&,
47                SkScalar width,
48                RunHandler*) const override;
49 #endif
50 
51     void shape(const char* utf8, size_t utf8Bytes,
52                FontRunIterator&,
53                BiDiRunIterator&,
54                ScriptRunIterator&,
55                LanguageRunIterator&,
56                const Feature*, size_t featureSize,
57                SkScalar width,
58                RunHandler*) const override;
59 
60 #ifdef ENABLE_TEXT_ENHANCE
61     void shapeProcessUtf(const char* utf8, size_t utf8Bytes, SkScalar width, RunHandler* handler,
62         RSFont font, std::unique_ptr<SkGlyphID[]>& glyphs, std::unique_ptr<SkScalar[]>& advances) const;
63 #endif
64 };
65 
is_breaking_whitespace(SkUnichar c)66 static inline bool is_breaking_whitespace(SkUnichar c) {
67     switch (c) {
68         case 0x0020: // SPACE
69         //case 0x00A0: // NO-BREAK SPACE
70         case 0x1680: // OGHAM SPACE MARK
71         case 0x180E: // MONGOLIAN VOWEL SEPARATOR
72         case 0x2000: // EN QUAD
73         case 0x2001: // EM QUAD
74         case 0x2002: // EN SPACE (nut)
75         case 0x2003: // EM SPACE (mutton)
76         case 0x2004: // THREE-PER-EM SPACE (thick space)
77         case 0x2005: // FOUR-PER-EM SPACE (mid space)
78         case 0x2006: // SIX-PER-EM SPACE
79         case 0x2007: // FIGURE SPACE
80         case 0x2008: // PUNCTUATION SPACE
81         case 0x2009: // THIN SPACE
82         case 0x200A: // HAIR SPACE
83         case 0x200B: // ZERO WIDTH SPACE
84         case 0x202F: // NARROW NO-BREAK SPACE
85         case 0x205F: // MEDIUM MATHEMATICAL SPACE
86         case 0x3000: // IDEOGRAPHIC SPACE
87         //case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
88             return true;
89         default:
90             return false;
91     }
92 }
93 
linebreak(const char text[],const char stop[],const RSFont & font,SkScalar width,SkScalar * advance,size_t * trailing)94 static size_t linebreak(const char text[], const char stop[],
95 #ifdef ENABLE_TEXT_ENHANCE
96                         const RSFont& font, SkScalar width,
97 #else
98                         const SkFont& font, SkScalar width,
99 #endif
100                         SkScalar* advance,
101                         size_t* trailing)
102 {
103     SkScalar accumulatedWidth = 0;
104     int glyphIndex = 0;
105     const char* start = text;
106     const char* wordStart = text;
107     bool prevWS = true;
108     *trailing = 0;
109 
110     while (text < stop) {
111         const char* prevText = text;
112         SkUnichar uni = SkUTF::NextUTF8(&text, stop);
113         accumulatedWidth += advance[glyphIndex++];
114         bool currWS = is_breaking_whitespace(uni);
115 
116         if (!currWS && prevWS) {
117             wordStart = prevText;
118         }
119         prevWS = currWS;
120 
121         if (width < accumulatedWidth) {
122             bool consumeWhitespace = false;
123             if (currWS) {
124                 // previous fit, put this and following whitespace in trailing
125                 if (prevText == start) {
126                     // don't put this in trailing if it's the first thing
127                     prevText = text;
128                 }
129                 consumeWhitespace = true;
130             } else if (wordStart != start) {
131                 // backup to the last whitespace that fit
132                 text = wordStart;
133             } else if (prevText > start) {
134                 // backup to just before the glyph that didn't fit
135                 text = prevText;
136             } else {
137                 // let it overflow, put any following whitespace in trailing
138                 prevText = text;
139                 consumeWhitespace = true;
140             }
141             if (consumeWhitespace) {
142                 const char* next = text;
143                 while (next < stop && is_breaking_whitespace(SkUTF::NextUTF8(&next, stop))) {
144                     text = next;
145                 }
146                 if (trailing) {
147                     *trailing = text - prevText;
148                 }
149             }
150             break;
151         }
152     }
153 
154     return text - start;
155 }
156 
157 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
shape(const char * utf8,size_t utf8Bytes,FontRunIterator & font,BiDiRunIterator & bidi,ScriptRunIterator & script,LanguageRunIterator & lang,SkScalar width,RunHandler * handler) const158 void SkShaperPrimitive::shape(const char* utf8,
159                               size_t utf8Bytes,
160                               FontRunIterator& font,
161                               BiDiRunIterator& bidi,
162                               ScriptRunIterator& script,
163                               LanguageRunIterator& lang,
164                               SkScalar width,
165                               RunHandler* handler) const {
166     return this->shape(utf8, utf8Bytes, font, bidi, script, lang, nullptr, 0, width, handler);
167 }
168 
shape(const char * utf8,size_t utf8Bytes,const RSFont & font,bool leftToRight,SkScalar width,RunHandler * handler) const169 void SkShaperPrimitive::shape(const char* utf8,
170                               size_t utf8Bytes,
171 #ifdef ENABLE_TEXT_ENHANCE
172                               const RSFont& font,
173 #else
174                               const SkFont& font,
175 #endif
176                               bool leftToRight,
177                               SkScalar width,
178                               RunHandler* handler) const {
179     std::unique_ptr<FontRunIterator> fontRuns(
180             MakeFontMgrRunIterator(utf8, utf8Bytes, font, nullptr));
181     if (!fontRuns) {
182         return;
183     }
184     // bidi, script, and lang are all unused so we can construct them with empty data.
185     TrivialBiDiRunIterator bidi{0, 0};
186     TrivialScriptRunIterator script{0, 0};
187     TrivialLanguageRunIterator lang{nullptr, 0};
188     return this->shape(utf8, utf8Bytes, *fontRuns, bidi, script, lang, nullptr, 0, width, handler);
189 }
190 #endif
191 
192 #ifdef ENABLE_TEXT_ENHANCE
shapeProcessUtf(const char * utf8,size_t utf8Bytes,SkScalar width,RunHandler * handler,RSFont font,std::unique_ptr<SkGlyphID[]> & glyphs,std::unique_ptr<SkScalar[]> & advances) const193 void SkShaperPrimitive::shapeProcessUtf(const char* utf8, size_t utf8Bytes, SkScalar width, RunHandler* handler,
194     RSFont font, std::unique_ptr<SkGlyphID[]>& glyphs, std::unique_ptr<SkScalar[]>& advances) const {
195     size_t glyphOffset = 0;
196     size_t utf8Offset = 0;
197     do {
198         size_t bytesCollapsed;
199         size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width,
200                                          advances.get() + glyphOffset, &bytesCollapsed);
201         size_t bytesVisible = bytesConsumed - bytesCollapsed;
202 
203         size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible);
204         const RunHandler::RunInfo info = {
205             font,
206             0,
207             { font.MeasureText(utf8, bytesVisible, RSDrawing::TextEncoding::UTF8), 0 },
208             numGlyphs,
209             RunHandler::Range(utf8Offset, bytesVisible)
210         };
211         handler->beginLine();
212         if (info.glyphCount) {
213             handler->runInfo(info);
214         }
215         handler->commitRunInfo();
216         if (info.glyphCount) {
217             const auto buffer = handler->runBuffer(info);
218 
219             memcpy(buffer.glyphs, glyphs.get() + glyphOffset, info.glyphCount * sizeof(SkGlyphID));
220             SkPoint position = buffer.point;
221             for (size_t i = 0; i < info.glyphCount; ++i) {
222                 buffer.positions[i] = position;
223                 position.fX += advances[i + glyphOffset];
224             }
225             if (buffer.clusters) {
226                 const char* txtPtr = utf8;
227                 for (size_t i = 0; i < info.glyphCount; ++i) {
228                     // Each character maps to exactly one glyph.
229                     buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset);
230                     SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes);
231                 }
232             }
233             handler->commitRunBuffer(info);
234         }
235         handler->commitLine();
236 
237         glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed);
238         utf8Offset += bytesConsumed;
239         utf8 += bytesConsumed;
240         utf8Bytes -= bytesConsumed;
241     } while (0 < utf8Bytes);
242 }
243 #endif
244 
shape(const char * utf8,size_t utf8Bytes,FontRunIterator & fontRuns,BiDiRunIterator &,ScriptRunIterator &,LanguageRunIterator &,const Feature *,size_t,SkScalar width,RunHandler * handler) const245 void SkShaperPrimitive::shape(const char* utf8,
246                               size_t utf8Bytes,
247                               FontRunIterator& fontRuns,
248                               BiDiRunIterator&,
249                               ScriptRunIterator&,
250                               LanguageRunIterator&,
251                               const Feature*,
252                               size_t,
253                               SkScalar width,
254                               RunHandler* handler) const {
255 #ifdef ENABLE_TEXT_ENHANCE
256     RSFont font;
257     if (!fontRuns.atEnd()) {
258         fontRuns.consume();
259         font = fontRuns.currentFont();
260     }
261     SkASSERT(font.getTypeface());
262 
263     int glyphCount = font.CountText(utf8, utf8Bytes, RSDrawing::TextEncoding::UTF8);
264     if (glyphCount < 0) {
265         return;
266     }
267 
268     std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]);
269     font.TextToGlyphs(utf8, utf8Bytes, RSDrawing::TextEncoding::UTF8, glyphs.get(), glyphCount);
270 
271     std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]);
272     font.GetWidths(glyphs.get(), glyphCount, advances.get(), nullptr);
273 
274     shapeProcessUtf(utf8, utf8Bytes, width, handler, font, glyphs, advances);
275 }
276 #else
277     SkFont font;
278     if (!fontRuns.atEnd()) {
279         fontRuns.consume();
280         font = fontRuns.currentFont();
281     }
282     SkASSERT(font.getTypeface());
283 
284     int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8);
285     if (glyphCount < 0) {
286         return;
287     }
288 
289     std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]);
290     font.textToGlyphs(utf8, utf8Bytes, SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
291 
292     std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]);
293     font.getWidthsBounds(glyphs.get(), glyphCount, advances.get(), nullptr, nullptr);
294 
295     size_t glyphOffset = 0;
296     size_t utf8Offset = 0;
297     do {
298         size_t bytesCollapsed;
299         size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width,
300                                          advances.get() + glyphOffset, &bytesCollapsed);
301         size_t bytesVisible = bytesConsumed - bytesCollapsed;
302 
303         size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible);
304         const RunHandler::RunInfo info = {
305             font,
306             0,
307             { font.measureText(utf8, bytesVisible, SkTextEncoding::kUTF8), 0 },
308             numGlyphs,
309             RunHandler::Range(utf8Offset, bytesVisible)
310         };
311         handler->beginLine();
312         if (info.glyphCount) {
313             handler->runInfo(info);
314         }
315         handler->commitRunInfo();
316         if (info.glyphCount) {
317             const auto buffer = handler->runBuffer(info);
318 
319             memcpy(buffer.glyphs, glyphs.get() + glyphOffset, info.glyphCount * sizeof(SkGlyphID));
320             SkPoint position = buffer.point;
321             for (size_t i = 0; i < info.glyphCount; ++i) {
322                 buffer.positions[i] = position;
323                 position.fX += advances[i + glyphOffset];
324             }
325             if (buffer.clusters) {
326                 const char* txtPtr = utf8;
327                 for (size_t i = 0; i < info.glyphCount; ++i) {
328                     // Each character maps to exactly one glyph.
329                     buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset);
330                     SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes);
331                 }
332             }
333             handler->commitRunBuffer(info);
334         }
335         handler->commitLine();
336 
337         glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed);
338         utf8Offset += bytesConsumed;
339         utf8 += bytesConsumed;
340         utf8Bytes -= bytesConsumed;
341     } while (0 < utf8Bytes);
342 }
343 #endif
344 
345 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
MakePrimitive()346 std::unique_ptr<SkShaper> SkShaper::MakePrimitive() { return SkShapers::Primitive::PrimitiveText(); }
347 #endif
348 
349 namespace SkShapers::Primitive {
PrimitiveText()350 std::unique_ptr<SkShaper> PrimitiveText() { return std::make_unique<SkShaperPrimitive>(); }
351 }  // namespace SkShapers
352 #ifdef ENABLE_DRAWING_ADAPTER
353 } // namespace SkiaRsText
354 #endif // ENABLE_DRAWING_ADAPTER
355