blob: fffeefa124e3b4d1f3dbda96acf77a69945937e4 [file] [log] [blame]
halcanary13cba492016-08-03 10:43:55 -07001/*
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 */
Hal Canaryc640d0d2018-06-13 09:59:02 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#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/core/SkMakeUnique.h"
14#include "src/utils/SkUTF.h"
halcanary13cba492016-08-03 10:43:55 -070015
Ben Wagnerb0591942019-02-15 14:46:18 -050016class SkShaperPrimitive : public SkShaper {
17public:
18 SkShaperPrimitive() {}
19private:
Ben Wagner3bdb69c2019-04-01 19:01:09 -040020 void shape(const char* utf8, size_t utf8Bytes,
21 const SkFont& srcFont,
22 bool leftToRight,
23 SkScalar width,
24 RunHandler*) const override;
Ben Wagner1e08a7c2019-03-27 15:37:13 -040025
Ben Wagner3bdb69c2019-04-01 19:01:09 -040026 void shape(const char* utf8, size_t utf8Bytes,
27 FontRunIterator&,
28 BiDiRunIterator&,
29 ScriptRunIterator&,
30 LanguageRunIterator&,
31 SkScalar width,
32 RunHandler*) const override;
Ben Wagner24ee4e02019-10-11 10:36:10 -040033
34 void shape(const char* utf8, size_t utf8Bytes,
35 FontRunIterator&,
36 BiDiRunIterator&,
37 ScriptRunIterator&,
38 LanguageRunIterator&,
39 const Feature*, size_t featureSize,
40 SkScalar width,
41 RunHandler*) const override;
Ben Wagnerb0591942019-02-15 14:46:18 -050042};
halcanary13cba492016-08-03 10:43:55 -070043
Ben Wagnerb0591942019-02-15 14:46:18 -050044std::unique_ptr<SkShaper> SkShaper::MakePrimitive() {
45 return skstd::make_unique<SkShaperPrimitive>();
46}
halcanary13cba492016-08-03 10:43:55 -070047
Ben Wagner50becee2019-02-12 10:41:16 -050048static inline bool is_breaking_whitespace(SkUnichar c) {
49 switch (c) {
50 case 0x0020: // SPACE
51 //case 0x00A0: // NO-BREAK SPACE
52 case 0x1680: // OGHAM SPACE MARK
53 case 0x180E: // MONGOLIAN VOWEL SEPARATOR
54 case 0x2000: // EN QUAD
55 case 0x2001: // EM QUAD
56 case 0x2002: // EN SPACE (nut)
57 case 0x2003: // EM SPACE (mutton)
58 case 0x2004: // THREE-PER-EM SPACE (thick space)
59 case 0x2005: // FOUR-PER-EM SPACE (mid space)
60 case 0x2006: // SIX-PER-EM SPACE
61 case 0x2007: // FIGURE SPACE
62 case 0x2008: // PUNCTUATION SPACE
63 case 0x2009: // THIN SPACE
64 case 0x200A: // HAIR SPACE
65 case 0x200B: // ZERO WIDTH SPACE
66 case 0x202F: // NARROW NO-BREAK SPACE
67 case 0x205F: // MEDIUM MATHEMATICAL SPACE
68 case 0x3000: // IDEOGRAPHIC SPACE
69 //case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
70 return true;
71 default:
72 return false;
73 }
74}
75
76static size_t linebreak(const char text[], const char stop[],
77 const SkFont& font, SkScalar width,
78 SkScalar* advance,
79 size_t* trailing)
80{
81 SkScalar accumulatedWidth = 0;
82 int glyphIndex = 0;
83 const char* start = text;
84 const char* word_start = text;
85 bool prevWS = true;
86 *trailing = 0;
87
88 while (text < stop) {
89 const char* prevText = text;
90 SkUnichar uni = SkUTF::NextUTF8(&text, stop);
91 accumulatedWidth += advance[glyphIndex++];
92 bool currWS = is_breaking_whitespace(uni);
93
94 if (!currWS && prevWS) {
95 word_start = prevText;
96 }
97 prevWS = currWS;
98
99 if (width < accumulatedWidth) {
100 if (currWS) {
101 // eat the rest of the whitespace
102 const char* next = text;
103 while (next < stop && is_breaking_whitespace(SkUTF::NextUTF8(&next, stop))) {
104 text = next;
105 }
106 if (trailing) {
107 *trailing = text - prevText;
108 }
109 } else {
110 // backup until a whitespace (or 1 char)
111 if (word_start == start) {
112 if (prevText > start) {
113 text = prevText;
114 }
115 } else {
116 text = word_start;
117 }
118 }
119 break;
120 }
Ben Wagner50becee2019-02-12 10:41:16 -0500121 }
122
123 return text - start;
halcanary3eee9d92016-09-10 07:01:53 -0700124}
125
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400126void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
127 FontRunIterator& font,
128 BiDiRunIterator& bidi,
129 ScriptRunIterator&,
Ben Wagnere8db3252019-05-29 18:54:26 -0400130 LanguageRunIterator&,
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400131 SkScalar width,
132 RunHandler* handler) const
Ben Wagner1e08a7c2019-03-27 15:37:13 -0400133{
Ben Wagnerda53dd52019-11-05 17:29:16 -0500134 SkFont skfont;
135 if (!font.atEnd()) {
136 font.consume();
137 skfont = font.currentFont();
138 } else {
139 skfont.setTypeface(sk_ref_sp(skfont.getTypefaceOrDefault()));
140 }
141 SkASSERT(skfont.getTypeface());
142 bool skbidi = 0;
143 if (!bidi.atEnd()) {
144 bidi.consume();
145 skbidi = (bidi.currentLevel() % 2) == 0;
146 }
147 return this->shape(utf8, utf8Bytes, skfont, skbidi, width, handler);
Ben Wagner1e08a7c2019-03-27 15:37:13 -0400148}
149
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400150void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
Ben Wagner24ee4e02019-10-11 10:36:10 -0400151 FontRunIterator& font,
152 BiDiRunIterator& bidi,
153 ScriptRunIterator&,
154 LanguageRunIterator&,
155 const Feature*, size_t,
156 SkScalar width,
157 RunHandler* handler) const {
158 font.consume();
159 SkASSERT(font.currentFont().getTypeface());
160 bidi.consume();
161 return this->shape(utf8, utf8Bytes, font.currentFont(), (bidi.currentLevel() % 2) == 0,
162 width, handler);
163}
164
165void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400166 const SkFont& font,
167 bool leftToRight,
168 SkScalar width,
169 RunHandler* handler) const {
Ben Wagnera25fbef2017-08-30 13:56:19 -0400170 sk_ignore_unused_variable(leftToRight);
171
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400172 int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8);
halcanary13cba492016-08-03 10:43:55 -0700173 if (glyphCount <= 0) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400174 return;
halcanary13cba492016-08-03 10:43:55 -0700175 }
Florin Malita9867f612018-12-12 10:54:49 -0500176
Ben Wagner50becee2019-02-12 10:41:16 -0500177 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]);
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400178 font.textToGlyphs(utf8, utf8Bytes, SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
Ben Wagner50becee2019-02-12 10:41:16 -0500179
180 std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]);
181 font.getWidthsBounds(glyphs.get(), glyphCount, advances.get(), nullptr, nullptr);
182
Ben Wagner50becee2019-02-12 10:41:16 -0500183 size_t glyphOffset = 0;
184 size_t utf8Offset = 0;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400185 while (0 < utf8Bytes) {
Ben Wagner50becee2019-02-12 10:41:16 -0500186 size_t bytesCollapsed;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400187 size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width,
Ben Wagner50becee2019-02-12 10:41:16 -0500188 advances.get() + glyphOffset, &bytesCollapsed);
189 size_t bytesVisible = bytesConsumed - bytesCollapsed;
190
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400191 size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible);
Ben Wagner50becee2019-02-12 10:41:16 -0500192 const RunHandler::RunInfo info = {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400193 font,
194 0,
195 { font.measureText(utf8, bytesVisible, SkTextEncoding::kUTF8), 0 },
196 numGlyphs,
197 RunHandler::Range(utf8Offset, bytesVisible)
Ben Wagner50becee2019-02-12 10:41:16 -0500198 };
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400199 handler->beginLine();
200 handler->runInfo(info);
201 handler->commitRunInfo();
202 const auto buffer = handler->runBuffer(info);
Ben Wagner50becee2019-02-12 10:41:16 -0500203
204 memcpy(buffer.glyphs, glyphs.get() + glyphOffset, numGlyphs * sizeof(SkGlyphID));
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400205 SkPoint position = buffer.point;
206 for (size_t i = 0; i < numGlyphs; ++i) {
207 buffer.positions[i] = position;
208 position.fX += advances[i + glyphOffset];
Florin Malita9867f612018-12-12 10:54:49 -0500209 }
Ben Wagner50becee2019-02-12 10:41:16 -0500210 if (buffer.clusters) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400211 const char* txtPtr = utf8;
212 for (size_t i = 0; i < numGlyphs; ++i) {
Ben Wagner50becee2019-02-12 10:41:16 -0500213 // Each character maps to exactly one glyph.
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400214 buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset);
215 SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes);
Ben Wagner50becee2019-02-12 10:41:16 -0500216 }
217 }
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400218 handler->commitRunBuffer(info);
Ben Wagner50becee2019-02-12 10:41:16 -0500219 handler->commitLine();
Florin Malita500133b2019-02-07 10:56:55 -0500220
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400221 glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed);
Ben Wagner50becee2019-02-12 10:41:16 -0500222 utf8Offset += bytesConsumed;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400223 utf8 += bytesConsumed;
224 utf8Bytes -= bytesConsumed;
Ben Wagner50becee2019-02-12 10:41:16 -0500225 }
226
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400227 return;
halcanary13cba492016-08-03 10:43:55 -0700228}