1*c8dee2aaSAndroid Build Coastguard Worker // Copyright 2019 Google LLC.
2*c8dee2aaSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skplaintexteditor/src/shape.h"
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMetrics.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMgr.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTextBlob.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTFitsIn.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skplaintexteditor/src/word_boundaries.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skshaper/include/SkShaper.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkUTF.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTextBlobPriv.h"
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
22*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skshaper/include/SkShaper_harfbuzz.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skshaper/include/SkShaper_skunicode.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode.h"
25*c8dee2aaSAndroid Build Coastguard Worker #else
26*c8dee2aaSAndroid Build Coastguard Worker class SkUnicode;
27*c8dee2aaSAndroid Build Coastguard Worker #endif
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
30*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode_icu.h"
31*c8dee2aaSAndroid Build Coastguard Worker #endif
32*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
33*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode_libgrapheme.h"
34*c8dee2aaSAndroid Build Coastguard Worker #endif
35*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
36*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skunicode/include/SkUnicode_icu4x.h"
37*c8dee2aaSAndroid Build Coastguard Worker #endif
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker #include <cfloat>
40*c8dee2aaSAndroid Build Coastguard Worker #include <climits>
41*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
42*c8dee2aaSAndroid Build Coastguard Worker
43*c8dee2aaSAndroid Build Coastguard Worker using namespace SkPlainTextEditor;
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker namespace {
46*c8dee2aaSAndroid Build Coastguard Worker class RunHandler final : public SkShaper::RunHandler {
47*c8dee2aaSAndroid Build Coastguard Worker public:
RunHandler(const char * utf8Text,size_t)48*c8dee2aaSAndroid Build Coastguard Worker RunHandler(const char* utf8Text, size_t) : fUtf8Text(utf8Text) {}
49*c8dee2aaSAndroid Build Coastguard Worker using RunCallback = void (*)(void* context,
50*c8dee2aaSAndroid Build Coastguard Worker const char* utf8Text,
51*c8dee2aaSAndroid Build Coastguard Worker size_t utf8TextBytes,
52*c8dee2aaSAndroid Build Coastguard Worker size_t glyphCount,
53*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID* glyphs,
54*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* positions,
55*c8dee2aaSAndroid Build Coastguard Worker const uint32_t* clusters,
56*c8dee2aaSAndroid Build Coastguard Worker const SkFont& font);
setRunCallback(RunCallback f,void * context)57*c8dee2aaSAndroid Build Coastguard Worker void setRunCallback(RunCallback f, void* context) {
58*c8dee2aaSAndroid Build Coastguard Worker fCallbackContext = context;
59*c8dee2aaSAndroid Build Coastguard Worker fCallbackFunction = f;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> makeBlob();
endPoint() const63*c8dee2aaSAndroid Build Coastguard Worker SkPoint endPoint() const { return fOffset; }
finalPosition() const64*c8dee2aaSAndroid Build Coastguard Worker SkPoint finalPosition() const { return fCurrentPosition; }
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker void beginLine() override;
67*c8dee2aaSAndroid Build Coastguard Worker void runInfo(const RunInfo&) override;
68*c8dee2aaSAndroid Build Coastguard Worker void commitRunInfo() override;
69*c8dee2aaSAndroid Build Coastguard Worker SkShaper::RunHandler::Buffer runBuffer(const RunInfo&) override;
70*c8dee2aaSAndroid Build Coastguard Worker void commitRunBuffer(const RunInfo&) override;
71*c8dee2aaSAndroid Build Coastguard Worker void commitLine() override;
72*c8dee2aaSAndroid Build Coastguard Worker
lineEndOffsets() const73*c8dee2aaSAndroid Build Coastguard Worker const std::vector<size_t>& lineEndOffsets() const { return fLineEndOffsets; }
74*c8dee2aaSAndroid Build Coastguard Worker
finalRect(const SkFont & font) const75*c8dee2aaSAndroid Build Coastguard Worker SkRect finalRect(const SkFont& font) const {
76*c8dee2aaSAndroid Build Coastguard Worker if (0 == fMaxRunAscent || 0 == fMaxRunDescent) {
77*c8dee2aaSAndroid Build Coastguard Worker SkFontMetrics metrics;
78*c8dee2aaSAndroid Build Coastguard Worker font.getMetrics(&metrics);
79*c8dee2aaSAndroid Build Coastguard Worker return {fCurrentPosition.x(),
80*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.y(),
81*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.x() + font.getSize(),
82*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.y() + metrics.fDescent - metrics.fAscent};
83*c8dee2aaSAndroid Build Coastguard Worker } else {
84*c8dee2aaSAndroid Build Coastguard Worker return {fCurrentPosition.x(),
85*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.y() + fMaxRunAscent,
86*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.x() + font.getSize(),
87*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.y() + fMaxRunDescent};
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker private:
93*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder fBuilder;
94*c8dee2aaSAndroid Build Coastguard Worker std::vector<size_t> fLineEndOffsets;
95*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID* fCurrentGlyphs = nullptr;
96*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* fCurrentPoints = nullptr;
97*c8dee2aaSAndroid Build Coastguard Worker void* fCallbackContext = nullptr;
98*c8dee2aaSAndroid Build Coastguard Worker RunCallback fCallbackFunction = nullptr;
99*c8dee2aaSAndroid Build Coastguard Worker char const * const fUtf8Text;
100*c8dee2aaSAndroid Build Coastguard Worker size_t fTextOffset = 0;
101*c8dee2aaSAndroid Build Coastguard Worker uint32_t* fClusters = nullptr;
102*c8dee2aaSAndroid Build Coastguard Worker int fClusterOffset = 0;
103*c8dee2aaSAndroid Build Coastguard Worker int fGlyphCount = 0;
104*c8dee2aaSAndroid Build Coastguard Worker SkScalar fMaxRunAscent = 0;
105*c8dee2aaSAndroid Build Coastguard Worker SkScalar fMaxRunDescent = 0;
106*c8dee2aaSAndroid Build Coastguard Worker SkScalar fMaxRunLeading = 0;
107*c8dee2aaSAndroid Build Coastguard Worker SkPoint fCurrentPosition = {0, 0};
108*c8dee2aaSAndroid Build Coastguard Worker SkPoint fOffset = {0, 0};
109*c8dee2aaSAndroid Build Coastguard Worker };
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker // TODO(kjlubick,jlavrova) Remove these defines by having clients register something or somehow
112*c8dee2aaSAndroid Build Coastguard Worker // plumbing this all into the animation builder factories.
113*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
get_unicode()114*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkUnicode> get_unicode() {
115*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
116*c8dee2aaSAndroid Build Coastguard Worker if (auto unicode = SkUnicodes::ICU::Make()) {
117*c8dee2aaSAndroid Build Coastguard Worker return unicode;
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_UNICODE_ICU_IMPLEMENTATION)
120*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
121*c8dee2aaSAndroid Build Coastguard Worker if (auto unicode = SkUnicodes::Libgrapheme::Make()) {
122*c8dee2aaSAndroid Build Coastguard Worker return unicode;
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker #endif
125*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
126*c8dee2aaSAndroid Build Coastguard Worker if (auto unicode = SkUnicodes::ICU4X::Make()) {
127*c8dee2aaSAndroid Build Coastguard Worker return unicode;
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker #endif
130*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker #endif
133*c8dee2aaSAndroid Build Coastguard Worker } // namespace
134*c8dee2aaSAndroid Build Coastguard Worker
beginLine()135*c8dee2aaSAndroid Build Coastguard Worker void RunHandler::beginLine() {
136*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition = fOffset;
137*c8dee2aaSAndroid Build Coastguard Worker fMaxRunAscent = 0;
138*c8dee2aaSAndroid Build Coastguard Worker fMaxRunDescent = 0;
139*c8dee2aaSAndroid Build Coastguard Worker fMaxRunLeading = 0;
140*c8dee2aaSAndroid Build Coastguard Worker }
141*c8dee2aaSAndroid Build Coastguard Worker
runInfo(const SkShaper::RunHandler::RunInfo & info)142*c8dee2aaSAndroid Build Coastguard Worker void RunHandler::runInfo(const SkShaper::RunHandler::RunInfo& info) {
143*c8dee2aaSAndroid Build Coastguard Worker SkFontMetrics metrics;
144*c8dee2aaSAndroid Build Coastguard Worker info.fFont.getMetrics(&metrics);
145*c8dee2aaSAndroid Build Coastguard Worker fMaxRunAscent = std::min(fMaxRunAscent, metrics.fAscent);
146*c8dee2aaSAndroid Build Coastguard Worker fMaxRunDescent = std::max(fMaxRunDescent, metrics.fDescent);
147*c8dee2aaSAndroid Build Coastguard Worker fMaxRunLeading = std::max(fMaxRunLeading, metrics.fLeading);
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker
commitRunInfo()150*c8dee2aaSAndroid Build Coastguard Worker void RunHandler::commitRunInfo() {
151*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition.fY -= fMaxRunAscent;
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker
runBuffer(const RunInfo & info)154*c8dee2aaSAndroid Build Coastguard Worker SkShaper::RunHandler::Buffer RunHandler::runBuffer(const RunInfo& info) {
155*c8dee2aaSAndroid Build Coastguard Worker int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
156*c8dee2aaSAndroid Build Coastguard Worker int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
157*c8dee2aaSAndroid Build Coastguard Worker
158*c8dee2aaSAndroid Build Coastguard Worker const auto& runBuffer = fBuilder.allocRunTextPos(info.fFont, glyphCount, utf8RangeSize);
159*c8dee2aaSAndroid Build Coastguard Worker fCurrentGlyphs = runBuffer.glyphs;
160*c8dee2aaSAndroid Build Coastguard Worker fCurrentPoints = runBuffer.points();
161*c8dee2aaSAndroid Build Coastguard Worker
162*c8dee2aaSAndroid Build Coastguard Worker if (runBuffer.utf8text && fUtf8Text) {
163*c8dee2aaSAndroid Build Coastguard Worker memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker fClusters = runBuffer.clusters;
166*c8dee2aaSAndroid Build Coastguard Worker fGlyphCount = glyphCount;
167*c8dee2aaSAndroid Build Coastguard Worker fClusterOffset = info.utf8Range.begin();
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker return {runBuffer.glyphs,
170*c8dee2aaSAndroid Build Coastguard Worker runBuffer.points(),
171*c8dee2aaSAndroid Build Coastguard Worker nullptr,
172*c8dee2aaSAndroid Build Coastguard Worker runBuffer.clusters,
173*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition};
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker
commitRunBuffer(const RunInfo & info)176*c8dee2aaSAndroid Build Coastguard Worker void RunHandler::commitRunBuffer(const RunInfo& info) {
177*c8dee2aaSAndroid Build Coastguard Worker // for (size_t i = 0; i < info.glyphCount; ++i) {
178*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT(fClusters[i] >= info.utf8Range.begin());
179*c8dee2aaSAndroid Build Coastguard Worker // // this fails for khmer example.
180*c8dee2aaSAndroid Build Coastguard Worker // SkASSERT(fClusters[i] < info.utf8Range.end());
181*c8dee2aaSAndroid Build Coastguard Worker // }
182*c8dee2aaSAndroid Build Coastguard Worker if (fCallbackFunction) {
183*c8dee2aaSAndroid Build Coastguard Worker fCallbackFunction(fCallbackContext,
184*c8dee2aaSAndroid Build Coastguard Worker fUtf8Text,
185*c8dee2aaSAndroid Build Coastguard Worker info.utf8Range.end(),
186*c8dee2aaSAndroid Build Coastguard Worker info.glyphCount,
187*c8dee2aaSAndroid Build Coastguard Worker fCurrentGlyphs,
188*c8dee2aaSAndroid Build Coastguard Worker fCurrentPoints,
189*c8dee2aaSAndroid Build Coastguard Worker fClusters,
190*c8dee2aaSAndroid Build Coastguard Worker info.fFont);
191*c8dee2aaSAndroid Build Coastguard Worker }
192*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 <= fClusterOffset);
193*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fGlyphCount; ++i) {
194*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
195*c8dee2aaSAndroid Build Coastguard Worker fClusters[i] -= fClusterOffset;
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker fCurrentPosition += info.fAdvance;
198*c8dee2aaSAndroid Build Coastguard Worker fTextOffset = std::max(fTextOffset, info.utf8Range.end());
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker
commitLine()201*c8dee2aaSAndroid Build Coastguard Worker void RunHandler::commitLine() {
202*c8dee2aaSAndroid Build Coastguard Worker if (fLineEndOffsets.empty() || fTextOffset > fLineEndOffsets.back()) {
203*c8dee2aaSAndroid Build Coastguard Worker // Ensure that fLineEndOffsets is monotonic.
204*c8dee2aaSAndroid Build Coastguard Worker fLineEndOffsets.push_back(fTextOffset);
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
207*c8dee2aaSAndroid Build Coastguard Worker }
208*c8dee2aaSAndroid Build Coastguard Worker
makeBlob()209*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> RunHandler::makeBlob() {
210*c8dee2aaSAndroid Build Coastguard Worker return fBuilder.make();
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker
selection_box(const SkFontMetrics & metrics,float advance,SkPoint pos)213*c8dee2aaSAndroid Build Coastguard Worker static SkRect selection_box(const SkFontMetrics& metrics,
214*c8dee2aaSAndroid Build Coastguard Worker float advance,
215*c8dee2aaSAndroid Build Coastguard Worker SkPoint pos) {
216*c8dee2aaSAndroid Build Coastguard Worker if (fabsf(advance) < 1.0f) {
217*c8dee2aaSAndroid Build Coastguard Worker advance = copysignf(1.0f, advance);
218*c8dee2aaSAndroid Build Coastguard Worker }
219*c8dee2aaSAndroid Build Coastguard Worker return SkRect{pos.x(),
220*c8dee2aaSAndroid Build Coastguard Worker pos.y() + metrics.fAscent,
221*c8dee2aaSAndroid Build Coastguard Worker pos.x() + advance,
222*c8dee2aaSAndroid Build Coastguard Worker pos.y() + metrics.fDescent}.makeSorted();
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker
set_character_bounds(void * context,const char * utf8Text,size_t utf8TextBytes,size_t glyphCount,const SkGlyphID * glyphs,const SkPoint * positions,const uint32_t * clusters,const SkFont & font)225*c8dee2aaSAndroid Build Coastguard Worker static void set_character_bounds(void* context,
226*c8dee2aaSAndroid Build Coastguard Worker const char* utf8Text,
227*c8dee2aaSAndroid Build Coastguard Worker size_t utf8TextBytes,
228*c8dee2aaSAndroid Build Coastguard Worker size_t glyphCount,
229*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphID* glyphs,
230*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* positions,
231*c8dee2aaSAndroid Build Coastguard Worker const uint32_t* clusters,
232*c8dee2aaSAndroid Build Coastguard Worker const SkFont& font)
233*c8dee2aaSAndroid Build Coastguard Worker {
234*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(context);
235*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(glyphCount > 0);
236*c8dee2aaSAndroid Build Coastguard Worker SkRect* cursors = (SkRect*)context;
237*c8dee2aaSAndroid Build Coastguard Worker
238*c8dee2aaSAndroid Build Coastguard Worker SkFontMetrics metrics;
239*c8dee2aaSAndroid Build Coastguard Worker font.getMetrics(&metrics);
240*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<float[]> advances(new float[glyphCount]);
241*c8dee2aaSAndroid Build Coastguard Worker font.getWidths(glyphs, glyphCount, advances.get());
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker // Loop over each cluster in this run.
244*c8dee2aaSAndroid Build Coastguard Worker size_t clusterStart = 0;
245*c8dee2aaSAndroid Build Coastguard Worker for (size_t glyphIndex = 0; glyphIndex < glyphCount; ++glyphIndex) {
246*c8dee2aaSAndroid Build Coastguard Worker if (glyphIndex + 1 < glyphCount // more glyphs
247*c8dee2aaSAndroid Build Coastguard Worker && clusters[glyphIndex] == clusters[glyphIndex + 1]) {
248*c8dee2aaSAndroid Build Coastguard Worker continue; // multi-glyph cluster
249*c8dee2aaSAndroid Build Coastguard Worker }
250*c8dee2aaSAndroid Build Coastguard Worker unsigned textBegin = clusters[glyphIndex];
251*c8dee2aaSAndroid Build Coastguard Worker unsigned textEnd = utf8TextBytes;
252*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < glyphCount; ++i) {
253*c8dee2aaSAndroid Build Coastguard Worker if (clusters[i] >= textEnd) {
254*c8dee2aaSAndroid Build Coastguard Worker textEnd = clusters[i] + 1;
255*c8dee2aaSAndroid Build Coastguard Worker }
256*c8dee2aaSAndroid Build Coastguard Worker }
257*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < glyphCount; ++i) {
258*c8dee2aaSAndroid Build Coastguard Worker if (clusters[i] > textBegin && clusters[i] < textEnd) {
259*c8dee2aaSAndroid Build Coastguard Worker textEnd = clusters[i];
260*c8dee2aaSAndroid Build Coastguard Worker if (textEnd == textBegin + 1) { break; }
261*c8dee2aaSAndroid Build Coastguard Worker }
262*c8dee2aaSAndroid Build Coastguard Worker }
263*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(glyphIndex + 1 > clusterStart);
264*c8dee2aaSAndroid Build Coastguard Worker unsigned clusterGlyphCount = glyphIndex + 1 - clusterStart;
265*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* clusterGlyphPositions = &positions[clusterStart];
266*c8dee2aaSAndroid Build Coastguard Worker const float* clusterAdvances = &advances[clusterStart];
267*c8dee2aaSAndroid Build Coastguard Worker clusterStart = glyphIndex + 1; // for next loop
268*c8dee2aaSAndroid Build Coastguard Worker
269*c8dee2aaSAndroid Build Coastguard Worker SkRect clusterBox = selection_box(metrics, clusterAdvances[0], clusterGlyphPositions[0]);
270*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 1; i < clusterGlyphCount; ++i) { // multiple glyphs
271*c8dee2aaSAndroid Build Coastguard Worker clusterBox.join(selection_box(metrics, clusterAdvances[i], clusterGlyphPositions[i]));
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker if (textBegin + 1 == textEnd) { // single byte, fast path.
274*c8dee2aaSAndroid Build Coastguard Worker cursors[textBegin] = clusterBox;
275*c8dee2aaSAndroid Build Coastguard Worker continue;
276*c8dee2aaSAndroid Build Coastguard Worker }
277*c8dee2aaSAndroid Build Coastguard Worker int textCount = textEnd - textBegin;
278*c8dee2aaSAndroid Build Coastguard Worker int codePointCount = SkUTF::CountUTF8(utf8Text + textBegin, textCount);
279*c8dee2aaSAndroid Build Coastguard Worker if (codePointCount == 1) { // single codepoint, fast path.
280*c8dee2aaSAndroid Build Coastguard Worker cursors[textBegin] = clusterBox;
281*c8dee2aaSAndroid Build Coastguard Worker continue;
282*c8dee2aaSAndroid Build Coastguard Worker }
283*c8dee2aaSAndroid Build Coastguard Worker
284*c8dee2aaSAndroid Build Coastguard Worker float width = clusterBox.width() / codePointCount;
285*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(width > 0);
286*c8dee2aaSAndroid Build Coastguard Worker const char* ptr = utf8Text + textBegin;
287*c8dee2aaSAndroid Build Coastguard Worker const char* end = utf8Text + textEnd;
288*c8dee2aaSAndroid Build Coastguard Worker float x = clusterBox.left();
289*c8dee2aaSAndroid Build Coastguard Worker while (ptr < end) { // for each codepoint in cluster
290*c8dee2aaSAndroid Build Coastguard Worker const char* nextPtr = ptr;
291*c8dee2aaSAndroid Build Coastguard Worker SkUTF::NextUTF8(&nextPtr, end);
292*c8dee2aaSAndroid Build Coastguard Worker int firstIndex = ptr - utf8Text;
293*c8dee2aaSAndroid Build Coastguard Worker float nextX = x + width;
294*c8dee2aaSAndroid Build Coastguard Worker cursors[firstIndex] = SkRect{x, clusterBox.top(), nextX, clusterBox.bottom()};
295*c8dee2aaSAndroid Build Coastguard Worker x = nextX;
296*c8dee2aaSAndroid Build Coastguard Worker ptr = nextPtr;
297*c8dee2aaSAndroid Build Coastguard Worker }
298*c8dee2aaSAndroid Build Coastguard Worker }
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker
Shape(const char * utf8Text,size_t textByteLen,const SkFont & font,sk_sp<SkFontMgr> fontMgr,const char * locale,float width)301*c8dee2aaSAndroid Build Coastguard Worker ShapeResult SkPlainTextEditor::Shape(const char* utf8Text,
302*c8dee2aaSAndroid Build Coastguard Worker size_t textByteLen,
303*c8dee2aaSAndroid Build Coastguard Worker const SkFont& font,
304*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkFontMgr> fontMgr,
305*c8dee2aaSAndroid Build Coastguard Worker const char* locale,
306*c8dee2aaSAndroid Build Coastguard Worker float width)
307*c8dee2aaSAndroid Build Coastguard Worker {
308*c8dee2aaSAndroid Build Coastguard Worker ShapeResult result;
309*c8dee2aaSAndroid Build Coastguard Worker if (SkUTF::CountUTF8(utf8Text, textByteLen) < 0) {
310*c8dee2aaSAndroid Build Coastguard Worker utf8Text = nullptr;
311*c8dee2aaSAndroid Build Coastguard Worker textByteLen = 0;
312*c8dee2aaSAndroid Build Coastguard Worker }
313*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkShaper> shaper = nullptr;
314*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
315*c8dee2aaSAndroid Build Coastguard Worker auto unicode = get_unicode();
316*c8dee2aaSAndroid Build Coastguard Worker shaper = SkShapers::HB::ShaperDrivenWrapper(unicode, fontMgr);
317*c8dee2aaSAndroid Build Coastguard Worker #else
318*c8dee2aaSAndroid Build Coastguard Worker shaper = SkShapers::Primitive::PrimitiveText();
319*c8dee2aaSAndroid Build Coastguard Worker #endif
320*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(shaper);
321*c8dee2aaSAndroid Build Coastguard Worker
322*c8dee2aaSAndroid Build Coastguard Worker float height = font.getSpacing();
323*c8dee2aaSAndroid Build Coastguard Worker RunHandler runHandler(utf8Text, textByteLen);
324*c8dee2aaSAndroid Build Coastguard Worker if (textByteLen) {
325*c8dee2aaSAndroid Build Coastguard Worker result.glyphBounds.resize(textByteLen);
326*c8dee2aaSAndroid Build Coastguard Worker for (SkRect& c : result.glyphBounds) {
327*c8dee2aaSAndroid Build Coastguard Worker c = SkRect{-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX};
328*c8dee2aaSAndroid Build Coastguard Worker }
329*c8dee2aaSAndroid Build Coastguard Worker runHandler.setRunCallback(set_character_bounds, result.glyphBounds.data());
330*c8dee2aaSAndroid Build Coastguard Worker
331*c8dee2aaSAndroid Build Coastguard Worker static constexpr uint8_t kBidiLevelLTR = 0;
332*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkShaper::BiDiRunIterator> bidi = nullptr;
333*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
334*c8dee2aaSAndroid Build Coastguard Worker bidi = SkShapers::unicode::BidiRunIterator(
335*c8dee2aaSAndroid Build Coastguard Worker unicode, utf8Text, textByteLen, kBidiLevelLTR);
336*c8dee2aaSAndroid Build Coastguard Worker #endif
337*c8dee2aaSAndroid Build Coastguard Worker if (!bidi) {
338*c8dee2aaSAndroid Build Coastguard Worker bidi = std::make_unique<SkShaper::TrivialBiDiRunIterator>(kBidiLevelLTR, textByteLen);
339*c8dee2aaSAndroid Build Coastguard Worker }
340*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(bidi);
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkShaper::LanguageRunIterator> language =
343*c8dee2aaSAndroid Build Coastguard Worker SkShaper::MakeStdLanguageRunIterator(utf8Text, textByteLen);
344*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(language);
345*c8dee2aaSAndroid Build Coastguard Worker
346*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkShaper::ScriptRunIterator> script =
347*c8dee2aaSAndroid Build Coastguard Worker SkShaper::MakeScriptRunIterator(utf8Text, textByteLen, SkSetFourByteTag('Z','z','z','z'));
348*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(script);
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
351*c8dee2aaSAndroid Build Coastguard Worker SkShaper::MakeFontMgrRunIterator(utf8Text, textByteLen, font, fontMgr);
352*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fontRuns);
353*c8dee2aaSAndroid Build Coastguard Worker
354*c8dee2aaSAndroid Build Coastguard Worker shaper->shape(utf8Text,
355*c8dee2aaSAndroid Build Coastguard Worker textByteLen,
356*c8dee2aaSAndroid Build Coastguard Worker *fontRuns,
357*c8dee2aaSAndroid Build Coastguard Worker *bidi,
358*c8dee2aaSAndroid Build Coastguard Worker *script,
359*c8dee2aaSAndroid Build Coastguard Worker *language,
360*c8dee2aaSAndroid Build Coastguard Worker nullptr,
361*c8dee2aaSAndroid Build Coastguard Worker 0,
362*c8dee2aaSAndroid Build Coastguard Worker width,
363*c8dee2aaSAndroid Build Coastguard Worker &runHandler);
364*c8dee2aaSAndroid Build Coastguard Worker if (runHandler.lineEndOffsets().size() > 1) {
365*c8dee2aaSAndroid Build Coastguard Worker result.lineBreakOffsets = runHandler.lineEndOffsets();
366*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(result.lineBreakOffsets.size() > 0);
367*c8dee2aaSAndroid Build Coastguard Worker result.lineBreakOffsets.pop_back();
368*c8dee2aaSAndroid Build Coastguard Worker }
369*c8dee2aaSAndroid Build Coastguard Worker height = std::max(height, runHandler.endPoint().y());
370*c8dee2aaSAndroid Build Coastguard Worker result.blob = runHandler.makeBlob();
371*c8dee2aaSAndroid Build Coastguard Worker }
372*c8dee2aaSAndroid Build Coastguard Worker result.glyphBounds.push_back(runHandler.finalRect(font));
373*c8dee2aaSAndroid Build Coastguard Worker result.verticalAdvance = (int)ceilf(height);
374*c8dee2aaSAndroid Build Coastguard Worker result.wordBreaks = GetUtf8WordBoundaries(utf8Text, textByteLen, locale);
375*c8dee2aaSAndroid Build Coastguard Worker return result;
376*c8dee2aaSAndroid Build Coastguard Worker }
377