• 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 "include/core/SkColorFilter.h"
9 #include "include/gpu/GrRecordingContext.h"
10 #include "include/private/SkTemplates.h"
11 #include "include/private/chromium/GrSlug.h"
12 #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
13 #include "src/core/SkFontPriv.h"
14 #include "src/core/SkMaskFilterBase.h"
15 #include "src/core/SkMatrixProvider.h"
16 #include "src/core/SkPaintPriv.h"
17 #include "src/core/SkReadBuffer.h"
18 #include "src/core/SkStrikeCache.h"
19 #include "src/core/SkStrikeSpec.h"
20 #include "src/gpu/GrClip.h"
21 #include "src/gpu/GrGlyph.h"
22 #include "src/gpu/GrMeshDrawTarget.h"
23 #include "src/gpu/GrRecordingContextPriv.h"
24 #include "src/gpu/GrStyle.h"
25 #include "src/gpu/SkGr.h"
26 #include "src/gpu/effects/GrDistanceFieldGeoProc.h"
27 #include "src/gpu/geometry/GrStyledShape.h"
28 #include "src/gpu/text/GrAtlasManager.h"
29 #include "src/gpu/text/GrGlyphVector.h"
30 #include "src/gpu/text/GrStrikeCache.h"
31 #include "src/gpu/text/GrTextBlob.h"
32 
33 #include "src/gpu/GrBlurUtils.h"
34 #include "src/gpu/ops/AtlasTextOp.h"
35 #include "src/gpu/v1/Device_v1.h"
36 #include "src/gpu/v1/SurfaceDrawContext_v1.h"
37 
38 using AtlasTextOp = skgpu::v1::AtlasTextOp;
39 
40 // -- GPU Text -------------------------------------------------------------------------------------
41 // There are three broad types of SubRun implementations for drawing text using the GPU.
42 // GrTextBlob (runs with no postfix) - these runs support drawing for GrTextBlobs.
43 // GrSlug (Slug postfix) - these runs support drawing of GrSlugs.
44 // (NoCache postfix) - These runs support Canvas direct drawing like drawText, etc.
45 //
46 // Naming conventions
47 //  * drawMatrix - the CTM from the canvas.
48 //  * drawOrigin - the x, y location of the drawTextBlob call.
49 //  * positionMatrix - this is the combination of the drawMatrix and the drawOrigin:
50 //        positionMatrix = drawMatrix * TranslationMatrix(drawOrigin.x, drawOrigin.y);
51 //
52 // Note:
53 //   In order to use GrSlugs, you need to set the fSupportBilerpFromGlyphAtlas on GrContextOptions.
54 
55 enum GrSubRun::SubRunType : int {
56     kBad = 0,  // Make this 0 to line up with errors from readInt.
57     kDirectMask,
58     kSDFT,
59     kTransformMask,
60     kPath,
61     kDrawable,
62     kSubRunTypeCount,
63 };
64 
65 // -- GrBlobSubRun ---------------------------------------------------------------------------------
66 class GrBlobSubRun {
67 public:
68     virtual ~GrBlobSubRun() = default;
69     // Given an already cached subRun, can this subRun handle this combination paint, matrix, and
70     // position.
71     virtual bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const = 0;
72 
73     // Return the underlying atlas SubRun if it exists. Otherwise, return nullptr.
74     // * Don't use this API. It is only to support testing.
75     virtual const GrAtlasSubRun* testingOnly_atlasSubRun() const = 0;
76 };
77 
78 // -- GrSubRun -------------------------------------------------------------------------------------
79 GrSubRun::~GrSubRun() = default;
blobCast() const80 const GrBlobSubRun* GrSubRun::blobCast() const {
81     SK_ABORT("This is not a subclass of GrBlobSubRun.");
82 }
83 
84 namespace {
85 // -- TransformedMaskVertexFiller ------------------------------------------------------------------
86 class TransformedMaskVertexFiller {
87 public:
88     TransformedMaskVertexFiller(GrMaskFormat maskFormat,
89                                 int dstPadding,
90                                 SkScalar strikeToSourceScale);
91 
92     struct PositionAndExtent {
93         const SkPoint pos;
94         // The rectangle of the glyphs in strike space. But, for kDirectMask this also implies a
95         // device space rect.
96         GrIRect16 rect;
97     };
98 
vertexStride(const SkMatrix & matrix) const99     size_t vertexStride(const SkMatrix& matrix) const {
100         if (fMaskType != kARGB_GrMaskFormat) {
101             // For formats kA565_GrMaskFormat and kA8_GrMaskFormat where A8 include SDFT.
102             return matrix.hasPerspective() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex);
103         } else {
104             // For format kARGB_GrMaskFormat
105             return matrix.hasPerspective() ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex);
106         }
107     }
108 
109     void fillVertexData(SkSpan<const GrGlyph*> glyphs,
110                         SkSpan<const PositionAndExtent> positioning,
111                         GrColor color,
112                         const SkMatrix& positionMatrix,
113                         SkIRect clip,
114                         void* vertexBuffer) const;
115 
116     AtlasTextOp::MaskType opMaskType() const;
grMaskType() const117     GrMaskFormat grMaskType() const {return fMaskType;}
118 
119 private:
120     struct AtlasPt {
121         uint16_t u;
122         uint16_t v;
123     };
124 
125     // Normal text mask, SDFT, or color.
126     struct Mask2DVertex {
127         SkPoint devicePos;
128         GrColor color;
129         AtlasPt atlasPos;
130     };
131 
132     struct ARGB2DVertex {
ARGB2DVertex__anon2878be480111::TransformedMaskVertexFiller::ARGB2DVertex133         ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
134 
135         SkPoint devicePos;
136         AtlasPt atlasPos;
137     };
138 
139     // Perspective SDFT or SDFT forced to 3D or perspective color.
140     struct Mask3DVertex {
141         SkPoint3 devicePos;
142         GrColor color;
143         AtlasPt atlasPos;
144     };
145 
146     struct ARGB3DVertex {
ARGB3DVertex__anon2878be480111::TransformedMaskVertexFiller::ARGB3DVertex147         ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
148 
149         SkPoint3 devicePos;
150         AtlasPt atlasPos;
151     };
152 
153     std::array<SkScalar, 4> sourceRect(PositionAndExtent positionAndExtent) const;
154 
155     template<typename Quad, typename VertexData>
156     void fill2D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
157                 GrColor color,
158                 const SkMatrix& matrix) const;
159 
160     template<typename Quad, typename VertexData>
161     void fill3D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
162                 GrColor color,
163                 const SkMatrix& matrix) const;
164 
165     const GrMaskFormat fMaskType;
166     const SkPoint fPaddingInset;
167     const SkScalar fStrikeToSourceScale;
168 };
169 
TransformedMaskVertexFiller(GrMaskFormat maskFormat,int dstPadding,SkScalar strikeToSourceScale)170 TransformedMaskVertexFiller::TransformedMaskVertexFiller(GrMaskFormat maskFormat,
171                                                          int dstPadding,
172                                                          SkScalar strikeToSourceScale)
173         : fMaskType{maskFormat}
174         , fPaddingInset{SkPoint::Make(dstPadding, dstPadding)}
175         , fStrikeToSourceScale{strikeToSourceScale} {}
176 
fillVertexData(SkSpan<const GrGlyph * > glyphs,SkSpan<const PositionAndExtent> positioning,GrColor color,const SkMatrix & positionMatrix,SkIRect clip,void * vertexBuffer) const177 void TransformedMaskVertexFiller::fillVertexData(SkSpan<const GrGlyph*> glyphs,
178                                                  SkSpan<const PositionAndExtent> positioning,
179                                                  GrColor color,
180                                                  const SkMatrix& positionMatrix,
181                                                  SkIRect clip,
182                                                  void* vertexBuffer) const {
183     auto quadData = [&](auto dst) {
184         return SkMakeZip(dst, glyphs, positioning);
185     };
186 
187     if (!positionMatrix.hasPerspective()) {
188         if (fMaskType == GrMaskFormat::kARGB_GrMaskFormat) {
189             using Quad = ARGB2DVertex[4];
190             SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(positionMatrix));
191             this->fill2D(quadData((Quad*) vertexBuffer), color, positionMatrix);
192         } else {
193             using Quad = Mask2DVertex[4];
194             SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
195             this->fill2D(quadData((Quad*) vertexBuffer), color, positionMatrix);
196         }
197     } else {
198         if (fMaskType == GrMaskFormat::kARGB_GrMaskFormat) {
199             using Quad = ARGB3DVertex[4];
200             SkASSERT(sizeof(ARGB3DVertex) == this->vertexStride(positionMatrix));
201             this->fill3D(quadData((Quad*) vertexBuffer), color, positionMatrix);
202         } else {
203             using Quad = Mask3DVertex[4];
204             SkASSERT(sizeof(Mask3DVertex) == this->vertexStride(positionMatrix));
205             this->fill3D(quadData((Quad*) vertexBuffer), color, positionMatrix);
206         }
207     }
208 }
209 
210 std::array<SkScalar, 4>
sourceRect(PositionAndExtent positionAndExtent) const211 TransformedMaskVertexFiller::sourceRect(PositionAndExtent positionAndExtent) const {
212     auto[pos, rect] = positionAndExtent;
213     auto[l, t, r, b] = rect;
214     SkPoint LT = (SkPoint::Make(l, t) + fPaddingInset) * fStrikeToSourceScale + pos,
215             RB = (SkPoint::Make(r, b) - fPaddingInset) * fStrikeToSourceScale + pos;
216     return {LT.x(), LT.y(), RB.x(), RB.y()};
217 }
218 
219 template<typename Quad, typename VertexData>
fill2D(SkZip<Quad,const GrGlyph *,const VertexData> quadData,GrColor color,const SkMatrix & positionMatrix) const220 void TransformedMaskVertexFiller::fill2D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
221                                          GrColor color,
222                                          const SkMatrix& positionMatrix) const {
223     for (auto[quad, glyph, positionAndExtent] : quadData) {
224         auto [l, t, r, b] = this->sourceRect(positionAndExtent);
225         SkPoint lt = positionMatrix.mapXY(l, t),
226                 lb = positionMatrix.mapXY(l, b),
227                 rt = positionMatrix.mapXY(r, t),
228                 rb = positionMatrix.mapXY(r, b);
229         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
230         quad[0] = {lt, color, {al, at}};  // L,T
231         quad[1] = {lb, color, {al, ab}};  // L,B
232         quad[2] = {rt, color, {ar, at}};  // R,T
233         quad[3] = {rb, color, {ar, ab}};  // R,B
234     }
235 }
236 
237 template<typename Quad, typename VertexData>
fill3D(SkZip<Quad,const GrGlyph *,const VertexData> quadData,GrColor color,const SkMatrix & positionMatrix) const238 void TransformedMaskVertexFiller::fill3D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
239                                          GrColor color,
240                                          const SkMatrix& positionMatrix) const {
241     auto mapXYZ = [&](SkScalar x, SkScalar y) {
242         SkPoint pt{x, y};
243         SkPoint3 result;
244         positionMatrix.mapHomogeneousPoints(&result, &pt, 1);
245         return result;
246     };
247     for (auto[quad, glyph, positionAndExtent] : quadData) {
248         auto [l, t, r, b] = this->sourceRect(positionAndExtent);
249         SkPoint3 lt = mapXYZ(l, t),
250                  lb = mapXYZ(l, b),
251                  rt = mapXYZ(r, t),
252                  rb = mapXYZ(r, b);
253         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
254         quad[0] = {lt, color, {al, at}};  // L,T
255         quad[1] = {lb, color, {al, ab}};  // L,B
256         quad[2] = {rt, color, {ar, at}};  // R,T
257         quad[3] = {rb, color, {ar, ab}};  // R,B
258     }
259 }
260 
opMaskType() const261 AtlasTextOp::MaskType TransformedMaskVertexFiller::opMaskType() const {
262     switch (fMaskType) {
263         case kA8_GrMaskFormat:   return AtlasTextOp::MaskType::kGrayscaleCoverage;
264         case kA565_GrMaskFormat: return AtlasTextOp::MaskType::kLCDCoverage;
265         case kARGB_GrMaskFormat: return AtlasTextOp::MaskType::kColorBitmap;
266     }
267     SkUNREACHABLE;
268 }
269 
270 struct AtlasPt {
271     uint16_t u;
272     uint16_t v;
273 };
274 
275 // Normal text mask, SDFT, or color.
276 struct Mask2DVertex {
277     SkPoint devicePos;
278     GrColor color;
279     AtlasPt atlasPos;
280 };
281 
282 struct ARGB2DVertex {
ARGB2DVertex__anon2878be480111::ARGB2DVertex283     ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
284 
285     SkPoint devicePos;
286     AtlasPt atlasPos;
287 };
288 
289 // Perspective SDFT or SDFT forced to 3D or perspective color.
290 struct Mask3DVertex {
291     SkPoint3 devicePos;
292     GrColor color;
293     AtlasPt atlasPos;
294 };
295 
296 struct ARGB3DVertex {
ARGB3DVertex__anon2878be480111::ARGB3DVertex297     ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
298 
299     SkPoint3 devicePos;
300     AtlasPt atlasPos;
301 };
302 
op_mask_type(GrMaskFormat grMaskFormat)303 AtlasTextOp::MaskType op_mask_type(GrMaskFormat grMaskFormat) {
304     switch (grMaskFormat) {
305         case kA8_GrMaskFormat:   return AtlasTextOp::MaskType::kGrayscaleCoverage;
306         case kA565_GrMaskFormat: return AtlasTextOp::MaskType::kLCDCoverage;
307         case kARGB_GrMaskFormat: return AtlasTextOp::MaskType::kColorBitmap;
308     }
309     SkUNREACHABLE;
310 }
311 
position_matrix(const SkMatrix & drawMatrix,SkPoint drawOrigin)312 SkMatrix position_matrix(const SkMatrix& drawMatrix, SkPoint drawOrigin) {
313     SkMatrix position_matrix = drawMatrix;
314     return position_matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
315 }
316 
calculate_colors(skgpu::SurfaceContext * sc,const SkPaint & paint,const SkMatrixProvider & matrix,GrMaskFormat grMaskFormat,GrPaint * grPaint)317 SkPMColor4f calculate_colors(skgpu::SurfaceContext* sc,
318                              const SkPaint& paint,
319                              const SkMatrixProvider& matrix,
320                              GrMaskFormat grMaskFormat,
321                              GrPaint* grPaint) {
322     GrRecordingContext* rContext = sc->recordingContext();
323     const GrColorInfo& colorInfo = sc->colorInfo();
324     if (grMaskFormat == kARGB_GrMaskFormat) {
325         SkPaintToGrPaintReplaceShader(rContext, colorInfo, paint, matrix, nullptr, grPaint);
326         float a = grPaint->getColor4f().fA;
327         return {a, a, a, a};
328     }
329     SkPaintToGrPaint(rContext, colorInfo, paint, matrix, grPaint);
330     return grPaint->getColor4f();
331 }
332 
333 template<typename Quad, typename VertexData>
fill_transformed_vertices_2D(SkZip<Quad,const GrGlyph *,const VertexData> quadData,SkScalar dstPadding,SkScalar strikeToSource,GrColor color,const SkMatrix & matrix)334 void fill_transformed_vertices_2D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
335                                   SkScalar dstPadding,
336                                   SkScalar strikeToSource,
337                                   GrColor color,
338                                   const SkMatrix& matrix) {
339     SkPoint inset = {dstPadding, dstPadding};
340     for (auto[quad, glyph, vertexData] : quadData) {
341         auto[pos, rect] = vertexData;
342         auto[l, t, r, b] = rect;
343         SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos,
344                 sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos;
345         SkPoint lt = matrix.mapXY(sLT.x(), sLT.y()),
346                 lb = matrix.mapXY(sLT.x(), sRB.y()),
347                 rt = matrix.mapXY(sRB.x(), sLT.y()),
348                 rb = matrix.mapXY(sRB.x(), sRB.y());
349         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
350         quad[0] = {lt, color, {al, at}};  // L,T
351         quad[1] = {lb, color, {al, ab}};  // L,B
352         quad[2] = {rt, color, {ar, at}};  // R,T
353         quad[3] = {rb, color, {ar, ab}};  // R,B
354     }
355 }
356 
357 // Check for integer translate with the same 2x2 matrix.
358 // Returns the translation, and true if the change from initial matrix to the position matrix
359 // support using direct glyph masks.
can_use_direct(const SkMatrix & initialPositionMatrix,const SkMatrix & positionMatrix)360 std::tuple<bool, SkVector> can_use_direct(
361         const SkMatrix& initialPositionMatrix, const SkMatrix& positionMatrix) {
362     // The existing direct glyph info can be used if the initialPositionMatrix, and the
363     // positionMatrix have the same 2x2, and the translation between them is integer.
364     // Calculate the translation in source space to a translation in device space by mapping
365     // (0, 0) through both the initial position matrix and the position matrix; take the difference.
366     SkVector translation = positionMatrix.mapOrigin() - initialPositionMatrix.mapOrigin();
367     return {initialPositionMatrix.getScaleX() == positionMatrix.getScaleX() &&
368             initialPositionMatrix.getScaleY() == positionMatrix.getScaleY() &&
369             initialPositionMatrix.getSkewX()  == positionMatrix.getSkewX()  &&
370             initialPositionMatrix.getSkewY()  == positionMatrix.getSkewY()  &&
371             SkScalarIsInt(translation.x()) && SkScalarIsInt(translation.y()),
372             translation};
373 }
374 
375 // -- PathOpSubmitter ------------------------------------------------------------------------------
376 // Shared code for submitting GPU ops for drawing glyphs as paths.
377 class PathOpSubmitter {
378     struct PathAndPosition;
379 public:
380     PathOpSubmitter(bool isAntiAliased,
381                     SkScalar strikeToSourceScale,
382                     SkSpan<PathAndPosition> paths,
383                     std::unique_ptr<PathAndPosition[], GrSubRunAllocator::ArrayDestroyer> pathData);
384 
385     PathOpSubmitter(PathOpSubmitter&& that);
386 
387     static PathOpSubmitter Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
388                                 bool isAntiAliased,
389                                 SkScalar strikeToSourceScale,
390                                 GrSubRunAllocator* alloc);
391 
392     void submitOps(SkCanvas*,
393                    const GrClip* clip,
394                    const SkMatrixProvider& viewMatrix,
395                    SkPoint drawOrigin,
396                    const SkPaint& paint,
397                    skgpu::v1::SurfaceDrawContext* sdc) const;
398 
399 private:
400     struct PathAndPosition {
401         SkPath fPath;
402         SkPoint fPosition;
403     };
404     const bool fIsAntiAliased;
405     const SkScalar fStrikeToSourceScale;
406     const SkSpan<const PathAndPosition> fPaths;
407     std::unique_ptr<PathAndPosition[], GrSubRunAllocator::ArrayDestroyer> fPathData;
408 };
409 
PathOpSubmitter(bool isAntiAliased,SkScalar strikeToSourceScale,SkSpan<PathAndPosition> paths,std::unique_ptr<PathAndPosition[],GrSubRunAllocator::ArrayDestroyer> pathData)410 PathOpSubmitter::PathOpSubmitter(
411         bool isAntiAliased,
412         SkScalar strikeToSourceScale,
413         SkSpan<PathAndPosition> paths,
414         std::unique_ptr<PathAndPosition[], GrSubRunAllocator::ArrayDestroyer> pathData)
415             : fIsAntiAliased{isAntiAliased}
416             , fStrikeToSourceScale{strikeToSourceScale}
417             , fPaths{paths}
418             , fPathData{std::move(pathData)} {
419     SkASSERT(!fPaths.empty());
420 }
421 
PathOpSubmitter(PathOpSubmitter && that)422 PathOpSubmitter::PathOpSubmitter(PathOpSubmitter&& that)
423     : fIsAntiAliased{that.fIsAntiAliased}
424     , fStrikeToSourceScale{that.fStrikeToSourceScale}
425     , fPaths{that.fPaths}
426     , fPathData{std::move(that.fPathData)} {}
427 
Make(const SkZip<SkGlyphVariant,SkPoint> & accepted,bool isAntiAliased,SkScalar strikeToSourceScale,GrSubRunAllocator * alloc)428 PathOpSubmitter PathOpSubmitter::Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
429                                       bool isAntiAliased,
430                                       SkScalar strikeToSourceScale,
431                                       GrSubRunAllocator* alloc) {
432     auto pathData = alloc->makeUniqueArray<PathAndPosition>(
433             accepted.size(),
434             [&](int i){
435                 auto [variant, pos] = accepted[i];
436                 return PathAndPosition{*variant.path(), pos};
437             });
438     SkSpan<PathAndPosition> paths{pathData.get(), accepted.size()};
439 
440     return PathOpSubmitter{isAntiAliased, strikeToSourceScale, paths, std::move(pathData)};
441 }
442 
submitOps(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const443 void PathOpSubmitter::submitOps(SkCanvas* canvas,
444                                 const GrClip* clip,
445                                 const SkMatrixProvider& viewMatrix,
446                                 SkPoint drawOrigin,
447                                 const SkPaint& paint,
448                                 skgpu::v1::SurfaceDrawContext* sdc) const {
449     SkPaint runPaint{paint};
450     runPaint.setAntiAlias(fIsAntiAliased);
451     // If there are shaders, blurs or styles, the path must be scaled into source
452     // space independently of the CTM. This allows the CTM to be correct for the
453     // different effects.
454     GrStyle style(runPaint);
455 
456     bool needsExactCTM = runPaint.getShader()
457                          || style.applies()
458                          || runPaint.getMaskFilter();
459 
460     // Calculate the matrix that maps the path glyphs from their size in the strike to
461     // the graphics source space.
462     SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
463     strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
464     if (!needsExactCTM) {
465         for (const auto& pathPos : fPaths) {
466             const SkPath& path = pathPos.fPath;
467             const SkPoint pos = pathPos.fPosition;
468             // Transform the glyph to source space.
469             SkMatrix pathMatrix = strikeToSource;
470             pathMatrix.postTranslate(pos.x(), pos.y());
471 
472             SkAutoCanvasRestore acr(canvas, true);
473             canvas->concat(pathMatrix);
474             canvas->drawPath(path, runPaint);
475         }
476     } else {
477         // Transform the path to device because the deviceMatrix must be unchanged to
478         // draw effect, filter or shader paths.
479         for (const auto& pathPos : fPaths) {
480             const SkPath& path = pathPos.fPath;
481             const SkPoint pos = pathPos.fPosition;
482             // Transform the glyph to source space.
483             SkMatrix pathMatrix = strikeToSource;
484             pathMatrix.postTranslate(pos.x(), pos.y());
485 
486             SkPath deviceOutline;
487             path.transform(pathMatrix, &deviceOutline);
488             deviceOutline.setIsVolatile(true);
489             canvas->drawPath(deviceOutline, runPaint);
490         }
491     }
492 }
493 
494 // -- PathSubRun -----------------------------------------------------------------------------------
495 class PathSubRun final : public GrSubRun, public GrBlobSubRun {
496 public:
PathSubRun(PathOpSubmitter && pathDrawing)497     PathSubRun(PathOpSubmitter&& pathDrawing) : fPathDrawing(std::move(pathDrawing)) {}
498 
Make(const SkZip<SkGlyphVariant,SkPoint> & accepted,bool isAntiAliased,SkScalar strikeToSourceScale,GrSubRunAllocator * alloc)499     static GrSubRunOwner Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
500                               bool isAntiAliased,
501                               SkScalar strikeToSourceScale,
502                               GrSubRunAllocator* alloc) {
503         return alloc->makeUnique<PathSubRun>(
504                 PathOpSubmitter::Make(accepted, isAntiAliased, strikeToSourceScale, alloc));
505     }
506 
draw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const507     void draw(SkCanvas* canvas,
508               const GrClip* clip,
509               const SkMatrixProvider& viewMatrix,
510               SkPoint drawOrigin,
511               const SkPaint& paint,
512               skgpu::v1::SurfaceDrawContext* sdc) const override {
513         fPathDrawing.submitOps(canvas, clip, viewMatrix, drawOrigin, paint, sdc);
514     }
515 
blobCast() const516     const GrBlobSubRun* blobCast() const override { return this; }
unflattenSize() const517     int unflattenSize() const override { return 0; }
518 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const519     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
520         return true;
521     }
testingOnly_atlasSubRun() const522     const GrAtlasSubRun* testingOnly_atlasSubRun() const override { return nullptr; }
MakeFromBuffer(const GrTextReferenceFrame * referenceFrame,SkReadBuffer & buffer,GrSubRunAllocator * alloc,const SkStrikeClient * client)523     static GrSubRunOwner MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
524                                         SkReadBuffer& buffer,
525                                         GrSubRunAllocator* alloc,
526                                         const SkStrikeClient* client) {
527         return nullptr;
528     }
529 
530 protected:
subRunType() const531     SubRunType subRunType() const override { return kPath; }
doFlatten(SkWriteBuffer & buffer) const532     void doFlatten(SkWriteBuffer& buffer) const override {
533         SK_ABORT("Not implemented.");
534     }
535 
536 private:
537     PathOpSubmitter fPathDrawing;
538 };
539 
540 // -- DrawableOpSubmitter --------------------------------------------------------------------------
541 // Shared code for submitting GPU ops for drawing glyphs as drawables.
542 class DrawableOpSubmitter {
543     struct DrawableAndPosition;
544 public:
545     DrawableOpSubmitter(bool isAntiAliased,
546                         SkScalar strikeToSourceScale,
547                         SkSpan<DrawableAndPosition> drawables,
548                         std::unique_ptr<DrawableAndPosition[],
549                                         GrSubRunAllocator::ArrayDestroyer> drawableData);
550 
551     DrawableOpSubmitter(DrawableOpSubmitter&& that);
552 
553     static DrawableOpSubmitter Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
554                                     bool isAntiAliased,
555                                     SkScalar strikeToSourceScale,
556                                     GrSubRunAllocator* alloc);
557 
558     void submitOps(SkCanvas*,
559                    const GrClip* clip,
560                    const SkMatrixProvider& viewMatrix,
561                    SkPoint drawOrigin,
562                    const SkPaint& paint,
563                    skgpu::v1::SurfaceDrawContext* sdc) const;
564 
565 private:
566     struct DrawableAndPosition {
567         sk_sp<SkDrawable> fDrawable;
568         SkPoint fPosition;
569     };
570     const bool fIsAntiAliased;
571     const SkScalar fStrikeToSourceScale;
572     const SkSpan<const DrawableAndPosition> fDrawables;
573     std::unique_ptr<DrawableAndPosition[], GrSubRunAllocator::ArrayDestroyer> fDrawableData;
574 };
575 
DrawableOpSubmitter(bool isAntiAliased,SkScalar strikeToSourceScale,SkSpan<DrawableAndPosition> drawables,std::unique_ptr<DrawableAndPosition[],GrSubRunAllocator::ArrayDestroyer> drawableData)576 DrawableOpSubmitter::DrawableOpSubmitter(
577         bool isAntiAliased,
578         SkScalar strikeToSourceScale,
579         SkSpan<DrawableAndPosition> drawables,
580         std::unique_ptr<DrawableAndPosition[], GrSubRunAllocator::ArrayDestroyer> drawableData)
581             : fIsAntiAliased{isAntiAliased}
582             , fStrikeToSourceScale{strikeToSourceScale}
583             , fDrawables{drawables}
584             , fDrawableData{std::move(drawableData)} {
585     SkASSERT(!fDrawables.empty());
586 }
587 
DrawableOpSubmitter(DrawableOpSubmitter && that)588 DrawableOpSubmitter::DrawableOpSubmitter(DrawableOpSubmitter&& that)
589     : fIsAntiAliased{that.fIsAntiAliased}
590     , fStrikeToSourceScale{that.fStrikeToSourceScale}
591     , fDrawables{that.fDrawables}
592     , fDrawableData{std::move(that.fDrawableData)} {}
593 
Make(const SkZip<SkGlyphVariant,SkPoint> & accepted,bool isAntiAliased,SkScalar strikeToSourceScale,GrSubRunAllocator * alloc)594 DrawableOpSubmitter DrawableOpSubmitter::Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
595                                               bool isAntiAliased,
596                                               SkScalar strikeToSourceScale,
597                                               GrSubRunAllocator* alloc) {
598     auto drawableData = alloc->makeUniqueArray<DrawableAndPosition>(
599             accepted.size(),
600             [&](int i){
601                 auto [variant, pos] = accepted[i];
602                 return DrawableAndPosition{sk_ref_sp(variant.drawable()), pos};
603             });
604     SkSpan<DrawableAndPosition> drawables{drawableData.get(), accepted.size()};
605 
606     return DrawableOpSubmitter{isAntiAliased, strikeToSourceScale,
607                                drawables, std::move(drawableData)};
608 }
609 
submitOps(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const610 void DrawableOpSubmitter::submitOps(SkCanvas* canvas,
611                                     const GrClip* clip,
612                                     const SkMatrixProvider& viewMatrix,
613                                     SkPoint drawOrigin,
614                                     const SkPaint& paint,
615                                     skgpu::v1::SurfaceDrawContext* sdc) const {
616     // Calculate the matrix that maps the path glyphs from their size in the strike to
617     // the graphics source space.
618     SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
619     strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
620 
621     // Transform the path to device because the deviceMatrix must be unchanged to
622     // draw effect, filter or shader paths.
623     for (const auto& pathPos : fDrawables) {
624         const sk_sp<SkDrawable>& drawable = pathPos.fDrawable;
625         const SkPoint pos = pathPos.fPosition;
626         // Transform the glyph to source space.
627         SkMatrix pathMatrix = strikeToSource;
628         pathMatrix.postTranslate(pos.x(), pos.y());
629 
630         SkAutoCanvasRestore acr(canvas, false);
631         SkRect drawableBounds = drawable->getBounds();
632         pathMatrix.mapRect(&drawableBounds);
633         canvas->saveLayer(&drawableBounds, &paint);
634         drawable->draw(canvas, &pathMatrix);
635     }
636 }
637 
638 template <typename SubRun>
make_drawable_sub_run(const SkZip<SkGlyphVariant,SkPoint> & drawables,bool isAntiAliased,SkScalar strikeToSourceScale,GrSubRunAllocator * alloc)639 GrSubRunOwner make_drawable_sub_run(const SkZip<SkGlyphVariant, SkPoint>& drawables,
640                                    bool isAntiAliased,
641                                    SkScalar strikeToSourceScale,
642                                    GrSubRunAllocator* alloc) {
643     return alloc->makeUnique<SubRun>(
644             DrawableOpSubmitter::Make(drawables, isAntiAliased, strikeToSourceScale, alloc));
645 }
646 
647 // -- DrawableSubRunSlug ---------------------------------------------------------------------------
648 class DrawableSubRunSlug : public GrSubRun {
649 public:
DrawableSubRunSlug(DrawableOpSubmitter && drawingDrawing)650     DrawableSubRunSlug(DrawableOpSubmitter&& drawingDrawing)
651             : fDrawingDrawing(std::move(drawingDrawing)) {}
652 
MakeFromBuffer(const GrTextReferenceFrame * referenceFrame,SkReadBuffer & buffer,GrSubRunAllocator * alloc,const SkStrikeClient * client)653     static GrSubRunOwner MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
654                                         SkReadBuffer& buffer,
655                                         GrSubRunAllocator* alloc,
656                                         const SkStrikeClient* client) {
657         return nullptr;
658     }
659 
draw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const660     void draw(SkCanvas* canvas,
661               const GrClip* clip,
662               const SkMatrixProvider& viewMatrix,
663               SkPoint drawOrigin,
664               const SkPaint& paint,
665               skgpu::v1::SurfaceDrawContext* sdc) const override {
666         fDrawingDrawing.submitOps(canvas, clip, viewMatrix, drawOrigin, paint, sdc);
667     }
668 
unflattenSize() const669     int unflattenSize() const override { return 0; }
670 
671 protected:
subRunType() const672     SubRunType subRunType() const override { return kDrawable; }
doFlatten(SkWriteBuffer & buffer) const673     void doFlatten(SkWriteBuffer& buffer) const override {
674         SK_ABORT("Not implemented.");
675     }
676 
677 private:
678     DrawableOpSubmitter fDrawingDrawing;
679 };
680 
681 // -- DrawableSubRun -------------------------------------------------------------------------------
682 class DrawableSubRun final : public DrawableSubRunSlug, public GrBlobSubRun {
683 public:
684     using DrawableSubRunSlug::DrawableSubRunSlug;
blobCast() const685     const GrBlobSubRun* blobCast() const override { return this; }
unflattenSize() const686     int unflattenSize() const override { return 0; }
687 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const688     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
689         return true;
690     }
testingOnly_atlasSubRun() const691     const GrAtlasSubRun* testingOnly_atlasSubRun() const override { return nullptr; }
692 };
693 
694 // -- DirectMaskSubRun -----------------------------------------------------------------------------
695 class DirectMaskSubRun final : public GrSubRun, public GrBlobSubRun, public GrAtlasSubRun {
696 public:
697     using DevicePosition = skvx::Vec<2, int16_t>;
698 
699     DirectMaskSubRun(const GrTextReferenceFrame* referenceFrame,
700                      GrMaskFormat format,
701                      const SkGlyphRect& deviceBounds,
702                      SkSpan<const DevicePosition> devicePositions,
703                      GrGlyphVector&& glyphs,
704                      bool glyphsOutOfBounds,
705                      bool supportBilerpAtlas);
706 
707     static GrSubRunOwner Make(const GrTextBlob* blob,
708                               const SkZip<SkGlyphVariant, SkPoint>& accepted,
709                               sk_sp<SkStrike>&& strike,
710                               GrMaskFormat format,
711                               GrSubRunAllocator* alloc);
712 
713     void draw(SkCanvas*,
714               const GrClip*,
715               const SkMatrixProvider& viewMatrix,
716               SkPoint drawOrigin,
717               const SkPaint& paint,
718               skgpu::v1::SurfaceDrawContext*) const override;
719 
720     std::tuple<const GrClip*, GrOp::Owner>
721     makeAtlasTextOp(const GrClip* clip,
722                     const SkMatrixProvider& viewMatrix,
723                     SkPoint drawOrigin,
724                     const SkPaint& paint,
725                     skgpu::v1::SurfaceDrawContext* sdc,
726                     GrAtlasSubRunOwner) const override;
727 
blobCast() const728     const GrBlobSubRun* blobCast() const override { return this; }
unflattenSize() const729     int unflattenSize() const override { return 0; }
730 
731     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override;
732 
733     const GrAtlasSubRun* testingOnly_atlasSubRun() const override;
734 
735     size_t vertexStride(const SkMatrix& drawMatrix) const override;
736 
737     int glyphCount() const override;
738 
739     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
740 
741     std::tuple<bool, int>
742     regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
743 
744     void fillVertexData(void* vertexDst, int offset, int count,
745                         GrColor color,
746                         const SkMatrix& drawMatrix, SkPoint drawOrigin,
747                         SkIRect clip) const override;
748 
749 protected:
subRunType() const750     SubRunType subRunType() const override { return kDirectMask; }
doFlatten(SkWriteBuffer & buffer) const751     void doFlatten(SkWriteBuffer& buffer) const override {
752         SK_ABORT("Not implemented.");
753     }
754 
755 private:
756     // The rectangle that surrounds all the glyph bounding boxes in device space.
757     SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
758 
759     const GrTextReferenceFrame* const fTextReferenceFrame;
760     const GrMaskFormat fMaskFormat;
761 
762     // The union of all the glyph bounds in device space.
763     const SkGlyphRect fGlyphDeviceBounds;
764     const SkSpan<const DevicePosition> fLeftTopDevicePos;
765     const bool fSomeGlyphsExcluded;
766     const bool fSupportBilerpAtlas;
767 
768     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
769     // be single threaded.
770     mutable GrGlyphVector fGlyphs;
771 };
772 
DirectMaskSubRun(const GrTextReferenceFrame * referenceFrame,GrMaskFormat format,const SkGlyphRect & deviceBounds,SkSpan<const DevicePosition> devicePositions,GrGlyphVector && glyphs,bool glyphsOutOfBounds,bool supportBilerpAtlas)773 DirectMaskSubRun::DirectMaskSubRun(const GrTextReferenceFrame* referenceFrame,
774                                    GrMaskFormat format,
775                                    const SkGlyphRect& deviceBounds,
776                                    SkSpan<const DevicePosition> devicePositions,
777                                    GrGlyphVector&& glyphs,
778                                    bool glyphsOutOfBounds,
779                                    bool supportBilerpAtlas)
780         : fTextReferenceFrame{referenceFrame}
781         , fMaskFormat{format}
782         , fGlyphDeviceBounds{deviceBounds}
783         , fLeftTopDevicePos{devicePositions}
784         , fSomeGlyphsExcluded{glyphsOutOfBounds}
785         , fSupportBilerpAtlas{supportBilerpAtlas}
786         , fGlyphs{std::move(glyphs)} {}
787 
Make(const GrTextBlob * blob,const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,GrMaskFormat format,GrSubRunAllocator * alloc)788 GrSubRunOwner DirectMaskSubRun::Make(const GrTextBlob* blob,
789                                      const SkZip<SkGlyphVariant, SkPoint>& accepted,
790                                      sk_sp<SkStrike>&& strike,
791                                      GrMaskFormat format,
792                                      GrSubRunAllocator* alloc) {
793     auto glyphLeftTop = alloc->makePODArray<DevicePosition>(accepted.size());
794     auto glyphIDs = alloc->makePODArray<GrGlyphVector::Variant>(accepted.size());
795 
796     // Because this is the direct case, the maximum width or height is the size that fits in the
797     // atlas. This boundary is checked below to ensure that the call to SkGlyphRect below will
798     // not overflow.
799     constexpr SkScalar kMaxPos =
800             std::numeric_limits<int16_t>::max() - SkStrikeCommon::kSkSideTooBigForAtlas;
801     SkGlyphRect runBounds = skglyph::empty_rect();
802     size_t goodPosCount = 0;
803     for (auto [variant, pos] : accepted) {
804         auto [x, y] = pos;
805         // Ensure that the .offset() call below does not overflow. And, at this point none of the
806         // rectangles are empty because they were culled before the run was created. Basically,
807         // cull all the glyphs that can't appear on the screen.
808         if (-kMaxPos < x && x < kMaxPos && -kMaxPos  < y && y < kMaxPos) {
809             const SkGlyph* const skGlyph = variant;
810             const SkGlyphRect deviceBounds =
811                     skGlyph->glyphRect().offset(SkScalarRoundToInt(x), SkScalarRoundToInt(y));
812             runBounds = skglyph::rect_union(runBounds, deviceBounds);
813             glyphLeftTop[goodPosCount] = deviceBounds.topLeft();
814             glyphIDs[goodPosCount].packedGlyphID = skGlyph->getPackedID();
815             goodPosCount += 1;
816         }
817     }
818 
819     // Wow! no glyphs are in bounds and had non-empty bounds.
820     if (goodPosCount == 0) {
821         return nullptr;
822     }
823 
824     // If some glyphs were excluded by the bounds, then this subrun can't be generally be used
825     // for other draws. Mark the subrun as not general.
826     bool glyphsExcluded = goodPosCount != accepted.size();
827     SkSpan<const DevicePosition> leftTop{glyphLeftTop, goodPosCount};
828     return alloc->makeUnique<DirectMaskSubRun>(
829             blob, format, runBounds, leftTop,
830             GrGlyphVector{std::move(strike), {glyphIDs, goodPosCount}},
831             glyphsExcluded,
832             blob->supportBilerpAtlas());
833 }
834 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const835 bool DirectMaskSubRun::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
836     auto [reuse, translation] =
837             can_use_direct(fTextReferenceFrame->initialPositionMatrix(), positionMatrix);
838 
839     // If glyphs were excluded because of position bounds, then this subrun can only be reused if
840     // there is no change in position.
841     if (fSomeGlyphsExcluded) {
842         return translation.x() == 0 && translation.y() == 0;
843     }
844 
845     return reuse;
846 }
847 
vertexStride(const SkMatrix &) const848 size_t DirectMaskSubRun::vertexStride(const SkMatrix&) const {
849     if (fMaskFormat != kARGB_GrMaskFormat) {
850         return sizeof(Mask2DVertex);
851     } else {
852         return sizeof(ARGB2DVertex);
853     }
854 }
855 
glyphCount() const856 int DirectMaskSubRun::glyphCount() const {
857     return SkCount(fGlyphs.glyphs());
858 }
859 
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const860 void DirectMaskSubRun::draw(SkCanvas*,
861                             const GrClip* clip,
862                             const SkMatrixProvider& viewMatrix,
863                             SkPoint drawOrigin,
864                             const SkPaint& paint,
865                             skgpu::v1::SurfaceDrawContext* sdc) const{
866     auto[drawingClip, op] = this->makeAtlasTextOp(
867             clip, viewMatrix, drawOrigin, paint, sdc, nullptr);
868     if (op != nullptr) {
869         sdc->addDrawOp(drawingClip, std::move(op));
870     }
871 }
872 
873 namespace {
874 enum ClipMethod {
875     kClippedOut,
876     kUnclipped,
877     kGPUClipped,
878     kGeometryClipped
879 };
880 
881 std::tuple<ClipMethod, SkIRect>
calculate_clip(const GrClip * clip,SkRect deviceBounds,SkRect glyphBounds)882 calculate_clip(const GrClip* clip, SkRect deviceBounds, SkRect glyphBounds) {
883     if (clip == nullptr && !deviceBounds.intersects(glyphBounds)) {
884         return {kClippedOut, SkIRect::MakeEmpty()};
885     } else if (clip != nullptr) {
886         switch (auto result = clip->preApply(glyphBounds, GrAA::kNo); result.fEffect) {
887             case GrClip::Effect::kClippedOut:
888                 return {kClippedOut, SkIRect::MakeEmpty()};
889             case GrClip::Effect::kUnclipped:
890                 return {kUnclipped, SkIRect::MakeEmpty()};
891             case GrClip::Effect::kClipped: {
892                 if (result.fIsRRect && result.fRRect.isRect()) {
893                     SkRect r = result.fRRect.rect();
894                     if (result.fAA == GrAA::kNo || GrClip::IsPixelAligned(r)) {
895                         SkIRect clipRect = SkIRect::MakeEmpty();
896                         // Clip geometrically during onPrepare using clipRect.
897                         r.round(&clipRect);
898                         if (clipRect.contains(glyphBounds)) {
899                             // If fully within the clip, signal no clipping using the empty rect.
900                             return {kUnclipped, SkIRect::MakeEmpty()};
901                         }
902                         // Use the clipRect to clip the geometry.
903                         return {kGeometryClipped, clipRect};
904                     }
905                     // Partial pixel clipped at this point. Have the GPU handle it.
906                 }
907             }
908             break;
909         }
910     }
911     return {kGPUClipped, SkIRect::MakeEmpty()};
912 }
913 }  // namespace
914 
915 std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner) const916 DirectMaskSubRun::makeAtlasTextOp(const GrClip* clip,
917                                   const SkMatrixProvider& viewMatrix,
918                                   SkPoint drawOrigin,
919                                   const SkPaint& paint,
920                                   skgpu::v1::SurfaceDrawContext* sdc,
921                                   GrAtlasSubRunOwner) const {
922     SkASSERT(this->glyphCount() != 0);
923 
924     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
925 
926     // We can clip geometrically using clipRect and ignore clip when an axis-aligned rectangular
927     // non-AA clip is used. If clipRect is empty, and clip is nullptr, then there is no clipping
928     // needed.
929     const SkRect subRunBounds = this->deviceRect(drawMatrix, drawOrigin);
930     const SkRect deviceBounds = SkRect::MakeWH(sdc->width(), sdc->height());
931     auto [clipMethod, clipRect] = calculate_clip(clip, deviceBounds, subRunBounds);
932 
933     switch (clipMethod) {
934         case kClippedOut:
935             // Returning nullptr as op means skip this op.
936             return {nullptr, nullptr};
937         case kUnclipped:
938         case kGeometryClipped:
939             // GPU clip is not needed.
940             clip = nullptr;
941             break;
942         case kGPUClipped:
943             // Use the GPU clip; clipRect is ignored.
944             break;
945     }
946 
947     if (!clipRect.isEmpty()) { SkASSERT(clip == nullptr); }
948 
949     GrPaint grPaint;
950     const SkPMColor4f drawingColor =
951             calculate_colors(sdc, paint, viewMatrix, fMaskFormat, &grPaint);
952 
953     auto geometry = AtlasTextOp::Geometry::MakeForBlob(*this,
954                                                        drawMatrix,
955                                                        drawOrigin,
956                                                        clipRect,
957                                                        sk_ref_sp(fTextReferenceFrame),
958                                                        drawingColor,
959                                                        sdc->arenaAlloc());
960 
961     GrRecordingContext* const rContext = sdc->recordingContext();
962     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
963                                              op_mask_type(fMaskFormat),
964                                              false,
965                                              this->glyphCount(),
966                                              subRunBounds,
967                                              geometry,
968                                              std::move(grPaint));
969 
970     return {clip, std::move(op)};
971 }
972 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const973 void DirectMaskSubRun::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
974     fGlyphs.packedGlyphIDToGrGlyph(cache);
975 }
976 
977 std::tuple<bool, int>
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const978 DirectMaskSubRun::regenerateAtlas(int begin, int end, GrMeshDrawTarget* target) const {
979     int srcPadding = fSupportBilerpAtlas ? 1 : 0;
980     return fGlyphs.regenerateAtlas(
981             begin, end, fMaskFormat, srcPadding, target, fSupportBilerpAtlas);
982 }
983 
984 // The 99% case. No clip. Non-color only.
direct_2D(SkZip<Mask2DVertex[4],const GrGlyph *,const DirectMaskSubRun::DevicePosition> quadData,GrColor color,SkPoint originOffset)985 void direct_2D(SkZip<Mask2DVertex[4],
986                const GrGlyph*,
987                const DirectMaskSubRun::DevicePosition> quadData,
988                GrColor color,
989                SkPoint originOffset) {
990     for (auto[quad, glyph, leftTop] : quadData) {
991         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
992         SkScalar dl = leftTop[0] + originOffset.x(),
993                  dt = leftTop[1] + originOffset.y(),
994                  dr = dl + (ar - al),
995                  db = dt + (ab - at);
996 
997         quad[0] = {{dl, dt}, color, {al, at}};  // L,T
998         quad[1] = {{dl, db}, color, {al, ab}};  // L,B
999         quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
1000         quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
1001     }
1002 }
1003 
1004 template <typename Rect>
ltbr(const Rect & r)1005 auto ltbr(const Rect& r) {
1006     return std::make_tuple(r.left(), r.top(), r.right(), r.bottom());
1007 }
1008 
1009 // Handle any combination of BW or color and clip or no clip.
1010 template<typename Quad, typename VertexData>
generalized_direct_2D(SkZip<Quad,const GrGlyph *,const VertexData> quadData,GrColor color,SkPoint originOffset,SkIRect * clip=nullptr)1011 void generalized_direct_2D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
1012                            GrColor color,
1013                            SkPoint originOffset,
1014                            SkIRect* clip = nullptr) {
1015     for (auto[quad, glyph, leftTop] : quadData) {
1016         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
1017         uint16_t w = ar - al,
1018                  h = ab - at;
1019         SkScalar l = (SkScalar)leftTop[0] + originOffset.x(),
1020                  t = (SkScalar)leftTop[1] + originOffset.y();
1021         if (clip == nullptr) {
1022             auto[dl, dt, dr, db] = SkRect::MakeLTRB(l, t, l + w, t + h);
1023             quad[0] = {{dl, dt}, color, {al, at}};  // L,T
1024             quad[1] = {{dl, db}, color, {al, ab}};  // L,B
1025             quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
1026             quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
1027         } else {
1028             SkIRect devIRect = SkIRect::MakeLTRB(l, t, l + w, t + h);
1029             SkScalar dl, dt, dr, db;
1030             if (!clip->containsNoEmptyCheck(devIRect)) {
1031                 if (SkIRect clipped; clipped.intersect(devIRect, *clip)) {
1032                     al += clipped.left()   - devIRect.left();
1033                     at += clipped.top()    - devIRect.top();
1034                     ar += clipped.right()  - devIRect.right();
1035                     ab += clipped.bottom() - devIRect.bottom();
1036                     std::tie(dl, dt, dr, db) = ltbr(clipped);
1037                 } else {
1038                     // TODO: omit generating any vertex data for fully clipped glyphs ?
1039                     std::tie(dl, dt, dr, db) = std::make_tuple(0, 0, 0, 0);
1040                     std::tie(al, at, ar, ab) = std::make_tuple(0, 0, 0, 0);
1041                 }
1042             } else {
1043                 std::tie(dl, dt, dr, db) = ltbr(devIRect);
1044             }
1045             quad[0] = {{dl, dt}, color, {al, at}};  // L,T
1046             quad[1] = {{dl, db}, color, {al, ab}};  // L,B
1047             quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
1048             quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
1049         }
1050     }
1051 }
1052 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1053 void DirectMaskSubRun::fillVertexData(void* vertexDst, int offset, int count,
1054                                       GrColor color,
1055                                       const SkMatrix& drawMatrix, SkPoint drawOrigin,
1056                                       SkIRect clip) const {
1057     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1058     auto quadData = [&](auto dst) {
1059         return SkMakeZip(dst,
1060                          fGlyphs.glyphs().subspan(offset, count),
1061                          fLeftTopDevicePos.subspan(offset, count));
1062     };
1063 
1064     SkPoint originOffset =
1065             positionMatrix.mapOrigin() - fTextReferenceFrame->initialPositionMatrix().mapOrigin();
1066 
1067     if (clip.isEmpty()) {
1068         if (fMaskFormat != kARGB_GrMaskFormat) {
1069             using Quad = Mask2DVertex[4];
1070             SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
1071             direct_2D(quadData((Quad*)vertexDst), color, originOffset);
1072         } else {
1073             using Quad = ARGB2DVertex[4];
1074             SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(positionMatrix));
1075             generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset);
1076         }
1077     } else {
1078         if (fMaskFormat != kARGB_GrMaskFormat) {
1079             using Quad = Mask2DVertex[4];
1080             SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
1081             generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset, &clip);
1082         } else {
1083             using Quad = ARGB2DVertex[4];
1084             SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(positionMatrix));
1085             generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset, &clip);
1086         }
1087     }
1088 }
1089 
deviceRect(const SkMatrix & drawMatrix,SkPoint drawOrigin) const1090 SkRect DirectMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
1091     SkIRect outBounds = fGlyphDeviceBounds.iRect();
1092 
1093     // Calculate the offset from the initial device origin to the current device origin.
1094     SkVector offset = drawMatrix.mapPoint(drawOrigin) -
1095                       fTextReferenceFrame->initialPositionMatrix().mapOrigin();
1096 
1097     // The offset should be integer, but make sure.
1098     SkIVector iOffset = {SkScalarRoundToInt(offset.x()), SkScalarRoundToInt(offset.y())};
1099 
1100     return SkRect::Make(outBounds.makeOffset(iOffset));
1101 }
1102 
testingOnly_atlasSubRun() const1103 const GrAtlasSubRun* DirectMaskSubRun::testingOnly_atlasSubRun() const {
1104     return this;
1105 }
1106 
1107 // -- TransformedMaskSubRun ------------------------------------------------------------------------
1108 class TransformedMaskSubRun final : public GrSubRun, public GrBlobSubRun, public GrAtlasSubRun {
1109 public:
1110     using VertexData = TransformedMaskVertexFiller::PositionAndExtent;
1111 
1112     TransformedMaskSubRun(const GrTextReferenceFrame* referenceFrame,
1113                           GrMaskFormat format,
1114                           SkScalar strikeToSourceScale,
1115                           const SkRect& bounds,
1116                           SkSpan<const VertexData> vertexData,
1117                           GrGlyphVector&& glyphs);
1118 
1119     static GrSubRunOwner Make(const GrTextReferenceFrame* referenceFrame,
1120                               const SkZip<SkGlyphVariant, SkPoint>& accepted,
1121                               sk_sp<SkStrike>&& strike,
1122                               SkScalar strikeToSourceScale,
1123                               GrMaskFormat format,
1124                               GrSubRunAllocator* alloc);
1125 
MakeFromBuffer(const GrTextReferenceFrame * referenceFrame,SkReadBuffer & buffer,GrSubRunAllocator * alloc,const SkStrikeClient * client)1126     static GrSubRunOwner MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
1127                                         SkReadBuffer& buffer,
1128                                         GrSubRunAllocator* alloc,
1129                                         const SkStrikeClient* client) {
1130         return nullptr;
1131     }
1132 
1133     void draw(SkCanvas*,
1134               const GrClip*,
1135               const SkMatrixProvider& viewMatrix,
1136               SkPoint drawOrigin,
1137               const SkPaint& paint,
1138               skgpu::v1::SurfaceDrawContext*) const override;
1139 
1140     std::tuple<const GrClip*, GrOp::Owner>
1141     makeAtlasTextOp(const GrClip*,
1142                     const SkMatrixProvider& viewMatrix,
1143                     SkPoint drawOrigin,
1144                     const SkPaint&,
1145                     skgpu::v1::SurfaceDrawContext*,
1146                     GrAtlasSubRunOwner) const override;
1147 
blobCast() const1148     const GrBlobSubRun* blobCast() const override { return this; }
unflattenSize() const1149     int unflattenSize() const override { return 0; }
1150 
1151     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override;
1152 
1153     const GrAtlasSubRun* testingOnly_atlasSubRun() const override;
1154 
1155     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
1156 
1157     std::tuple<bool, int> regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
1158 
1159     void fillVertexData(
1160             void* vertexDst, int offset, int count,
1161             GrColor color,
1162             const SkMatrix& drawMatrix, SkPoint drawOrigin,
1163             SkIRect clip) const override;
1164 
1165     size_t vertexStride(const SkMatrix& drawMatrix) const override;
1166     int glyphCount() const override;
1167 
1168 protected:
subRunType() const1169     SubRunType subRunType() const override { return kTransformMask; }
doFlatten(SkWriteBuffer & buffer) const1170     void doFlatten(SkWriteBuffer& buffer) const override {
1171         SK_ABORT("Not implemented.");
1172     }
1173 
1174 private:
1175     // The rectangle that surrounds all the glyph bounding boxes in device space.
1176     SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
1177 
1178     const TransformedMaskVertexFiller fVertexFiller;
1179 
1180     const GrTextReferenceFrame* const fReferenceFrame;
1181 
1182     // The bounds in source space. The bounds are the joined rectangles of all the glyphs.
1183     const SkRect fVertexBounds;
1184     const SkSpan<const VertexData> fVertexData;
1185 
1186     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1187     // be single threaded.
1188     mutable GrGlyphVector fGlyphs;
1189 };
1190 
TransformedMaskSubRun(const GrTextReferenceFrame * referenceFrame,GrMaskFormat format,SkScalar strikeToSourceScale,const SkRect & bounds,SkSpan<const VertexData> vertexData,GrGlyphVector && glyphs)1191 TransformedMaskSubRun::TransformedMaskSubRun(const GrTextReferenceFrame* referenceFrame,
1192                                              GrMaskFormat format,
1193                                              SkScalar strikeToSourceScale,
1194                                              const SkRect& bounds,
1195                                              SkSpan<const VertexData> vertexData,
1196                                              GrGlyphVector&& glyphs)
1197         : fVertexFiller{format, 0, strikeToSourceScale}
1198         , fReferenceFrame{referenceFrame}
1199         , fVertexBounds{bounds}
1200         , fVertexData{vertexData}
1201         , fGlyphs{std::move(glyphs)} { }
1202 
Make(const GrTextReferenceFrame * referenceFrame,const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,GrMaskFormat format,GrSubRunAllocator * alloc)1203 GrSubRunOwner TransformedMaskSubRun::Make(const GrTextReferenceFrame* referenceFrame,
1204                                           const SkZip<SkGlyphVariant, SkPoint>& accepted,
1205                                           sk_sp<SkStrike>&& strike,
1206                                           SkScalar strikeToSourceScale,
1207                                           GrMaskFormat format,
1208                                           GrSubRunAllocator* alloc) {
1209     SkRect bounds = SkRectPriv::MakeLargestInverted();
1210 
1211     SkSpan<VertexData> vertexData = alloc->makePODArray<VertexData>(
1212             accepted,
1213             [&](auto e) {
1214                 auto [variant, pos] = e;
1215                 const SkGlyph* skGlyph = variant;
1216                 int16_t l = skGlyph->left(),
1217                         t = skGlyph->top(),
1218                         r = l + skGlyph->width(),
1219                         b = t + skGlyph->height();
1220                 SkPoint lt = SkPoint::Make(l, t) * strikeToSourceScale + pos,
1221                         rb = SkPoint::Make(r, b) * strikeToSourceScale + pos;
1222 
1223                 bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
1224                 return VertexData{pos, {l, t, r, b}};
1225             });
1226 
1227     return alloc->makeUnique<TransformedMaskSubRun>(
1228             referenceFrame, format, strikeToSourceScale, bounds, vertexData,
1229             GrGlyphVector::Make(std::move(strike), accepted.get<0>(), alloc));
1230 }
1231 
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const1232 void TransformedMaskSubRun::draw(SkCanvas*,
1233                                  const GrClip* clip,
1234                                  const SkMatrixProvider& viewMatrix,
1235                                  SkPoint drawOrigin,
1236                                  const SkPaint& paint,
1237                                  skgpu::v1::SurfaceDrawContext* sdc) const {
1238     auto[drawingClip, op] = this->makeAtlasTextOp(
1239             clip, viewMatrix, drawOrigin, paint, sdc, nullptr);
1240     if (op != nullptr) {
1241         sdc->addDrawOp(drawingClip, std::move(op));
1242     }
1243 }
1244 
1245 std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner) const1246 TransformedMaskSubRun::makeAtlasTextOp(const GrClip* clip,
1247                                        const SkMatrixProvider& viewMatrix,
1248                                        SkPoint drawOrigin,
1249                                        const SkPaint& paint,
1250                                        skgpu::v1::SurfaceDrawContext* sdc,
1251                                        GrAtlasSubRunOwner) const {
1252     SkASSERT(this->glyphCount() != 0);
1253 
1254     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
1255 
1256     GrPaint grPaint;
1257     SkPMColor4f drawingColor = calculate_colors(
1258             sdc, paint, viewMatrix, fVertexFiller.grMaskType(), &grPaint);
1259 
1260     auto geometry = AtlasTextOp::Geometry::MakeForBlob(*this,
1261                                                        drawMatrix,
1262                                                        drawOrigin,
1263                                                        SkIRect::MakeEmpty(),
1264                                                        sk_ref_sp(fReferenceFrame),
1265                                                        drawingColor,
1266                                                        sdc->arenaAlloc());
1267 
1268     GrRecordingContext* const rContext = sdc->recordingContext();
1269     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1270                                              fVertexFiller.opMaskType(),
1271                                              true,
1272                                              this->glyphCount(),
1273                                              this->deviceRect(drawMatrix, drawOrigin),
1274                                              geometry,
1275                                              std::move(grPaint));
1276     return {clip, std::move(op)};
1277 }
1278 
1279 // If we are not scaling the cache entry to be larger, than a cache with smaller glyphs may be
1280 // better.
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1281 bool TransformedMaskSubRun::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
1282     if (fReferenceFrame->initialPositionMatrix().getMaxScale() < 1) {
1283         return false;
1284     }
1285     return true;
1286 }
1287 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const1288 void TransformedMaskSubRun::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
1289     fGlyphs.packedGlyphIDToGrGlyph(cache);
1290 }
1291 
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const1292 std::tuple<bool, int> TransformedMaskSubRun::regenerateAtlas(int begin, int end,
1293                                                              GrMeshDrawTarget* target) const {
1294     return fGlyphs.regenerateAtlas(begin, end, fVertexFiller.grMaskType(), 1, target, true);
1295 }
1296 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1297 void TransformedMaskSubRun::fillVertexData(void* vertexDst, int offset, int count,
1298                                            GrColor color,
1299                                            const SkMatrix& drawMatrix, SkPoint drawOrigin,
1300                                            SkIRect clip) const {
1301     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1302     fVertexFiller.fillVertexData(fGlyphs.glyphs().subspan(offset, count),
1303                                  fVertexData.subspan(offset, count),
1304                                  color,
1305                                  positionMatrix,
1306                                  clip,
1307                                  vertexDst);
1308 }
1309 
vertexStride(const SkMatrix & drawMatrix) const1310 size_t TransformedMaskSubRun::vertexStride(const SkMatrix& drawMatrix) const {
1311     return fVertexFiller.vertexStride(drawMatrix);
1312 }
1313 
glyphCount() const1314 int TransformedMaskSubRun::glyphCount() const {
1315     return SkCount(fVertexData);
1316 }
1317 
deviceRect(const SkMatrix & drawMatrix,SkPoint drawOrigin) const1318 SkRect TransformedMaskSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
1319     SkRect outBounds = fVertexBounds;
1320     outBounds.offset(drawOrigin);
1321     return drawMatrix.mapRect(outBounds);
1322 }
1323 
testingOnly_atlasSubRun() const1324 const GrAtlasSubRun* TransformedMaskSubRun::testingOnly_atlasSubRun() const {
1325     return this;
1326 }
1327 
1328 // -- SDFTSubRun -----------------------------------------------------------------------------------
1329 class SDFTSubRun final : public GrSubRun, public GrBlobSubRun, public GrAtlasSubRun {
1330 public:
1331     using VertexData = TransformedMaskVertexFiller::PositionAndExtent;
1332 
1333     SDFTSubRun(const GrTextReferenceFrame* referenceFrame,
1334                SkScalar strikeToSource,
1335                SkRect vertexBounds,
1336                SkSpan<const VertexData> vertexData,
1337                GrGlyphVector&& glyphs,
1338                bool useLCDText,
1339                bool antiAliased,
1340                const GrSDFTMatrixRange& matrixRange);
1341 
1342     static GrSubRunOwner Make(const GrTextReferenceFrame* referenceFrame,
1343                               const SkZip<SkGlyphVariant, SkPoint>& accepted,
1344                               const SkFont& runFont,
1345                               sk_sp<SkStrike>&& strike,
1346                               SkScalar strikeToSourceScale,
1347                               const GrSDFTMatrixRange& matrixRange,
1348                               GrSubRunAllocator* alloc);
1349 
MakeFromBuffer(const GrTextReferenceFrame * referenceFrame,SkReadBuffer & buffer,GrSubRunAllocator * alloc,const SkStrikeClient * client)1350     static GrSubRunOwner MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
1351                                         SkReadBuffer& buffer,
1352                                         GrSubRunAllocator* alloc,
1353                                         const SkStrikeClient* client) {
1354         return nullptr;
1355     }
1356 
1357     void draw(SkCanvas*,
1358               const GrClip*,
1359               const SkMatrixProvider& viewMatrix,
1360               SkPoint drawOrigin,
1361               const SkPaint&,
1362               skgpu::v1::SurfaceDrawContext*) const override;
1363 
1364     std::tuple<const GrClip*, GrOp::Owner>
1365     makeAtlasTextOp(const GrClip*,
1366                     const SkMatrixProvider& viewMatrix,
1367                     SkPoint drawOrigin,
1368                     const SkPaint&,
1369                     skgpu::v1::SurfaceDrawContext*,
1370                     GrAtlasSubRunOwner) const override;
1371 
blobCast() const1372     const GrBlobSubRun* blobCast() const override { return this; }
unflattenSize() const1373     int unflattenSize() const override { return 0; }
1374 
1375     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override;
1376 
1377     const GrAtlasSubRun* testingOnly_atlasSubRun() const override;
1378 
1379     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
1380 
1381     std::tuple<bool, int> regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
1382 
1383     void fillVertexData(
1384             void* vertexDst, int offset, int count,
1385             GrColor color,
1386             const SkMatrix& drawMatrix, SkPoint drawOrigin,
1387             SkIRect clip) const override;
1388 
1389     size_t vertexStride(const SkMatrix& drawMatrix) const override;
1390     int glyphCount() const override;
1391 
1392 protected:
subRunType() const1393     SubRunType subRunType() const override { return kSDFT; }
doFlatten(SkWriteBuffer & buffer) const1394     void doFlatten(SkWriteBuffer& buffer) const override {
1395         SK_ABORT("Not implemented.");
1396     }
1397 
1398 private:
1399     // The rectangle that surrounds all the glyph bounding boxes in device space.
1400     SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
1401 
1402     const GrTextReferenceFrame* const fReferenceFrame;
1403 
1404     const TransformedMaskVertexFiller fVertexFiller;
1405 
1406     // The bounds in source space. The bounds are the joined rectangles of all the glyphs.
1407     const SkRect fVertexBounds;
1408     const SkSpan<const VertexData> fVertexData;
1409 
1410     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1411     // be single threaded.
1412     mutable GrGlyphVector fGlyphs;
1413 
1414     const bool fUseLCDText;
1415     const bool fAntiAliased;
1416     const GrSDFTMatrixRange fMatrixRange;
1417 };
1418 
SDFTSubRun(const GrTextReferenceFrame * referenceFrame,SkScalar strikeToSource,SkRect vertexBounds,SkSpan<const VertexData> vertexData,GrGlyphVector && glyphs,bool useLCDText,bool antiAliased,const GrSDFTMatrixRange & matrixRange)1419 SDFTSubRun::SDFTSubRun(const GrTextReferenceFrame* referenceFrame,
1420                        SkScalar strikeToSource,
1421                        SkRect vertexBounds,
1422                        SkSpan<const VertexData> vertexData,
1423                        GrGlyphVector&& glyphs,
1424                        bool useLCDText,
1425                        bool antiAliased,
1426                        const GrSDFTMatrixRange& matrixRange)
1427         : fReferenceFrame{referenceFrame}
1428         , fVertexFiller{kA8_GrMaskFormat, SK_DistanceFieldInset, strikeToSource}
1429         , fVertexBounds{vertexBounds}
1430         , fVertexData{vertexData}
1431         , fGlyphs{std::move(glyphs)}
1432         , fUseLCDText{useLCDText}
1433         , fAntiAliased{antiAliased}
1434         , fMatrixRange{matrixRange} {}
1435 
has_some_antialiasing(const SkFont & font)1436 bool has_some_antialiasing(const SkFont& font ) {
1437     SkFont::Edging edging = font.getEdging();
1438     return edging == SkFont::Edging::kAntiAlias
1439            || edging == SkFont::Edging::kSubpixelAntiAlias;
1440 }
1441 
Make(const GrTextReferenceFrame * referenceFrame,const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,const GrSDFTMatrixRange & matrixRange,GrSubRunAllocator * alloc)1442 GrSubRunOwner SDFTSubRun::Make(const GrTextReferenceFrame* referenceFrame,
1443                                const SkZip<SkGlyphVariant, SkPoint>& accepted,
1444                                const SkFont& runFont,
1445                                sk_sp<SkStrike>&& strike,
1446                                SkScalar strikeToSourceScale,
1447                                const GrSDFTMatrixRange& matrixRange,
1448                                GrSubRunAllocator* alloc) {
1449     SkRect bounds = SkRectPriv::MakeLargestInverted();
1450     auto mapper = [&](const auto& d) {
1451         auto& [variant, pos] = d;
1452         const SkGlyph* skGlyph = variant;
1453         int16_t l = skGlyph->left(),
1454                 t = skGlyph->top(),
1455                 r = l + skGlyph->width(),
1456                 b = t + skGlyph->height();
1457         SkPoint lt = SkPoint::Make(l, t) * strikeToSourceScale + pos,
1458                 rb = SkPoint::Make(r, b) * strikeToSourceScale + pos;
1459 
1460         bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
1461         return VertexData{pos, {l, t, r, b}};
1462     };
1463 
1464     SkSpan<VertexData> vertexData = alloc->makePODArray<VertexData>(accepted, mapper);
1465 
1466     return alloc->makeUnique<SDFTSubRun>(
1467             referenceFrame,
1468             strikeToSourceScale,
1469             bounds,
1470             vertexData,
1471             GrGlyphVector::Make(std::move(strike), accepted.get<0>(), alloc),
1472             runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
1473             has_some_antialiasing(runFont),
1474             matrixRange);
1475 }
1476 
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const1477 void SDFTSubRun::draw(SkCanvas*,
1478                       const GrClip* clip,
1479                       const SkMatrixProvider& viewMatrix,
1480                       SkPoint drawOrigin,
1481                       const SkPaint& paint,
1482                       skgpu::v1::SurfaceDrawContext* sdc) const {
1483     auto[drawingClip, op] = this->makeAtlasTextOp(
1484             clip, viewMatrix, drawOrigin, paint, sdc, nullptr);
1485     if (op != nullptr) {
1486         sdc->addDrawOp(drawingClip, std::move(op));
1487     }
1488 }
1489 
calculate_sdf_parameters(const skgpu::v1::SurfaceDrawContext & sdc,const SkMatrix & drawMatrix,bool useLCDText,bool isAntiAliased)1490 static std::tuple<AtlasTextOp::MaskType, uint32_t, bool> calculate_sdf_parameters(
1491         const skgpu::v1::SurfaceDrawContext& sdc,
1492         const SkMatrix& drawMatrix,
1493         bool useLCDText,
1494         bool isAntiAliased) {
1495     const GrColorInfo& colorInfo = sdc.colorInfo();
1496     const SkSurfaceProps& props = sdc.surfaceProps();
1497     bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
1498     bool isLCD = useLCDText && SkPixelGeometryIsH(props.pixelGeometry());
1499     using MT = AtlasTextOp::MaskType;
1500     MT maskType = !isAntiAliased ? MT::kAliasedDistanceField
1501                                  : isLCD ? (isBGR ? MT::kLCDBGRDistanceField
1502                                                   : MT::kLCDDistanceField)
1503                                          : MT::kGrayscaleDistanceField;
1504 
1505     bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
1506     uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
1507     DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
1508     DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
1509     DFGPFlags |= MT::kAliasedDistanceField == maskType ? kAliased_DistanceFieldEffectFlag : 0;
1510 
1511     if (isLCD) {
1512         DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
1513         DFGPFlags |= MT::kLCDBGRDistanceField == maskType ? kBGR_DistanceFieldEffectFlag : 0;
1514     }
1515     return {maskType, DFGPFlags, useGammaCorrectDistanceTable};
1516 }
1517 
1518 std::tuple<const GrClip*, GrOp::Owner >
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner) const1519 SDFTSubRun::makeAtlasTextOp(const GrClip* clip,
1520                             const SkMatrixProvider& viewMatrix,
1521                             SkPoint drawOrigin,
1522                             const SkPaint& paint,
1523                             skgpu::v1::SurfaceDrawContext* sdc,
1524                             GrAtlasSubRunOwner) const {
1525     SkASSERT(this->glyphCount() != 0);
1526     SkASSERT(!viewMatrix.localToDevice().hasPerspective());
1527 
1528     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
1529 
1530     GrPaint grPaint;
1531     SkPMColor4f drawingColor = calculate_colors(sdc, paint, viewMatrix, kA8_GrMaskFormat, &grPaint);
1532 
1533     auto [maskType, DFGPFlags, useGammaCorrectDistanceTable] =
1534         calculate_sdf_parameters(*sdc, drawMatrix, fUseLCDText, fAntiAliased);
1535 
1536     auto geometry = AtlasTextOp::Geometry::MakeForBlob(*this,
1537                                                        drawMatrix,
1538                                                        drawOrigin,
1539                                                        SkIRect::MakeEmpty(),
1540                                                        sk_ref_sp(fReferenceFrame),
1541                                                        drawingColor,
1542                                                        sdc->arenaAlloc());
1543 
1544     GrRecordingContext* const rContext = sdc->recordingContext();
1545     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1546                                              maskType,
1547                                              true,
1548                                              this->glyphCount(),
1549                                              this->deviceRect(drawMatrix, drawOrigin),
1550                                              SkPaintPriv::ComputeLuminanceColor(paint),
1551                                              useGammaCorrectDistanceTable,
1552                                              DFGPFlags,
1553                                              geometry,
1554                                              std::move(grPaint));
1555 
1556     return {clip, std::move(op)};
1557 }
1558 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1559 bool SDFTSubRun::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
1560     return fMatrixRange.matrixInRange(positionMatrix);
1561 }
1562 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const1563 void SDFTSubRun::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
1564     fGlyphs.packedGlyphIDToGrGlyph(cache);
1565 }
1566 
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const1567 std::tuple<bool, int> SDFTSubRun::regenerateAtlas(
1568         int begin, int end, GrMeshDrawTarget *target) const {
1569     return fGlyphs.regenerateAtlas(begin, end, kA8_GrMaskFormat, SK_DistanceFieldInset, target);
1570 }
1571 
vertexStride(const SkMatrix & drawMatrix) const1572 size_t SDFTSubRun::vertexStride(const SkMatrix& drawMatrix) const {
1573     return sizeof(Mask2DVertex);
1574 }
1575 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1576 void SDFTSubRun::fillVertexData(
1577         void *vertexDst, int offset, int count,
1578         GrColor color,
1579         const SkMatrix& drawMatrix, SkPoint drawOrigin,
1580         SkIRect clip) const {
1581     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1582 
1583     fVertexFiller.fillVertexData(fGlyphs.glyphs().subspan(offset, count),
1584                                  fVertexData.subspan(offset, count),
1585                                  color,
1586                                  positionMatrix,
1587                                  clip,
1588                                  vertexDst);
1589 }
1590 
glyphCount() const1591 int SDFTSubRun::glyphCount() const {
1592     return SkCount(fVertexData);
1593 }
1594 
deviceRect(const SkMatrix & drawMatrix,SkPoint drawOrigin) const1595 SkRect SDFTSubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
1596     SkRect outBounds = fVertexBounds;
1597     outBounds.offset(drawOrigin);
1598     return drawMatrix.mapRect(outBounds);
1599 }
1600 
testingOnly_atlasSubRun() const1601 const GrAtlasSubRun* SDFTSubRun::testingOnly_atlasSubRun() const {
1602     return this;
1603 }
1604 
1605 template<typename AddSingleMaskFormat>
add_multi_mask_format(AddSingleMaskFormat addSingleMaskFormat,const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike)1606 void add_multi_mask_format(
1607         AddSingleMaskFormat addSingleMaskFormat,
1608         const SkZip<SkGlyphVariant, SkPoint>& accepted,
1609         sk_sp<SkStrike>&& strike) {
1610     if (accepted.empty()) { return; }
1611 
1612     auto glyphSpan = accepted.get<0>();
1613     const SkGlyph* glyph = glyphSpan[0];
1614     GrMaskFormat format = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
1615     size_t startIndex = 0;
1616     for (size_t i = 1; i < accepted.size(); i++) {
1617         glyph = glyphSpan[i];
1618         GrMaskFormat nextFormat = GrGlyph::FormatFromSkGlyph(glyph->maskFormat());
1619         if (format != nextFormat) {
1620             auto glyphsWithSameFormat = accepted.subspan(startIndex, i - startIndex);
1621             // Take a ref on the strike. This should rarely happen.
1622             addSingleMaskFormat(glyphsWithSameFormat, format, sk_sp<SkStrike>(strike));
1623             format = nextFormat;
1624             startIndex = i;
1625         }
1626     }
1627     auto glyphsWithSameFormat = accepted.last(accepted.size() - startIndex);
1628     addSingleMaskFormat(glyphsWithSameFormat, format, std::move(strike));
1629 }
1630 
1631 }  // namespace
1632 
1633 // -- GrTextBlob::Key ------------------------------------------------------------------------------
1634 
compute_canonical_color(const SkPaint & paint,bool lcd)1635 static SkColor compute_canonical_color(const SkPaint& paint, bool lcd) {
1636     SkColor canonicalColor = SkPaintPriv::ComputeLuminanceColor(paint);
1637     if (lcd) {
1638         // This is the correct computation for canonicalColor, but there are tons of cases where LCD
1639         // can be modified. For now we just regenerate if any run in a textblob has LCD.
1640         // TODO figure out where all of these modifications are and see if we can incorporate that
1641         //      logic at a higher level *OR* use sRGB
1642         //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor);
1643 
1644         // TODO we want to figure out a way to be able to use the canonical color on LCD text,
1645         // see the note above.  We pick a placeholder value for LCD text to ensure we always match
1646         // the same key
1647         return SK_ColorTRANSPARENT;
1648     } else {
1649         // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have
1650         // gamma corrected masks anyways, nor color
1651         U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor),
1652                                        SkColorGetG(canonicalColor),
1653                                        SkColorGetB(canonicalColor));
1654         // reduce to our finite number of bits
1655         canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum));
1656     }
1657     return canonicalColor;
1658 }
1659 
Make(const SkGlyphRunList & glyphRunList,const SkPaint & paint,const SkSurfaceProps & surfaceProps,const GrColorInfo & colorInfo,const SkMatrix & drawMatrix,const GrSDFTControl & control)1660 auto GrTextBlob::Key::Make(const SkGlyphRunList& glyphRunList,
1661                            const SkPaint& paint,
1662                            const SkSurfaceProps& surfaceProps,
1663                            const GrColorInfo& colorInfo,
1664                            const SkMatrix& drawMatrix,
1665                            const GrSDFTControl& control) -> std::tuple<bool, Key> {
1666     SkMaskFilterBase::BlurRec blurRec;
1667     // It might be worth caching these things, but its not clear at this time
1668     // TODO for animated mask filters, this will fill up our cache.  We need a safeguard here
1669     const SkMaskFilter* maskFilter = paint.getMaskFilter();
1670     bool canCache = glyphRunList.canCache() &&
1671                     !(paint.getPathEffect() ||
1672                         (maskFilter && !as_MFB(maskFilter)->asABlur(&blurRec)));
1673 
1674     // If we're doing linear blending, then we can disable the gamma hacks.
1675     // Otherwise, leave them on. In either case, we still want the contrast boost:
1676     // TODO: Can we be even smarter about mask gamma based on the dest transfer function?
1677     SkScalerContextFlags scalerContextFlags = colorInfo.isLinearlyBlended()
1678                                               ? SkScalerContextFlags::kBoostContrast
1679                                               : SkScalerContextFlags::kFakeGammaAndBoostContrast;
1680 
1681     GrTextBlob::Key key;
1682     if (canCache) {
1683         bool hasLCD = glyphRunList.anyRunsLCD();
1684 
1685         // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry
1686         SkPixelGeometry pixelGeometry =
1687                 hasLCD ? surfaceProps.pixelGeometry() : kUnknown_SkPixelGeometry;
1688 
1689         GrColor canonicalColor = compute_canonical_color(paint, hasLCD);
1690 
1691         key.fPixelGeometry = pixelGeometry;
1692         key.fUniqueID = glyphRunList.uniqueID();
1693         key.fStyle = paint.getStyle();
1694         if (key.fStyle != SkPaint::kFill_Style) {
1695             key.fFrameWidth = paint.getStrokeWidth();
1696             key.fMiterLimit = paint.getStrokeMiter();
1697             key.fJoin = paint.getStrokeJoin();
1698         }
1699         key.fHasBlur = maskFilter != nullptr;
1700         if (key.fHasBlur) {
1701             key.fBlurRec = blurRec;
1702         }
1703         key.fCanonicalColor = canonicalColor;
1704         key.fScalerContextFlags = scalerContextFlags;
1705 
1706         // Do any runs use direct drawing types?.
1707         key.fHasSomeDirectSubRuns = false;
1708         for (auto& run : glyphRunList) {
1709             SkScalar approximateDeviceTextSize =
1710                     SkFontPriv::ApproximateTransformedTextSize(run.font(), drawMatrix);
1711             key.fHasSomeDirectSubRuns |= control.isDirect(approximateDeviceTextSize, paint);
1712         }
1713 
1714         if (key.fHasSomeDirectSubRuns) {
1715             // Store the fractional offset of the position. We know that the matrix can't be
1716             // perspective at this point.
1717             SkPoint mappedOrigin = drawMatrix.mapOrigin();
1718             key.fPositionMatrix = drawMatrix;
1719             key.fPositionMatrix.setTranslateX(
1720                     mappedOrigin.x() - SkScalarFloorToScalar(mappedOrigin.x()));
1721             key.fPositionMatrix.setTranslateY(
1722                     mappedOrigin.y() - SkScalarFloorToScalar(mappedOrigin.y()));
1723         } else {
1724             // For path and SDFT, the matrix doesn't matter.
1725             key.fPositionMatrix = SkMatrix::I();
1726         }
1727     }
1728 
1729     return {canCache, key};
1730 }
1731 
operator ==(const GrTextBlob::Key & that) const1732 bool GrTextBlob::Key::operator==(const GrTextBlob::Key& that) const {
1733     if (fUniqueID != that.fUniqueID) { return false; }
1734     if (fCanonicalColor != that.fCanonicalColor) { return false; }
1735     if (fStyle != that.fStyle) { return false; }
1736     if (fStyle != SkPaint::kFill_Style) {
1737         if (fFrameWidth != that.fFrameWidth ||
1738             fMiterLimit != that.fMiterLimit ||
1739             fJoin != that.fJoin) {
1740             return false;
1741         }
1742     }
1743     if (fPixelGeometry != that.fPixelGeometry) { return false; }
1744     if (fHasBlur != that.fHasBlur) { return false; }
1745     if (fHasBlur) {
1746         if (fBlurRec.fStyle != that.fBlurRec.fStyle || fBlurRec.fSigma != that.fBlurRec.fSigma) {
1747             return false;
1748         }
1749     }
1750     if (fScalerContextFlags != that.fScalerContextFlags) { return false; }
1751 
1752     // Just punt on perspective.
1753     if (fPositionMatrix.hasPerspective()) {
1754         return false;
1755     }
1756 
1757     if (fHasSomeDirectSubRuns != that.fHasSomeDirectSubRuns) {
1758         return false;
1759     }
1760 
1761     if (fHasSomeDirectSubRuns) {
1762         auto [compatible, _] = can_use_direct(fPositionMatrix, that.fPositionMatrix);
1763         return compatible;
1764     }
1765 
1766     return true;
1767 }
1768 
1769 // -- GrTextBlob -----------------------------------------------------------------------------------
operator delete(void * p)1770 void GrTextBlob::operator delete(void* p) { ::operator delete(p); }
operator new(size_t)1771 void* GrTextBlob::operator new(size_t) { SK_ABORT("All blobs are created by placement new."); }
operator new(size_t,void * p)1772 void* GrTextBlob::operator new(size_t, void* p) { return p; }
1773 
1774 GrTextBlob::~GrTextBlob() = default;
1775 
Make(const SkGlyphRunList & glyphRunList,const SkPaint & paint,const SkMatrix & positionMatrix,bool supportBilerpAtlas,const GrSDFTControl & control,SkGlyphRunListPainter * painter)1776 sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList,
1777                                    const SkPaint& paint,
1778                                    const SkMatrix& positionMatrix,
1779                                    bool supportBilerpAtlas,
1780                                    const GrSDFTControl& control,
1781                                    SkGlyphRunListPainter* painter) {
1782     // The difference in alignment from the per-glyph data to the SubRun;
1783     constexpr size_t alignDiff =
1784             alignof(DirectMaskSubRun) - alignof(DirectMaskSubRun::DevicePosition);
1785     constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
1786     size_t totalGlyphCount = glyphRunList.totalGlyphCount();
1787 
1788     // The neededForSubRun is optimized for DirectMaskSubRun which is by far the most common case.
1789     size_t bytesNeededForSubRun = GrBagOfBytes::PlatformMinimumSizeWithOverhead(
1790             totalGlyphCount * sizeof(DirectMaskSubRun::DevicePosition)
1791             + GrGlyphVector::GlyphVectorSize(totalGlyphCount)
1792             + glyphRunList.runCount() * (sizeof(DirectMaskSubRun) + vertexDataToSubRunPadding),
1793             alignof(GrTextBlob));
1794 
1795     size_t allocationSize = sizeof(GrTextBlob) + bytesNeededForSubRun;
1796 
1797     void* allocation = ::operator new (allocationSize);
1798 
1799     SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(paint);
1800     sk_sp<GrTextBlob> blob{
1801         new (allocation) GrTextBlob(
1802                 bytesNeededForSubRun, supportBilerpAtlas, positionMatrix, initialLuminance)};
1803 
1804     const uint64_t uniqueID = glyphRunList.uniqueID();
1805     for (auto& glyphRun : glyphRunList) {
1806         painter->processGlyphRun(blob.get(),
1807                                  glyphRun,
1808                                  positionMatrix,
1809                                  paint,
1810                                  control,
1811                                  "GrTextBlob",
1812                                  uniqueID);
1813     }
1814 
1815     return blob;
1816 }
1817 
addKey(const Key & key)1818 void GrTextBlob::addKey(const Key& key) {
1819     fKey = key;
1820 }
1821 
hasPerspective() const1822 bool GrTextBlob::hasPerspective() const { return fInitialPositionMatrix.hasPerspective(); }
1823 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1824 bool GrTextBlob::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
1825     // A singular matrix will create a GrTextBlob with no SubRuns, but unknown glyphs can
1826     // also cause empty runs. If there are no subRuns or some glyphs were excluded or perspective,
1827     // then regenerate when the matrices don't match.
1828     if ((fSubRunList.isEmpty() || fSomeGlyphsExcluded || hasPerspective()) &&
1829         fInitialPositionMatrix != positionMatrix)
1830     {
1831         return false;
1832     }
1833 
1834     // If we have LCD text then our canonical color will be set to transparent, in this case we have
1835     // to regenerate the blob on any color change
1836     // We use the grPaint to get any color filter effects
1837     if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
1838         fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) {
1839         return false;
1840     }
1841 
1842     for (const GrSubRun& subRun : fSubRunList) {
1843         if (!subRun.blobCast()->canReuse(paint, positionMatrix)) {
1844             return false;
1845         }
1846     }
1847 
1848     return true;
1849 }
1850 
key() const1851 const GrTextBlob::Key& GrTextBlob::key() const { return fKey; }
size() const1852 size_t GrTextBlob::size() const { return fSize; }
1853 
draw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc)1854 void GrTextBlob::draw(SkCanvas* canvas,
1855                       const GrClip* clip,
1856                       const SkMatrixProvider& viewMatrix,
1857                       SkPoint drawOrigin,
1858                       const SkPaint& paint,
1859                       skgpu::v1::SurfaceDrawContext* sdc) {
1860     for (const GrSubRun& subRun : fSubRunList) {
1861         subRun.draw(canvas, clip, viewMatrix, drawOrigin, paint, sdc);
1862     }
1863 }
1864 
testingOnlyFirstSubRun() const1865 const GrAtlasSubRun* GrTextBlob::testingOnlyFirstSubRun() const {
1866     if (fSubRunList.isEmpty()) {
1867         return nullptr;
1868     }
1869 
1870     return fSubRunList.front().blobCast()->testingOnly_atlasSubRun();
1871 }
1872 
GrTextBlob(int allocSize,bool supportBilerpAtlas,const SkMatrix & positionMatrix,SkColor initialLuminance)1873 GrTextBlob::GrTextBlob(int allocSize,
1874                        bool supportBilerpAtlas,
1875                        const SkMatrix& positionMatrix,
1876                        SkColor initialLuminance)
1877         : fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2}
1878         , fSize{allocSize}
1879         , fSupportBilerpAtlas{supportBilerpAtlas}
1880         , fInitialPositionMatrix{positionMatrix}
1881         , fInitialLuminance{initialLuminance} { }
1882 
processDeviceMasks(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike)1883 void GrTextBlob::processDeviceMasks(
1884         const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike) {
1885     SkASSERT(strike != nullptr);
1886     auto addGlyphsWithSameFormat = [&] (const SkZip<SkGlyphVariant, SkPoint>& accepted,
1887                                         GrMaskFormat format,
1888                                         sk_sp<SkStrike>&& runStrike) {
1889         GrSubRunOwner subRun = DirectMaskSubRun::Make(
1890                 this, accepted, std::move(runStrike), format, &fAlloc);
1891         if (subRun != nullptr) {
1892             fSubRunList.append(std::move(subRun));
1893         } else {
1894             fSomeGlyphsExcluded = true;
1895         }
1896     };
1897     add_multi_mask_format(addGlyphsWithSameFormat, accepted, std::move(strike));
1898 }
1899 
processSourcePaths(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,SkScalar strikeToSourceScale)1900 void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& accepted,
1901                                     const SkFont& runFont,
1902                                     SkScalar strikeToSourceScale) {
1903     fSubRunList.append(PathSubRun::Make(
1904             accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
1905 }
1906 
processSourceDrawables(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,SkScalar strikeToSourceScale)1907 void GrTextBlob::processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
1908                                         const SkFont& runFont,
1909                                         SkScalar strikeToSourceScale) {
1910     fSubRunList.append(make_drawable_sub_run<DrawableSubRun>(
1911             accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
1912 }
1913 
processSourceSDFT(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,const SkFont & runFont,const GrSDFTMatrixRange & matrixRange)1914 void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
1915                                    sk_sp<SkStrike>&& strike,
1916                                    SkScalar strikeToSourceScale,
1917                                    const SkFont& runFont,
1918                                    const GrSDFTMatrixRange& matrixRange) {
1919     fSubRunList.append(SDFTSubRun::Make(
1920             this, accepted, runFont, std::move(strike), strikeToSourceScale, matrixRange, &fAlloc));
1921 }
1922 
processSourceMasks(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale)1923 void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& accepted,
1924                                     sk_sp<SkStrike>&& strike,
1925                                     SkScalar strikeToSourceScale) {
1926     auto addGlyphsWithSameFormat = [&] (const SkZip<SkGlyphVariant, SkPoint>& accepted,
1927                                         GrMaskFormat format,
1928                                         sk_sp<SkStrike>&& runStrike) {
1929         GrSubRunOwner subRun = TransformedMaskSubRun::Make(
1930                 this, accepted, std::move(runStrike), strikeToSourceScale, format, &fAlloc);
1931         if (subRun != nullptr) {
1932             fSubRunList.append(std::move(subRun));
1933         } else {
1934             fSomeGlyphsExcluded = true;
1935         }
1936     };
1937     add_multi_mask_format(addGlyphsWithSameFormat, accepted, std::move(strike));
1938 }
1939 
1940 // ----------------------------- Begin no cache implementation -------------------------------------
1941 namespace {
1942 // -- DirectMaskSubRunNoCache ----------------------------------------------------------------------
1943 class DirectMaskSubRunNoCache final : public GrAtlasSubRun {
1944 public:
1945     using DevicePosition = skvx::Vec<2, int16_t>;
1946 
1947     DirectMaskSubRunNoCache(GrMaskFormat format,
1948                             bool supportBilerpAtlas,
1949                             const SkRect& bounds,
1950                             SkSpan<const DevicePosition> devicePositions,
1951                             GrGlyphVector&& glyphs);
1952 
1953     static GrAtlasSubRunOwner Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
1954                                    sk_sp<SkStrike>&& strike,
1955                                    GrMaskFormat format,
1956                                    bool supportBilerpAtlas,
1957                                    GrSubRunAllocator* alloc);
1958 
1959     size_t vertexStride(const SkMatrix& drawMatrix) const override;
1960 
1961     int glyphCount() const override;
1962 
1963     std::tuple<const GrClip*, GrOp::Owner>
1964     makeAtlasTextOp(const GrClip*,
1965                     const SkMatrixProvider& viewMatrix,
1966                     SkPoint,
1967                     const SkPaint&,
1968                     skgpu::v1::SurfaceDrawContext*,
1969                     GrAtlasSubRunOwner) const override;
1970 
1971     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
1972 
1973     std::tuple<bool, int>
1974     regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
1975 
1976     void fillVertexData(void* vertexDst, int offset, int count,
1977                         GrColor color,
1978                         const SkMatrix& drawMatrix, SkPoint drawOrigin,
1979                         SkIRect clip) const override;
1980 
1981 private:
1982     const GrMaskFormat fMaskFormat;
1983 
1984     // Support bilerping from the atlas.
1985     const bool fSupportBilerpAtlas;
1986 
1987     // The vertex bounds in device space. The bounds are the joined rectangles of all the glyphs.
1988     const SkRect fGlyphDeviceBounds;
1989     const SkSpan<const DevicePosition> fLeftTopDevicePos;
1990 
1991     // Space for geometry
1992     alignas(alignof(AtlasTextOp::Geometry)) char fGeom[sizeof(AtlasTextOp::Geometry)];
1993 
1994     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1995     // be single threaded.
1996     mutable GrGlyphVector fGlyphs;
1997 };
1998 
DirectMaskSubRunNoCache(GrMaskFormat format,bool supportBilerpAtlas,const SkRect & deviceBounds,SkSpan<const DevicePosition> devicePositions,GrGlyphVector && glyphs)1999 DirectMaskSubRunNoCache::DirectMaskSubRunNoCache(GrMaskFormat format,
2000                                                  bool supportBilerpAtlas,
2001                                                  const SkRect& deviceBounds,
2002                                                  SkSpan<const DevicePosition> devicePositions,
2003                                                  GrGlyphVector&& glyphs)
2004         : fMaskFormat{format}
2005         , fSupportBilerpAtlas{supportBilerpAtlas}
2006         , fGlyphDeviceBounds{deviceBounds}
2007         , fLeftTopDevicePos{devicePositions}
2008         , fGlyphs{std::move(glyphs)} { }
2009 
Make(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,GrMaskFormat format,bool supportBilerpAtlas,GrSubRunAllocator * alloc)2010 GrAtlasSubRunOwner DirectMaskSubRunNoCache::Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2011                                                  sk_sp<SkStrike>&& strike,
2012                                                  GrMaskFormat format,
2013                                                  bool supportBilerpAtlas,
2014                                                  GrSubRunAllocator* alloc) {
2015     auto glyphLeftTop = alloc->makePODArray<DevicePosition>(accepted.size());
2016     auto glyphIDs = alloc->makePODArray<GrGlyphVector::Variant>(accepted.size());
2017 
2018     // Because this is the direct case, the maximum width or height is the size that fits in the
2019     // atlas. This boundary is checked below to ensure that the call to SkGlyphRect below will
2020     // not overflow.
2021     constexpr SkScalar kMaxPos =
2022             std::numeric_limits<int16_t>::max() - SkStrikeCommon::kSkSideTooBigForAtlas;
2023     SkGlyphRect runBounds = skglyph::empty_rect();
2024     size_t goodPosCount = 0;
2025     for (auto [variant, pos] : accepted) {
2026         auto [x, y] = pos;
2027         // Ensure that the .offset() call below does not overflow. And, at this point none of the
2028         // rectangles are empty because they were culled before the run was created. Basically,
2029         // cull all the glyphs that can't appear on the screen.
2030         if (-kMaxPos < x && x < kMaxPos && -kMaxPos < y && y < kMaxPos) {
2031             const SkGlyph* const skGlyph = variant;
2032             const SkGlyphRect deviceBounds =
2033                     skGlyph->glyphRect().offset(SkScalarRoundToInt(x), SkScalarRoundToInt(y));
2034             runBounds = skglyph::rect_union(runBounds, deviceBounds);
2035             glyphLeftTop[goodPosCount] = deviceBounds.topLeft();
2036             glyphIDs[goodPosCount].packedGlyphID = skGlyph->getPackedID();
2037             goodPosCount += 1;
2038         }
2039     }
2040 
2041     // Wow! no glyphs are in bounds and had non-empty bounds.
2042     if (goodPosCount == 0) {
2043         return nullptr;
2044     }
2045 
2046     SkSpan<const DevicePosition> leftTop{glyphLeftTop, goodPosCount};
2047     return alloc->makeUnique<DirectMaskSubRunNoCache>(
2048             format, supportBilerpAtlas, runBounds.rect(), leftTop,
2049             GrGlyphVector{std::move(strike), {glyphIDs, goodPosCount}});
2050 }
2051 
vertexStride(const SkMatrix &) const2052 size_t DirectMaskSubRunNoCache::vertexStride(const SkMatrix&) const {
2053     if (fMaskFormat != kARGB_GrMaskFormat) {
2054         return sizeof(Mask2DVertex);
2055     } else {
2056         return sizeof(ARGB2DVertex);
2057     }
2058 }
2059 
glyphCount() const2060 int DirectMaskSubRunNoCache::glyphCount() const {
2061     return SkCount(fGlyphs.glyphs());
2062 }
2063 
2064 std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner subRunOwner) const2065 DirectMaskSubRunNoCache::makeAtlasTextOp(const GrClip* clip,
2066                                          const SkMatrixProvider& viewMatrix,
2067                                          SkPoint drawOrigin,
2068                                          const SkPaint& paint,
2069                                          skgpu::v1::SurfaceDrawContext* sdc,
2070                                          GrAtlasSubRunOwner subRunOwner) const {
2071     SkASSERT(this->glyphCount() != 0);
2072 
2073     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
2074 
2075     // We can clip geometrically using clipRect and ignore clip when an axis-aligned rectangular
2076     // non-AA clip is used. If clipRect is empty, and clip is nullptr, then there is no clipping
2077     // needed.
2078     const SkRect deviceBounds = SkRect::MakeWH(sdc->width(), sdc->height());
2079     auto [clipMethod, clipRect] = calculate_clip(clip, deviceBounds, fGlyphDeviceBounds);
2080 
2081     switch (clipMethod) {
2082         case kClippedOut:
2083             // Returning nullptr as op means skip this op.
2084             return {nullptr, nullptr};
2085         case kUnclipped:
2086         case kGeometryClipped:
2087             // GPU clip is not needed.
2088             clip = nullptr;
2089             break;
2090         case kGPUClipped:
2091             // Use the the GPU clip; clipRect is ignored.
2092             break;
2093     }
2094 
2095     if (!clipRect.isEmpty()) { SkASSERT(clip == nullptr); }
2096 
2097     GrPaint grPaint;
2098     const SkPMColor4f drawingColor =
2099             calculate_colors(sdc, paint, viewMatrix, fMaskFormat, &grPaint);
2100 
2101     GrRecordingContext* const rContext = sdc->recordingContext();
2102 
2103     auto geometry = new ((void*)fGeom) AtlasTextOp::Geometry{
2104             *this,
2105             drawMatrix,
2106             drawOrigin,
2107             clipRect,
2108             nullptr,
2109             std::move(subRunOwner),
2110             drawingColor
2111     };
2112 
2113     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
2114                                              op_mask_type(fMaskFormat),
2115                                              false,
2116                                              this->glyphCount(),
2117                                              fGlyphDeviceBounds,
2118                                              geometry,
2119                                              std::move(grPaint));
2120 
2121     return {clip, std::move(op)};
2122 }
2123 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const2124 void DirectMaskSubRunNoCache::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
2125     fGlyphs.packedGlyphIDToGrGlyph(cache);
2126 }
2127 
2128 std::tuple<bool, int>
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const2129 DirectMaskSubRunNoCache::regenerateAtlas(int begin, int end, GrMeshDrawTarget* target) const {
2130     if (fSupportBilerpAtlas) {
2131         return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 1, target, true);
2132     } else {
2133         return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 0, target, false);
2134     }
2135 }
2136 
2137 // The 99% case. No clip. Non-color only.
direct_2D2(SkZip<Mask2DVertex[4],const GrGlyph *,const DirectMaskSubRunNoCache::DevicePosition> quadData,GrColor color)2138 void direct_2D2(SkZip<Mask2DVertex[4],
2139         const GrGlyph*,
2140         const DirectMaskSubRunNoCache::DevicePosition> quadData,
2141         GrColor color) {
2142     for (auto[quad, glyph, leftTop] : quadData) {
2143         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
2144         SkScalar dl = leftTop[0],
2145                  dt = leftTop[1],
2146                  dr = dl + (ar - al),
2147                  db = dt + (ab - at);
2148 
2149         quad[0] = {{dl, dt}, color, {al, at}};  // L,T
2150         quad[1] = {{dl, db}, color, {al, ab}};  // L,B
2151         quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
2152         quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
2153     }
2154 }
2155 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const2156 void DirectMaskSubRunNoCache::fillVertexData(void* vertexDst, int offset, int count,
2157                                              GrColor color,
2158                                              const SkMatrix& drawMatrix, SkPoint drawOrigin,
2159                                              SkIRect clip) const {
2160     auto quadData = [&](auto dst) {
2161         return SkMakeZip(dst,
2162                          fGlyphs.glyphs().subspan(offset, count),
2163                          fLeftTopDevicePos.subspan(offset, count));
2164     };
2165 
2166     // Notice that no matrix manipulation is needed because all the rectangles are already mapped
2167     // to device space.
2168     if (clip.isEmpty()) {
2169         if (fMaskFormat != kARGB_GrMaskFormat) {
2170             using Quad = Mask2DVertex[4];
2171             SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(SkMatrix::I()));
2172             direct_2D2(quadData((Quad*)vertexDst), color);
2173         } else {
2174             using Quad = ARGB2DVertex[4];
2175             SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(SkMatrix::I()));
2176             generalized_direct_2D(quadData((Quad*)vertexDst), color, {0,0});
2177         }
2178     } else {
2179         if (fMaskFormat != kARGB_GrMaskFormat) {
2180             using Quad = Mask2DVertex[4];
2181             SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(SkMatrix::I()));
2182             generalized_direct_2D(quadData((Quad*)vertexDst), color, {0,0}, &clip);
2183         } else {
2184             using Quad = ARGB2DVertex[4];
2185             SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(SkMatrix::I()));
2186             generalized_direct_2D(quadData((Quad*)vertexDst), color, {0,0}, &clip);
2187         }
2188     }
2189 }
2190 
2191 // -- TransformedMaskSubRunNoCache -----------------------------------------------------------------
2192 class TransformedMaskSubRunNoCache final : public GrAtlasSubRun {
2193 public:
2194     using VertexData = TransformedMaskVertexFiller::PositionAndExtent;
2195 
2196     TransformedMaskSubRunNoCache(GrMaskFormat format,
2197                                  SkScalar strikeToSourceScale,
2198                                  const SkRect& bounds,
2199                                  SkSpan<const VertexData> vertexData,
2200                                  GrGlyphVector&& glyphs);
2201 
2202     static GrAtlasSubRunOwner Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2203                                    sk_sp<SkStrike>&& strike,
2204                                    SkScalar strikeToSourceScale,
2205                                    GrMaskFormat format,
2206                                    GrSubRunAllocator* alloc);
2207 
2208     std::tuple<const GrClip*, GrOp::Owner>
2209     makeAtlasTextOp(const GrClip*,
2210                     const SkMatrixProvider& viewMatrix,
2211                     SkPoint drawOrigin,
2212                     const SkPaint&,
2213                     skgpu::v1::SurfaceDrawContext*,
2214                     GrAtlasSubRunOwner) const override;
2215 
2216     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
2217 
2218     std::tuple<bool, int> regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
2219 
2220     void fillVertexData(
2221             void* vertexDst, int offset, int count,
2222             GrColor color,
2223             const SkMatrix& drawMatrix, SkPoint drawOrigin,
2224             SkIRect clip) const override;
2225 
2226     size_t vertexStride(const SkMatrix& drawMatrix) const override;
2227     int glyphCount() const override;
2228 
2229 private:
2230     // The rectangle that surrounds all the glyph bounding boxes in device space.
2231     SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
2232 
2233     const TransformedMaskVertexFiller fVertexFiller;
2234 
2235     // The bounds in source space. The bounds are the joined rectangles of all the glyphs.
2236     const SkRect fVertexBounds;
2237     const SkSpan<const VertexData> fVertexData;
2238 
2239     // Space for geometry
2240     alignas(alignof(AtlasTextOp::Geometry)) char fGeom[sizeof(AtlasTextOp::Geometry)];
2241 
2242     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
2243     // be single threaded.
2244     mutable GrGlyphVector fGlyphs;
2245 };
2246 
TransformedMaskSubRunNoCache(GrMaskFormat format,SkScalar strikeToSourceScale,const SkRect & bounds,SkSpan<const VertexData> vertexData,GrGlyphVector && glyphs)2247 TransformedMaskSubRunNoCache::TransformedMaskSubRunNoCache(GrMaskFormat format,
2248                                                            SkScalar strikeToSourceScale,
2249                                                            const SkRect& bounds,
2250                                                            SkSpan<const VertexData> vertexData,
2251                                                            GrGlyphVector&& glyphs)
2252         : fVertexFiller{format, 0, strikeToSourceScale}
2253         , fVertexBounds{bounds}
2254         , fVertexData{vertexData}
2255         , fGlyphs{std::move(glyphs)} {}
2256 
Make(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,GrMaskFormat format,GrSubRunAllocator * alloc)2257 GrAtlasSubRunOwner TransformedMaskSubRunNoCache::Make(
2258         const SkZip<SkGlyphVariant, SkPoint>& accepted,
2259         sk_sp<SkStrike>&& strike,
2260         SkScalar strikeToSourceScale,
2261         GrMaskFormat format,
2262         GrSubRunAllocator* alloc) {
2263     SkRect bounds = SkRectPriv::MakeLargestInverted();
2264     auto initializer = [&](auto acceptedGlyph) {
2265         auto [variant, pos] = acceptedGlyph;
2266         const SkGlyph* skGlyph = variant;
2267         int16_t l = skGlyph->left(),
2268                 t = skGlyph->top(),
2269                 r = l + skGlyph->width(),
2270                 b = t + skGlyph->height();
2271         SkPoint lt = SkPoint::Make(l, t) * strikeToSourceScale + pos,
2272                 rb = SkPoint::Make(r, b) * strikeToSourceScale + pos;
2273 
2274         bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
2275         return VertexData{pos, {l, t, r, b}};
2276     };
2277 
2278     SkSpan<VertexData> vertexData = alloc->makePODArray<VertexData>(accepted, initializer);
2279 
2280     return alloc->makeUnique<TransformedMaskSubRunNoCache>(
2281             format, strikeToSourceScale, bounds, vertexData,
2282             GrGlyphVector::Make(std::move(strike), accepted.get<0>(), alloc));
2283 }
2284 
2285 std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner subRunOwner) const2286 TransformedMaskSubRunNoCache::makeAtlasTextOp(const GrClip* clip,
2287                                               const SkMatrixProvider& viewMatrix,
2288                                               SkPoint drawOrigin,
2289                                               const SkPaint& paint,
2290                                               skgpu::v1::SurfaceDrawContext* sdc,
2291                                               GrAtlasSubRunOwner subRunOwner) const {
2292     SkASSERT(this->glyphCount() != 0);
2293 
2294     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
2295 
2296     GrPaint grPaint;
2297     SkPMColor4f drawingColor = calculate_colors(
2298             sdc, paint, viewMatrix, fVertexFiller.grMaskType(), &grPaint);
2299 
2300     // We can clip geometrically using clipRect and ignore clip if we're not using SDFs or
2301     // transformed glyphs, and we have an axis-aligned rectangular non-AA clip.
2302     auto geometry = new ((void*)fGeom) AtlasTextOp::Geometry{
2303             *this,
2304             drawMatrix,
2305             drawOrigin,
2306             SkIRect::MakeEmpty(),
2307             nullptr,
2308             std::move(subRunOwner),
2309             drawingColor
2310     };
2311 
2312     GrRecordingContext* rContext = sdc->recordingContext();
2313     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
2314                                              fVertexFiller.opMaskType(),
2315                                              true,
2316                                              this->glyphCount(),
2317                                              this->deviceRect(drawMatrix, drawOrigin),
2318                                              geometry,
2319                                              std::move(grPaint));
2320     return {clip, std::move(op)};
2321 }
2322 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const2323 void TransformedMaskSubRunNoCache::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
2324     fGlyphs.packedGlyphIDToGrGlyph(cache);
2325 }
2326 
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const2327 std::tuple<bool, int> TransformedMaskSubRunNoCache::regenerateAtlas(
2328         int begin, int end, GrMeshDrawTarget* target) const {
2329     return fGlyphs.regenerateAtlas(begin, end, fVertexFiller.grMaskType(), 1, target, true);
2330 }
2331 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const2332 void TransformedMaskSubRunNoCache::fillVertexData(
2333         void* vertexDst, int offset, int count,
2334         GrColor color,
2335         const SkMatrix& drawMatrix, SkPoint drawOrigin,
2336         SkIRect clip) const {
2337     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
2338     fVertexFiller.fillVertexData(fGlyphs.glyphs().subspan(offset, count),
2339                                  fVertexData.subspan(offset, count),
2340                                  color,
2341                                  positionMatrix,
2342                                  clip,
2343                                  vertexDst);
2344 }
2345 
vertexStride(const SkMatrix & drawMatrix) const2346 size_t TransformedMaskSubRunNoCache::vertexStride(const SkMatrix& drawMatrix) const {
2347     return fVertexFiller.vertexStride(drawMatrix);
2348 }
2349 
glyphCount() const2350 int TransformedMaskSubRunNoCache::glyphCount() const {
2351     return SkCount(fVertexData);
2352 }
2353 
deviceRect(const SkMatrix & drawMatrix,SkPoint drawOrigin) const2354 SkRect TransformedMaskSubRunNoCache::deviceRect(
2355         const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
2356     SkRect outBounds = fVertexBounds;
2357     outBounds.offset(drawOrigin);
2358     return drawMatrix.mapRect(outBounds);
2359 }
2360 
2361 // -- SDFTSubRunNoCache ----------------------------------------------------------------------------
2362 class SDFTSubRunNoCache final : public GrAtlasSubRun {
2363 public:
2364     struct VertexData {
2365         const SkPoint pos;
2366         // The rectangle of the glyphs in strike space.
2367         GrIRect16 rect;
2368     };
2369 
2370     SDFTSubRunNoCache(GrMaskFormat format,
2371                       SkScalar strikeToSourceScale,
2372                       SkRect vertexBounds,
2373                       SkSpan<const VertexData> vertexData,
2374                       GrGlyphVector&& glyphs,
2375                       bool useLCDText,
2376                       bool antiAliased);
2377 
2378     static GrAtlasSubRunOwner Make(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2379                                    const SkFont& runFont,
2380                                    sk_sp<SkStrike>&& strike,
2381                                    SkScalar strikeToSourceScale,
2382                                    GrSubRunAllocator* alloc);
2383 
2384     std::tuple<const GrClip*, GrOp::Owner>
2385     makeAtlasTextOp(const GrClip*,
2386                     const SkMatrixProvider& viewMatrix,
2387                     SkPoint drawOrigin,
2388                     const SkPaint&,
2389                     skgpu::v1::SurfaceDrawContext*,
2390                     GrAtlasSubRunOwner) const override;
2391 
2392     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
2393 
2394     std::tuple<bool, int> regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
2395 
2396     void fillVertexData(
2397             void* vertexDst, int offset, int count,
2398             GrColor color,
2399             const SkMatrix& drawMatrix, SkPoint drawOrigin,
2400             SkIRect clip) const override;
2401 
2402     size_t vertexStride(const SkMatrix& drawMatrix) const override;
2403     int glyphCount() const override;
2404 
2405 private:
2406     // The rectangle that surrounds all the glyph bounding boxes in device space.
2407     SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
2408 
2409     const GrMaskFormat fMaskFormat;
2410 
2411     // The scale factor between the strike size, and the source size.
2412     const SkScalar fStrikeToSourceScale;
2413 
2414     // The bounds in source space. The bounds are the joined rectangles of all the glyphs.
2415     const SkRect fVertexBounds;
2416     const SkSpan<const VertexData> fVertexData;
2417 
2418     // Space for geometry
2419     alignas(alignof(AtlasTextOp::Geometry)) char fGeom[sizeof(AtlasTextOp::Geometry)];
2420 
2421     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
2422     // be single threaded.
2423     mutable GrGlyphVector fGlyphs;
2424 
2425     const bool fUseLCDText;
2426     const bool fAntiAliased;
2427 };
2428 
SDFTSubRunNoCache(GrMaskFormat format,SkScalar strikeToSourceScale,SkRect vertexBounds,SkSpan<const VertexData> vertexData,GrGlyphVector && glyphs,bool useLCDText,bool antiAliased)2429 SDFTSubRunNoCache::SDFTSubRunNoCache(GrMaskFormat format,
2430                                      SkScalar strikeToSourceScale,
2431                                      SkRect vertexBounds,
2432                                      SkSpan<const VertexData> vertexData,
2433                                      GrGlyphVector&& glyphs,
2434                                      bool useLCDText,
2435                                      bool antiAliased)
2436         : fMaskFormat{format}
2437         , fStrikeToSourceScale{strikeToSourceScale}
2438         , fVertexBounds{vertexBounds}
2439         , fVertexData{vertexData}
2440         , fGlyphs{std::move(glyphs)}
2441         , fUseLCDText{useLCDText}
2442         , fAntiAliased{antiAliased} {}
2443 
2444 
Make(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,GrSubRunAllocator * alloc)2445 GrAtlasSubRunOwner SDFTSubRunNoCache::Make(
2446         const SkZip<SkGlyphVariant, SkPoint>& accepted,
2447         const SkFont& runFont,
2448         sk_sp<SkStrike>&& strike,
2449         SkScalar strikeToSourceScale,
2450         GrSubRunAllocator* alloc) {
2451 
2452     SkRect bounds = SkRectPriv::MakeLargestInverted();
2453     auto initializer = [&](auto acceptedGlyph) {
2454         auto [variant, pos] = acceptedGlyph;
2455         const SkGlyph* skGlyph = variant;
2456         int16_t l = skGlyph->left(),
2457                 t = skGlyph->top(),
2458                 r = l + skGlyph->width(),
2459                 b = t + skGlyph->height();
2460         SkPoint lt = SkPoint::Make(l, t) * strikeToSourceScale + pos,
2461                 rb = SkPoint::Make(r, b) * strikeToSourceScale + pos;
2462 
2463         bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y()));
2464         return VertexData{pos, {l, t, r, b}};
2465     };
2466 
2467     SkSpan<VertexData> vertexData = alloc->makePODArray<VertexData>(accepted, initializer);
2468 
2469     return alloc->makeUnique<SDFTSubRunNoCache>(
2470             kA8_GrMaskFormat,
2471             strikeToSourceScale,
2472             bounds,
2473             vertexData,
2474             GrGlyphVector::Make(std::move(strike), accepted.get<0>(), alloc),
2475             runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
2476             has_some_antialiasing(runFont));
2477 }
2478 
2479 std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner subRunOwner) const2480 SDFTSubRunNoCache::makeAtlasTextOp(const GrClip* clip,
2481                                    const SkMatrixProvider& viewMatrix,
2482                                    SkPoint drawOrigin,
2483                                    const SkPaint& paint,
2484                                    skgpu::v1::SurfaceDrawContext* sdc,
2485                                    GrAtlasSubRunOwner subRunOwner) const {
2486     SkASSERT(this->glyphCount() != 0);
2487 
2488     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
2489 
2490     GrPaint grPaint;
2491     SkPMColor4f drawingColor = calculate_colors(sdc, paint, viewMatrix, fMaskFormat, &grPaint);
2492 
2493     auto [maskType, DFGPFlags, useGammaCorrectDistanceTable] =
2494     calculate_sdf_parameters(*sdc, drawMatrix, fUseLCDText, fAntiAliased);
2495 
2496     auto geometry = new ((void*)fGeom) AtlasTextOp::Geometry {
2497             *this,
2498             drawMatrix,
2499             drawOrigin,
2500             SkIRect::MakeEmpty(),
2501             nullptr,
2502             std::move(subRunOwner),
2503             drawingColor
2504     };
2505 
2506     GrRecordingContext* rContext = sdc->recordingContext();
2507     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
2508                                              maskType,
2509                                              true,
2510                                              this->glyphCount(),
2511                                              this->deviceRect(drawMatrix, drawOrigin),
2512                                              SkPaintPriv::ComputeLuminanceColor(paint),
2513                                              useGammaCorrectDistanceTable,
2514                                              DFGPFlags,
2515                                              geometry,
2516                                              std::move(grPaint));
2517 
2518     return {clip, std::move(op)};
2519 }
2520 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const2521 void SDFTSubRunNoCache::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
2522     fGlyphs.packedGlyphIDToGrGlyph(cache);
2523 }
2524 
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const2525 std::tuple<bool, int> SDFTSubRunNoCache::regenerateAtlas(
2526         int begin, int end, GrMeshDrawTarget *target) const {
2527 
2528     return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, SK_DistanceFieldInset, target);
2529 }
2530 
vertexStride(const SkMatrix & drawMatrix) const2531 size_t SDFTSubRunNoCache::vertexStride(const SkMatrix& drawMatrix) const {
2532     return sizeof(Mask2DVertex);
2533 }
2534 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const2535 void SDFTSubRunNoCache::fillVertexData(
2536         void *vertexDst, int offset, int count,
2537         GrColor color,
2538         const SkMatrix& drawMatrix, SkPoint drawOrigin,
2539         SkIRect clip) const {
2540     using Quad = Mask2DVertex[4];
2541 
2542     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
2543 
2544     SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
2545     fill_transformed_vertices_2D(
2546             SkMakeZip((Quad*)vertexDst,
2547                       fGlyphs.glyphs().subspan(offset, count),
2548                       fVertexData.subspan(offset, count)),
2549             SK_DistanceFieldInset,
2550             fStrikeToSourceScale,
2551             color,
2552             positionMatrix);
2553 }
2554 
glyphCount() const2555 int SDFTSubRunNoCache::glyphCount() const {
2556     return SkCount(fVertexData);
2557 }
2558 
deviceRect(const SkMatrix & drawMatrix,SkPoint drawOrigin) const2559 SkRect SDFTSubRunNoCache::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const {
2560     SkRect outBounds = fVertexBounds;
2561     outBounds.offset(drawOrigin);
2562     return drawMatrix.mapRect(outBounds);
2563 }
2564 }  // namespace
2565 
GrSubRunNoCachePainter(SkCanvas * canvas,skgpu::v1::SurfaceDrawContext * sdc,GrSubRunAllocator * alloc,const GrClip * clip,const SkMatrixProvider & viewMatrix,const SkGlyphRunList & glyphRunList,const SkPaint & paint)2566 GrSubRunNoCachePainter::GrSubRunNoCachePainter(SkCanvas* canvas,
2567                                                skgpu::v1::SurfaceDrawContext* sdc,
2568                                                GrSubRunAllocator* alloc,
2569                                                const GrClip* clip,
2570                                                const SkMatrixProvider& viewMatrix,
2571                                                const SkGlyphRunList& glyphRunList,
2572                                                const SkPaint& paint)
2573             : fCanvas{canvas}
2574             , fSDC{sdc}
2575             , fAlloc{alloc}
2576             , fClip{clip}
2577             , fViewMatrix{viewMatrix}
2578             , fGlyphRunList{glyphRunList}
2579             , fPaint {paint} {}
2580 
processDeviceMasks(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike)2581 void GrSubRunNoCachePainter::processDeviceMasks(
2582         const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike) {
2583     auto addGlyphsWithSameFormat = [&] (const SkZip<SkGlyphVariant, SkPoint>& accepted,
2584                                         GrMaskFormat format,
2585                                         sk_sp<SkStrike>&& runStrike) {
2586         const bool padAtlas =
2587                 fSDC->recordingContext()->priv().options().fSupportBilerpFromGlyphAtlas;
2588         this->draw(DirectMaskSubRunNoCache::Make(
2589                 accepted, std::move(runStrike), format, padAtlas, fAlloc));
2590     };
2591 
2592     add_multi_mask_format(addGlyphsWithSameFormat, accepted, std::move(strike));
2593 }
2594 
processSourceMasks(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale)2595 void GrSubRunNoCachePainter::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2596                                                 sk_sp<SkStrike>&& strike,
2597                                                 SkScalar strikeToSourceScale) {
2598     auto addGlyphsWithSameFormat = [&] (const SkZip<SkGlyphVariant, SkPoint>& accepted,
2599                                         GrMaskFormat format,
2600                                         sk_sp<SkStrike>&& runStrike) {
2601         this->draw(TransformedMaskSubRunNoCache::Make(
2602                 accepted, std::move(runStrike), strikeToSourceScale, format, fAlloc));
2603     };
2604     add_multi_mask_format(addGlyphsWithSameFormat, accepted, std::move(strike));
2605 }
2606 
processSourcePaths(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,SkScalar strikeToSourceScale)2607 void GrSubRunNoCachePainter::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2608                                                 const SkFont& runFont,
2609                                                 SkScalar strikeToSourceScale) {
2610     PathOpSubmitter pathDrawing =
2611             PathOpSubmitter::Make(accepted,
2612                                   has_some_antialiasing(runFont),
2613                                   strikeToSourceScale,
2614                                   fAlloc);
2615 
2616     pathDrawing.submitOps(fCanvas, fClip, fViewMatrix, fGlyphRunList.origin(), fPaint, fSDC);
2617 }
2618 
processSourceDrawables(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,SkScalar strikeToSourceScale)2619 void GrSubRunNoCachePainter::processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2620                                                     const SkFont& runFont,
2621                                                     SkScalar strikeToSourceScale) {
2622     DrawableOpSubmitter drawableDrawing =
2623             DrawableOpSubmitter::Make(accepted,
2624                                       has_some_antialiasing(runFont),
2625                                       strikeToSourceScale,
2626                                       fAlloc);
2627 
2628     drawableDrawing.submitOps(fCanvas, fClip, fViewMatrix, fGlyphRunList.origin(), fPaint, fSDC);
2629 }
2630 
processSourceSDFT(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,const SkFont & runFont,const GrSDFTMatrixRange &)2631 void GrSubRunNoCachePainter::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
2632                                                sk_sp<SkStrike>&& strike,
2633                                                SkScalar strikeToSourceScale,
2634                                                const SkFont& runFont,
2635                                                const GrSDFTMatrixRange&) {
2636     if (accepted.empty()) {
2637         return;
2638     }
2639     this->draw(SDFTSubRunNoCache::Make(
2640             accepted, runFont, std::move(strike), strikeToSourceScale, fAlloc));
2641 }
2642 
draw(GrAtlasSubRunOwner subRun)2643 void GrSubRunNoCachePainter::draw(GrAtlasSubRunOwner subRun) {
2644     if (subRun == nullptr) {
2645         return;
2646     }
2647     GrAtlasSubRun* subRunPtr = subRun.get();
2648     auto [drawingClip, op] = subRunPtr->makeAtlasTextOp(
2649             fClip, fViewMatrix, fGlyphRunList.origin(), fPaint, fSDC, std::move(subRun));
2650     if (op != nullptr) {
2651         fSDC->addDrawOp(drawingClip, std::move(op));
2652     }
2653 }
2654 
2655 namespace {
2656 // -- Slug -----------------------------------------------------------------------------------------
2657 class Slug final : public GrSlug, public SkGlyphRunPainterInterface {
2658 public:
2659     Slug(SkRect sourceBounds,
2660          const SkPaint& paint,
2661          const SkMatrix& positionMatrix,
2662          SkPoint origin,
2663          int allocSize);
2664     ~Slug() override = default;
2665 
2666     static sk_sp<Slug> Make(const SkMatrixProvider& viewMatrix,
2667                             const SkGlyphRunList& glyphRunList,
2668                             const SkPaint& paint,
2669                             const GrSDFTControl& control,
2670                             SkGlyphRunListPainter* painter);
2671     static sk_sp<GrSlug> MakeFromBuffer(SkReadBuffer& buffer,
2672                                         const SkStrikeClient* client);
2673 
2674     void surfaceDraw(SkCanvas*,
2675                      const GrClip* clip,
2676                      const SkMatrixProvider& viewMatrix,
2677                      skgpu::v1::SurfaceDrawContext* sdc);
2678 
2679     void flatten(SkWriteBuffer& buffer) const override;
sourceBounds() const2680     SkRect sourceBounds() const override { return fSourceBounds; }
paint() const2681     const SkPaint& paint() const override { return fPaint; }
2682 
2683     // SkGlyphRunPainterInterface
2684     void processDeviceMasks(
2685             const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike) override;
2686     void processSourceMasks(
2687             const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike,
2688             SkScalar strikeToSourceScale) override;
2689     void processSourcePaths(
2690             const SkZip<SkGlyphVariant, SkPoint>& accepted, const SkFont& runFont,
2691             SkScalar strikeToSourceScale) override;
2692     void processSourceDrawables(
2693             const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkFont& runFont,
2694             SkScalar strikeToSourceScale) override;
2695     void processSourceSDFT(
2696             const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike,
2697             SkScalar strikeToSourceScale, const SkFont& runFont,
2698             const GrSDFTMatrixRange& matrixRange) override;
2699 
initialPositionMatrix() const2700     const SkMatrix& initialPositionMatrix() const override { return fInitialPositionMatrix; }
origin() const2701     SkPoint origin() const { return fOrigin; }
2702 
2703     // Change memory management to handle the data after Slug, but in the same allocation
2704     // of memory. Only allow placement new.
operator delete(void * p)2705     void operator delete(void* p) { ::operator delete(p); }
operator new(size_t)2706     void* operator new(size_t) { SK_ABORT("All slugs are created by placement new."); }
operator new(size_t,void * p)2707     void* operator new(size_t, void* p) { return p; }
2708 
subRunCountAndUnflattenSizeHint() const2709     std::tuple<int, int> subRunCountAndUnflattenSizeHint() const {
2710         int unflattenSizeHint = 0;
2711         int subRunCount = 0;
2712         for (auto& subrun : fSubRuns) {
2713             subRunCount += 1;
2714             unflattenSizeHint += subrun.unflattenSize();
2715         }
2716         return {subRunCount, unflattenSizeHint};
2717     }
2718 
2719 private:
2720     // The allocator must come first because it needs to be destroyed last. Other fields of this
2721     // structure may have pointers into it.
2722     GrSubRunAllocator fAlloc;
2723     const SkRect fSourceBounds;
2724     const SkPaint fPaint;
2725     const SkMatrix fInitialPositionMatrix;
2726     const SkPoint fOrigin;
2727     GrSubRunList fSubRuns;
2728 };
2729 
Slug(SkRect sourceBounds,const SkPaint & paint,const SkMatrix & positionMatrix,SkPoint origin,int allocSize)2730 Slug::Slug(SkRect sourceBounds,
2731            const SkPaint& paint,
2732            const SkMatrix& positionMatrix,
2733            SkPoint origin,
2734            int allocSize)
2735            : fAlloc {SkTAddOffset<char>(this, sizeof(Slug)), allocSize, allocSize/2}
2736            , fSourceBounds{sourceBounds}
2737            , fPaint{paint}
2738            , fInitialPositionMatrix{positionMatrix}
2739            , fOrigin{origin} { }
2740 
surfaceDraw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,skgpu::v1::SurfaceDrawContext * sdc)2741 void Slug::surfaceDraw(SkCanvas* canvas, const GrClip* clip, const SkMatrixProvider& viewMatrix,
2742                        skgpu::v1::SurfaceDrawContext* sdc) {
2743     for (const GrSubRun& subRun : fSubRuns) {
2744         subRun.draw(canvas, clip, viewMatrix, fOrigin, fPaint, sdc);
2745     }
2746 }
2747 
flatten(SkWriteBuffer & buffer) const2748 void Slug::flatten(SkWriteBuffer& buffer) const {
2749     buffer.writeRect(fSourceBounds);
2750     SkPaintPriv::Flatten(fPaint, buffer);
2751     buffer.writeMatrix(fInitialPositionMatrix);
2752     buffer.writePoint(fOrigin);
2753     auto [subRunCount, subRunsUnflattenSizeHint] = this->subRunCountAndUnflattenSizeHint();
2754     buffer.writeInt(subRunCount);
2755     buffer.writeInt(subRunsUnflattenSizeHint);
2756     for (auto& subRun : fSubRuns) {
2757         subRun.flatten(buffer);
2758     }
2759 }
2760 
MakeFromBuffer(SkReadBuffer & buffer,const SkStrikeClient * client)2761 sk_sp<GrSlug> Slug::MakeFromBuffer(SkReadBuffer& buffer, const SkStrikeClient* client) {
2762     SkRect sourceBounds = buffer.readRect();
2763     if (!buffer.validate(!sourceBounds.isEmpty())) { return nullptr; }
2764 
2765     SkPaint paint = buffer.readPaint();
2766     SkMatrix positionMatrix;
2767     buffer.readMatrix(&positionMatrix);
2768     SkPoint origin = buffer.readPoint();
2769     int subRunCount = buffer.readInt();
2770     if (!buffer.validate(subRunCount != 0)) { return nullptr; }
2771     int subRunsUnflattenSizeHint = buffer.readInt();
2772 
2773     sk_sp<Slug> slug{new (::operator new (sizeof(Slug) + subRunsUnflattenSizeHint))
2774                              Slug(sourceBounds,
2775                                   paint,
2776                                   positionMatrix,
2777                                   origin,
2778                                   subRunsUnflattenSizeHint)};
2779     for (int i = 0; i < subRunCount; ++i) {
2780         auto subRun = GrSubRun::MakeFromBuffer(slug.get(), buffer, &slug->fAlloc, client);
2781         if (!buffer.validate(subRun != nullptr)) { return nullptr; }
2782         slug->fSubRuns.append(std::move(subRun));
2783     }
2784 
2785     // Something went wrong while reading.
2786     if (!buffer.isValid()) { return nullptr;}
2787 
2788     return std::move(slug);
2789 }
2790 
2791 // -- DirectMaskSubRunSlug -------------------------------------------------------------------------
2792 class DirectMaskSubRunSlug final : public GrSubRun, public GrAtlasSubRun {
2793 public:
2794     using DevicePosition = skvx::Vec<2, int16_t>;
2795 
2796     DirectMaskSubRunSlug(const GrTextReferenceFrame* referenceFrame,
2797                          GrMaskFormat format,
2798                          SkGlyphRect deviceBounds,
2799                          SkSpan<const DevicePosition> devicePositions,
2800                          GrGlyphVector&& glyphs);
2801 
2802     static GrSubRunOwner Make(const GrTextReferenceFrame* referenceFrame,
2803                               const SkZip<SkGlyphVariant, SkPoint>& accepted,
2804                               sk_sp<SkStrike>&& strike,
2805                               GrMaskFormat format,
2806                               GrSubRunAllocator* alloc);
2807 
2808     static GrSubRunOwner MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
2809                                         SkReadBuffer& buffer,
2810                                         GrSubRunAllocator* alloc,
2811                                         const SkStrikeClient* client);
2812 
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc) const2813     void draw(SkCanvas*,
2814               const GrClip* clip,
2815               const SkMatrixProvider& viewMatrix,
2816               SkPoint drawOrigin,
2817               const SkPaint& paint,
2818               skgpu::v1::SurfaceDrawContext* sdc) const override {
2819         auto [drawingClip, op] = this->makeAtlasTextOp(
2820                 clip, viewMatrix, drawOrigin, paint, sdc, nullptr);
2821         if (op != nullptr) {
2822             sdc->addDrawOp(drawingClip, std::move(op));
2823         }
2824     }
2825 
2826     int unflattenSize() const override;
2827 
2828     size_t vertexStride(const SkMatrix& drawMatrix) const override;
2829 
2830     int glyphCount() const override;
2831 
2832     std::tuple<const GrClip*, GrOp::Owner>
2833     makeAtlasTextOp(const GrClip*,
2834                     const SkMatrixProvider& viewMatrix,
2835                     SkPoint,
2836                     const SkPaint&,
2837                     skgpu::v1::SurfaceDrawContext*,
2838                     GrAtlasSubRunOwner) const override;
2839 
2840     void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const override;
2841 
2842     std::tuple<bool, int>
2843     regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
2844 
2845     void fillVertexData(void* vertexDst, int offset, int count,
2846                         GrColor color,
2847                         const SkMatrix& drawMatrix, SkPoint drawOrigin,
2848                         SkIRect clip) const override;
2849 
2850 protected:
subRunType() const2851     SubRunType subRunType() const override { return kDirectMask; }
2852     void doFlatten(SkWriteBuffer& buffer) const override;
2853 
2854 private:
2855     // Return true if the positionMatrix represents an integer translation. Return the device
2856     // bounding box of all the glyphs. If the bounding box is empty, then something went singular
2857     // and this operation should be dropped.
2858     std::tuple<bool, SkRect> deviceRectAndCheckTransform(const SkMatrix& positionMatrix) const;
2859 
2860     const GrTextReferenceFrame* const fReferenceFrame;
2861     const GrMaskFormat fMaskFormat;
2862 
2863     // The vertex bounds in device space. The bounds are the joined rectangles of all the glyphs.
2864     const SkGlyphRect fGlyphDeviceBounds;
2865     const SkSpan<const DevicePosition> fLeftTopDevicePos;
2866 
2867     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
2868     // be single threaded.
2869     mutable GrGlyphVector fGlyphs;
2870 };
2871 
DirectMaskSubRunSlug(const GrTextReferenceFrame * referenceFrame,GrMaskFormat format,SkGlyphRect deviceBounds,SkSpan<const DevicePosition> devicePositions,GrGlyphVector && glyphs)2872 DirectMaskSubRunSlug::DirectMaskSubRunSlug(const GrTextReferenceFrame* referenceFrame,
2873                                            GrMaskFormat format,
2874                                            SkGlyphRect deviceBounds,
2875                                            SkSpan<const DevicePosition> devicePositions,
2876                                            GrGlyphVector&& glyphs)
2877         : fReferenceFrame{referenceFrame}
2878         , fMaskFormat{format}
2879         , fGlyphDeviceBounds{deviceBounds}
2880         , fLeftTopDevicePos{devicePositions}
2881         , fGlyphs{std::move(glyphs)} { }
2882 
Make(const GrTextReferenceFrame * referenceFrame,const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,GrMaskFormat format,GrSubRunAllocator * alloc)2883 GrSubRunOwner DirectMaskSubRunSlug::Make(const GrTextReferenceFrame* referenceFrame,
2884                                          const SkZip<SkGlyphVariant, SkPoint>& accepted,
2885                                          sk_sp<SkStrike>&& strike,
2886                                          GrMaskFormat format,
2887                                          GrSubRunAllocator* alloc) {
2888     auto glyphLeftTop = alloc->makePODArray<DevicePosition>(accepted.size());
2889     auto glyphIDs = alloc->makePODArray<GrGlyphVector::Variant>(accepted.size());
2890 
2891     // Because this is the direct case, the maximum width or height is the size that fits in the
2892     // atlas. This boundary is checked below to ensure that the call to SkGlyphRect below will
2893     // not overflow.
2894     constexpr SkScalar kMaxPos =
2895             std::numeric_limits<int16_t>::max() - SkStrikeCommon::kSkSideTooBigForAtlas;
2896     SkGlyphRect runBounds = skglyph::empty_rect();
2897     size_t goodPosCount = 0;
2898     for (auto [variant, pos] : accepted) {
2899         auto [x, y] = pos;
2900         // Ensure that the .offset() call below does not overflow. And, at this point none of the
2901         // rectangles are empty because they were culled before the run was created. Basically,
2902         // cull all the glyphs that can't appear on the screen.
2903         if (-kMaxPos < x && x < kMaxPos && -kMaxPos  < y && y < kMaxPos) {
2904             const SkGlyph* const skGlyph = variant;
2905             const SkGlyphRect deviceBounds =
2906                     skGlyph->glyphRect().offset(SkScalarRoundToInt(x), SkScalarRoundToInt(y));
2907             runBounds = skglyph::rect_union(runBounds, deviceBounds);
2908             glyphLeftTop[goodPosCount] = deviceBounds.topLeft();
2909             glyphIDs[goodPosCount].packedGlyphID = skGlyph->getPackedID();
2910             goodPosCount += 1;
2911         }
2912     }
2913 
2914     // Wow! no glyphs are in bounds and had non-empty bounds.
2915     if (goodPosCount == 0) {
2916         return nullptr;
2917     }
2918 
2919     SkSpan<const DevicePosition> leftTop{glyphLeftTop, goodPosCount};
2920     return alloc->makeUnique<DirectMaskSubRunSlug>(
2921             referenceFrame, format, runBounds, leftTop,
2922             GrGlyphVector{std::move(strike), {glyphIDs, goodPosCount}});
2923 }
2924 
2925 template <typename T>
pun_read(SkReadBuffer & buffer,T * dst)2926 static bool pun_read(SkReadBuffer& buffer, T* dst) {
2927     return buffer.readPad32(dst, sizeof(T));
2928 }
2929 
MakeFromBuffer(const GrTextReferenceFrame * referenceFrame,SkReadBuffer & buffer,GrSubRunAllocator * alloc,const SkStrikeClient *)2930 GrSubRunOwner DirectMaskSubRunSlug::MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
2931                                                    SkReadBuffer& buffer,
2932                                                    GrSubRunAllocator* alloc,
2933                                                    const SkStrikeClient*) {
2934 
2935     GrMaskFormat format = (GrMaskFormat)buffer.readInt();
2936     SkGlyphRect runBounds;
2937     pun_read(buffer, &runBounds);
2938 
2939     int glyphCount = buffer.readInt();
2940     SkASSERT(0 < glyphCount);
2941     if (glyphCount <= 0) { return nullptr; }
2942     DevicePosition* positionsData = alloc->makePODArray<DevicePosition>(glyphCount);
2943     for (int i = 0; i < glyphCount; ++i) {
2944         pun_read(buffer, &positionsData[i]);
2945     }
2946     SkSpan<DevicePosition> positions(positionsData, glyphCount);
2947 
2948     auto glyphVector = GrGlyphVector::MakeFromBuffer(buffer, alloc);
2949     SkASSERT(glyphVector.has_value());
2950     if (!glyphVector) { return nullptr; }
2951     SkASSERT(SkTo<int>(glyphVector->glyphs().size()) == glyphCount);
2952     if (SkTo<int>(glyphVector->glyphs().size()) != glyphCount) { return nullptr; }
2953     return alloc->makeUnique<DirectMaskSubRunSlug>(
2954             referenceFrame, format, runBounds, positions, std::move(glyphVector.value()));
2955 }
2956 
2957 template <typename T>
pun_write(SkWriteBuffer & buffer,const T & src)2958 static void pun_write(SkWriteBuffer& buffer, const T& src) {
2959     buffer.writePad32(&src, sizeof(T));
2960 }
2961 
doFlatten(SkWriteBuffer & buffer) const2962 void DirectMaskSubRunSlug::doFlatten(SkWriteBuffer& buffer) const {
2963     buffer.writeInt(fMaskFormat);
2964     pun_write(buffer, fGlyphDeviceBounds);
2965     int glyphCount = SkTo<int>(fLeftTopDevicePos.size());
2966     buffer.writeInt(glyphCount);
2967     for (auto pos : fLeftTopDevicePos) {
2968         pun_write(buffer, pos);
2969     }
2970     fGlyphs.flatten(buffer);
2971 }
2972 
unflattenSize() const2973 int DirectMaskSubRunSlug::unflattenSize() const {
2974     return sizeof(DirectMaskSubRunSlug) +
2975            fGlyphs.unflattenSize() +
2976            sizeof(DevicePosition) * fGlyphs.glyphs().size();
2977 }
2978 
vertexStride(const SkMatrix & positionMatrix) const2979 size_t DirectMaskSubRunSlug::vertexStride(const SkMatrix& positionMatrix) const {
2980     if (!positionMatrix.hasPerspective()) {
2981         if (fMaskFormat != kARGB_GrMaskFormat) {
2982             return sizeof(Mask2DVertex);
2983         } else {
2984             return sizeof(ARGB2DVertex);
2985         }
2986     } else {
2987         if (fMaskFormat != kARGB_GrMaskFormat) {
2988             return sizeof(Mask3DVertex);
2989         } else {
2990             return sizeof(ARGB3DVertex);
2991         }
2992     }
2993 }
2994 
glyphCount() const2995 int DirectMaskSubRunSlug::glyphCount() const {
2996     return SkCount(fGlyphs.glyphs());
2997 }
2998 
2999 std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,skgpu::v1::SurfaceDrawContext * sdc,GrAtlasSubRunOwner subRunOwner) const3000 DirectMaskSubRunSlug::makeAtlasTextOp(const GrClip* clip,
3001                                       const SkMatrixProvider& viewMatrix,
3002                                       SkPoint drawOrigin,
3003                                       const SkPaint& paint,
3004                                       skgpu::v1::SurfaceDrawContext* sdc,
3005                                       GrAtlasSubRunOwner subRunOwner) const {
3006     SkASSERT(this->glyphCount() != 0);
3007     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
3008     const SkMatrix& positionMatrix = position_matrix(drawMatrix, drawOrigin);
3009 
3010     auto [integerTranslate, subRunDeviceBounds] = this->deviceRectAndCheckTransform(positionMatrix);
3011     if (subRunDeviceBounds.isEmpty()) {
3012         return {nullptr, nullptr};
3013     }
3014     // Rect for optimized bounds clipping when doing an integer translate.
3015     SkIRect geometricClipRect = SkIRect::MakeEmpty();
3016     if (integerTranslate) {
3017         // We can clip geometrically using clipRect and ignore clip when an axis-aligned rectangular
3018         // non-AA clip is used. If clipRect is empty, and clip is nullptr, then there is no clipping
3019         // needed.
3020         const SkRect deviceBounds = SkRect::MakeWH(sdc->width(), sdc->height());
3021         auto [clipMethod, clipRect] = calculate_clip(clip, deviceBounds, subRunDeviceBounds);
3022 
3023         switch (clipMethod) {
3024             case kClippedOut:
3025                 // Returning nullptr as op means skip this op.
3026                 return {nullptr, nullptr};
3027             case kUnclipped:
3028             case kGeometryClipped:
3029                 // GPU clip is not needed.
3030                 clip = nullptr;
3031                 break;
3032             case kGPUClipped:
3033                 // Use th GPU clip; clipRect is ignored.
3034                 break;
3035         }
3036         geometricClipRect = clipRect;
3037 
3038         if (!geometricClipRect.isEmpty()) { SkASSERT(clip == nullptr); }
3039     }
3040 
3041     GrPaint grPaint;
3042     const SkPMColor4f drawingColor =
3043             calculate_colors(sdc, paint, viewMatrix, fMaskFormat, &grPaint);
3044 
3045     auto geometry = AtlasTextOp::Geometry::MakeForBlob(*this,
3046                                                        drawMatrix,
3047                                                        drawOrigin,
3048                                                        geometricClipRect,
3049                                                        sk_ref_sp(fReferenceFrame),
3050                                                        drawingColor,
3051                                                        sdc->arenaAlloc());
3052 
3053     GrRecordingContext* const rContext = sdc->recordingContext();
3054     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
3055                                              op_mask_type(fMaskFormat),
3056                                              !integerTranslate,
3057                                              this->glyphCount(),
3058                                              subRunDeviceBounds,
3059                                              geometry,
3060                                              std::move(grPaint));
3061     return {clip, std::move(op)};
3062 }
3063 
testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache * cache) const3064 void DirectMaskSubRunSlug::testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) const {
3065     fGlyphs.packedGlyphIDToGrGlyph(cache);
3066 }
3067 
3068 std::tuple<bool, int>
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const3069 DirectMaskSubRunSlug::regenerateAtlas(int begin, int end, GrMeshDrawTarget* target) const {
3070     return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 1, target, true);
3071 }
3072 
3073 // The 99% case. No clip. Non-color only.
direct_2D3(SkZip<Mask2DVertex[4],const GrGlyph *,const DirectMaskSubRunNoCache::DevicePosition> quadData,GrColor color,SkPoint originOffset)3074 void direct_2D3(SkZip<Mask2DVertex[4],
3075         const GrGlyph*,
3076         const DirectMaskSubRunNoCache::DevicePosition> quadData,
3077                 GrColor color,
3078                 SkPoint originOffset) {
3079     for (auto[quad, glyph, leftTop] : quadData) {
3080         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
3081         SkScalar dl = leftTop[0] + originOffset.x(),
3082                  dt = leftTop[1] + originOffset.y(),
3083                  dr = dl + (ar - al),
3084                  db = dt + (ab - at);
3085 
3086         quad[0] = {{dl, dt}, color, {al, at}};  // L,T
3087         quad[1] = {{dl, db}, color, {al, ab}};  // L,B
3088         quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
3089         quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
3090     }
3091 }
3092 
3093 template<typename Quad, typename VertexData>
transformed_direct_2D(SkZip<Quad,const GrGlyph *,const VertexData> quadData,GrColor color,const SkMatrix & matrix)3094 void transformed_direct_2D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
3095                            GrColor color,
3096                            const SkMatrix& matrix) {
3097     for (auto[quad, glyph, leftTop] : quadData) {
3098         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
3099         SkScalar dl = leftTop[0],
3100                  dt = leftTop[1],
3101                  dr = dl + (ar - al),
3102                  db = dt + (ab - at);
3103         SkPoint lt = matrix.mapXY(dl, dt),
3104                 lb = matrix.mapXY(dl, db),
3105                 rt = matrix.mapXY(dr, dt),
3106                 rb = matrix.mapXY(dr, db);
3107         quad[0] = {lt, color, {al, at}};  // L,T
3108         quad[1] = {lb, color, {al, ab}};  // L,B
3109         quad[2] = {rt, color, {ar, at}};  // R,T
3110         quad[3] = {rb, color, {ar, ab}};  // R,B
3111     }
3112 }
3113 
3114 template<typename Quad, typename VertexData>
transformed_direct_3D(SkZip<Quad,const GrGlyph *,const VertexData> quadData,GrColor color,const SkMatrix & matrix)3115 void transformed_direct_3D(SkZip<Quad, const GrGlyph*, const VertexData> quadData,
3116                            GrColor color,
3117                            const SkMatrix& matrix) {
3118     auto mapXYZ = [&](SkScalar x, SkScalar y) {
3119         SkPoint pt{x, y};
3120         SkPoint3 result;
3121         matrix.mapHomogeneousPoints(&result, &pt, 1);
3122         return result;
3123     };
3124     for (auto[quad, glyph, leftTop] : quadData) {
3125         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
3126         SkScalar dl = leftTop[0],
3127                  dt = leftTop[1],
3128                  dr = dl + (ar - al),
3129                  db = dt + (ab - at);
3130         SkPoint3 lt = mapXYZ(dl, dt),
3131                  lb = mapXYZ(dl, db),
3132                  rt = mapXYZ(dr, dt),
3133                  rb = mapXYZ(dr, db);
3134         quad[0] = {lt, color, {al, at}};  // L,T
3135         quad[1] = {lb, color, {al, ab}};  // L,B
3136         quad[2] = {rt, color, {ar, at}};  // R,T
3137         quad[3] = {rb, color, {ar, ab}};  // R,B
3138     }
3139 }
3140 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const3141 void DirectMaskSubRunSlug::fillVertexData(void* vertexDst, int offset, int count,
3142                                           GrColor color,
3143                                           const SkMatrix& drawMatrix, SkPoint drawOrigin,
3144                                           SkIRect clip) const {
3145     auto quadData = [&](auto dst) {
3146         return SkMakeZip(dst,
3147                          fGlyphs.glyphs().subspan(offset, count),
3148                          fLeftTopDevicePos.subspan(offset, count));
3149     };
3150 
3151     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
3152     auto [noTransformNeeded, originOffset] =
3153             can_use_direct(fReferenceFrame->initialPositionMatrix(), positionMatrix);
3154 
3155     if (noTransformNeeded) {
3156         if (clip.isEmpty()) {
3157             if (fMaskFormat != kARGB_GrMaskFormat) {
3158                 using Quad = Mask2DVertex[4];
3159                 SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(SkMatrix::I()));
3160                 direct_2D3(quadData((Quad*)vertexDst), color, originOffset);
3161             } else {
3162                 using Quad = ARGB2DVertex[4];
3163                 SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(SkMatrix::I()));
3164                 generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset);
3165             }
3166         } else {
3167             if (fMaskFormat != kARGB_GrMaskFormat) {
3168                 using Quad = Mask2DVertex[4];
3169                 SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(SkMatrix::I()));
3170                 generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset, &clip);
3171             } else {
3172                 using Quad = ARGB2DVertex[4];
3173                 SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(SkMatrix::I()));
3174                 generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset, &clip);
3175             }
3176         }
3177     } else if (SkMatrix inverse; fReferenceFrame->initialPositionMatrix().invert(&inverse)) {
3178         SkMatrix viewDifference = SkMatrix::Concat(positionMatrix, inverse);
3179         if (!viewDifference.hasPerspective()) {
3180             if (fMaskFormat != kARGB_GrMaskFormat) {
3181                 using Quad = Mask2DVertex[4];
3182                 SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
3183                 transformed_direct_2D(quadData((Quad*)vertexDst), color, viewDifference);
3184             } else {
3185                 using Quad = ARGB2DVertex[4];
3186                 SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(positionMatrix));
3187                 transformed_direct_2D(quadData((Quad*)vertexDst), color, viewDifference);
3188             }
3189         } else {
3190             if (fMaskFormat != kARGB_GrMaskFormat) {
3191                 using Quad = Mask3DVertex[4];
3192                 SkASSERT(sizeof(Mask3DVertex) == this->vertexStride(positionMatrix));
3193                 transformed_direct_3D(quadData((Quad*)vertexDst), color, viewDifference);
3194             } else {
3195                 using Quad = ARGB3DVertex[4];
3196                 SkASSERT(sizeof(ARGB3DVertex) == this->vertexStride(positionMatrix));
3197                 transformed_direct_3D(quadData((Quad*)vertexDst), color, viewDifference);
3198             }
3199         }
3200     }
3201 }
3202 
3203 // true if only need to translate by integer amount, device rect.
3204 std::tuple<bool, SkRect>
deviceRectAndCheckTransform(const SkMatrix & positionMatrix) const3205 DirectMaskSubRunSlug::deviceRectAndCheckTransform(const SkMatrix& positionMatrix) const {
3206     SkPoint offset =
3207             positionMatrix.mapOrigin() - fReferenceFrame->initialPositionMatrix().mapOrigin();
3208     if (positionMatrix.isTranslate() && SkScalarIsInt(offset.x()) && SkScalarIsInt(offset.y())) {
3209         // Handle the integer offset case.
3210         // The offset should be integer, but make sure.
3211         SkIVector iOffset = {SkScalarRoundToInt(offset.x()), SkScalarRoundToInt(offset.y())};
3212 
3213         SkIRect outBounds = fGlyphDeviceBounds.iRect();
3214         return {true, SkRect::Make(outBounds.makeOffset(iOffset))};
3215     } else if (SkMatrix inverse; fReferenceFrame->initialPositionMatrix().invert(&inverse)) {
3216         SkMatrix viewDifference = SkMatrix::Concat(positionMatrix, inverse);
3217         return {false, viewDifference.mapRect(fGlyphDeviceBounds.rect())};
3218     }
3219 
3220     // initialPositionMatrix is singular. Do nothing.
3221     return {false, SkRect::MakeEmpty()};
3222 }
3223 
processDeviceMasks(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike)3224 void Slug::processDeviceMasks(
3225         const SkZip<SkGlyphVariant, SkPoint>& accepted, sk_sp<SkStrike>&& strike) {
3226     auto addGlyphsWithSameFormat = [&] (const SkZip<SkGlyphVariant, SkPoint>& accepted,
3227                                         GrMaskFormat format,
3228                                         sk_sp<SkStrike>&& runStrike) {
3229         GrSubRunOwner subRun = DirectMaskSubRunSlug::Make(
3230                 this, accepted, std::move(runStrike), format, &fAlloc);
3231         if (subRun != nullptr) {
3232             fSubRuns.append(std::move(subRun));
3233         }
3234     };
3235 
3236     add_multi_mask_format(addGlyphsWithSameFormat, accepted, std::move(strike));
3237 }
3238 
Make(const SkMatrixProvider & viewMatrix,const SkGlyphRunList & glyphRunList,const SkPaint & paint,const GrSDFTControl & control,SkGlyphRunListPainter * painter)3239 sk_sp<Slug> Slug::Make(const SkMatrixProvider& viewMatrix,
3240                        const SkGlyphRunList& glyphRunList,
3241                        const SkPaint& paint,
3242                        const GrSDFTControl& control,
3243                        SkGlyphRunListPainter* painter) {
3244     // The difference in alignment from the per-glyph data to the SubRun;
3245     constexpr size_t alignDiff =
3246             alignof(DirectMaskSubRun) - alignof(DirectMaskSubRun::DevicePosition);
3247     constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
3248     size_t totalGlyphCount = glyphRunList.totalGlyphCount();
3249     // The bytesNeededForSubRun is optimized for DirectMaskSubRun which is by far the most
3250     // common case.
3251     size_t bytesNeededForSubRun = GrBagOfBytes::PlatformMinimumSizeWithOverhead(
3252             totalGlyphCount * sizeof(DirectMaskSubRunSlug::DevicePosition)
3253             + GrGlyphVector::GlyphVectorSize(totalGlyphCount)
3254             + glyphRunList.runCount() * (sizeof(DirectMaskSubRunSlug) + vertexDataToSubRunPadding),
3255             alignof(Slug));
3256 
3257     size_t allocationSize = sizeof(GrTextBlob) + bytesNeededForSubRun;
3258 
3259     const SkMatrix positionMatrix =
3260             position_matrix(viewMatrix.localToDevice(), glyphRunList.origin());
3261 
3262     sk_sp<Slug> slug{new (::operator new (allocationSize))
3263                              Slug(glyphRunList.sourceBounds(),
3264                                   paint,
3265                                   positionMatrix,
3266                                   glyphRunList.origin(),
3267                                   bytesNeededForSubRun)};
3268 
3269     const uint64_t uniqueID = glyphRunList.uniqueID();
3270     for (auto& glyphRun : glyphRunList) {
3271         painter->processGlyphRun(slug.get(),
3272                                  glyphRun,
3273                                  positionMatrix,
3274                                  paint,
3275                                  control,
3276                                  "Make Slug",
3277                                  uniqueID);
3278     }
3279 
3280     // There is nothing to draw here. This is particularly a problem with RSX form blobs where a
3281     // single space becomes a run with no glyphs.
3282     if (slug->fSubRuns.isEmpty()) { return nullptr; }
3283 
3284     return slug;
3285 }
3286 
processSourcePaths(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,SkScalar strikeToSourceScale)3287 void Slug::processSourcePaths(const SkZip<SkGlyphVariant,
3288                               SkPoint>& accepted,
3289                               const SkFont& runFont,
3290                               SkScalar strikeToSourceScale) {
3291     fSubRuns.append(PathSubRun::Make(
3292             accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
3293 }
3294 
processSourceDrawables(const SkZip<SkGlyphVariant,SkPoint> & accepted,const SkFont & runFont,SkScalar strikeToSourceScale)3295 void Slug::processSourceDrawables(const SkZip<SkGlyphVariant, SkPoint>& accepted,
3296                                   const SkFont& runFont,
3297                                   SkScalar strikeToSourceScale) {
3298     fSubRuns.append(make_drawable_sub_run<DrawableSubRunSlug>(
3299             accepted, has_some_antialiasing(runFont), strikeToSourceScale, &fAlloc));
3300 }
3301 
processSourceSDFT(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale,const SkFont & runFont,const GrSDFTMatrixRange & matrixRange)3302 void Slug::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& accepted,
3303                                    sk_sp<SkStrike>&& strike,
3304                                    SkScalar strikeToSourceScale,
3305                                    const SkFont& runFont,
3306                                    const GrSDFTMatrixRange& matrixRange) {
3307     fSubRuns.append(SDFTSubRun::Make(
3308         this, accepted, runFont, std::move(strike), strikeToSourceScale, matrixRange, &fAlloc));
3309 }
3310 
processSourceMasks(const SkZip<SkGlyphVariant,SkPoint> & accepted,sk_sp<SkStrike> && strike,SkScalar strikeToSourceScale)3311 void Slug::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& accepted,
3312                               sk_sp<SkStrike>&& strike,
3313                               SkScalar strikeToSourceScale) {
3314 
3315     auto addGlyphsWithSameFormat = [&] (const SkZip<SkGlyphVariant, SkPoint>& accepted,
3316                                         GrMaskFormat format,
3317                                         sk_sp<SkStrike>&& runStrike) {
3318         GrSubRunOwner subRun = TransformedMaskSubRun::Make(
3319                 this, accepted, std::move(runStrike), strikeToSourceScale, format, &fAlloc);
3320         if (subRun != nullptr) {
3321             fSubRuns.append(std::move(subRun));
3322         }
3323     };
3324 
3325     add_multi_mask_format(addGlyphsWithSameFormat, accepted, std::move(strike));
3326 }
3327 }  // namespace
3328 
3329 namespace skgpu::v1 {
3330 sk_sp<GrSlug>
convertGlyphRunListToSlug(const SkGlyphRunList & glyphRunList,const SkPaint & paint)3331 Device::convertGlyphRunListToSlug(const SkGlyphRunList& glyphRunList, const SkPaint& paint) {
3332     return fSurfaceDrawContext->convertGlyphRunListToSlug(
3333             this->asMatrixProvider(), glyphRunList, paint);
3334 }
3335 
drawSlug(SkCanvas * canvas,GrSlug * slug)3336 void Device::drawSlug(SkCanvas* canvas, GrSlug* slug) {
3337     fSurfaceDrawContext->drawSlug(canvas, this->clip(), this->asMatrixProvider(), slug);
3338 }
3339 
3340 sk_sp<GrSlug>
convertGlyphRunListToSlug(const SkMatrixProvider & viewMatrix,const SkGlyphRunList & glyphRunList,const SkPaint & paint)3341 SurfaceDrawContext::convertGlyphRunListToSlug(const SkMatrixProvider& viewMatrix,
3342                                               const SkGlyphRunList& glyphRunList,
3343                                               const SkPaint& paint) {
3344     SkASSERT(fContext->priv().options().fSupportBilerpFromGlyphAtlas);
3345 
3346     GrSDFTControl control =
3347             this->recordingContext()->priv().getSDFTControl(
3348                     this->surfaceProps().isUseDeviceIndependentFonts());
3349 
3350     return Slug::Make(viewMatrix, glyphRunList, paint, control, &fGlyphPainter);
3351 }
3352 
drawSlug(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,GrSlug * slugPtr)3353 void SurfaceDrawContext::drawSlug(SkCanvas* canvas,
3354                                   const GrClip* clip,
3355                                   const SkMatrixProvider& viewMatrix,
3356                                   GrSlug* slugPtr) {
3357     Slug* slug = static_cast<Slug*>(slugPtr);
3358 
3359     slug->surfaceDraw(canvas, clip, viewMatrix, this);
3360 }
3361 
MakeSlug(const SkMatrixProvider & drawMatrix,const SkGlyphRunList & glyphRunList,const SkPaint & paint,const GrSDFTControl & control,SkGlyphRunListPainter * painter)3362 sk_sp<GrSlug> MakeSlug(const SkMatrixProvider& drawMatrix,
3363                        const SkGlyphRunList& glyphRunList,
3364                        const SkPaint& paint,
3365                        const GrSDFTControl& control,
3366                        SkGlyphRunListPainter* painter) {
3367     return Slug::Make(drawMatrix, glyphRunList, paint, control, painter);
3368 }
3369 }  // namespace skgpu::v1
3370 
3371 // -- GrSubRun -------------------------------------------------------------------------------------
flatten(SkWriteBuffer & buffer) const3372 void GrSubRun::flatten(SkWriteBuffer& buffer) const {
3373     buffer.writeInt(this->subRunType());
3374     this->doFlatten(buffer);
3375 }
3376 
MakeFromBuffer(const GrTextReferenceFrame * referenceFrame,SkReadBuffer & buffer,GrSubRunAllocator * alloc,const SkStrikeClient * client)3377 GrSubRunOwner GrSubRun::MakeFromBuffer(const GrTextReferenceFrame* referenceFrame,
3378                                        SkReadBuffer& buffer,
3379                                        GrSubRunAllocator* alloc,
3380                                        const SkStrikeClient* client) {
3381     using Maker = GrSubRunOwner (*)(const GrTextReferenceFrame*,
3382                                     SkReadBuffer&,
3383                                     GrSubRunAllocator*,
3384                                     const SkStrikeClient*);
3385 
3386     /* The makers will be populated in the next CL. */
3387     static Maker makers[kSubRunTypeCount] = {
3388             nullptr,                                             // 0 index is bad.
3389             DirectMaskSubRunSlug::MakeFromBuffer,
3390             SDFTSubRun::MakeFromBuffer,
3391             TransformedMaskSubRun::MakeFromBuffer,
3392             PathSubRun::MakeFromBuffer,
3393             DrawableSubRunSlug::MakeFromBuffer,
3394     };
3395     int subRunTypeInt = buffer.readInt();
3396     SkASSERT(kBad < subRunTypeInt && subRunTypeInt < kSubRunTypeCount);
3397     if (!buffer.validate(kBad < subRunTypeInt && subRunTypeInt < kSubRunTypeCount)) {
3398         return nullptr;
3399     }
3400     auto maker = makers[subRunTypeInt];
3401     if (!buffer.validate(maker != nullptr)) { return nullptr; }
3402     return maker(referenceFrame, buffer, alloc, client);
3403 }
3404 
SkMakeSlugFromBuffer(SkReadBuffer & buffer,const SkStrikeClient * client)3405 sk_sp<GrSlug> SkMakeSlugFromBuffer(SkReadBuffer& buffer, const SkStrikeClient* client) {
3406     return Slug::MakeFromBuffer(buffer, client);
3407 }
3408