blob: 30b7c7aff213e5c6b8b02eb3cfab5cdd1884d61b [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 Reed9a4a05e2019-01-21 20:42:04 -05008#include "SkFontMetrics.h"
Ben Wagnerb0591942019-02-15 14:46:18 -05009#include "SkMakeUnique.h"
10#include "SkShaper.h"
halcanary13cba492016-08-03 10:43:55 -070011#include "SkStream.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040012#include "SkTo.h"
halcanary13cba492016-08-03 10:43:55 -070013#include "SkTypeface.h"
Ben Wagner50becee2019-02-12 10:41:16 -050014#include "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 Wagnerb0591942019-02-15 14:46:18 -050033};
halcanary13cba492016-08-03 10:43:55 -070034
Ben Wagnerb0591942019-02-15 14:46:18 -050035std::unique_ptr<SkShaper> SkShaper::MakePrimitive() {
36 return skstd::make_unique<SkShaperPrimitive>();
37}
halcanary13cba492016-08-03 10:43:55 -070038
Ben Wagner50becee2019-02-12 10:41:16 -050039static inline bool is_breaking_whitespace(SkUnichar c) {
40 switch (c) {
41 case 0x0020: // SPACE
42 //case 0x00A0: // NO-BREAK SPACE
43 case 0x1680: // OGHAM SPACE MARK
44 case 0x180E: // MONGOLIAN VOWEL SEPARATOR
45 case 0x2000: // EN QUAD
46 case 0x2001: // EM QUAD
47 case 0x2002: // EN SPACE (nut)
48 case 0x2003: // EM SPACE (mutton)
49 case 0x2004: // THREE-PER-EM SPACE (thick space)
50 case 0x2005: // FOUR-PER-EM SPACE (mid space)
51 case 0x2006: // SIX-PER-EM SPACE
52 case 0x2007: // FIGURE SPACE
53 case 0x2008: // PUNCTUATION SPACE
54 case 0x2009: // THIN SPACE
55 case 0x200A: // HAIR SPACE
56 case 0x200B: // ZERO WIDTH SPACE
57 case 0x202F: // NARROW NO-BREAK SPACE
58 case 0x205F: // MEDIUM MATHEMATICAL SPACE
59 case 0x3000: // IDEOGRAPHIC SPACE
60 //case 0xFEFF: // ZERO WIDTH NO-BREAK SPACE
61 return true;
62 default:
63 return false;
64 }
65}
66
67static size_t linebreak(const char text[], const char stop[],
68 const SkFont& font, SkScalar width,
69 SkScalar* advance,
70 size_t* trailing)
71{
72 SkScalar accumulatedWidth = 0;
73 int glyphIndex = 0;
74 const char* start = text;
75 const char* word_start = text;
76 bool prevWS = true;
77 *trailing = 0;
78
79 while (text < stop) {
80 const char* prevText = text;
81 SkUnichar uni = SkUTF::NextUTF8(&text, stop);
82 accumulatedWidth += advance[glyphIndex++];
83 bool currWS = is_breaking_whitespace(uni);
84
85 if (!currWS && prevWS) {
86 word_start = prevText;
87 }
88 prevWS = currWS;
89
90 if (width < accumulatedWidth) {
91 if (currWS) {
92 // eat the rest of the whitespace
93 const char* next = text;
94 while (next < stop && is_breaking_whitespace(SkUTF::NextUTF8(&next, stop))) {
95 text = next;
96 }
97 if (trailing) {
98 *trailing = text - prevText;
99 }
100 } else {
101 // backup until a whitespace (or 1 char)
102 if (word_start == start) {
103 if (prevText > start) {
104 text = prevText;
105 }
106 } else {
107 text = word_start;
108 }
109 }
110 break;
111 }
Ben Wagner50becee2019-02-12 10:41:16 -0500112 }
113
114 return text - start;
halcanary3eee9d92016-09-10 07:01:53 -0700115}
116
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400117void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
118 FontRunIterator& font,
119 BiDiRunIterator& bidi,
120 ScriptRunIterator&,
121 LanguageRunIterator& ,
122 SkScalar width,
123 RunHandler* handler) const
Ben Wagner1e08a7c2019-03-27 15:37:13 -0400124{
125 font.consume();
126 bidi.consume();
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400127 return this->shape(utf8, utf8Bytes, font.currentFont(), (bidi.currentLevel() % 2) == 0,
128 width, handler);
Ben Wagner1e08a7c2019-03-27 15:37:13 -0400129}
130
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400131void SkShaperPrimitive::shape(const char* utf8, size_t utf8Bytes,
132 const SkFont& font,
133 bool leftToRight,
134 SkScalar width,
135 RunHandler* handler) const {
Ben Wagnera25fbef2017-08-30 13:56:19 -0400136 sk_ignore_unused_variable(leftToRight);
137
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400138 int glyphCount = font.countText(utf8, utf8Bytes, SkTextEncoding::kUTF8);
halcanary13cba492016-08-03 10:43:55 -0700139 if (glyphCount <= 0) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400140 return;
halcanary13cba492016-08-03 10:43:55 -0700141 }
Florin Malita9867f612018-12-12 10:54:49 -0500142
Ben Wagner50becee2019-02-12 10:41:16 -0500143 std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[glyphCount]);
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400144 font.textToGlyphs(utf8, utf8Bytes, SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
Ben Wagner50becee2019-02-12 10:41:16 -0500145
146 std::unique_ptr<SkScalar[]> advances(new SkScalar[glyphCount]);
147 font.getWidthsBounds(glyphs.get(), glyphCount, advances.get(), nullptr, nullptr);
148
Ben Wagner50becee2019-02-12 10:41:16 -0500149 size_t glyphOffset = 0;
150 size_t utf8Offset = 0;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400151 while (0 < utf8Bytes) {
Ben Wagner50becee2019-02-12 10:41:16 -0500152 size_t bytesCollapsed;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400153 size_t bytesConsumed = linebreak(utf8, utf8 + utf8Bytes, font, width,
Ben Wagner50becee2019-02-12 10:41:16 -0500154 advances.get() + glyphOffset, &bytesCollapsed);
155 size_t bytesVisible = bytesConsumed - bytesCollapsed;
156
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400157 size_t numGlyphs = SkUTF::CountUTF8(utf8, bytesVisible);
Ben Wagner50becee2019-02-12 10:41:16 -0500158 const RunHandler::RunInfo info = {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400159 font,
160 0,
161 { font.measureText(utf8, bytesVisible, SkTextEncoding::kUTF8), 0 },
162 numGlyphs,
163 RunHandler::Range(utf8Offset, bytesVisible)
Ben Wagner50becee2019-02-12 10:41:16 -0500164 };
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400165 handler->beginLine();
166 handler->runInfo(info);
167 handler->commitRunInfo();
168 const auto buffer = handler->runBuffer(info);
Ben Wagner50becee2019-02-12 10:41:16 -0500169
170 memcpy(buffer.glyphs, glyphs.get() + glyphOffset, numGlyphs * sizeof(SkGlyphID));
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400171 SkPoint position = buffer.point;
172 for (size_t i = 0; i < numGlyphs; ++i) {
173 buffer.positions[i] = position;
174 position.fX += advances[i + glyphOffset];
Florin Malita9867f612018-12-12 10:54:49 -0500175 }
Ben Wagner50becee2019-02-12 10:41:16 -0500176 if (buffer.clusters) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400177 const char* txtPtr = utf8;
178 for (size_t i = 0; i < numGlyphs; ++i) {
Ben Wagner50becee2019-02-12 10:41:16 -0500179 // Each character maps to exactly one glyph.
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400180 buffer.clusters[i] = SkToU32(txtPtr - utf8 + utf8Offset);
181 SkUTF::NextUTF8(&txtPtr, utf8 + utf8Bytes);
Ben Wagner50becee2019-02-12 10:41:16 -0500182 }
183 }
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400184 handler->commitRunBuffer(info);
Ben Wagner50becee2019-02-12 10:41:16 -0500185 handler->commitLine();
Florin Malita500133b2019-02-07 10:56:55 -0500186
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400187 glyphOffset += SkUTF::CountUTF8(utf8, bytesConsumed);
Ben Wagner50becee2019-02-12 10:41:16 -0500188 utf8Offset += bytesConsumed;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400189 utf8 += bytesConsumed;
190 utf8Bytes -= bytesConsumed;
Ben Wagner50becee2019-02-12 10:41:16 -0500191 }
192
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400193 return;
halcanary13cba492016-08-03 10:43:55 -0700194}