Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 */
7
16#include "src/base/SkUTF.h"
17
18#include <cstdint>
19#include <cstring>
20#include <memory>
21
23public:
25private:
26#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
27 void shape(const char* utf8, size_t utf8Bytes,
28 const SkFont& srcFont,
29 bool leftToRight,
31 RunHandler*) const override;
32
33 void shape(const char* utf8, size_t utf8Bytes,
34 FontRunIterator&,
35 BiDiRunIterator&,
36 ScriptRunIterator&,
37 LanguageRunIterator&,
39 RunHandler*) const override;
40#endif
41
42 void shape(const char* utf8, size_t utf8Bytes,
43 FontRunIterator&,
44 BiDiRunIterator&,
45 ScriptRunIterator&,
46 LanguageRunIterator&,
47 const Feature*, size_t featureSize,
49 RunHandler*) const override;
50};
51
52static inline bool is_breaking_whitespace(SkUnichar c) {
53 switch (c) {
54 case 0x0020: // SPACE
55 //case 0x00A0: // NO-BREAK SPACE
56 case 0x1680: // OGHAM SPACE MARK
57 case 0x180E: // MONGOLIAN VOWEL SEPARATOR
58 case 0x2000: // EN QUAD
59 case 0x2001: // EM QUAD
60 case 0x2002: // EN SPACE (nut)
61 case 0x2003: // EM SPACE (mutton)
62 case 0x2004: // THREE-PER-EM SPACE (thick space)
63 case 0x2005: // FOUR-PER-EM SPACE (mid space)
64 case 0x2006: // SIX-PER-EM SPACE
65 case 0x2007: // FIGURE SPACE
66 case 0x2008: // PUNCTUATION SPACE
67 case 0x2009: // THIN SPACE
68 case 0x200A: // HAIR SPACE
69 case 0x200B: // ZERO WIDTH SPACE
70 case 0x202F: // NARROW NO-BREAK SPACE
71 case 0x205F: // MEDIUM MATHEMATICAL SPACE
72 case 0x3000: // IDEOGRAPHIC SPACE
73 //case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
74 return true;
75 default:
76 return false;
77 }
78}
79
80static size_t linebreak(const char text[], const char stop[],
81 const SkFont& font, SkScalar width,
82 SkScalar* advance,
83 size_t* trailing)
84{
85 SkScalar accumulatedWidth = 0;
86 int glyphIndex = 0;
87 const char* start = text;
88 const char* wordStart = text;
89 bool prevWS = true;
90 *trailing = 0;
91
92 while (text < stop) {
93 const char* prevText = text;
94 SkUnichar uni = SkUTF::NextUTF8(&text, stop);
95 accumulatedWidth += advance[glyphIndex++];
96 bool currWS = is_breaking_whitespace(uni);
97
98 if (!currWS && prevWS) {
99 wordStart = prevText;
100 }
101 prevWS = currWS;
102
103 if (width < accumulatedWidth) {
104 bool consumeWhitespace = false;
105 if (currWS) {
106 // previous fit, put this and following whitespace in trailing
107 if (prevText == start) {
108 // don't put this in trailing if it's the first thing
109 prevText = text;
110 }
111 consumeWhitespace = true;
112 } else if (wordStart != start) {
113 // backup to the last whitespace that fit
114 text = wordStart;
115 } else if (prevText > start) {
116 // backup to just before the glyph that didn't fit
117 text = prevText;
118 } else {
119 // let it overflow, put any following whitespace in trailing
120 prevText = text;
121 consumeWhitespace = true;
122 }
123 if (consumeWhitespace) {
124 const char* next = text;
125 while (next < stop && is_breaking_whitespace(SkUTF::NextUTF8(&next, stop))) {
126 text = next;
127 }
128 if (trailing) {
129 *trailing = text - prevText;
130 }
131 }
132 break;
133 }
134 }
135
136 return text - start;
137}
138
139#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
140void SkShaperPrimitive::shape(const char* utf8,
141 size_t utf8Bytes,
142 FontRunIterator& font,
143 BiDiRunIterator& bidi,
144 ScriptRunIterator& script,
147 RunHandler* handler) const {
148 return this->shape(utf8, utf8Bytes, font, bidi, script, lang, nullptr, 0, width, handler);
149}
150
151void SkShaperPrimitive::shape(const char* utf8,
152 size_t utf8Bytes,
153 const SkFont& font,
154 bool leftToRight,
156 RunHandler* handler) const {
157 std::unique_ptr<FontRunIterator> fontRuns(
158 MakeFontMgrRunIterator(utf8, utf8Bytes, font, nullptr));
159 if (!fontRuns) {
160 return;
161 }
162 // bidi, script, and lang are all unused so we can construct them with empty data.
163 TrivialBiDiRunIterator bidi{0, 0};
164 TrivialScriptRunIterator script{0, 0};
165 TrivialLanguageRunIterator lang{nullptr, 0};
166 return this->shape(utf8, utf8Bytes, *fontRuns, bidi, script, lang, nullptr, 0, width, handler);
167}
168#endif
169
170void SkShaperPrimitive::shape(const char* utf8,
171 size_t utf8Bytes,
172 FontRunIterator& fontRuns,
176 const Feature*,
177 size_t,
179 RunHandler* handler) const {
180 SkFont font;
181 if (!fontRuns.atEnd()) {
182 fontRuns.consume();
183 font = fontRuns.currentFont();
184 }
185 SkASSERT(font.getTypeface());
186
187 int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8);
188 if (glyphCount < 0) {
189 return;
190 }
191
192 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]);
193 font.textToGlyphs(utf8, utf8Bytes, SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
194
195 std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]);
196 font.getWidthsBounds(glyphs.get(), glyphCount, advances.get(), nullptr, nullptr);
197
198 size_t glyphOffset = 0;
199 size_t utf8Offset = 0;
200 do {
201 size_t bytesCollapsed;
202 size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width,
203 advances.get() + glyphOffset, &bytesCollapsed);
204 size_t bytesVisible = bytesConsumed - bytesCollapsed;
205
206 size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible);
207 const RunHandler::RunInfo info = {
208 font,
209 0,
210 { font.measureText(utf8, bytesVisible, SkTextEncoding::kUTF8), 0 },
211 numGlyphs,
212 RunHandler::Range(utf8Offset, bytesVisible)
213 };
214 handler->beginLine();
215 if (info.glyphCount) {
216 handler->runInfo(info);
217 }
218 handler->commitRunInfo();
219 if (info.glyphCount) {
220 const auto buffer = handler->runBuffer(info);
221
222 memcpy(buffer.glyphs, glyphs.get() + glyphOffset, info.glyphCount * sizeof(SkGlyphID));
223 SkPoint position = buffer.point;
224 for (size_t i = 0; i < info.glyphCount; ++i) {
225 buffer.positions[i] = position;
226 position.fX += advances[i + glyphOffset];
227 }
228 if (buffer.clusters) {
229 const char* txtPtr = utf8;
230 for (size_t i = 0; i < info.glyphCount; ++i) {
231 // Each character maps to exactly one glyph.
232 buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset);
233 SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes);
234 }
235 }
236 handler->commitRunBuffer(info);
237 }
238 handler->commitLine();
239
240 glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed);
241 utf8Offset += bytesConsumed;
242 utf8 += bytesConsumed;
243 utf8Bytes -= bytesConsumed;
244 } while (0 < utf8Bytes);
245}
246
247#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
248std::unique_ptr<SkShaper> SkShaper::MakePrimitive() { return SkShapers::Primitive::PrimitiveText(); }
249#endif
250
251namespace SkShapers::Primitive {
252std::unique_ptr<SkShaper> PrimitiveText() { return std::make_unique<SkShaperPrimitive>(); }
253} // namespace SkShapers
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
uint16_t glyphs[5]
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
void shape(const char *utf8, size_t utf8Bytes, const SkFont &srcFont, bool leftToRight, SkScalar width, RunHandler *) const override
virtual const SkFont & currentFont() const =0
virtual void commitLine()=0
Definition shape.cpp:201
virtual void commitRunBuffer(const RunInfo &)=0
Definition shape.cpp:176
virtual void commitRunInfo()=0
Definition shape.cpp:150
virtual void runInfo(const RunInfo &)=0
Definition shape.cpp:142
virtual void beginLine()=0
Definition shape.cpp:135
virtual Buffer runBuffer(const RunInfo &)=0
Definition shape.cpp:154
virtual bool atEnd() const =0
virtual void consume()=0
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
static const uint8_t buffer[]
std::u16string text
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
int32_t width
float fX
x-axis value