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