Flutter Engine
The Flutter Engine
SkShaper_primitive.cpp
Go to the documentation of this file.
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 */
14#include "src/base/SkUTF.h"
15
16#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
18#endif
19
20#include <cstdint>
21#include <cstring>
22#include <memory>
23
25public:
27private:
28#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
29 void shape(const char* utf8, size_t utf8Bytes,
30 const SkFont& srcFont,
31 bool leftToRight,
33 RunHandler*) const override;
34
35 void shape(const char* utf8, size_t utf8Bytes,
36 FontRunIterator&,
37 BiDiRunIterator&,
39 LanguageRunIterator&,
41 RunHandler*) const override;
42#endif
43
44 void shape(const char* utf8, size_t utf8Bytes,
45 FontRunIterator&,
46 BiDiRunIterator&,
48 LanguageRunIterator&,
49 const Feature*, size_t featureSize,
51 RunHandler*) const override;
52};
53
54static inline bool is_breaking_whitespace(SkUnichar c) {
55 switch (c) {
56 case 0x0020: // SPACE
57 //case 0x00A0: // NO-BREAK SPACE
58 case 0x1680: // OGHAM SPACE MARK
59 case 0x180E: // MONGOLIAN VOWEL SEPARATOR
60 case 0x2000: // EN QUAD
61 case 0x2001: // EM QUAD
62 case 0x2002: // EN SPACE (nut)
63 case 0x2003: // EM SPACE (mutton)
64 case 0x2004: // THREE-PER-EM SPACE (thick space)
65 case 0x2005: // FOUR-PER-EM SPACE (mid space)
66 case 0x2006: // SIX-PER-EM SPACE
67 case 0x2007: // FIGURE SPACE
68 case 0x2008: // PUNCTUATION SPACE
69 case 0x2009: // THIN SPACE
70 case 0x200A: // HAIR SPACE
71 case 0x200B: // ZERO WIDTH SPACE
72 case 0x202F: // NARROW NO-BREAK SPACE
73 case 0x205F: // MEDIUM MATHEMATICAL SPACE
74 case 0x3000: // IDEOGRAPHIC SPACE
75 //case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
76 return true;
77 default:
78 return false;
79 }
80}
81
82static size_t linebreak(const char text[], const char stop[],
83 const SkFont& font, SkScalar width,
84 SkScalar* advance,
85 size_t* trailing)
86{
87 SkScalar accumulatedWidth = 0;
88 int glyphIndex = 0;
89 const char* start = text;
90 const char* wordStart = text;
91 bool prevWS = true;
92 *trailing = 0;
93
94 while (text < stop) {
95 const char* prevText = text;
96 SkUnichar uni = SkUTF::NextUTF8(&text, stop);
97 accumulatedWidth += advance[glyphIndex++];
98 bool currWS = is_breaking_whitespace(uni);
99
100 if (!currWS && prevWS) {
101 wordStart = prevText;
102 }
103 prevWS = currWS;
104
105 if (width < accumulatedWidth) {
106 bool consumeWhitespace = false;
107 if (currWS) {
108 // previous fit, put this and following whitespace in trailing
109 if (prevText == start) {
110 // don't put this in trailing if it's the first thing
111 prevText = text;
112 }
113 consumeWhitespace = true;
114 } else if (wordStart != start) {
115 // backup to the last whitespace that fit
116 text = wordStart;
117 } else if (prevText > start) {
118 // backup to just before the glyph that didn't fit
119 text = prevText;
120 } else {
121 // let it overflow, put any following whitespace in trailing
122 prevText = text;
123 consumeWhitespace = true;
124 }
125 if (consumeWhitespace) {
126 const char* next = text;
127 while (next < stop && is_breaking_whitespace(SkUTF::NextUTF8(&next, stop))) {
128 text = next;
129 }
130 if (trailing) {
131 *trailing = text - prevText;
132 }
133 }
134 break;
135 }
136 }
137
138 return text - start;
139}
140
141#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
142void SkShaperPrimitive::shape(const char* utf8,
143 size_t utf8Bytes,
144 FontRunIterator& font,
145 BiDiRunIterator& bidi,
147 LanguageRunIterator& lang,
149 RunHandler* handler) const {
150 return this->shape(utf8, utf8Bytes, font, bidi, script, lang, nullptr, 0, width, handler);
151}
152
153void SkShaperPrimitive::shape(const char* utf8,
154 size_t utf8Bytes,
155 const SkFont& font,
156 bool leftToRight,
158 RunHandler* handler) const {
159 std::unique_ptr<FontRunIterator> fontRuns(
160 MakeFontMgrRunIterator(utf8, utf8Bytes, font, nullptr));
161 if (!fontRuns) {
162 return;
163 }
164 // bidi, script, and lang are all unused so we can construct them with empty data.
165 TrivialBiDiRunIterator bidi{0, 0};
167 TrivialLanguageRunIterator lang{nullptr, 0};
168 return this->shape(utf8, utf8Bytes, *fontRuns, bidi, script, lang, nullptr, 0, width, handler);
169}
170#endif
171
172void SkShaperPrimitive::shape(const char* utf8,
173 size_t utf8Bytes,
174 FontRunIterator& fontRuns,
175 BiDiRunIterator&,
177 LanguageRunIterator&,
178 const Feature*,
179 size_t,
181 RunHandler* handler) const {
182 SkFont font;
183 if (!fontRuns.atEnd()) {
184 fontRuns.consume();
185 font = fontRuns.currentFont();
186 }
187 SkASSERT(font.getTypeface());
188
189 int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8);
190 if (glyphCount < 0) {
191 return;
192 }
193
194 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]);
195 font.textToGlyphs(utf8, utf8Bytes, SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
196
197 std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]);
198 font.getWidthsBounds(glyphs.get(), glyphCount, advances.get(), nullptr, nullptr);
199
200 size_t glyphOffset = 0;
201 size_t utf8Offset = 0;
202 do {
203 size_t bytesCollapsed;
204 size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width,
205 advances.get() + glyphOffset, &bytesCollapsed);
206 size_t bytesVisible = bytesConsumed - bytesCollapsed;
207
208 size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible);
209 const RunHandler::RunInfo info = {
210 font,
211 0,
212 { font.measureText(utf8, bytesVisible, SkTextEncoding::kUTF8), 0 },
213 numGlyphs,
214 RunHandler::Range(utf8Offset, bytesVisible)
215 };
216 handler->beginLine();
217 if (info.glyphCount) {
218 handler->runInfo(info);
219 }
220 handler->commitRunInfo();
221 if (info.glyphCount) {
222 const auto buffer = handler->runBuffer(info);
223
224 memcpy(buffer.glyphs, glyphs.get() + glyphOffset, info.glyphCount * sizeof(SkGlyphID));
225 SkPoint position = buffer.point;
226 for (size_t i = 0; i < info.glyphCount; ++i) {
227 buffer.positions[i] = position;
228 position.fX += advances[i + glyphOffset];
229 }
230 if (buffer.clusters) {
231 const char* txtPtr = utf8;
232 for (size_t i = 0; i < info.glyphCount; ++i) {
233 // Each character maps to exactly one glyph.
234 buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset);
235 SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes);
236 }
237 }
238 handler->commitRunBuffer(info);
239 }
240 handler->commitLine();
241
242 glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed);
243 utf8Offset += bytesConsumed;
244 utf8 += bytesConsumed;
245 utf8Bytes -= bytesConsumed;
246 } while (0 < utf8Bytes);
247}
248
249#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
250std::unique_ptr<SkShaper> SkShaper::MakePrimitive() { return SkShapers::Primitive::PrimitiveText(); }
251#endif
252
253namespace SkShapers::Primitive {
254std::unique_ptr<SkShaper> PrimitiveText() { return std::make_unique<SkShaperPrimitive>(); }
255} // namespace SkShapers
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
static float next(float f)
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kUTF8
uses bytes to represent UTF-8 or ASCII
static bool is_breaking_whitespace(SkUnichar c)
static size_t linebreak(const char text[], const char stop[], const SkFont &font, SkScalar width, SkScalar *advance, size_t *trailing)
constexpr uint32_t SkToU32(S x)
Definition: SkTo.h:26
int32_t SkUnichar
Definition: SkTypes.h:175
uint16_t SkGlyphID
Definition: SkTypes.h:179
Definition: SkFont.h:35
static std::unique_ptr< FontRunIterator > MakeFontMgrRunIterator(const char *utf8, size_t utf8Bytes, const SkFont &font, sk_sp< SkFontMgr > fallback)
Definition: SkShaper.cpp:187
static std::unique_ptr< SkShaper > MakePrimitive()
float SkScalar
Definition: extension.cpp:12
std::u16string text
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIterator > ScriptRunIterator(const char *utf8, size_t utf8Bytes)
SKSHAPER_API std::unique_ptr< SkShaper::BiDiRunIterator > TrivialBiDiRunIterator(size_t utf8Bytes, uint8_t bidiLevel)
SKSHAPER_API std::unique_ptr< SkShaper > PrimitiveText()
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIterator > TrivialScriptRunIterator(size_t utf8Bytes, SkFourByteTag scriptTag)
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition: SkUTF.cpp:118
SK_SPI int CountUTF8(const char *utf8, size_t byteLength)
Definition: SkUTF.cpp:47
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
font
Font Metadata and Metrics.
int32_t width
float fX
x-axis value
Definition: SkPoint_impl.h:164