• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 
8 #include "src/text/gpu/TextBlob.h"
9 
10 #include "include/core/SkMatrix.h"
11 #include "include/core/SkScalar.h"
12 #include "include/private/base/SkTemplates.h"
13 #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
14 #include "include/private/chromium/Slug.h"
15 #include "src/core/SkFontPriv.h"
16 #include "src/core/SkMaskFilterBase.h"
17 #include "src/core/SkMatrixProvider.h"
18 #include "src/core/SkPaintPriv.h"
19 #include "src/core/SkReadBuffer.h"
20 #include "src/core/SkRectPriv.h"
21 #include "src/core/SkStrikeCache.h"
22 #include "src/core/SkWriteBuffer.h"
23 #include "src/text/GlyphRun.h"
24 #include "src/text/gpu/SubRunAllocator.h"
25 #include "src/text/gpu/SubRunContainer.h"
26 
27 #if defined(SK_GANESH)  // Ganesh Support
28 #include "src/gpu/ganesh/Device_v1.h"
29 #include "src/gpu/ganesh/GrClip.h"
30 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
31 #include "src/gpu/ganesh/SurfaceDrawContext.h"
32 #endif
33 
34 using namespace sktext::gpu;
35 namespace {
position_matrix(const SkMatrix & drawMatrix,SkPoint drawOrigin)36 SkMatrix position_matrix(const SkMatrix& drawMatrix, SkPoint drawOrigin) {
37     SkMatrix position_matrix = drawMatrix;
38     return position_matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
39 }
40 
41 // Check for integer translate with the same 2x2 matrix.
42 // Returns the translation, and true if the change from initial matrix to the position matrix
43 // support using direct glyph masks.
can_use_direct(const SkMatrix & initialPositionMatrix,const SkMatrix & positionMatrix)44 std::tuple<bool, SkVector> can_use_direct(
45         const SkMatrix& initialPositionMatrix, const SkMatrix& positionMatrix) {
46     // The existing direct glyph info can be used if the initialPositionMatrix, and the
47     // positionMatrix have the same 2x2, and the translation between them is integer.
48     // Calculate the translation in source space to a translation in device space by mapping
49     // (0, 0) through both the initial position matrix and the position matrix; take the difference.
50     SkVector translation = positionMatrix.mapOrigin() - initialPositionMatrix.mapOrigin();
51     return {initialPositionMatrix.getScaleX() == positionMatrix.getScaleX() &&
52             initialPositionMatrix.getScaleY() == positionMatrix.getScaleY() &&
53             initialPositionMatrix.getSkewX()  == positionMatrix.getSkewX()  &&
54             initialPositionMatrix.getSkewY()  == positionMatrix.getSkewY()  &&
55             SkScalarIsInt(translation.x()) && SkScalarIsInt(translation.y()),
56             translation};
57 }
58 
59 
compute_canonical_color(const SkPaint & paint,bool lcd)60 static SkColor compute_canonical_color(const SkPaint& paint, bool lcd) {
61     SkColor canonicalColor = SkPaintPriv::ComputeLuminanceColor(paint);
62     if (lcd) {
63         // This is the correct computation for canonicalColor, but there are tons of cases where LCD
64         // can be modified. For now we just regenerate if any run in a textblob has LCD.
65         // TODO figure out where all of these modifications are and see if we can incorporate that
66         //      logic at a higher level *OR* use sRGB
67         //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor);
68 
69         // TODO we want to figure out a way to be able to use the canonical color on LCD text,
70         // see the note above.  We pick a placeholder value for LCD text to ensure we always match
71         // the same key
72         return SK_ColorTRANSPARENT;
73     } else {
74         // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have
75         // gamma corrected masks anyways, nor color
76         U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor),
77                                        SkColorGetG(canonicalColor),
78                                        SkColorGetB(canonicalColor));
79         // reduce to our finite number of bits
80         canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum));
81     }
82     return canonicalColor;
83 }
84 
85 // -- SlugImpl -------------------------------------------------------------------------------------
86 class SlugImpl final : public Slug {
87 public:
88     SlugImpl(SubRunAllocator&& alloc,
89              SubRunContainerOwner subRuns,
90              SkRect sourceBounds,
91              const SkPaint& paint,
92              SkPoint origin);
93     ~SlugImpl() override = default;
94 
95     static sk_sp<SlugImpl> Make(const SkMatrixProvider& viewMatrix,
96                                 const sktext::GlyphRunList& glyphRunList,
97                                 const SkPaint& initialPaint,
98                                 const SkPaint& drawingPaint,
99                                 SkStrikeDeviceInfo strikeDeviceInfo,
100                                 sktext::StrikeForGPUCacheInterface* strikeCache);
101     static sk_sp<Slug> MakeFromBuffer(SkReadBuffer& buffer,
102                                       const SkStrikeClient* client);
103     void doFlatten(SkWriteBuffer& buffer) const override;
104 
105 #if defined(SK_GANESH)
106     void surfaceDraw(SkCanvas*,
107                      const GrClip* clip,
108                      const SkMatrixProvider& viewMatrix,
109                      const SkPaint& paint,
110                      skgpu::v1::SurfaceDrawContext* sdc) const;
111 #endif
112 
sourceBounds() const113     SkRect sourceBounds() const override { return fSourceBounds; }
sourceBoundsWithOrigin() const114     SkRect sourceBoundsWithOrigin() const override { return fSourceBounds.makeOffset(fOrigin); }
initialPaint() const115     const SkPaint& initialPaint() const override { return fInitialPaint; }
116 
initialPositionMatrix() const117     const SkMatrix& initialPositionMatrix() const { return fSubRuns->initialPosition(); }
origin() const118     SkPoint origin() const { return fOrigin; }
119 
120     // Change memory management to handle the data after Slug, but in the same allocation
121     // of memory. Only allow placement new.
operator delete(void * p)122     void operator delete(void* p) { ::operator delete(p); }
operator new(size_t)123     void* operator new(size_t) { SK_ABORT("All slugs are created by placement new."); }
operator new(size_t,void * p)124     void* operator new(size_t, void* p) { return p; }
125 
126 private:
127     // The allocator must come first because it needs to be destroyed last. Other fields of this
128     // structure may have pointers into it.
129     SubRunAllocator fAlloc;
130     SubRunContainerOwner fSubRuns;
131     const SkRect fSourceBounds;
132     const SkPaint fInitialPaint;
133     const SkMatrix fInitialPositionMatrix;
134     const SkPoint fOrigin;
135 };
136 
SlugImpl(SubRunAllocator && alloc,SubRunContainerOwner subRuns,SkRect sourceBounds,const SkPaint & paint,SkPoint origin)137 SlugImpl::SlugImpl(SubRunAllocator&& alloc,
138                    SubRunContainerOwner subRuns,
139                    SkRect sourceBounds,
140                    const SkPaint& paint,
141                    SkPoint origin)
142         : fAlloc {std::move(alloc)}
143         , fSubRuns(std::move(subRuns))
144         , fSourceBounds{sourceBounds}
145         , fInitialPaint{paint}
146         , fOrigin{origin} {}
147 
148 #if defined(SK_GANESH)
surfaceDraw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,const SkPaint & drawingPaint,skgpu::v1::SurfaceDrawContext * sdc) const149 void SlugImpl::surfaceDraw(SkCanvas* canvas, const GrClip* clip, const SkMatrixProvider& viewMatrix,
150                            const SkPaint& drawingPaint, skgpu::v1::SurfaceDrawContext* sdc) const {
151     fSubRuns->draw(canvas, clip, viewMatrix, fOrigin, drawingPaint, this, sdc);
152 }
153 #endif
154 
doFlatten(SkWriteBuffer & buffer) const155 void SlugImpl::doFlatten(SkWriteBuffer& buffer) const {
156     buffer.writeRect(fSourceBounds);
157     SkPaintPriv::Flatten(fInitialPaint, buffer);
158     buffer.writePoint(fOrigin);
159     fSubRuns->flattenAllocSizeHint(buffer);
160     fSubRuns->flattenRuns(buffer);
161 }
162 
MakeFromBuffer(SkReadBuffer & buffer,const SkStrikeClient * client)163 sk_sp<Slug> SlugImpl::MakeFromBuffer(SkReadBuffer& buffer, const SkStrikeClient* client) {
164     SkRect sourceBounds = buffer.readRect();
165     SkASSERT(!sourceBounds.isEmpty());
166     if (!buffer.validate(!sourceBounds.isEmpty())) { return nullptr; }
167     SkPaint paint = buffer.readPaint();
168     SkPoint origin = buffer.readPoint();
169     int allocSizeHint = SubRunContainer::AllocSizeHintFromBuffer(buffer);
170 
171     auto [initializer, _, alloc] =
172             SubRunAllocator::AllocateClassMemoryAndArena<SlugImpl>(allocSizeHint);
173 
174     SubRunContainerOwner container = SubRunContainer::MakeFromBufferInAlloc(buffer, client, &alloc);
175 
176     // Something went wrong while reading.
177     SkASSERT(buffer.isValid());
178     if (!buffer.isValid()) { return nullptr;}
179 
180     return sk_sp<SlugImpl>(initializer.initialize(
181             std::move(alloc), std::move(container), sourceBounds, paint, origin));
182 }
183 
Make(const SkMatrixProvider & viewMatrix,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint,SkStrikeDeviceInfo strikeDeviceInfo,sktext::StrikeForGPUCacheInterface * strikeCache)184 sk_sp<SlugImpl> SlugImpl::Make(const SkMatrixProvider& viewMatrix,
185                                const sktext::GlyphRunList& glyphRunList,
186                                const SkPaint& initialPaint,
187                                const SkPaint& drawingPaint,
188                                SkStrikeDeviceInfo strikeDeviceInfo,
189                                sktext::StrikeForGPUCacheInterface* strikeCache) {
190     size_t subRunSizeHint = SubRunContainer::EstimateAllocSize(glyphRunList);
191     auto [initializer, _, alloc] =
192             SubRunAllocator::AllocateClassMemoryAndArena<SlugImpl>(subRunSizeHint);
193 
194     const SkMatrix positionMatrix =
195             position_matrix(viewMatrix.localToDevice(), glyphRunList.origin());
196 
197     auto subRuns = SubRunContainer::MakeInAlloc(glyphRunList,
198                                                 positionMatrix,
199                                                 drawingPaint,
200                                                 strikeDeviceInfo,
201                                                 strikeCache,
202                                                 &alloc,
203                                                 SubRunContainer::kAddSubRuns,
204                                                 "Make Slug");
205 
206     sk_sp<SlugImpl> slug = sk_sp<SlugImpl>(initializer.initialize(
207             std::move(alloc),
208             std::move(subRuns),
209             glyphRunList.sourceBounds(),
210             initialPaint,
211             glyphRunList.origin()));
212 
213     // There is nothing to draw here. This is particularly a problem with RSX form blobs where a
214     // single space becomes a run with no glyphs.
215     if (slug->fSubRuns->isEmpty()) { return nullptr; }
216 
217     return slug;
218 }
219 }  // namespace
220 
221 namespace sktext::gpu {
222 // -- TextBlob::Key ------------------------------------------------------------------------------
Make(const GlyphRunList & glyphRunList,const SkPaint & paint,const SkMatrix & drawMatrix,const SkStrikeDeviceInfo & strikeDevice)223 auto TextBlob::Key::Make(const GlyphRunList& glyphRunList,
224                          const SkPaint& paint,
225                          const SkMatrix& drawMatrix,
226                          const SkStrikeDeviceInfo& strikeDevice) -> std::tuple<bool, Key> {
227     SkASSERT(strikeDevice.fSDFTControl != nullptr);
228     SkMaskFilterBase::BlurRec blurRec;
229     // It might be worth caching these things, but its not clear at this time
230     // TODO for animated mask filters, this will fill up our cache.  We need a safeguard here
231     const SkMaskFilter* maskFilter = paint.getMaskFilter();
232     bool canCache = glyphRunList.canCache() &&
233                     !(paint.getPathEffect() ||
234                         (maskFilter && !as_MFB(maskFilter)->asABlur(&blurRec)));
235 
236     TextBlob::Key key;
237     if (canCache) {
238         bool hasLCD = glyphRunList.anyRunsLCD();
239 
240         // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry
241         SkPixelGeometry pixelGeometry = hasLCD ? strikeDevice.fSurfaceProps.pixelGeometry()
242                                                : kUnknown_SkPixelGeometry;
243 
244         SkColor canonicalColor = compute_canonical_color(paint, hasLCD);
245 
246         key.fPixelGeometry = pixelGeometry;
247         key.fUniqueID = glyphRunList.uniqueID();
248         key.fStyle = paint.getStyle();
249         if (key.fStyle != SkPaint::kFill_Style) {
250             key.fFrameWidth = paint.getStrokeWidth();
251             key.fMiterLimit = paint.getStrokeMiter();
252             key.fJoin = paint.getStrokeJoin();
253         }
254         key.fHasBlur = maskFilter != nullptr;
255         if (key.fHasBlur) {
256             key.fBlurRec = blurRec;
257         }
258         key.fCanonicalColor = canonicalColor;
259         key.fScalerContextFlags = SkTo<uint32_t>(strikeDevice.fScalerContextFlags);
260 
261         // Do any runs use direct drawing types?.
262         key.fHasSomeDirectSubRuns = false;
263         SkPoint glyphRunListLocation = glyphRunList.sourceBoundsWithOrigin().center();
264         for (auto& run : glyphRunList) {
265             SkScalar approximateDeviceTextSize =
266                     SkFontPriv::ApproximateTransformedTextSize(run.font(), drawMatrix,
267                                                                glyphRunListLocation);
268             key.fHasSomeDirectSubRuns |=
269                     strikeDevice.fSDFTControl->isDirect(approximateDeviceTextSize, paint,
270                                                         drawMatrix);
271         }
272 
273         if (key.fHasSomeDirectSubRuns) {
274             // Store the fractional offset of the position. We know that the matrix can't be
275             // perspective at this point.
276             SkPoint mappedOrigin = drawMatrix.mapOrigin();
277             key.fPositionMatrix = drawMatrix;
278             key.fPositionMatrix.setTranslateX(
279                     mappedOrigin.x() - SkScalarFloorToScalar(mappedOrigin.x()));
280             key.fPositionMatrix.setTranslateY(
281                     mappedOrigin.y() - SkScalarFloorToScalar(mappedOrigin.y()));
282         } else {
283             // For path and SDFT, the matrix doesn't matter.
284             key.fPositionMatrix = SkMatrix::I();
285         }
286     }
287 
288     return {canCache, key};
289 }
290 
operator ==(const TextBlob::Key & that) const291 bool TextBlob::Key::operator==(const TextBlob::Key& that) const {
292     if (fUniqueID != that.fUniqueID) { return false; }
293     if (fCanonicalColor != that.fCanonicalColor) { return false; }
294     if (fStyle != that.fStyle) { return false; }
295     if (fStyle != SkPaint::kFill_Style) {
296         if (fFrameWidth != that.fFrameWidth ||
297             fMiterLimit != that.fMiterLimit ||
298             fJoin != that.fJoin) {
299             return false;
300         }
301     }
302     if (fPixelGeometry != that.fPixelGeometry) { return false; }
303     if (fHasBlur != that.fHasBlur) { return false; }
304     if (fHasBlur) {
305         if (fBlurRec.fStyle != that.fBlurRec.fStyle || fBlurRec.fSigma != that.fBlurRec.fSigma) {
306             return false;
307         }
308     }
309 
310     if (fScalerContextFlags != that.fScalerContextFlags) { return false; }
311 
312     // DirectSubRuns do not support perspective when used with a TextBlob. SDFT, Transformed,
313     // Path, and Drawable do support perspective.
314     if (fPositionMatrix.hasPerspective() && fHasSomeDirectSubRuns) { return false; }
315 
316     if (fHasSomeDirectSubRuns != that.fHasSomeDirectSubRuns) { return false; }
317 
318     if (fHasSomeDirectSubRuns) {
319         auto [compatible, _] = can_use_direct(fPositionMatrix, that.fPositionMatrix);
320         return compatible;
321     }
322 
323     return true;
324 }
325 
326 // -- TextBlob -----------------------------------------------------------------------------------
operator delete(void * p)327 void TextBlob::operator delete(void* p) { ::operator delete(p); }
operator new(size_t)328 void* TextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
operator new(size_t,void * p)329 void* TextBlob::operator new(size_t, void* p) { return p; }
330 
331 TextBlob::~TextBlob() = default;
332 
Make(const GlyphRunList & glyphRunList,const SkPaint & paint,const SkMatrix & positionMatrix,SkStrikeDeviceInfo strikeDeviceInfo,StrikeForGPUCacheInterface * strikeCache)333 sk_sp<TextBlob> TextBlob::Make(const GlyphRunList& glyphRunList,
334                                const SkPaint& paint,
335                                const SkMatrix& positionMatrix,
336                                SkStrikeDeviceInfo strikeDeviceInfo,
337                                StrikeForGPUCacheInterface* strikeCache) {
338     size_t subRunSizeHint = SubRunContainer::EstimateAllocSize(glyphRunList);
339     auto [initializer, totalMemoryAllocated, alloc] =
340             SubRunAllocator::AllocateClassMemoryAndArena<TextBlob>(subRunSizeHint);
341 
342     auto container = SubRunContainer::MakeInAlloc(
343             glyphRunList, positionMatrix, paint,
344             strikeDeviceInfo, strikeCache, &alloc, SubRunContainer::kAddSubRuns, "TextBlob");
345 
346     SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(paint);
347     sk_sp<TextBlob> blob = sk_sp<TextBlob>(initializer.initialize(std::move(alloc),
348                                                                   std::move(container),
349                                                                   totalMemoryAllocated,
350                                                                   initialLuminance));
351     return blob;
352 }
353 
addKey(const Key & key)354 void TextBlob::addKey(const Key& key) {
355     fKey = key;
356 }
357 
hasPerspective() const358 bool TextBlob::hasPerspective() const {
359     return fSubRuns->initialPosition().hasPerspective();
360 }
361 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const362 bool TextBlob::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
363     // A singular matrix will create a TextBlob with no SubRuns, but unknown glyphs can also
364     // cause empty runs. If there are no subRuns, then regenerate when the matrices don't match.
365     if (fSubRuns->isEmpty() && fSubRuns->initialPosition() != positionMatrix) {
366         return false;
367     }
368 
369     // If we have LCD text then our canonical color will be set to transparent, in this case we have
370     // to regenerate the blob on any color change
371     // We use the grPaint to get any color filter effects
372     if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
373         fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) {
374         return false;
375     }
376 
377     return fSubRuns->canReuse(paint, positionMatrix);
378 }
379 
key() const380 const TextBlob::Key& TextBlob::key() const { return fKey; }
381 
382 #if defined(SK_GANESH)
draw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc)383 void TextBlob::draw(SkCanvas* canvas,
384                     const GrClip* clip,
385                     const SkMatrixProvider& viewMatrix,
386                     SkPoint drawOrigin,
387                     const SkPaint& paint,
388                     skgpu::v1::SurfaceDrawContext* sdc) {
389     fSubRuns->draw(canvas, clip, viewMatrix, drawOrigin, paint, this, sdc);
390 }
391 #endif
392 
393 #if defined(SK_GRAPHITE)
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,skgpu::graphite::Device * device)394 void TextBlob::draw(SkCanvas* canvas,
395                     SkPoint drawOrigin,
396                     const SkPaint& paint,
397                     skgpu::graphite::Device* device) {
398     fSubRuns->draw(canvas, drawOrigin, paint, this, device);
399 }
400 #endif
401 
402 #if GR_TEST_UTILS
403 struct SubRunContainerPeer {
getAtlasSubRunsktext::gpu::SubRunContainerPeer404     static const AtlasSubRun* getAtlasSubRun(const SubRunContainer& subRuns) {
405         if (subRuns.isEmpty()) {
406             return nullptr;
407         }
408         return subRuns.fSubRuns.front().testingOnly_atlasSubRun();
409     }
410 };
411 #endif
412 
testingOnlyFirstSubRun() const413 const AtlasSubRun* TextBlob::testingOnlyFirstSubRun() const {
414 #if GR_TEST_UTILS
415     return SubRunContainerPeer::getAtlasSubRun(*fSubRuns);
416 #else
417     return nullptr;
418 #endif
419 }
420 
TextBlob(SubRunAllocator && alloc,SubRunContainerOwner subRuns,int totalMemorySize,SkColor initialLuminance)421 TextBlob::TextBlob(SubRunAllocator&& alloc,
422                    SubRunContainerOwner subRuns,
423                    int totalMemorySize,
424                    SkColor initialLuminance)
425         : fAlloc{std::move(alloc)}
426         , fSubRuns{std::move(subRuns)}
427         , fSize(totalMemorySize)
428         , fInitialLuminance{initialLuminance} { }
429 
SkMakeSlugFromBuffer(SkReadBuffer & buffer,const SkStrikeClient * client)430 sk_sp<Slug> SkMakeSlugFromBuffer(SkReadBuffer& buffer, const SkStrikeClient* client) {
431     return SlugImpl::MakeFromBuffer(buffer, client);
432 }
433 }  // namespace sktext::gpu
434 
435 #if defined(SK_GANESH)
436 namespace skgpu::v1 {
437 sk_sp<Slug>
convertGlyphRunListToSlug(const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint)438 Device::convertGlyphRunListToSlug(const sktext::GlyphRunList& glyphRunList,
439                                   const SkPaint& initialPaint,
440                                   const SkPaint& drawingPaint) {
441     return SlugImpl::Make(this->asMatrixProvider(),
442                           glyphRunList,
443                           initialPaint,
444                           drawingPaint,
445                           this->strikeDeviceInfo(),
446                           SkStrikeCache::GlobalStrikeCache());
447 }
448 
drawSlug(SkCanvas * canvas,const Slug * slug,const SkPaint & drawingPaint)449 void Device::drawSlug(SkCanvas* canvas, const Slug* slug, const SkPaint& drawingPaint) {
450     const SlugImpl* slugImpl = static_cast<const SlugImpl*>(slug);
451     auto matrixProvider = this->asMatrixProvider();
452 #if defined(SK_DEBUG)
453     if (!fContext->priv().options().fSupportBilerpFromGlyphAtlas) {
454         // We can draw a slug if the atlas has padding or if the creation matrix and the
455         // drawing matrix are the same. If they are the same, then the Slug will use the direct
456         // drawing code and not use bi-lerp.
457         SkMatrix slugMatrix = slugImpl->initialPositionMatrix();
458         SkMatrix positionMatrix = matrixProvider.localToDevice();
459         positionMatrix.preTranslate(slugImpl->origin().x(), slugImpl->origin().y());
460         SkASSERT(slugMatrix == positionMatrix);
461     }
462 #endif
463     slugImpl->surfaceDraw(
464             canvas, this->clip(), matrixProvider, drawingPaint, fSurfaceDrawContext.get());
465 }
466 
MakeSlug(const SkMatrixProvider & drawMatrix,const sktext::GlyphRunList & glyphRunList,const SkPaint & initialPaint,const SkPaint & drawingPaint,SkStrikeDeviceInfo strikeDeviceInfo,sktext::StrikeForGPUCacheInterface * strikeCache)467 sk_sp<Slug> MakeSlug(const SkMatrixProvider& drawMatrix,
468                      const sktext::GlyphRunList& glyphRunList,
469                      const SkPaint& initialPaint,
470                      const SkPaint& drawingPaint,
471                      SkStrikeDeviceInfo strikeDeviceInfo,
472                      sktext::StrikeForGPUCacheInterface* strikeCache) {
473     return SlugImpl::Make(
474             drawMatrix, glyphRunList, initialPaint, drawingPaint, strikeDeviceInfo, strikeCache);
475 }
476 }  // namespace skgpu::v1
477 #endif
478