• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/text/gpu/SubRunContainer.h"
9 
10 #include "include/core/SkMatrix.h"
11 #include "include/core/SkScalar.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/base/SkOnce.h"
14 #include "include/private/chromium/SkChromeRemoteGlyphCache.h"
15 #include "src/core/SkDescriptor.h"
16 #include "src/core/SkDistanceFieldGen.h"
17 #include "src/core/SkEnumerate.h"
18 #include "src/core/SkGlyph.h"
19 #include "src/core/SkGlyphBuffer.h"
20 #include "src/core/SkReadBuffer.h"
21 #include "src/core/SkRectPriv.h"
22 #include "src/core/SkStrike.h"
23 #include "src/core/SkStrikeCache.h"
24 #include "src/gpu/AtlasTypes.h"
25 #include "src/text/GlyphRun.h"
26 #include "src/text/StrikeForGPU.h"
27 #include "src/text/gpu/Glyph.h"
28 #include "src/text/gpu/GlyphVector.h"
29 #include "src/text/gpu/SubRunAllocator.h"
30 
31 #if defined(SK_GANESH)  // Ganesh Support
32 #include "src/gpu/ganesh/GrClip.h"
33 #include "src/gpu/ganesh/GrStyle.h"
34 #include "src/gpu/ganesh/SkGr.h"
35 #include "src/gpu/ganesh/SurfaceDrawContext.h"
36 #include "src/gpu/ganesh/ops/AtlasTextOp.h"
37 using AtlasTextOp = skgpu::ganesh::AtlasTextOp;
38 #endif  // defined(SK_GANESH)
39 
40 #if defined(SK_GRAPHITE)
41 #include "src/gpu/graphite/Device.h"
42 #include "src/gpu/graphite/DrawWriter.h"
43 #include "src/gpu/graphite/Renderer.h"
44 #include "src/gpu/graphite/RendererProvider.h"
45 #endif
46 
47 #include <cinttypes>
48 #include <cmath>
49 #include <optional>
50 
51 using namespace skglyph;
52 
53 // -- GPU Text -------------------------------------------------------------------------------------
54 // Naming conventions
55 //  * drawMatrix - the CTM from the canvas.
56 //  * drawOrigin - the x, y location of the drawTextBlob call.
57 //  * positionMatrix - this is the combination of the drawMatrix and the drawOrigin:
58 //        positionMatrix = drawMatrix * TranslationMatrix(drawOrigin.x, drawOrigin.y);
59 //
60 // Note:
61 //   In order to transform Slugs, you need to set the fSupportBilerpFromGlyphAtlas on
62 //   GrContextOptions.
63 
64 namespace sktext::gpu {
65 // -- SubRunType -----------------------------------------------------------------------------------
66 enum SubRun::SubRunType : int {
67     kBad = 0,  // Make this 0 to line up with errors from readInt.
68     kDirectMask,
69 #if !defined(SK_DISABLE_SDF_TEXT)
70     kSDFT,
71 #endif
72     kTransformMask,
73     kPath,
74     kDrawable,
75     kSubRunTypeCount,
76 };
77 
78 #if defined(SK_GRAPHITE)
79 // AtlasSubRun provides a draw() function that grants the anonymous subclasses access to
80 // Device::drawAtlasSubRun.
draw(skgpu::graphite::Device * device,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage) const81 void AtlasSubRun::draw(skgpu::graphite::Device* device,
82                        SkPoint drawOrigin,
83                        const SkPaint& paint,
84                        sk_sp<SkRefCnt> subRunStorage) const {
85     device->drawAtlasSubRun(this, drawOrigin, paint, std::move(subRunStorage));
86 }
87 #endif
88 
89 }  // namespace sktext::gpu
90 
91 using MaskFormat = skgpu::MaskFormat;
92 
93 using namespace sktext;
94 using namespace sktext::gpu;
95 
96 #if defined(SK_GRAPHITE)
97 namespace gr = skgpu::graphite;
98 
99 using BindBufferInfo = gr::BindBufferInfo;
100 using BufferType = gr::BufferType;
101 using Device = gr::Device;
102 using DrawWriter = gr::DrawWriter;
103 using Recorder = gr::Recorder;
104 using Renderer = gr::Renderer;
105 using RendererProvider = gr::RendererProvider;
106 using TextureProxy = gr::TextureProxy;
107 using Transform = gr::Transform;
108 #endif
109 
110 namespace {
111 // Returns the empty span if there is a problem reading the positions.
make_points_from_buffer(SkReadBuffer & buffer,SubRunAllocator * alloc)112 SkSpan<SkPoint> make_points_from_buffer(SkReadBuffer& buffer, SubRunAllocator* alloc) {
113     uint32_t glyphCount = buffer.getArrayCount();
114 
115     // Zero indicates a problem with serialization.
116     if (!buffer.validate(glyphCount != 0)) { return {}; }
117 
118     // Check that the count will not overflow the arena.
119     if (!buffer.validate(glyphCount <= INT_MAX &&
120                          BagOfBytes::WillCountFit<SkPoint>(glyphCount))) { return {}; }
121 
122     SkPoint* positionsData = alloc->makePODArray<SkPoint>(glyphCount);
123     if (!buffer.readPointArray(positionsData, glyphCount)) { return {}; }
124     return {positionsData, glyphCount};
125 }
126 
127 // -- TransformedMaskVertexFiller ------------------------------------------------------------------
128 // The TransformedMaskVertexFiller assumes that all points, glyph atlas entries, and bounds are
129 // created with respect to the CreationMatrix. This assumes that mapping any point, mask or
130 // bounds through the CreationMatrix will result in the proper device position. In order to draw
131 // using an arbitrary PositionMatrix, calculate a
132 //
133 //    viewDifference = [PositionMatrix] * [CreationMatrix] ^ -1.
134 //
135 // The viewDifference is used to map all points, masks and bounds to position to the device
136 // respecting the PositionMatrix.
137 class TransformedMaskVertexFiller {
138 public:
TransformedMaskVertexFiller(MaskFormat maskFormat,const SkMatrix & creationMatrix,SkRect creationBounds,SkSpan<const SkPoint> leftTop)139     TransformedMaskVertexFiller(MaskFormat maskFormat,
140                                 const SkMatrix& creationMatrix,
141                                 SkRect creationBounds,
142                                 SkSpan<const SkPoint> leftTop)
143             : fMaskType{maskFormat}
144             , fCreationMatrix{creationMatrix}
145             , fCreationBounds{creationBounds}
146             , fLeftTop{leftTop} {}
147 
Make(MaskFormat maskType,const SkMatrix & creationMatrix,SkRect creationBounds,const SkZip<SkPackedGlyphID,SkPoint> & accepted,SubRunAllocator * alloc)148     static TransformedMaskVertexFiller Make(MaskFormat maskType,
149                                             const SkMatrix& creationMatrix,
150                                             SkRect creationBounds,
151                                             const SkZip<SkPackedGlyphID, SkPoint>& accepted,
152                                             SubRunAllocator* alloc) {
153         SkSpan<SkPoint> leftTop = alloc->makePODArray<SkPoint>(
154                 accepted,
155                 [&](auto e) -> SkPoint {
156                     auto [variant, pos] = e;
157                     return pos;
158                 });
159         return TransformedMaskVertexFiller{maskType, creationMatrix, creationBounds, leftTop};
160     }
161 
162     static std::optional<TransformedMaskVertexFiller> MakeFromBuffer(
163             SkReadBuffer& buffer, SubRunAllocator* alloc);
164 
165     int unflattenSize() const;
166     void flatten(SkWriteBuffer& buffer) const;
167 
viewDifference(const SkMatrix & positionMatrix) const168     SkMatrix viewDifference(const SkMatrix& positionMatrix) const {
169         if (SkMatrix inverse; fCreationMatrix.invert(&inverse)) {
170             return SkMatrix::Concat(positionMatrix, inverse);
171         }
172         return SkMatrix::I();
173     }
174 
175 #if defined(SK_GANESH)
vertexStride(const SkMatrix & matrix) const176     size_t vertexStride(const SkMatrix& matrix) const {
177         if (fMaskType != MaskFormat::kARGB) {
178             // For formats MaskFormat::kA565 and MaskFormat::kA8 where A8 include SDF.
179             return matrix.hasPerspective() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex);
180         } else {
181             // For format MaskFormat::kARGB
182             return matrix.hasPerspective() ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex);
183         }
184     }
185 
186     void fillVertexData(int offset, int count,
187                         SkSpan<const Glyph*> glyphs,
188                         GrColor color,
189                         const SkMatrix& positionMatrix,
190                         SkIRect clip,
191                         void* vertexBuffer) const;
192 
193     AtlasTextOp::MaskType opMaskType() const;
194 #endif  // defined(SK_GANESH)
195 
196 #if defined(SK_GRAPHITE)
197     void fillVertexData(DrawWriter* dw,
198                         int offset, int count,
199                         int ssboIndex,
200                         SkSpan<const Glyph*> glyphs,
201                         SkScalar depth,
202                         const skgpu::graphite::Transform& toDevice) const;
203     void fillInstanceData(DrawWriter* dw,
204                           int offset, int count,
205                           unsigned short flags,
206                           int ssboIndex,
207                           SkSpan<const Glyph*> glyphs,
208                           SkScalar depth) const;
209 #endif
210     SkRect deviceRect(const SkMatrix& positionMatrix) const;
creationBounds() const211     SkRect creationBounds() const { return fCreationBounds; }
grMaskType() const212     MaskFormat grMaskType() const { return fMaskType; }
count() const213     int count() const { return SkCount(fLeftTop); }
214 
215 private:
216     struct AtlasPt {
217         uint16_t u;
218         uint16_t v;
219     };
220 
221 #if defined(SK_GANESH)
222     // Normal text mask, SDFT, or color.
223     struct Mask2DVertex {
224         SkPoint devicePos;
225         GrColor color;
226         AtlasPt atlasPos;
227     };
228 
229     struct ARGB2DVertex {
ARGB2DVertex__anon459911e60111::TransformedMaskVertexFiller::ARGB2DVertex230         ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
231 
232         SkPoint devicePos;
233         AtlasPt atlasPos;
234     };
235 
236     // Perspective SDFT or SDFT forced to 3D or perspective color.
237     struct Mask3DVertex {
238         SkPoint3 devicePos;
239         GrColor color;
240         AtlasPt atlasPos;
241     };
242 
243     struct ARGB3DVertex {
ARGB3DVertex__anon459911e60111::TransformedMaskVertexFiller::ARGB3DVertex244         ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
245 
246         SkPoint3 devicePos;
247         AtlasPt atlasPos;
248     };
249 
250     template<typename Quad, typename VertexData>
251     void fill2D(SkZip<Quad, const Glyph*, const VertexData> quadData,
252                 GrColor color,
253                 const SkMatrix& viewDifference) const;
254 
255     template<typename Quad, typename VertexData>
256     void fill3D(SkZip<Quad, const Glyph*, const VertexData> quadData,
257                 GrColor color,
258                 const SkMatrix& viewDifference) const;
259 #endif  // defined(SK_GANESH)
260 
261     const MaskFormat fMaskType;
262     const SkMatrix fCreationMatrix;
263     const SkRect fCreationBounds;
264     const SkSpan<const SkPoint> fLeftTop;
265 };
266 
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc)267 std::optional<TransformedMaskVertexFiller> TransformedMaskVertexFiller::MakeFromBuffer(
268         SkReadBuffer& buffer, SubRunAllocator* alloc) {
269     int checkingMaskType = buffer.readInt();
270     if (!buffer.validate(0 <= checkingMaskType && checkingMaskType < skgpu::kMaskFormatCount)) {
271         return std::nullopt;
272     }
273     MaskFormat maskType = (MaskFormat)checkingMaskType;
274 
275     SkMatrix creationMatrix;
276     buffer.readMatrix(&creationMatrix);
277 
278     SkRect creationBounds = buffer.readRect();
279 
280     SkSpan<SkPoint> leftTop = make_points_from_buffer(buffer, alloc);
281     if (leftTop.empty()) { return std::nullopt; }
282 
283     SkASSERT(buffer.isValid());
284     return TransformedMaskVertexFiller{maskType, creationMatrix, creationBounds, leftTop};
285 }
286 
flatten(SkWriteBuffer & buffer) const287 void TransformedMaskVertexFiller::flatten(SkWriteBuffer& buffer) const {
288     buffer.writeInt(static_cast<int>(fMaskType));
289     buffer.writeMatrix(fCreationMatrix);
290     buffer.writeRect(fCreationBounds);
291     buffer.writePointArray(fLeftTop.data(), SkCount(fLeftTop));
292 }
293 
deviceRect(const SkMatrix & positionMatrix) const294 SkRect TransformedMaskVertexFiller::deviceRect(const SkMatrix& positionMatrix) const {
295     SkMatrix viewDiff = this->viewDifference(positionMatrix);
296     return viewDiff.mapRect(fCreationBounds);
297 }
298 
unflattenSize() const299 int TransformedMaskVertexFiller::unflattenSize() const {
300     return fLeftTop.size_bytes();
301 }
302 
303 #if defined(SK_GANESH)
fillVertexData(int offset,int count,SkSpan<const Glyph * > glyphs,GrColor color,const SkMatrix & positionMatrix,SkIRect clip,void * vertexBuffer) const304 void TransformedMaskVertexFiller::fillVertexData(int offset, int count,
305                                                  SkSpan<const Glyph*> glyphs,
306                                                  GrColor color,
307                                                  const SkMatrix& positionMatrix,
308                                                  SkIRect clip,
309                                                  void* vertexBuffer) const {
310     auto quadData = [&](auto dst) {
311         return SkMakeZip(dst,
312                          glyphs.subspan(offset, count),
313                          fLeftTop.subspan(offset, count));
314     };
315 
316     SkMatrix viewDifference = this->viewDifference(positionMatrix);
317 
318     if (!positionMatrix.hasPerspective()) {
319         if (fMaskType == MaskFormat::kARGB) {
320             using Quad = ARGB2DVertex[4];
321             SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(positionMatrix));
322             this->fill2D(quadData((Quad*)vertexBuffer), color, viewDifference);
323         } else {
324             using Quad = Mask2DVertex[4];
325             SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
326             this->fill2D(quadData((Quad*)vertexBuffer), color, viewDifference);
327         }
328     } else {
329         if (fMaskType == MaskFormat::kARGB) {
330             using Quad = ARGB3DVertex[4];
331             SkASSERT(sizeof(ARGB3DVertex) == this->vertexStride(positionMatrix));
332             this->fill3D(quadData((Quad*)vertexBuffer), color, viewDifference);
333         } else {
334             using Quad = Mask3DVertex[4];
335             SkASSERT(sizeof(Mask3DVertex) == this->vertexStride(positionMatrix));
336             this->fill3D(quadData((Quad*)vertexBuffer), color, viewDifference);
337         }
338     }
339 }
340 
341 template <typename Quad, typename VertexData>
fill2D(SkZip<Quad,const Glyph *,const VertexData> quadData,GrColor color,const SkMatrix & viewDifference) const342 void TransformedMaskVertexFiller::fill2D(SkZip<Quad, const Glyph*, const VertexData> quadData,
343                                          GrColor color,
344                                          const SkMatrix& viewDifference) const {
345     for (auto [quad, glyph, leftTop] : quadData) {
346         auto [l, t] = leftTop;
347         auto [r, b] = leftTop + glyph->fAtlasLocator.widthHeight();
348         SkPoint lt = viewDifference.mapXY(l, t),
349                 lb = viewDifference.mapXY(l, b),
350                 rt = viewDifference.mapXY(r, t),
351                 rb = viewDifference.mapXY(r, b);
352         auto [al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
353         quad[0] = {lt, color, {al, at}};  // L,T
354         quad[1] = {lb, color, {al, ab}};  // L,B
355         quad[2] = {rt, color, {ar, at}};  // R,T
356         quad[3] = {rb, color, {ar, ab}};  // R,B
357     }
358 }
359 
360 template <typename Quad, typename VertexData>
fill3D(SkZip<Quad,const Glyph *,const VertexData> quadData,GrColor color,const SkMatrix & viewDifference) const361 void TransformedMaskVertexFiller::fill3D(SkZip<Quad, const Glyph*, const VertexData> quadData,
362                                          GrColor color,
363                                          const SkMatrix& viewDifference) const {
364     auto mapXYZ = [&](SkScalar x, SkScalar y) {
365         SkPoint pt{x, y};
366         SkPoint3 result;
367         viewDifference.mapHomogeneousPoints(&result, &pt, 1);
368         return result;
369     };
370     for (auto [quad, glyph, leftTop] : quadData) {
371         auto [l, t] = leftTop;
372         auto [r, b] = leftTop + glyph->fAtlasLocator.widthHeight();
373         SkPoint3 lt = mapXYZ(l, t),
374                  lb = mapXYZ(l, b),
375                  rt = mapXYZ(r, t),
376                  rb = mapXYZ(r, b);
377         auto [al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
378         quad[0] = {lt, color, {al, at}};  // L,T
379         quad[1] = {lb, color, {al, ab}};  // L,B
380         quad[2] = {rt, color, {ar, at}};  // R,T
381         quad[3] = {rb, color, {ar, ab}};  // R,B
382     }
383 }
384 
opMaskType() const385 AtlasTextOp::MaskType TransformedMaskVertexFiller::opMaskType() const {
386     switch (fMaskType) {
387         case MaskFormat::kA8:   return AtlasTextOp::MaskType::kGrayscaleCoverage;
388         case MaskFormat::kA565: return AtlasTextOp::MaskType::kLCDCoverage;
389         case MaskFormat::kARGB: return AtlasTextOp::MaskType::kColorBitmap;
390     }
391     SkUNREACHABLE;
392 }
393 #endif  // defined(SK_GANESH)
394 
395 #if defined(SK_GRAPHITE)
fillVertexData(DrawWriter * dw,int offset,int count,int ssboIndex,SkSpan<const Glyph * > glyphs,SkScalar depth,const Transform & toDevice) const396 void TransformedMaskVertexFiller::fillVertexData(DrawWriter* dw,
397                                                  int offset, int count,
398                                                  int ssboIndex,
399                                                  SkSpan<const Glyph*> glyphs,
400                                                  SkScalar depth,
401                                                  const Transform& toDevice) const {
402     auto quadData = [&]() {
403         return SkMakeZip(glyphs.subspan(offset, count),
404                          fLeftTop.subspan(offset, count));
405     };
406 
407     // TODO: can't handle perspective right now
408     if (toDevice.type() == Transform::Type::kProjection) {
409         return;
410     }
411 
412     DrawWriter::Vertices verts{*dw};
413     verts.reserve(6*count);
414     for (auto [glyph, leftTop]: quadData()) {
415         auto [al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
416         auto [l, t] = leftTop;
417         auto [r, b] = leftTop + glyph->fAtlasLocator.widthHeight();
418         SkV2 localCorners[4] = {{l, t}, {r, t}, {r, b}, {l, b}};
419         SkV4 devOut[4];
420         toDevice.mapPoints(localCorners, devOut, 4);
421         // TODO: Ganesh uses indices but that's not available with dynamic vertex data
422         // TODO: we should really use instances as well.
423         verts.append(6) << SkPoint{devOut[0].x, devOut[0].y} << depth << AtlasPt{al, at}  // L,T
424                         << ssboIndex
425                         << SkPoint{devOut[3].x, devOut[3].y} << depth << AtlasPt{al, ab}  // L,B
426                         << ssboIndex
427                         << SkPoint{devOut[1].x, devOut[1].y} << depth << AtlasPt{ar, at}  // R,T
428                         << ssboIndex
429                         << SkPoint{devOut[3].x, devOut[3].y} << depth << AtlasPt{al, ab}  // L,B
430                         << ssboIndex
431                         << SkPoint{devOut[2].x, devOut[2].y} << depth << AtlasPt{ar, ab}  // R,B
432                         << ssboIndex
433                         << SkPoint{devOut[1].x, devOut[1].y} << depth << AtlasPt{ar, at}  // R,T
434                         << ssboIndex;
435     }
436 }
437 
fillInstanceData(DrawWriter * dw,int offset,int count,unsigned short flags,int ssboIndex,SkSpan<const Glyph * > glyphs,SkScalar depth) const438 void TransformedMaskVertexFiller::fillInstanceData(DrawWriter* dw,
439                                                    int offset, int count,
440                                                    unsigned short flags,
441                                                    int ssboIndex,
442                                                    SkSpan<const Glyph*> glyphs,
443                                                    SkScalar depth) const {
444     auto quadData = [&]() {
445         return SkMakeZip(glyphs.subspan(offset, count),
446                          fLeftTop.subspan(offset, count));
447     };
448 
449     DrawWriter::Instances instances{*dw, {}, {}, 4};
450     instances.reserve(count);
451     // Need to send width, height, uvPos, xyPos, and strikeToSourceScale
452     // pre-transform coords = (s*w*b_x + t_x, s*h*b_y + t_y)
453     // where (b_x, b_y) are the vertexID coords
454     for (auto [glyph, leftTop]: quadData()) {
455         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
456         instances.append(1) << AtlasPt{uint16_t(ar-al), uint16_t(ab-at)}
457                             << AtlasPt{uint16_t(al & 0x1fff), at}
458                             << leftTop << /*index=*/uint16_t(al >> 13) << flags
459                             << 1.0f
460                             << depth << ssboIndex;
461     }
462 }
463 #endif
464 
465 struct AtlasPt {
466     uint16_t u;
467     uint16_t v;
468 };
469 
470 #if defined(SK_GANESH)
471 // Normal text mask, SDFT, or color.
472 struct Mask2DVertex {
473     SkPoint devicePos;
474     GrColor color;
475     AtlasPt atlasPos;
476 };
477 
478 struct ARGB2DVertex {
ARGB2DVertex__anon459911e60111::ARGB2DVertex479     ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
480 
481     SkPoint devicePos;
482     AtlasPt atlasPos;
483 };
484 
485 // Perspective SDFT or SDFT forced to 3D or perspective color.
486 struct Mask3DVertex {
487     SkPoint3 devicePos;
488     GrColor color;
489     AtlasPt atlasPos;
490 };
491 
492 struct ARGB3DVertex {
ARGB3DVertex__anon459911e60111::ARGB3DVertex493     ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
494 
495     SkPoint3 devicePos;
496     AtlasPt atlasPos;
497 };
498 
op_mask_type(MaskFormat maskFormat)499 AtlasTextOp::MaskType op_mask_type(MaskFormat maskFormat) {
500     switch (maskFormat) {
501         case MaskFormat::kA8:   return AtlasTextOp::MaskType::kGrayscaleCoverage;
502         case MaskFormat::kA565: return AtlasTextOp::MaskType::kLCDCoverage;
503         case MaskFormat::kARGB: return AtlasTextOp::MaskType::kColorBitmap;
504     }
505     SkUNREACHABLE;
506 }
507 
calculate_colors(skgpu::v1::SurfaceDrawContext * sdc,const SkPaint & paint,const SkMatrix & matrix,MaskFormat maskFormat,GrPaint * grPaint)508 SkPMColor4f calculate_colors(skgpu::v1::SurfaceDrawContext* sdc,
509                              const SkPaint& paint,
510                              const SkMatrix& matrix,
511                              MaskFormat maskFormat,
512                              GrPaint* grPaint) {
513     GrRecordingContext* rContext = sdc->recordingContext();
514     const GrColorInfo& colorInfo = sdc->colorInfo();
515     const SkSurfaceProps& props = sdc->surfaceProps();
516     if (maskFormat == MaskFormat::kARGB) {
517         SkPaintToGrPaintReplaceShader(rContext, colorInfo, paint, matrix, nullptr, props, grPaint);
518         float a = grPaint->getColor4f().fA;
519         return {a, a, a, a};
520     }
521     SkPaintToGrPaint(rContext, colorInfo, paint, matrix, props, grPaint);
522     return grPaint->getColor4f();
523 }
524 
position_matrix(const SkMatrix & drawMatrix,SkPoint drawOrigin)525 SkMatrix position_matrix(const SkMatrix& drawMatrix, SkPoint drawOrigin) {
526     SkMatrix position_matrix = drawMatrix;
527     return position_matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
528 }
529 #endif  // defined(SK_GANESH)
530 
531 // Check for integer translate with the same 2x2 matrix.
532 // Returns the translation, and true if the change from initial matrix to the position matrix
533 // support using direct glyph masks.
can_use_direct(const SkMatrix & initialPositionMatrix,const SkMatrix & positionMatrix)534 std::tuple<bool, SkVector> can_use_direct(
535         const SkMatrix& initialPositionMatrix, const SkMatrix& positionMatrix) {
536     // The existing direct glyph info can be used if the initialPositionMatrix, and the
537     // positionMatrix have the same 2x2, and the translation between them is integer.
538     // Calculate the translation in source space to a translation in device space by mapping
539     // (0, 0) through both the initial position matrix and the position matrix; take the difference.
540     SkVector translation = positionMatrix.mapOrigin() - initialPositionMatrix.mapOrigin();
541     return {initialPositionMatrix.getScaleX() == positionMatrix.getScaleX() &&
542                     initialPositionMatrix.getScaleY() == positionMatrix.getScaleY() &&
543                     initialPositionMatrix.getSkewX()  == positionMatrix.getSkewX()  &&
544                     initialPositionMatrix.getSkewY()  == positionMatrix.getSkewY()  &&
545                     SkScalarIsInt(translation.x()) && SkScalarIsInt(translation.y()),
546             translation};
547 }
548 
549 // -- PathOpSubmitter ------------------------------------------------------------------------------
550 // PathOpSubmitter holds glyph ids until ready to draw. During drawing, the glyph ids are
551 // converted to SkPaths. PathOpSubmitter can only be serialized when it is holding glyph ids;
552 // it can only be serialized before submitDraws has been called.
553 class PathOpSubmitter {
554 public:
555     PathOpSubmitter() = delete;
556     PathOpSubmitter(const PathOpSubmitter&) = delete;
557     const PathOpSubmitter& operator=(const PathOpSubmitter&) = delete;
PathOpSubmitter(PathOpSubmitter && that)558     PathOpSubmitter(PathOpSubmitter&& that)
559             // Transfer ownership of fIDsOrPaths from that to this.
560             : fIDsOrPaths{std::exchange(
561                       const_cast<SkSpan<IDOrPath>&>(that.fIDsOrPaths), SkSpan<IDOrPath>{})}
562             , fPositions{that.fPositions}
563             , fStrikeToSourceScale{that.fStrikeToSourceScale}
564             , fIsAntiAliased{that.fIsAntiAliased}
565             , fStrikePromise{std::move(that.fStrikePromise)} {}
operator =(PathOpSubmitter && that)566     PathOpSubmitter& operator=(PathOpSubmitter&& that) {
567         this->~PathOpSubmitter();
568         new (this) PathOpSubmitter{std::move(that)};
569         return *this;
570     }
571     PathOpSubmitter(bool isAntiAliased,
572                     SkScalar strikeToSourceScale,
573                     SkSpan<SkPoint> positions,
574                     SkSpan<IDOrPath> idsOrPaths,
575                     SkStrikePromise&& strikePromise);
576 
577     ~PathOpSubmitter();
578 
579     static PathOpSubmitter Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
580                                 bool isAntiAliased,
581                                 SkScalar strikeToSourceScale,
582                                 SkStrikePromise&& strikePromise,
583                                 SubRunAllocator* alloc);
584 
585     int unflattenSize() const;
586     void flatten(SkWriteBuffer& buffer) const;
587     static std::optional<PathOpSubmitter> MakeFromBuffer(SkReadBuffer& buffer,
588                                                          SubRunAllocator* alloc,
589                                                          const SkStrikeClient* client);
590 
591     // submitDraws is not thread safe. It only occurs the single thread drawing portion of the GPU
592     // rendering.
593     void submitDraws(SkCanvas*,
594                      SkPoint drawOrigin,
595                      const SkPaint& paint) const;
596 
597 private:
598     // When PathOpSubmitter is created only the glyphIDs are needed, during the submitDraws call,
599     // the glyphIDs are converted to SkPaths.
600     const SkSpan<IDOrPath> fIDsOrPaths;
601     const SkSpan<const SkPoint> fPositions;
602     const SkScalar fStrikeToSourceScale;
603     const bool fIsAntiAliased;
604 
605     mutable SkStrikePromise fStrikePromise;
606     mutable SkOnce fConvertIDsToPaths;
607     mutable bool fPathsAreCreated{false};
608 };
609 
unflattenSize() const610 int PathOpSubmitter::unflattenSize() const {
611     return fPositions.size_bytes() + fIDsOrPaths.size_bytes();
612 }
613 
flatten(SkWriteBuffer & buffer) const614 void PathOpSubmitter::flatten(SkWriteBuffer& buffer) const {
615     fStrikePromise.flatten(buffer);
616 
617     buffer.writeInt(fIsAntiAliased);
618     buffer.writeScalar(fStrikeToSourceScale);
619     buffer.writePointArray(fPositions.data(), SkCount(fPositions));
620     for (IDOrPath& idOrPath : fIDsOrPaths) {
621         buffer.writeInt(idOrPath.fGlyphID);
622     }
623 }
624 
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)625 std::optional<PathOpSubmitter> PathOpSubmitter::MakeFromBuffer(SkReadBuffer& buffer,
626                                                                SubRunAllocator* alloc,
627                                                                const SkStrikeClient* client) {
628     std::optional<SkStrikePromise> strikePromise =
629             SkStrikePromise::MakeFromBuffer(buffer, client, SkStrikeCache::GlobalStrikeCache());
630     if (!buffer.validate(strikePromise.has_value())) {
631         return std::nullopt;
632     }
633 
634     bool isAntiAlias = buffer.readInt();
635 
636     SkScalar strikeToSourceScale = buffer.readScalar();
637     if (!buffer.validate(0 < strikeToSourceScale)) { return std::nullopt; }
638 
639     SkSpan<SkPoint> positions = make_points_from_buffer(buffer, alloc);
640     if (positions.empty()) { return std::nullopt; }
641     const int glyphCount = SkCount(positions);
642 
643     // Remember, we stored an int for glyph id.
644     if (!buffer.validateCanReadN<int>(glyphCount)) { return std::nullopt; }
645     auto idsOrPaths = SkSpan(alloc->makeUniqueArray<IDOrPath>(glyphCount).release(), glyphCount);
646     for (auto& idOrPath : idsOrPaths) {
647         idOrPath.fGlyphID = SkTo<SkGlyphID>(buffer.readInt());
648     }
649 
650     if (!buffer.isValid()) { return std::nullopt; }
651 
652     return PathOpSubmitter{isAntiAlias,
653                            strikeToSourceScale,
654                            positions,
655                            idsOrPaths,
656                            std::move(strikePromise.value())};
657 }
658 
PathOpSubmitter(bool isAntiAliased,SkScalar strikeToSourceScale,SkSpan<SkPoint> positions,SkSpan<IDOrPath> idsOrPaths,SkStrikePromise && strikePromise)659 PathOpSubmitter::PathOpSubmitter(
660         bool isAntiAliased,
661         SkScalar strikeToSourceScale,
662         SkSpan<SkPoint> positions,
663         SkSpan<IDOrPath> idsOrPaths,
664         SkStrikePromise&& strikePromise)
665         : fIDsOrPaths{idsOrPaths}
666         , fPositions{positions}
667         , fStrikeToSourceScale{strikeToSourceScale}
668         , fIsAntiAliased{isAntiAliased}
669         , fStrikePromise{std::move(strikePromise)} {
670     SkASSERT(!fPositions.empty());
671 }
672 
~PathOpSubmitter()673 PathOpSubmitter::~PathOpSubmitter() {
674     // If we have converted glyph IDs to paths, then clean up the SkPaths.
675     if (fPathsAreCreated) {
676         for (auto& idOrPath : fIDsOrPaths) {
677             idOrPath.fPath.~SkPath();
678         }
679     }
680 }
681 
Make(const SkZip<SkPackedGlyphID,SkPoint> & accepted,bool isAntiAliased,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)682 PathOpSubmitter PathOpSubmitter::Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
683                                       bool isAntiAliased,
684                                       SkScalar strikeToSourceScale,
685                                       SkStrikePromise&& strikePromise,
686                                       SubRunAllocator* alloc) {
687     int glyphCount = SkCount(accepted);
688     SkPoint* positions = alloc->makePODArray<SkPoint>(glyphCount);
689     IDOrPath* idsOrPaths = alloc->makeUniqueArray<IDOrPath>(glyphCount).release();
690 
691     for (auto [dstIdOrPath, dstPosition, srcPackedGlyphID, srcPosition] :
692             SkMakeZip(idsOrPaths, positions, accepted.get<0>(), accepted.get<1>())) {
693         dstPosition = srcPosition;
694         dstIdOrPath.fGlyphID = srcPackedGlyphID.glyphID();
695     }
696 
697     return PathOpSubmitter{isAntiAliased,
698                            strikeToSourceScale,
699                            SkSpan(positions, glyphCount),
700                            SkSpan(idsOrPaths, glyphCount),
701                            std::move(strikePromise)};
702 }
703 
704 void
submitDraws(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint) const705 PathOpSubmitter::submitDraws(SkCanvas* canvas, SkPoint drawOrigin, const SkPaint& paint) const {
706     // Convert the glyph IDs to paths if it hasn't been done yet. This is thread safe.
707     fConvertIDsToPaths([&]() {
708         if (SkStrike* strike = fStrikePromise.strike()) {
709             strike->glyphIDsToPaths(fIDsOrPaths);
710 
711             // Drop ref to strike so that it can be purged from the cache if needed.
712             fStrikePromise.resetStrike();
713             fPathsAreCreated = true;
714         }
715     });
716 
717     SkPaint runPaint{paint};
718     runPaint.setAntiAlias(fIsAntiAliased);
719 
720     SkMaskFilterBase* maskFilter = as_MFB(runPaint.getMaskFilter());
721 
722     // Calculate the matrix that maps the path glyphs from their size in the strike to
723     // the graphics source space.
724     SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
725     strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
726 
727     // If there are shaders, non-blur mask filters or styles, the path must be scaled into source
728     // space independently of the CTM. This allows the CTM to be correct for the different effects.
729     SkStrokeRec style(runPaint);
730     bool needsExactCTM = runPaint.getShader()
731                          || runPaint.getPathEffect()
732                          || (!style.isFillStyle() && !style.isHairlineStyle())
733                          || (maskFilter != nullptr && !maskFilter->asABlur(nullptr));
734     if (!needsExactCTM) {
735         SkMaskFilterBase::BlurRec blurRec;
736 
737         // If there is a blur mask filter, then sigma needs to be adjusted to account for the
738         // scaling of fStrikeToSourceScale.
739         if (maskFilter != nullptr && maskFilter->asABlur(&blurRec)) {
740             runPaint.setMaskFilter(
741                     SkMaskFilter::MakeBlur(blurRec.fStyle, blurRec.fSigma / fStrikeToSourceScale));
742         }
743         for (auto [idOrPath, pos] : SkMakeZip(fIDsOrPaths, fPositions)) {
744             // Transform the glyph to source space.
745             SkMatrix pathMatrix = strikeToSource;
746             pathMatrix.postTranslate(pos.x(), pos.y());
747 
748             SkAutoCanvasRestore acr(canvas, true);
749             canvas->concat(pathMatrix);
750             canvas->drawPath(idOrPath.fPath, runPaint);
751         }
752     } else {
753         // Transform the path to device because the deviceMatrix must be unchanged to
754         // draw effect, filter or shader paths.
755         for (auto [idOrPath, pos] : SkMakeZip(fIDsOrPaths, fPositions)) {
756             // Transform the glyph to source space.
757             SkMatrix pathMatrix = strikeToSource;
758             pathMatrix.postTranslate(pos.x(), pos.y());
759 
760             SkPath deviceOutline;
761             idOrPath.fPath.transform(pathMatrix, &deviceOutline);
762             deviceOutline.setIsVolatile(true);
763             canvas->drawPath(deviceOutline, runPaint);
764         }
765     }
766 }
767 
768 // -- PathSubRun -----------------------------------------------------------------------------------
769 class PathSubRun final : public SubRun {
770 public:
PathSubRun(PathOpSubmitter && pathDrawing)771     PathSubRun(PathOpSubmitter&& pathDrawing) : fPathDrawing(std::move(pathDrawing)) {}
772 
Make(const SkZip<SkPackedGlyphID,SkPoint> & accepted,bool isAntiAliased,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)773     static SubRunOwner Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
774                             bool isAntiAliased,
775                             SkScalar strikeToSourceScale,
776                             SkStrikePromise&& strikePromise,
777                             SubRunAllocator* alloc) {
778         return alloc->makeUnique<PathSubRun>(
779             PathOpSubmitter::Make(
780                     accepted, isAntiAliased, strikeToSourceScale, std::move(strikePromise), alloc));
781     }
782 
783 #if defined(SK_GANESH)
draw(SkCanvas * canvas,const GrClip *,const SkMatrixProvider &,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt>,skgpu::v1::SurfaceDrawContext *) const784     void draw(SkCanvas* canvas,
785               const GrClip*,
786               const SkMatrixProvider&,
787               SkPoint drawOrigin,
788               const SkPaint& paint,
789               sk_sp<SkRefCnt>,
790               skgpu::v1::SurfaceDrawContext*) const override {
791         fPathDrawing.submitDraws(canvas, drawOrigin, paint);
792     }
793 #endif  // defined(SK_GANESH)
794 #if defined(SK_GRAPHITE)
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,Device * device) const795     void draw(SkCanvas* canvas,
796               SkPoint drawOrigin,
797               const SkPaint& paint,
798               sk_sp<SkRefCnt> subRunStorage,
799               Device* device) const override {
800         fPathDrawing.submitDraws(canvas, drawOrigin, paint);
801     }
802 #endif  // SK_GRAPHITE
803 
804     int unflattenSize() const override;
805 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const806     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
807         return true;
808     }
testingOnly_atlasSubRun() const809     const AtlasSubRun* testingOnly_atlasSubRun() const override { return nullptr; }
810     static SubRunOwner MakeFromBuffer(const SkMatrix& initialPositionMatrix,
811                                       SkReadBuffer& buffer,
812                                       SubRunAllocator* alloc,
813                                       const SkStrikeClient* client);
814 
815 protected:
subRunType() const816     SubRunType subRunType() const override { return kPath; }
817     void doFlatten(SkWriteBuffer& buffer) const override;
818 
819 private:
820     PathOpSubmitter fPathDrawing;
821 };
822 
unflattenSize() const823 int PathSubRun::unflattenSize() const {
824     return sizeof(PathSubRun) + fPathDrawing.unflattenSize();
825 }
826 
doFlatten(SkWriteBuffer & buffer) const827 void PathSubRun::doFlatten(SkWriteBuffer& buffer) const {
828     fPathDrawing.flatten(buffer);
829 }
830 
MakeFromBuffer(const SkMatrix & initialPositionMatrix,SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)831 SubRunOwner PathSubRun::MakeFromBuffer(const SkMatrix& initialPositionMatrix,
832                                        SkReadBuffer& buffer,
833                                        SubRunAllocator* alloc,
834                                        const SkStrikeClient* client) {
835     auto pathOpSubmitter = PathOpSubmitter::MakeFromBuffer(buffer, alloc, client);
836     if (!buffer.validate(pathOpSubmitter.has_value())) { return nullptr; }
837     return alloc->makeUnique<PathSubRun>(std::move(*pathOpSubmitter));
838 }
839 
840 // -- DrawableOpSubmitter --------------------------------------------------------------------------
841 // Shared code for submitting GPU ops for drawing glyphs as drawables.
842 class DrawableOpSubmitter {
843 public:
844     DrawableOpSubmitter() = delete;
845     DrawableOpSubmitter(const DrawableOpSubmitter&) = delete;
846     const DrawableOpSubmitter& operator=(const DrawableOpSubmitter&) = delete;
DrawableOpSubmitter(DrawableOpSubmitter && that)847     DrawableOpSubmitter(DrawableOpSubmitter&& that)
848         : fStrikeToSourceScale{that.fStrikeToSourceScale}
849         , fPositions{that.fPositions}
850         , fIDsOrDrawables{that.fIDsOrDrawables}
851         , fStrikePromise{std::move(that.fStrikePromise)} {}
operator =(DrawableOpSubmitter && that)852     DrawableOpSubmitter& operator=(DrawableOpSubmitter&& that) {
853         this->~DrawableOpSubmitter();
854         new (this) DrawableOpSubmitter{std::move(that)};
855         return *this;
856     }
857     DrawableOpSubmitter(SkScalar strikeToSourceScale,
858                         SkSpan<SkPoint> positions,
859                         SkSpan<IDOrDrawable> idsOrDrawables,
860                         SkStrikePromise&& strikePromise);
861 
862     static DrawableOpSubmitter Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
863                                     SkScalar strikeToSourceScale,
864                                     SkStrikePromise&& strikePromise,
865                                     SubRunAllocator* alloc);
866 
867     int unflattenSize() const;
868     void flatten(SkWriteBuffer& buffer) const;
869     static std::optional<DrawableOpSubmitter> MakeFromBuffer(SkReadBuffer& buffer,
870                                                              SubRunAllocator* alloc,
871                                                              const SkStrikeClient* client);
872     void submitDraws(SkCanvas* canvas, SkPoint drawOrigin, const SkPaint& paint) const;
873 
874 private:
875     const SkScalar fStrikeToSourceScale;
876     const SkSpan<SkPoint> fPositions;
877     const SkSpan<IDOrDrawable> fIDsOrDrawables;
878     // When the promise is converted to a strike it acts as the ref on the strike to keep the
879     // SkDrawable data alive.
880     mutable SkStrikePromise fStrikePromise;
881     mutable SkOnce fConvertIDsToDrawables;
882 };
883 
unflattenSize() const884 int DrawableOpSubmitter::unflattenSize() const {
885     return fPositions.size_bytes() + fIDsOrDrawables.size_bytes();
886 }
887 
flatten(SkWriteBuffer & buffer) const888 void DrawableOpSubmitter::flatten(SkWriteBuffer& buffer) const {
889     fStrikePromise.flatten(buffer);
890 
891     buffer.writeScalar(fStrikeToSourceScale);
892     buffer.writePointArray(fPositions.data(), SkCount(fPositions));
893     for (IDOrDrawable idOrDrawable : fIDsOrDrawables) {
894         buffer.writeInt(idOrDrawable.fGlyphID);
895     }
896 }
897 
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)898 std::optional<DrawableOpSubmitter> DrawableOpSubmitter::MakeFromBuffer(
899         SkReadBuffer& buffer, SubRunAllocator* alloc, const SkStrikeClient* client) {
900     std::optional<SkStrikePromise> strikePromise =
901             SkStrikePromise::MakeFromBuffer(buffer, client, SkStrikeCache::GlobalStrikeCache());
902     if (!buffer.validate(strikePromise.has_value())) {
903         return std::nullopt;
904     }
905 
906     SkScalar strikeToSourceScale = buffer.readScalar();
907     if (!buffer.validate(0 < strikeToSourceScale)) { return std::nullopt; }
908 
909     SkSpan<SkPoint> positions = make_points_from_buffer(buffer, alloc);
910     if (positions.empty()) { return std::nullopt; }
911     const int glyphCount = SkCount(positions);
912 
913     if (!buffer.validateCanReadN<int>(glyphCount)) { return std::nullopt; }
914     auto idsOrDrawables = alloc->makePODArray<IDOrDrawable>(glyphCount);
915     for (int i = 0; i < SkToInt(glyphCount); ++i) {
916         // Remember, we stored an int for glyph id.
917         idsOrDrawables[i].fGlyphID = SkTo<SkGlyphID>(buffer.readInt());
918     }
919 
920     SkASSERT(buffer.isValid());
921     return DrawableOpSubmitter{strikeToSourceScale,
922                                positions,
923                                SkSpan(idsOrDrawables, glyphCount),
924                                std::move(strikePromise.value())};
925 }
926 
DrawableOpSubmitter(SkScalar strikeToSourceScale,SkSpan<SkPoint> positions,SkSpan<IDOrDrawable> idsOrDrawables,SkStrikePromise && strikePromise)927 DrawableOpSubmitter::DrawableOpSubmitter(
928         SkScalar strikeToSourceScale,
929         SkSpan<SkPoint> positions,
930         SkSpan<IDOrDrawable> idsOrDrawables,
931         SkStrikePromise&& strikePromise)
932         : fStrikeToSourceScale{strikeToSourceScale}
933         , fPositions{positions}
934         , fIDsOrDrawables{idsOrDrawables}
935         , fStrikePromise(std::move(strikePromise)) {
936     SkASSERT(!fPositions.empty());
937 }
938 
Make(const SkZip<SkPackedGlyphID,SkPoint> & accepted,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)939 DrawableOpSubmitter DrawableOpSubmitter::Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
940                                               SkScalar strikeToSourceScale,
941                                               SkStrikePromise&& strikePromise,
942                                               SubRunAllocator* alloc) {
943     int glyphCount = SkCount(accepted);
944     SkPoint* positions = alloc->makePODArray<SkPoint>(glyphCount);
945     IDOrDrawable* idsOrDrawables = alloc->makePODArray<IDOrDrawable>(glyphCount);
946     for (auto [i, variant, pos] : SkMakeEnumerate(accepted)) {
947         positions[i] = pos;
948         idsOrDrawables[i].fGlyphID = variant.glyphID();
949     }
950 
951     return DrawableOpSubmitter{strikeToSourceScale,
952                                SkSpan(positions, glyphCount),
953                                SkSpan(idsOrDrawables, glyphCount),
954                                std::move(strikePromise)};
955 }
956 
957 void
submitDraws(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint) const958 DrawableOpSubmitter::submitDraws(SkCanvas* canvas, SkPoint drawOrigin,const SkPaint& paint) const {
959     // Convert glyph IDs to Drawables if it hasn't been done yet.
960     fConvertIDsToDrawables([&]() {
961         fStrikePromise.strike()->glyphIDsToDrawables(fIDsOrDrawables);
962         // Do not call resetStrike() because the strike must remain owned to ensure the Drawable
963         // data is not freed.
964     });
965 
966     // Calculate the matrix that maps the path glyphs from their size in the strike to
967     // the graphics source space.
968     SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
969     strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
970 
971     // Transform the path to device because the deviceMatrix must be unchanged to
972     // draw effect, filter or shader paths.
973     for (auto [i, position] : SkMakeEnumerate(fPositions)) {
974         SkDrawable* drawable = fIDsOrDrawables[i].fDrawable;
975 
976         if (drawable == nullptr) {
977             // This better be pinned to keep the drawable data alive.
978             fStrikePromise.strike()->verifyPinnedStrike();
979             SkDEBUGFAIL("Drawable should not be nullptr.");
980             continue;
981         }
982 
983         // Transform the glyph to source space.
984         SkMatrix pathMatrix = strikeToSource;
985         pathMatrix.postTranslate(position.x(), position.y());
986 
987         SkAutoCanvasRestore acr(canvas, false);
988         SkRect drawableBounds = drawable->getBounds();
989         pathMatrix.mapRect(&drawableBounds);
990         canvas->saveLayer(&drawableBounds, &paint);
991         drawable->draw(canvas, &pathMatrix);
992     }
993 }
994 
995 template <typename SubRunT>
make_drawable_sub_run(const SkZip<SkPackedGlyphID,SkPoint> & drawables,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)996 SubRunOwner make_drawable_sub_run(const SkZip<SkPackedGlyphID, SkPoint>& drawables,
997                                   SkScalar strikeToSourceScale,
998                                   SkStrikePromise&& strikePromise,
999                                   SubRunAllocator* alloc) {
1000     return alloc->makeUnique<SubRunT>(
1001         DrawableOpSubmitter::Make(drawables, strikeToSourceScale, std::move(strikePromise), alloc));
1002 }
1003 
1004 // -- DrawableSubRun -------------------------------------------------------------------------------
1005 class DrawableSubRun : public SubRun {
1006 public:
DrawableSubRun(DrawableOpSubmitter && drawingDrawing)1007     DrawableSubRun(DrawableOpSubmitter&& drawingDrawing)
1008             : fDrawingDrawing(std::move(drawingDrawing)) {}
1009 
1010     static SubRunOwner MakeFromBuffer(const SkMatrix&,
1011                                       SkReadBuffer& buffer,
1012                                       SubRunAllocator* alloc,
1013                                       const SkStrikeClient* client);
1014 #if defined(SK_GANESH)
draw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const1015     void draw(SkCanvas* canvas,
1016               const GrClip* clip,
1017               const SkMatrixProvider& viewMatrix,
1018               SkPoint drawOrigin,
1019               const SkPaint& paint,
1020               sk_sp<SkRefCnt> subRunStorage,
1021               skgpu::v1::SurfaceDrawContext* sdc) const override {
1022         fDrawingDrawing.submitDraws(canvas, drawOrigin, paint);
1023     }
1024 #endif  // defined(SK_GANESH)
1025 #if defined(SK_GRAPHITE)
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,Device * device) const1026     void draw(SkCanvas* canvas,
1027               SkPoint drawOrigin,
1028               const SkPaint& paint,
1029               sk_sp<SkRefCnt> subRunStorage,
1030               Device* device) const override {
1031         fDrawingDrawing.submitDraws(canvas, drawOrigin, paint);
1032     }
1033 #endif  // SK_GRAPHITE
1034 
1035     int unflattenSize() const override;
1036 
1037     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override;
1038 
1039     const AtlasSubRun* testingOnly_atlasSubRun() const override;
1040 
1041 protected:
subRunType() const1042     SubRunType subRunType() const override { return kDrawable; }
1043     void doFlatten(SkWriteBuffer& buffer) const override;
1044 
1045 private:
1046     DrawableOpSubmitter fDrawingDrawing;
1047 };
1048 
unflattenSize() const1049 int DrawableSubRun::unflattenSize() const {
1050     return sizeof(DrawableSubRun) + fDrawingDrawing.unflattenSize();
1051 }
1052 
doFlatten(SkWriteBuffer & buffer) const1053 void DrawableSubRun::doFlatten(SkWriteBuffer& buffer) const {
1054     fDrawingDrawing.flatten(buffer);
1055 }
1056 
MakeFromBuffer(const SkMatrix &,SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)1057 SubRunOwner DrawableSubRun::MakeFromBuffer(const SkMatrix&,
1058                                            SkReadBuffer& buffer,
1059                                            SubRunAllocator* alloc,
1060                                            const SkStrikeClient* client) {
1061     auto drawableOpSubmitter = DrawableOpSubmitter::MakeFromBuffer(buffer, alloc, client);
1062     if (!buffer.validate(drawableOpSubmitter.has_value())) { return nullptr; }
1063     return alloc->makeUnique<DrawableSubRun>(std::move(*drawableOpSubmitter));
1064 }
1065 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1066 bool DrawableSubRun::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
1067     return true;
1068 }
1069 
testingOnly_atlasSubRun() const1070 const AtlasSubRun* DrawableSubRun::testingOnly_atlasSubRun() const {
1071     return nullptr;
1072 }
1073 
1074 #if defined(SK_GANESH)
1075 enum ClipMethod {
1076     kClippedOut,
1077     kUnclipped,
1078     kGPUClipped,
1079     kGeometryClipped
1080 };
1081 
1082 std::tuple<ClipMethod, SkIRect>
calculate_clip(const GrClip * clip,SkRect deviceBounds,SkRect glyphBounds)1083 calculate_clip(const GrClip* clip, SkRect deviceBounds, SkRect glyphBounds) {
1084     if (clip == nullptr && !deviceBounds.intersects(glyphBounds)) {
1085         return {kClippedOut, SkIRect::MakeEmpty()};
1086     } else if (clip != nullptr) {
1087         switch (auto result = clip->preApply(glyphBounds, GrAA::kNo); result.fEffect) {
1088             case GrClip::Effect::kClippedOut:
1089                 return {kClippedOut, SkIRect::MakeEmpty()};
1090             case GrClip::Effect::kUnclipped:
1091                 return {kUnclipped, SkIRect::MakeEmpty()};
1092             case GrClip::Effect::kClipped: {
1093                 if (result.fIsRRect && result.fRRect.isRect()) {
1094                     SkRect r = result.fRRect.rect();
1095                     if (result.fAA == GrAA::kNo || GrClip::IsPixelAligned(r)) {
1096                         SkIRect clipRect = SkIRect::MakeEmpty();
1097                         // Clip geometrically during onPrepare using clipRect.
1098                         r.round(&clipRect);
1099                         if (clipRect.contains(glyphBounds)) {
1100                             // If fully within the clip, signal no clipping using the empty rect.
1101                             return {kUnclipped, SkIRect::MakeEmpty()};
1102                         }
1103                         // Use the clipRect to clip the geometry.
1104                         return {kGeometryClipped, clipRect};
1105                     }
1106                     // Partial pixel clipped at this point. Have the GPU handle it.
1107                 }
1108             }
1109             break;
1110         }
1111     }
1112     return {kGPUClipped, SkIRect::MakeEmpty()};
1113 }
1114 template <typename Rect>
ltbr(const Rect & r)1115 auto ltbr(const Rect& r) {
1116     return std::make_tuple(r.left(), r.top(), r.right(), r.bottom());
1117 }
1118 
1119 // Handle any combination of BW or color and clip or no clip.
1120 template<typename Quad, typename VertexData>
generalized_direct_2D(SkZip<Quad,const Glyph *,const VertexData> quadData,GrColor color,SkPoint originOffset,SkIRect * clip=nullptr)1121 void generalized_direct_2D(SkZip<Quad, const Glyph*, const VertexData> quadData,
1122                            GrColor color,
1123                            SkPoint originOffset,
1124                            SkIRect* clip = nullptr) {
1125     for (auto[quad, glyph, leftTop] : quadData) {
1126         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
1127         uint16_t w = ar - al,
1128                  h = ab - at;
1129         SkScalar l = leftTop.x() + originOffset.x(),
1130                  t = leftTop.y() + originOffset.y();
1131         if (clip == nullptr) {
1132             auto[dl, dt, dr, db] = SkRect::MakeLTRB(l, t, l + w, t + h);
1133             quad[0] = {{dl, dt}, color, {al, at}};  // L,T
1134             quad[1] = {{dl, db}, color, {al, ab}};  // L,B
1135             quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
1136             quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
1137         } else {
1138             SkIRect devIRect = SkIRect::MakeLTRB(l, t, l + w, t + h);
1139             SkScalar dl, dt, dr, db;
1140             if (!clip->containsNoEmptyCheck(devIRect)) {
1141                 if (SkIRect clipped; clipped.intersect(devIRect, *clip)) {
1142                     al += clipped.left()   - devIRect.left();
1143                     at += clipped.top()    - devIRect.top();
1144                     ar += clipped.right()  - devIRect.right();
1145                     ab += clipped.bottom() - devIRect.bottom();
1146                     std::tie(dl, dt, dr, db) = ltbr(clipped);
1147                 } else {
1148                     // TODO: omit generating any vertex data for fully clipped glyphs ?
1149                     std::tie(dl, dt, dr, db) = std::make_tuple(0, 0, 0, 0);
1150                     std::tie(al, at, ar, ab) = std::make_tuple(0, 0, 0, 0);
1151                 }
1152             } else {
1153                 std::tie(dl, dt, dr, db) = ltbr(devIRect);
1154             }
1155             quad[0] = {{dl, dt}, color, {al, at}};  // L,T
1156             quad[1] = {{dl, db}, color, {al, ab}};  // L,B
1157             quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
1158             quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
1159         }
1160     }
1161 }
1162 
1163 // The 99% case. No clip. Non-color only.
direct_2D(SkZip<Mask2DVertex[4],const Glyph *,const SkPoint> quadData,GrColor color,SkPoint originOffset)1164 void direct_2D(SkZip<Mask2DVertex[4],
1165                      const Glyph*,
1166                      const SkPoint> quadData,
1167                GrColor color,
1168                SkPoint originOffset) {
1169     for (auto[quad, glyph, leftTop] : quadData) {
1170         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
1171         SkScalar dl = leftTop.x() + originOffset.x(),
1172                  dt = leftTop.y() + originOffset.y(),
1173                  dr = dl + (ar - al),
1174                  db = dt + (ab - at);
1175 
1176         quad[0] = {{dl, dt}, color, {al, at}};  // L,T
1177         quad[1] = {{dl, db}, color, {al, ab}};  // L,B
1178         quad[2] = {{dr, dt}, color, {ar, at}};  // R,T
1179         quad[3] = {{dr, db}, color, {ar, ab}};  // R,B
1180     }
1181 }
1182 #endif  // defined(SK_GANESH)
1183 
1184 // -- DirectMaskSubRun -------------------------------------------------------------------------
1185 class DirectMaskSubRun final : public SubRun, public AtlasSubRun {
1186 public:
1187     DirectMaskSubRun(MaskFormat format,
1188                      const SkMatrix& initialPositionMatrix,
1189                      SkRect deviceBounds,
1190                      SkSpan<const SkPoint> devicePositions,
1191                      GlyphVector&& glyphs);
1192 
1193     static SubRunOwner Make(SkRect runBounds,
1194                             const SkZip<SkPackedGlyphID, SkPoint>& accepted,
1195                             const SkMatrix& initialPositionMatrix,
1196                             SkStrikePromise&& strikePromise,
1197                             MaskFormat format,
1198                             SubRunAllocator* alloc);
1199 
1200     static SubRunOwner MakeFromBuffer(const SkMatrix& initialPositionMatrix,
1201                                       SkReadBuffer& buffer,
1202                                       SubRunAllocator* alloc,
1203                                       const SkStrikeClient* client);
1204 #if defined(SK_GANESH)
1205     void draw(SkCanvas*,
1206               const GrClip* clip,
1207               const SkMatrixProvider& viewMatrix,
1208               SkPoint drawOrigin,
1209               const SkPaint& paint,
1210               sk_sp<SkRefCnt> subRunOwner,
1211               skgpu::v1::SurfaceDrawContext* sdc) const override;
1212 #endif  // defined(SK_GANESH)
1213 
1214 #if defined(SK_GRAPHITE)
1215     void draw(SkCanvas*,
1216               SkPoint drawOrigin,
1217               const SkPaint&,
1218               sk_sp<SkRefCnt> subRunStorage,
1219               Device*) const override;
1220 #endif
1221 
1222     int unflattenSize() const override;
1223 
1224     int glyphCount() const override;
maskFormat() const1225     MaskFormat maskFormat() const override { return fMaskFormat; }
1226 
1227     void testingOnly_packedGlyphIDToGlyph(StrikeCache* cache) const override;
1228 
1229 #if defined(SK_GANESH)
1230     size_t vertexStride(const SkMatrix& drawMatrix) const override;
1231 
1232     std::tuple<const GrClip*, GrOp::Owner>
1233     makeAtlasTextOp(const GrClip*,
1234                     const SkMatrixProvider& viewMatrix,
1235                     SkPoint,
1236                     const SkPaint&,
1237                     sk_sp<SkRefCnt>&& subRunStorage,
1238                     skgpu::v1::SurfaceDrawContext*) const override;
1239 
1240     std::tuple<bool, int>
1241     regenerateAtlas(int begin, int end, GrMeshDrawTarget*) const override;
1242 
1243     void fillVertexData(void* vertexDst, int offset, int count,
1244                         GrColor color,
1245                         const SkMatrix& drawMatrix, SkPoint drawOrigin,
1246                         SkIRect clip) const override;
1247 #endif  // defined(SK_GANESH)
1248 
1249 #if defined(SK_GRAPHITE)
1250     std::tuple<bool, int>
1251     regenerateAtlas(int begin, int end, Recorder*) const override;
1252 
1253     std::tuple<gr::Rect, Transform> boundsAndDeviceMatrix(const Transform&,
1254                                                           SkPoint drawOrigin) const override;
1255 
renderer(const RendererProvider * renderers) const1256     const Renderer* renderer(const RendererProvider* renderers) const override {
1257         return renderers->bitmapText();
1258     }
1259 
1260     void fillInstanceData(skgpu::graphite::DrawWriter*,
1261                           int offset, int count,
1262                           int ssboIndex,
1263                           SkScalar depth) const override;
1264 #endif
1265 
1266     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override;
1267 
1268     const AtlasSubRun* testingOnly_atlasSubRun() const override;
1269 
1270 protected:
subRunType() const1271     SubRunType subRunType() const override { return kDirectMask; }
1272     void doFlatten(SkWriteBuffer& buffer) const override;
1273 
1274 private:
1275     // Return true if the positionMatrix represents an integer translation. Return the device
1276     // bounding box of all the glyphs. If the bounding box is empty, then something went singular
1277     // and this operation should be dropped.
1278     std::tuple<bool, SkRect> deviceRectAndCheckTransform(const SkMatrix& positionMatrix) const;
1279 
1280     const MaskFormat fMaskFormat;
1281     const SkMatrix& fInitialPositionMatrix;
1282 
1283     // The vertex bounds in device space. The bounds are the joined rectangles of all the glyphs.
1284     const SkRect fGlyphDeviceBounds;
1285     const SkSpan<const SkPoint> fLeftTopDevicePos;
1286 
1287     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1288     // be single threaded.
1289     mutable GlyphVector fGlyphs;
1290 };
1291 
DirectMaskSubRun(MaskFormat format,const SkMatrix & initialPositionMatrix,SkRect deviceBounds,SkSpan<const SkPoint> devicePositions,GlyphVector && glyphs)1292 DirectMaskSubRun::DirectMaskSubRun(MaskFormat format,
1293                                    const SkMatrix& initialPositionMatrix,
1294                                    SkRect deviceBounds,
1295                                    SkSpan<const SkPoint> devicePositions,
1296                                    GlyphVector&& glyphs)
1297         : fMaskFormat{format}
1298         , fInitialPositionMatrix{initialPositionMatrix}
1299         , fGlyphDeviceBounds{deviceBounds}
1300         , fLeftTopDevicePos{devicePositions}
1301         , fGlyphs{std::move(glyphs)} {}
1302 
Make(SkRect runBounds,const SkZip<SkPackedGlyphID,SkPoint> & accepted,const SkMatrix & initialPositionMatrix,SkStrikePromise && strikePromise,MaskFormat format,SubRunAllocator * alloc)1303 SubRunOwner DirectMaskSubRun::Make(SkRect runBounds,
1304                                    const SkZip<SkPackedGlyphID, SkPoint>& accepted,
1305                                    const SkMatrix& initialPositionMatrix,
1306                                    SkStrikePromise&& strikePromise,
1307                                    MaskFormat format,
1308                                    SubRunAllocator* alloc) {
1309     auto glyphLeftTop = alloc->makePODArray<SkPoint>(accepted.size());
1310     auto glyphIDs = alloc->makePODArray<GlyphVector::Variant>(accepted.size());
1311 
1312     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted)) {
1313         glyphLeftTop[i] = pos;
1314         glyphIDs[i].packedGlyphID = packedID;
1315     }
1316 
1317     SkSpan<const SkPoint> leftTop{glyphLeftTop, accepted.size()};
1318     return alloc->makeUnique<DirectMaskSubRun>(
1319             format, initialPositionMatrix, runBounds, leftTop,
1320             GlyphVector{std::move(strikePromise), {glyphIDs, accepted.size()}});
1321 }
1322 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1323 bool DirectMaskSubRun::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
1324     auto [reuse, _] = can_use_direct(fInitialPositionMatrix, positionMatrix);
1325     return reuse;
1326 }
1327 
MakeFromBuffer(const SkMatrix & initialPositionMatrix,SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)1328 SubRunOwner DirectMaskSubRun::MakeFromBuffer(const SkMatrix& initialPositionMatrix,
1329                                              SkReadBuffer& buffer,
1330                                              SubRunAllocator* alloc,
1331                                              const SkStrikeClient* client) {
1332     MaskFormat maskType = (MaskFormat)buffer.readInt();
1333     SkRect runBounds = buffer.readRect();
1334 
1335     SkSpan<SkPoint> leftTop = make_points_from_buffer(buffer, alloc);
1336     if (leftTop.empty()) { return nullptr; }
1337     const int glyphCount = SkCount(leftTop);
1338 
1339     auto glyphVector = GlyphVector::MakeFromBuffer(buffer, client, alloc);
1340     if (!buffer.validate(glyphVector.has_value())) { return nullptr; }
1341     if (!buffer.validate(SkCount(glyphVector->glyphs()) == glyphCount)) { return nullptr; }
1342     SkASSERT(buffer.isValid());
1343     return alloc->makeUnique<DirectMaskSubRun>(
1344             maskType, initialPositionMatrix, runBounds, leftTop,
1345             std::move(glyphVector.value()));
1346 }
1347 
doFlatten(SkWriteBuffer & buffer) const1348 void DirectMaskSubRun::doFlatten(SkWriteBuffer& buffer) const {
1349     buffer.writeInt(static_cast<int>(fMaskFormat));
1350     buffer.writeRect(fGlyphDeviceBounds);
1351     buffer.writePointArray(fLeftTopDevicePos.data(), SkCount(fLeftTopDevicePos));
1352     fGlyphs.flatten(buffer);
1353 }
1354 
unflattenSize() const1355 int DirectMaskSubRun::unflattenSize() const {
1356     return sizeof(DirectMaskSubRun) +
1357            fGlyphs.unflattenSize() +
1358            sizeof(SkPoint) * fGlyphs.glyphs().size();
1359 }
1360 
testingOnly_atlasSubRun() const1361 const AtlasSubRun* DirectMaskSubRun::testingOnly_atlasSubRun() const {
1362     return this;
1363 }
1364 
glyphCount() const1365 int DirectMaskSubRun::glyphCount() const {
1366     return SkCount(fGlyphs.glyphs());
1367 }
1368 
1369 #if defined(SK_GANESH)
vertexStride(const SkMatrix & positionMatrix) const1370 size_t DirectMaskSubRun::vertexStride(const SkMatrix& positionMatrix) const {
1371     if (!positionMatrix.hasPerspective()) {
1372         if (fMaskFormat != MaskFormat::kARGB) {
1373             return sizeof(Mask2DVertex);
1374         } else {
1375             return sizeof(ARGB2DVertex);
1376         }
1377     } else {
1378         if (fMaskFormat != MaskFormat::kARGB) {
1379             return sizeof(Mask3DVertex);
1380         } else {
1381             return sizeof(ARGB3DVertex);
1382         }
1383     }
1384 }
1385 
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const1386 void DirectMaskSubRun::draw(SkCanvas*,
1387                             const GrClip* clip,
1388                             const SkMatrixProvider& viewMatrix,
1389                             SkPoint drawOrigin,
1390                             const SkPaint& paint,
1391                             sk_sp<SkRefCnt> subRunStorage,
1392                             skgpu::v1::SurfaceDrawContext* sdc) const {
1393     auto[drawingClip, op] = this->makeAtlasTextOp(
1394             clip, viewMatrix, drawOrigin, paint, std::move(subRunStorage), sdc);
1395     if (op != nullptr) {
1396         sdc->addDrawOp(drawingClip, std::move(op));
1397     }
1398 }
1399 
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> && subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const1400 std::tuple<const GrClip*, GrOp::Owner> DirectMaskSubRun::makeAtlasTextOp(
1401         const GrClip* clip,
1402         const SkMatrixProvider& viewMatrix,
1403         SkPoint drawOrigin,
1404         const SkPaint& paint,
1405         sk_sp<SkRefCnt>&& subRunStorage,
1406         skgpu::v1::SurfaceDrawContext* sdc) const {
1407     SkASSERT(this->glyphCount() != 0);
1408     const SkMatrix& drawMatrix = viewMatrix.localToDevice();
1409     const SkMatrix& positionMatrix = position_matrix(drawMatrix, drawOrigin);
1410 
1411     auto [integerTranslate, subRunDeviceBounds] = this->deviceRectAndCheckTransform(positionMatrix);
1412     if (subRunDeviceBounds.isEmpty()) {
1413         return {nullptr, nullptr};
1414     }
1415     // Rect for optimized bounds clipping when doing an integer translate.
1416     SkIRect geometricClipRect = SkIRect::MakeEmpty();
1417     if (integerTranslate) {
1418         // We can clip geometrically using clipRect and ignore clip when an axis-aligned rectangular
1419         // non-AA clip is used. If clipRect is empty, and clip is nullptr, then there is no clipping
1420         // needed.
1421         const SkRect deviceBounds = SkRect::MakeWH(sdc->width(), sdc->height());
1422         auto [clipMethod, clipRect] = calculate_clip(clip, deviceBounds, subRunDeviceBounds);
1423 
1424         switch (clipMethod) {
1425             case kClippedOut:
1426                 // Returning nullptr as op means skip this op.
1427                 return {nullptr, nullptr};
1428             case kUnclipped:
1429             case kGeometryClipped:
1430                 // GPU clip is not needed.
1431                 clip = nullptr;
1432                 break;
1433             case kGPUClipped:
1434                 // Use th GPU clip; clipRect is ignored.
1435                 break;
1436         }
1437         geometricClipRect = clipRect;
1438 
1439         if (!geometricClipRect.isEmpty()) { SkASSERT(clip == nullptr); }
1440     }
1441 
1442     GrPaint grPaint;
1443     const SkPMColor4f drawingColor = calculate_colors(sdc,
1444                                                       paint,
1445                                                       drawMatrix,
1446                                                       fMaskFormat,
1447                                                       &grPaint);
1448 
1449     auto geometry = AtlasTextOp::Geometry::Make(*this,
1450                                                 drawMatrix,
1451                                                 drawOrigin,
1452                                                 geometricClipRect,
1453                                                 std::move(subRunStorage),
1454                                                 drawingColor,
1455                                                 sdc->arenaAlloc());
1456 
1457     GrRecordingContext* const rContext = sdc->recordingContext();
1458     GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1459                                              op_mask_type(fMaskFormat),
1460                                              !integerTranslate,
1461                                              this->glyphCount(),
1462                                              subRunDeviceBounds,
1463                                              geometry,
1464                                              sdc->colorInfo(),
1465                                              std::move(grPaint));
1466     return {clip, std::move(op)};
1467 }
1468 #endif  // defined(SK_GANESH)
1469 
1470 #if defined(SK_GRAPHITE)
draw(SkCanvas *,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,Device * device) const1471 void DirectMaskSubRun::draw(SkCanvas*,
1472                             SkPoint drawOrigin,
1473                             const SkPaint& paint,
1474                             sk_sp<SkRefCnt> subRunStorage,
1475                             Device* device) const {
1476     this->AtlasSubRun::draw(device, drawOrigin, paint, std::move(subRunStorage));
1477 }
1478 #endif
1479 
testingOnly_packedGlyphIDToGlyph(StrikeCache * cache) const1480 void DirectMaskSubRun::testingOnly_packedGlyphIDToGlyph(StrikeCache *cache) const {
1481     fGlyphs.packedGlyphIDToGlyph(cache);
1482 }
1483 
1484 #if defined(SK_GANESH)
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const1485 std::tuple<bool, int> DirectMaskSubRun::regenerateAtlas(int begin, int end,
1486                                                         GrMeshDrawTarget* target) const {
1487     return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 0, target);
1488 }
1489 
1490 template<typename Quad, typename VertexData>
transformed_direct_2D(SkZip<Quad,const Glyph *,const VertexData> quadData,GrColor color,const SkMatrix & matrix)1491 void transformed_direct_2D(SkZip<Quad, const Glyph*, const VertexData> quadData,
1492                            GrColor color,
1493                            const SkMatrix& matrix) {
1494     for (auto[quad, glyph, leftTop] : quadData) {
1495         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
1496         SkScalar dl = leftTop.x(),
1497                  dt = leftTop.y(),
1498                  dr = dl + (ar - al),
1499                  db = dt + (ab - at);
1500         SkPoint lt = matrix.mapXY(dl, dt),
1501                 lb = matrix.mapXY(dl, db),
1502                 rt = matrix.mapXY(dr, dt),
1503                 rb = matrix.mapXY(dr, db);
1504         quad[0] = {lt, color, {al, at}};  // L,T
1505         quad[1] = {lb, color, {al, ab}};  // L,B
1506         quad[2] = {rt, color, {ar, at}};  // R,T
1507         quad[3] = {rb, color, {ar, ab}};  // R,B
1508     }
1509 }
1510 
1511 template<typename Quad, typename VertexData>
transformed_direct_3D(SkZip<Quad,const Glyph *,const VertexData> quadData,GrColor color,const SkMatrix & matrix)1512 void transformed_direct_3D(SkZip<Quad, const Glyph*, const VertexData> quadData,
1513                            GrColor color,
1514                            const SkMatrix& matrix) {
1515     auto mapXYZ = [&](SkScalar x, SkScalar y) {
1516         SkPoint pt{x, y};
1517         SkPoint3 result;
1518         matrix.mapHomogeneousPoints(&result, &pt, 1);
1519         return result;
1520     };
1521     for (auto[quad, glyph, leftTop] : quadData) {
1522         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
1523         SkScalar dl = leftTop.x(),
1524                  dt = leftTop.y(),
1525                  dr = dl + (ar - al),
1526                  db = dt + (ab - at);
1527         SkPoint3 lt = mapXYZ(dl, dt),
1528                  lb = mapXYZ(dl, db),
1529                  rt = mapXYZ(dr, dt),
1530                  rb = mapXYZ(dr, db);
1531         quad[0] = {lt, color, {al, at}};  // L,T
1532         quad[1] = {lb, color, {al, ab}};  // L,B
1533         quad[2] = {rt, color, {ar, at}};  // R,T
1534         quad[3] = {rb, color, {ar, ab}};  // R,B
1535     }
1536 }
1537 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1538 void DirectMaskSubRun::fillVertexData(void* vertexDst, int offset, int count,
1539                                       GrColor color,
1540                                       const SkMatrix& drawMatrix, SkPoint drawOrigin,
1541                                       SkIRect clip) const {
1542     auto quadData = [&](auto dst) {
1543         return SkMakeZip(dst,
1544                          fGlyphs.glyphs().subspan(offset, count),
1545                          fLeftTopDevicePos.subspan(offset, count));
1546     };
1547 
1548     const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1549     auto [noTransformNeeded, originOffset] =
1550             can_use_direct(fInitialPositionMatrix, positionMatrix);
1551 
1552     if (noTransformNeeded) {
1553         if (clip.isEmpty()) {
1554             if (fMaskFormat != MaskFormat::kARGB) {
1555                 using Quad = Mask2DVertex[4];
1556                 SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(SkMatrix::I()));
1557                 direct_2D(quadData((Quad*)vertexDst), color, originOffset);
1558             } else {
1559                 using Quad = ARGB2DVertex[4];
1560                 SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(SkMatrix::I()));
1561                 generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset);
1562             }
1563         } else {
1564             if (fMaskFormat != MaskFormat::kARGB) {
1565                 using Quad = Mask2DVertex[4];
1566                 SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(SkMatrix::I()));
1567                 generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset, &clip);
1568             } else {
1569                 using Quad = ARGB2DVertex[4];
1570                 SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(SkMatrix::I()));
1571                 generalized_direct_2D(quadData((Quad*)vertexDst), color, originOffset, &clip);
1572             }
1573         }
1574     } else if (SkMatrix inverse; fInitialPositionMatrix.invert(&inverse)) {
1575         SkMatrix viewDifference = SkMatrix::Concat(positionMatrix, inverse);
1576         if (!viewDifference.hasPerspective()) {
1577             if (fMaskFormat != MaskFormat::kARGB) {
1578                 using Quad = Mask2DVertex[4];
1579                 SkASSERT(sizeof(Mask2DVertex) == this->vertexStride(positionMatrix));
1580                 transformed_direct_2D(quadData((Quad*)vertexDst), color, viewDifference);
1581             } else {
1582                 using Quad = ARGB2DVertex[4];
1583                 SkASSERT(sizeof(ARGB2DVertex) == this->vertexStride(positionMatrix));
1584                 transformed_direct_2D(quadData((Quad*)vertexDst), color, viewDifference);
1585             }
1586         } else {
1587             if (fMaskFormat != MaskFormat::kARGB) {
1588                 using Quad = Mask3DVertex[4];
1589                 SkASSERT(sizeof(Mask3DVertex) == this->vertexStride(positionMatrix));
1590                 transformed_direct_3D(quadData((Quad*)vertexDst), color, viewDifference);
1591             } else {
1592                 using Quad = ARGB3DVertex[4];
1593                 SkASSERT(sizeof(ARGB3DVertex) == this->vertexStride(positionMatrix));
1594                 transformed_direct_3D(quadData((Quad*)vertexDst), color, viewDifference);
1595             }
1596         }
1597     }
1598 }
1599 #endif  // defined(SK_GANESH)
1600 
1601 #if defined(SK_GRAPHITE)
regenerateAtlas(int begin,int end,Recorder * recorder) const1602 std::tuple<bool, int> DirectMaskSubRun::regenerateAtlas(int begin, int end,
1603                                                         Recorder* recorder) const {
1604     return fGlyphs.regenerateAtlas(begin, end, fMaskFormat, 0, recorder);
1605 }
1606 
boundsAndDeviceMatrix(const Transform & localToDevice,SkPoint drawOrigin) const1607 std::tuple<gr::Rect, Transform> DirectMaskSubRun::boundsAndDeviceMatrix(
1608         const Transform& localToDevice, SkPoint drawOrigin) const {
1609     // The baked-in matrix differs from the current localToDevice by a translation if the upper 2x2
1610     // remains the same, and there's no perspective. Since there's no projection, Z is irrelevant
1611     // so it's okay that fInitialPositionMatrix is an SkMatrix and has discarded the 3rd row/col,
1612     // and can ignore those values in localToDevice.
1613     const SkM44& positionMatrix = localToDevice.matrix();
1614     const bool compatibleMatrix = positionMatrix.rc(0,0) == fInitialPositionMatrix.rc(0,0) &&
1615                                   positionMatrix.rc(0,1) == fInitialPositionMatrix.rc(0,1) &&
1616                                   positionMatrix.rc(1,0) == fInitialPositionMatrix.rc(1,0) &&
1617                                   positionMatrix.rc(1,1) == fInitialPositionMatrix.rc(1,1) &&
1618                                   localToDevice.type() != Transform::Type::kProjection &&
1619                                   !fInitialPositionMatrix.hasPerspective();
1620 
1621     if (compatibleMatrix) {
1622         const SkV4 mappedOrigin = positionMatrix.map(drawOrigin.x(), drawOrigin.y(), 0.f, 1.f);
1623         const SkV2 offset = {mappedOrigin.x - fInitialPositionMatrix.getTranslateX(),
1624                              mappedOrigin.y - fInitialPositionMatrix.getTranslateY()};
1625         if (SkScalarIsInt(offset.x) && SkScalarIsInt(offset.y)) {
1626             // The offset is an integer (but make sure), which means the generated mask can be
1627             // accessed without changing how texels would be sampled.
1628             return {gr::Rect(fGlyphDeviceBounds),
1629                     Transform(SkM44::Translate(SkScalarRoundToInt(offset.x),
1630                                                SkScalarRoundToInt(offset.y)))};
1631         }
1632     }
1633 
1634     // Otherwise compute the relative transformation from fInitialPositionMatrix to localToDevice,
1635     // with the drawOrigin applied. If fInitialPositionMatrix or the concatenation is not invertible
1636     // the returned Transform is marked invalid and the draw will be automatically dropped.
1637     return {gr::Rect(fGlyphDeviceBounds),
1638             localToDevice.preTranslate(drawOrigin.x(), drawOrigin.y())
1639                          .concatInverse(SkM44(fInitialPositionMatrix))};
1640 }
1641 
fillInstanceData(DrawWriter * dw,int offset,int count,int ssboIndex,SkScalar depth) const1642 void DirectMaskSubRun::fillInstanceData(DrawWriter* dw,
1643                                         int offset, int count,
1644                                         int ssboIndex,
1645                                         SkScalar depth) const {
1646     auto quadData = [&]() {
1647         return SkMakeZip(fGlyphs.glyphs().subspan(offset, count),
1648                          fLeftTopDevicePos.subspan(offset, count));
1649     };
1650 
1651     DrawWriter::Instances instances{*dw, {}, {}, 4};
1652     instances.reserve(count);
1653     unsigned short flags = (unsigned short)fMaskFormat;
1654     for (auto [glyph, leftTop]: quadData()) {
1655         auto[al, at, ar, ab] = glyph->fAtlasLocator.getUVs();
1656         instances.append(1) << AtlasPt{uint16_t(ar-al), uint16_t(ab-at)}
1657                             << AtlasPt{uint16_t(al & 0x1fff), at}
1658                             << leftTop << /*index=*/uint16_t(al >> 13) << flags
1659                             << 1.0f
1660                             << depth << ssboIndex;
1661     }
1662 }
1663 
1664 #endif
1665 
1666 // true if only need to translate by integer amount, device rect.
deviceRectAndCheckTransform(const SkMatrix & positionMatrix) const1667 std::tuple<bool, SkRect> DirectMaskSubRun::deviceRectAndCheckTransform(
1668         const SkMatrix& positionMatrix) const {
1669     const SkMatrix& initialMatrix = fInitialPositionMatrix;
1670     const SkPoint offset = positionMatrix.mapOrigin() - initialMatrix.mapOrigin();
1671 
1672     const bool compatibleMatrix = positionMatrix[0] == initialMatrix[0] &&
1673                                   positionMatrix[1] == initialMatrix[1] &&
1674                                   positionMatrix[3] == initialMatrix[3] &&
1675                                   positionMatrix[4] == initialMatrix[4] &&
1676                                   !positionMatrix.hasPerspective() &&
1677                                   !initialMatrix.hasPerspective();
1678 
1679     if (compatibleMatrix && SkScalarIsInt(offset.x()) && SkScalarIsInt(offset.y())) {
1680         return {true, fGlyphDeviceBounds.makeOffset(offset)};
1681     } else if (SkMatrix inverse; fInitialPositionMatrix.invert(&inverse)) {
1682         SkMatrix viewDifference = SkMatrix::Concat(positionMatrix, inverse);
1683         return {false, viewDifference.mapRect(fGlyphDeviceBounds)};
1684     }
1685 
1686     // initialPositionMatrix is singular. Do nothing.
1687     return {false, SkRect::MakeEmpty()};
1688 }
1689 
1690 // -- TransformedMaskSubRun ------------------------------------------------------------------------
1691 class TransformedMaskSubRun final : public SubRun, public AtlasSubRun {
1692 public:
TransformedMaskSubRun(const SkMatrix & initialPositionMatrix,TransformedMaskVertexFiller && vertexFiller,GlyphVector && glyphs)1693     TransformedMaskSubRun(const SkMatrix& initialPositionMatrix,
1694                           TransformedMaskVertexFiller&& vertexFiller,
1695                           GlyphVector&& glyphs)
1696             : fInitialPositionMatrix{initialPositionMatrix}
1697             , fVertexFiller{std::move(vertexFiller)}
1698             , fGlyphs{std::move(glyphs)} {}
1699 
Make(const SkZip<SkPackedGlyphID,SkPoint> & accepted,const SkMatrix & initialPositionMatrix,SkStrikePromise && strikePromise,SkMatrix creationMatrix,SkRect creationBounds,MaskFormat maskType,SubRunAllocator * alloc)1700     static SubRunOwner Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
1701                             const SkMatrix& initialPositionMatrix,
1702                             SkStrikePromise&& strikePromise,
1703                             SkMatrix creationMatrix,
1704                             SkRect creationBounds,
1705                             MaskFormat maskType,
1706                             SubRunAllocator* alloc) {
1707         auto vertexFiller = TransformedMaskVertexFiller::Make(
1708                 maskType, creationMatrix, creationBounds, accepted, alloc);
1709 
1710         auto glyphVector = GlyphVector::Make(std::move(strikePromise), accepted.get<0>(), alloc);
1711 
1712         return alloc->makeUnique<TransformedMaskSubRun>(
1713                 initialPositionMatrix, std::move(vertexFiller), std::move(glyphVector));
1714     }
1715 
MakeFromBuffer(const SkMatrix & initialPositionMatrix,SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)1716     static SubRunOwner MakeFromBuffer(const SkMatrix& initialPositionMatrix,
1717                                       SkReadBuffer& buffer,
1718                                       SubRunAllocator* alloc,
1719                                       const SkStrikeClient* client) {
1720         auto vertexFiller = TransformedMaskVertexFiller::MakeFromBuffer(buffer, alloc);
1721         if (!buffer.validate(vertexFiller.has_value())) { return nullptr; }
1722 
1723         auto glyphVector = GlyphVector::MakeFromBuffer(buffer, client, alloc);
1724         if (!buffer.validate(glyphVector.has_value())) { return nullptr; }
1725         if (!buffer.validate(SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
1726             return nullptr;
1727         }
1728         return alloc->makeUnique<TransformedMaskSubRun>(
1729                 initialPositionMatrix, std::move(*vertexFiller), std::move(*glyphVector));
1730     }
1731 
unflattenSize() const1732     int unflattenSize() const override {
1733         return sizeof(TransformedMaskSubRun) +
1734                fGlyphs.unflattenSize() +
1735                fVertexFiller.unflattenSize();
1736     }
1737 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1738     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
1739         // If we are not scaling the cache entry to be larger, than a cache with smaller glyphs may
1740         // be better.
1741         if (fInitialPositionMatrix.getMaxScale() < 1) {
1742             return false;
1743         }
1744         return true;
1745     }
1746 
testingOnly_atlasSubRun() const1747     const AtlasSubRun* testingOnly_atlasSubRun() const override { return this; }
1748 
testingOnly_packedGlyphIDToGlyph(StrikeCache * cache) const1749     void testingOnly_packedGlyphIDToGlyph(StrikeCache *cache) const override {
1750         fGlyphs.packedGlyphIDToGlyph(cache);
1751     }
1752 
glyphCount() const1753     int glyphCount() const override { return SkCount(fGlyphs.glyphs()); }
1754 
maskFormat() const1755     MaskFormat maskFormat() const override { return fVertexFiller.grMaskType(); }
1756 
1757 #if defined(SK_GANESH)
1758 
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const1759     void draw(SkCanvas*,
1760               const GrClip* clip,
1761               const SkMatrixProvider& viewMatrix,
1762               SkPoint drawOrigin,
1763               const SkPaint& paint,
1764               sk_sp<SkRefCnt> subRunStorage,
1765               skgpu::v1::SurfaceDrawContext* sdc) const override {
1766         auto[drawingClip, op] = this->makeAtlasTextOp(
1767                 clip, viewMatrix, drawOrigin, paint, std::move(subRunStorage), sdc);
1768         if (op != nullptr) {
1769             sdc->addDrawOp(drawingClip, std::move(op));
1770         }
1771     }
1772 
1773     std::tuple<const GrClip*, GrOp::Owner>
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> && subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const1774     makeAtlasTextOp(const GrClip* clip,
1775                     const SkMatrixProvider& viewMatrix,
1776                     SkPoint drawOrigin,
1777                     const SkPaint& paint,
1778                     sk_sp<SkRefCnt>&& subRunStorage,
1779                     skgpu::v1::SurfaceDrawContext* sdc) const override {
1780         SkASSERT(this->glyphCount() != 0);
1781 
1782         const SkMatrix& drawMatrix = viewMatrix.localToDevice();
1783 
1784         GrPaint grPaint;
1785         SkPMColor4f drawingColor = calculate_colors(sdc,
1786                                                     paint,
1787                                                     drawMatrix,
1788                                                     fVertexFiller.grMaskType(),
1789                                                     &grPaint);
1790 
1791         auto geometry = AtlasTextOp::Geometry::Make(*this,
1792                                                     drawMatrix,
1793                                                     drawOrigin,
1794                                                     SkIRect::MakeEmpty(),
1795                                                     std::move(subRunStorage),
1796                                                     drawingColor,
1797                                                     sdc->arenaAlloc());
1798 
1799         GrRecordingContext* const rContext = sdc->recordingContext();
1800         SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1801         GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1802                                                  fVertexFiller.opMaskType(),
1803                                                  true,
1804                                                  this->glyphCount(),
1805                                                  this->deviceRect(positionMatrix),
1806                                                  geometry,
1807                                                  sdc->colorInfo(),
1808                                                  std::move(grPaint));
1809         return {clip, std::move(op)};
1810     }
1811 
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const1812     std::tuple<bool, int> regenerateAtlas(int begin, int end,
1813                                           GrMeshDrawTarget* target) const override {
1814         return fGlyphs.regenerateAtlas(begin, end, fVertexFiller.grMaskType(), 1, target);
1815     }
1816 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1817     void fillVertexData(
1818             void* vertexDst, int offset, int count,
1819             GrColor color,
1820             const SkMatrix& drawMatrix, SkPoint drawOrigin,
1821             SkIRect clip) const override {
1822         const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1823         fVertexFiller.fillVertexData(offset, count,
1824                                      fGlyphs.glyphs(),
1825                                      color,
1826                                      positionMatrix,
1827                                      clip,
1828                                      vertexDst);
1829     }
1830 
vertexStride(const SkMatrix & drawMatrix) const1831     size_t vertexStride(const SkMatrix& drawMatrix) const override {
1832         return fVertexFiller.vertexStride(drawMatrix);
1833     }
1834 
1835 #endif  // defined(SK_GANESH)
1836 
1837 #if defined(SK_GRAPHITE)
1838 
draw(SkCanvas *,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,Device * device) const1839     void draw(SkCanvas*,
1840               SkPoint drawOrigin,
1841               const SkPaint& paint,
1842               sk_sp<SkRefCnt> subRunStorage,
1843               Device* device) const override {
1844         this->AtlasSubRun::draw(device, drawOrigin, paint, std::move(subRunStorage));
1845     }
1846 
regenerateAtlas(int begin,int end,Recorder * recorder) const1847     std::tuple<bool, int> regenerateAtlas(int begin, int end, Recorder* recorder) const override {
1848         return fGlyphs.regenerateAtlas(begin, end, fVertexFiller.grMaskType(), 1, recorder);
1849     }
1850 
boundsAndDeviceMatrix(const Transform & localToDevice,SkPoint drawOrigin) const1851     std::tuple<gr::Rect, Transform> boundsAndDeviceMatrix(const Transform& localToDevice,
1852                                                           SkPoint drawOrigin) const override {
1853         const SkMatrix viewDifference = fVertexFiller.viewDifference(
1854                 localToDevice.preTranslate(drawOrigin.x(), drawOrigin.y()));
1855         return {gr::Rect(fVertexFiller.creationBounds()), Transform(SkM44(viewDifference))};
1856     }
1857 
renderer(const RendererProvider * renderers) const1858     const Renderer* renderer(const RendererProvider* renderers) const override {
1859         return renderers->bitmapText();
1860     }
1861 
fillInstanceData(DrawWriter * dw,int offset,int count,int ssboIndex,SkScalar depth) const1862     void fillInstanceData(DrawWriter* dw,
1863                           int offset, int count,
1864                           int ssboIndex,
1865                           SkScalar depth) const override {
1866         unsigned short flags = (unsigned short)fVertexFiller.grMaskType();
1867         fVertexFiller.fillInstanceData(dw,
1868                                        offset, count,
1869                                        flags,
1870                                        ssboIndex,
1871                                        fGlyphs.glyphs(),
1872                                        depth);
1873     }
1874 
1875 #endif  // SK_GRAPHITE
1876 
1877 protected:
subRunType() const1878     SubRunType subRunType() const override { return kTransformMask; }
1879 
doFlatten(SkWriteBuffer & buffer) const1880     void doFlatten(SkWriteBuffer& buffer) const override {
1881         fVertexFiller.flatten(buffer);
1882         fGlyphs.flatten(buffer);
1883     }
1884 
1885 private:
1886     // The rectangle that surrounds all the glyph bounding boxes in device space.
deviceRect(const SkMatrix & positionMatrix) const1887     SkRect deviceRect(const SkMatrix& positionMatrix) const {
1888         return fVertexFiller.deviceRect(positionMatrix);
1889     }
1890 
1891     const SkMatrix& fInitialPositionMatrix;
1892 
1893     const TransformedMaskVertexFiller fVertexFiller;
1894 
1895     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1896     // be single threaded.
1897     mutable GlyphVector fGlyphs;
1898 };  // class TransformedMaskSubRun
1899 
1900 // -- SDFTSubRun -----------------------------------------------------------------------------------
1901 
has_some_antialiasing(const SkFont & font)1902 bool has_some_antialiasing(const SkFont& font ) {
1903     SkFont::Edging edging = font.getEdging();
1904     return edging == SkFont::Edging::kAntiAlias
1905            || edging == SkFont::Edging::kSubpixelAntiAlias;
1906 }
1907 
1908 #if !defined(SK_DISABLE_SDF_TEXT)
1909 
1910 #if defined(SK_GANESH)
1911 
calculate_sdf_parameters(const skgpu::v1::SurfaceDrawContext & sdc,const SkMatrix & drawMatrix,bool useLCDText,bool isAntiAliased)1912 static std::tuple<AtlasTextOp::MaskType, uint32_t, bool> calculate_sdf_parameters(
1913         const skgpu::v1::SurfaceDrawContext& sdc,
1914         const SkMatrix& drawMatrix,
1915         bool useLCDText,
1916         bool isAntiAliased) {
1917     const GrColorInfo& colorInfo = sdc.colorInfo();
1918     const SkSurfaceProps& props = sdc.surfaceProps();
1919     bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
1920     bool isLCD = useLCDText && SkPixelGeometryIsH(props.pixelGeometry());
1921     using MT = AtlasTextOp::MaskType;
1922     MT maskType = !isAntiAliased ? MT::kAliasedDistanceField
1923                   : isLCD ? (isBGR ? MT::kLCDBGRDistanceField
1924                                           : MT::kLCDDistanceField)
1925                                  : MT::kGrayscaleDistanceField;
1926 
1927     bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
1928     uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
1929     DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
1930     DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
1931     DFGPFlags |= MT::kAliasedDistanceField == maskType ? kAliased_DistanceFieldEffectFlag : 0;
1932     DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
1933 
1934     if (isLCD) {
1935         DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
1936         DFGPFlags |= MT::kLCDBGRDistanceField == maskType ? kBGR_DistanceFieldEffectFlag : 0;
1937     }
1938     return {maskType, DFGPFlags, useGammaCorrectDistanceTable};
1939 }
1940 
1941 #endif  // defined(SK_GANESH)
1942 
1943 class SDFTSubRun final : public SubRun, public AtlasSubRun {
1944 public:
SDFTSubRun(bool useLCDText,bool antiAliased,const SDFTMatrixRange & matrixRange,TransformedMaskVertexFiller && vertexFiller,GlyphVector && glyphs)1945     SDFTSubRun(bool useLCDText,
1946                bool antiAliased,
1947                const SDFTMatrixRange& matrixRange,
1948                TransformedMaskVertexFiller&& vertexFiller,
1949                GlyphVector&& glyphs)
1950         : fUseLCDText{useLCDText}
1951         , fAntiAliased{antiAliased}
1952         , fMatrixRange{matrixRange}
1953         , fVertexFiller{std::move(vertexFiller)}
1954         , fGlyphs{std::move(glyphs)} { }
1955 
Make(const SkZip<SkPackedGlyphID,SkPoint> & accepted,const SkFont & runFont,SkStrikePromise && strikePromise,const SkMatrix & creationMatrix,SkRect creationBounds,const SDFTMatrixRange & matrixRange,SubRunAllocator * alloc)1956     static SubRunOwner Make(const SkZip<SkPackedGlyphID, SkPoint>& accepted,
1957                             const SkFont& runFont,
1958                             SkStrikePromise&& strikePromise,
1959                             const SkMatrix& creationMatrix,
1960                             SkRect creationBounds,
1961                             const SDFTMatrixRange& matrixRange,
1962                             SubRunAllocator* alloc) {
1963         auto vertexFiller = TransformedMaskVertexFiller::Make(
1964                 MaskFormat::kA8,
1965                 creationMatrix,
1966                 creationBounds,
1967                 accepted,
1968                 alloc);
1969 
1970         auto glyphVector = GlyphVector::Make(std::move(strikePromise), accepted.get<0>(), alloc);
1971 
1972         return alloc->makeUnique<SDFTSubRun>(
1973                 runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
1974                 has_some_antialiasing(runFont),
1975                 matrixRange,
1976                 std::move(vertexFiller),
1977                 std::move(glyphVector));
1978     }
1979 
MakeFromBuffer(const SkMatrix &,SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)1980     static SubRunOwner MakeFromBuffer(const SkMatrix&,
1981                                       SkReadBuffer& buffer,
1982                                       SubRunAllocator* alloc,
1983                                       const SkStrikeClient* client) {
1984         int useLCD = buffer.readInt();
1985         int isAntiAliased = buffer.readInt();
1986         SDFTMatrixRange matrixRange = SDFTMatrixRange::MakeFromBuffer(buffer);
1987         auto vertexFiller = TransformedMaskVertexFiller::MakeFromBuffer(buffer, alloc);
1988         if (!buffer.validate(vertexFiller.has_value())) { return nullptr; }
1989         auto glyphVector = GlyphVector::MakeFromBuffer(buffer, client, alloc);
1990         if (!buffer.validate(glyphVector.has_value())) { return nullptr; }
1991         if (!buffer.validate(SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
1992             return nullptr;
1993         }
1994         return alloc->makeUnique<SDFTSubRun>(useLCD,
1995                                              isAntiAliased,
1996                                              matrixRange,
1997                                              std::move(*vertexFiller),
1998                                              std::move(*glyphVector));
1999     }
2000 
unflattenSize() const2001     int unflattenSize() const override {
2002         return sizeof(SDFTSubRun) + fGlyphs.unflattenSize() + fVertexFiller.unflattenSize();
2003     }
2004 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const2005     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
2006         return fMatrixRange.matrixInRange(positionMatrix);
2007     }
2008 
testingOnly_atlasSubRun() const2009     const AtlasSubRun* testingOnly_atlasSubRun() const override { return this; }
2010 
testingOnly_packedGlyphIDToGlyph(StrikeCache * cache) const2011     void testingOnly_packedGlyphIDToGlyph(StrikeCache *cache) const override {
2012         fGlyphs.packedGlyphIDToGlyph(cache);
2013     }
2014 
glyphCount() const2015     int glyphCount() const override { return fVertexFiller.count(); }
maskFormat() const2016     MaskFormat maskFormat() const override { return fVertexFiller.grMaskType(); }
2017 
2018 #if defined(SK_GANESH)
draw(SkCanvas *,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const2019     void draw(SkCanvas*,
2020               const GrClip* clip,
2021               const SkMatrixProvider& viewMatrix,
2022               SkPoint drawOrigin,
2023               const SkPaint& paint,
2024               sk_sp<SkRefCnt> subRunStorage,
2025               skgpu::v1::SurfaceDrawContext* sdc) const override {
2026         auto[drawingClip, op] = this->makeAtlasTextOp(
2027                 clip, viewMatrix, drawOrigin, paint, std::move(subRunStorage), sdc);
2028         if (op != nullptr) {
2029             sdc->addDrawOp(drawingClip, std::move(op));
2030         }
2031     }
2032 
makeAtlasTextOp(const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> && subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const2033     std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
2034             const GrClip* clip,
2035             const SkMatrixProvider& viewMatrix,
2036             SkPoint drawOrigin,
2037             const SkPaint& paint,
2038             sk_sp<SkRefCnt>&& subRunStorage,
2039             skgpu::v1::SurfaceDrawContext* sdc) const override {
2040         SkASSERT(this->glyphCount() != 0);
2041 
2042         const SkMatrix& drawMatrix = viewMatrix.localToDevice();
2043 
2044         GrPaint grPaint;
2045         SkPMColor4f drawingColor = calculate_colors(sdc,
2046                                                     paint,
2047                                                     drawMatrix,
2048                                                     MaskFormat::kA8,
2049                                                     &grPaint);
2050 
2051         auto [maskType, DFGPFlags, useGammaCorrectDistanceTable] =
2052                 calculate_sdf_parameters(*sdc, drawMatrix, fUseLCDText, fAntiAliased);
2053 
2054         auto geometry = AtlasTextOp::Geometry::Make(*this,
2055                                                     drawMatrix,
2056                                                     drawOrigin,
2057                                                     SkIRect::MakeEmpty(),
2058                                                     std::move(subRunStorage),
2059                                                     drawingColor,
2060                                                     sdc->arenaAlloc());
2061 
2062         GrRecordingContext* const rContext = sdc->recordingContext();
2063         SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
2064         GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
2065                                                  maskType,
2066                                                  true,
2067                                                  this->glyphCount(),
2068                                                  this->deviceRect(positionMatrix),
2069                                                  SkPaintPriv::ComputeLuminanceColor(paint),
2070                                                  useGammaCorrectDistanceTable,
2071                                                  DFGPFlags,
2072                                                  geometry,
2073                                                  std::move(grPaint));
2074 
2075         return {clip, std::move(op)};
2076     }
2077 
regenerateAtlas(int begin,int end,GrMeshDrawTarget * target) const2078     std::tuple<bool, int> regenerateAtlas(
2079             int begin, int end, GrMeshDrawTarget* target) const override {
2080         return fGlyphs.regenerateAtlas(begin, end, MaskFormat::kA8, SK_DistanceFieldInset, target);
2081     }
2082 
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const2083     void fillVertexData(
2084             void *vertexDst, int offset, int count,
2085             GrColor color,
2086             const SkMatrix& drawMatrix, SkPoint drawOrigin,
2087             SkIRect clip) const override {
2088         const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
2089 
2090         fVertexFiller.fillVertexData(offset, count,
2091                                      fGlyphs.glyphs(),
2092                                      color,
2093                                      positionMatrix,
2094                                      clip,
2095                                      vertexDst);
2096     }
2097 
vertexStride(const SkMatrix & drawMatrix) const2098     size_t vertexStride(const SkMatrix& drawMatrix) const override {
2099         if (drawMatrix.hasPerspective()) {
2100             return sizeof(Mask3DVertex);
2101         } else {
2102             return sizeof(Mask2DVertex);
2103         }
2104     }
2105 
2106 #endif  // defined(SK_GANESH)
2107 
2108 #if defined(SK_GRAPHITE)
2109 
draw(SkCanvas *,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,Device * device) const2110     void draw(SkCanvas*,
2111               SkPoint drawOrigin,
2112               const SkPaint& paint,
2113               sk_sp<SkRefCnt> subRunStorage,
2114               Device* device) const override {
2115         this->AtlasSubRun::draw(device, drawOrigin, paint, std::move(subRunStorage));
2116     }
2117 
regenerateAtlas(int begin,int end,Recorder * recorder) const2118     std::tuple<bool, int> regenerateAtlas(int begin, int end, Recorder *recorder) const override {
2119         return fGlyphs.regenerateAtlas(
2120                 begin, end, MaskFormat::kA8, SK_DistanceFieldInset, recorder);
2121     }
2122 
boundsAndDeviceMatrix(const Transform & localToDevice,SkPoint drawOrigin) const2123     std::tuple<gr::Rect, Transform> boundsAndDeviceMatrix(const Transform& localToDevice,
2124                                                           SkPoint drawOrigin) const override {
2125         const SkMatrix viewDifference = fVertexFiller.viewDifference(
2126                 localToDevice.preTranslate(drawOrigin.x(), drawOrigin.y()));
2127         return {gr::Rect(fVertexFiller.creationBounds()), Transform(SkM44(viewDifference))};
2128     }
2129 
renderer(const RendererProvider * renderers) const2130     const Renderer* renderer(const RendererProvider* renderers) const override {
2131         return renderers->sdfText(fUseLCDText);
2132     }
2133 
fillInstanceData(DrawWriter * dw,int offset,int count,int ssboIndex,SkScalar depth) const2134     void fillInstanceData(DrawWriter* dw,
2135                           int offset, int count,
2136                           int ssboIndex,
2137                           SkScalar depth) const override {
2138         fVertexFiller.fillInstanceData(dw,
2139                                        offset, count, /*flags=*/0,
2140                                        ssboIndex,
2141                                        fGlyphs.glyphs(),
2142                                        depth);
2143     }
2144 
2145 #endif  // SK_GRAPHITE
2146 
2147 protected:
subRunType() const2148     SubRunType subRunType() const override { return kSDFT; }
doFlatten(SkWriteBuffer & buffer) const2149     void doFlatten(SkWriteBuffer& buffer) const override {
2150         buffer.writeInt(fUseLCDText);
2151         buffer.writeInt(fAntiAliased);
2152         fMatrixRange.flatten(buffer);
2153         fVertexFiller.flatten(buffer);
2154         fGlyphs.flatten(buffer);
2155     }
2156 
2157 private:
2158     // The rectangle that surrounds all the glyph bounding boxes in device space.
deviceRect(const SkMatrix & positionMatrix) const2159     SkRect deviceRect(const SkMatrix& positionMatrix) const {
2160         return fVertexFiller.deviceRect(positionMatrix);
2161     }
2162 
2163     const bool fUseLCDText;
2164     const bool fAntiAliased;
2165     const SDFTMatrixRange fMatrixRange;
2166 
2167     const TransformedMaskVertexFiller fVertexFiller;
2168 
2169     // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
2170     // be single threaded.
2171     mutable GlyphVector fGlyphs;
2172 };  // class SDFTSubRun
2173 
2174 #endif // !defined(SK_DISABLE_SDF_TEXT)
2175 
2176 // -- SubRun ---------------------------------------------------------------------------------------
2177 
2178 template<typename AddSingleMaskFormat>
add_multi_mask_format(AddSingleMaskFormat addSingleMaskFormat,const SkZip<SkPackedGlyphID,SkPoint,SkMask::Format> & accepted)2179 void add_multi_mask_format(
2180         AddSingleMaskFormat addSingleMaskFormat,
2181         const SkZip<SkPackedGlyphID, SkPoint, SkMask::Format>& accepted) {
2182     if (accepted.empty()) { return; }
2183 
2184     auto maskSpan = accepted.get<2>();
2185     MaskFormat format = Glyph::FormatFromSkGlyph(maskSpan[0]);
2186     size_t startIndex = 0;
2187     for (size_t i = 1; i < accepted.size(); i++) {
2188         MaskFormat nextFormat = Glyph::FormatFromSkGlyph(maskSpan[i]);
2189         if (format != nextFormat) {
2190             auto interval = accepted.subspan(startIndex, i - startIndex);
2191             // Only pass the packed glyph ids and positions.
2192             auto glyphsWithSameFormat = SkMakeZip(interval.get<0>(), interval.get<1>());
2193             // Take a ref on the strike. This should rarely happen.
2194             addSingleMaskFormat(glyphsWithSameFormat, format);
2195             format = nextFormat;
2196             startIndex = i;
2197         }
2198     }
2199     auto interval = accepted.last(accepted.size() - startIndex);
2200     auto glyphsWithSameFormat = SkMakeZip(interval.get<0>(), interval.get<1>());
2201     addSingleMaskFormat(glyphsWithSameFormat, format);
2202 }
2203 }  // namespace
2204 
2205 namespace sktext::gpu {
2206 SubRun::~SubRun() = default;
flatten(SkWriteBuffer & buffer) const2207 void SubRun::flatten(SkWriteBuffer& buffer) const {
2208     buffer.writeInt(this->subRunType());
2209     this->doFlatten(buffer);
2210 }
2211 
MakeFromBuffer(const SkMatrix & initialPositionMatrix,SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)2212 SubRunOwner SubRun::MakeFromBuffer(const SkMatrix& initialPositionMatrix,
2213                                    SkReadBuffer& buffer,
2214                                    SubRunAllocator* alloc,
2215                                    const SkStrikeClient* client) {
2216     using Maker = SubRunOwner (*)(const SkMatrix&,
2217                                   SkReadBuffer&,
2218                                   SubRunAllocator*,
2219                                   const SkStrikeClient*);
2220 
2221     static Maker makers[kSubRunTypeCount] = {
2222             nullptr,                                             // 0 index is bad.
2223             DirectMaskSubRun::MakeFromBuffer,
2224 #if !defined(SK_DISABLE_SDF_TEXT)
2225             SDFTSubRun::MakeFromBuffer,
2226 #endif
2227             TransformedMaskSubRun::MakeFromBuffer,
2228             PathSubRun::MakeFromBuffer,
2229             DrawableSubRun::MakeFromBuffer,
2230     };
2231     int subRunTypeInt = buffer.readInt();
2232     SkASSERT(kBad < subRunTypeInt && subRunTypeInt < kSubRunTypeCount);
2233     if (!buffer.validate(kBad < subRunTypeInt && subRunTypeInt < kSubRunTypeCount)) {
2234         return nullptr;
2235     }
2236     auto maker = makers[subRunTypeInt];
2237     if (!buffer.validate(maker != nullptr)) { return nullptr; }
2238     return maker(initialPositionMatrix, buffer, alloc, client);
2239 }
2240 
2241 // -- SubRunContainer ------------------------------------------------------------------------------
SubRunContainer(const SkMatrix & initialPositionMatrix)2242 SubRunContainer::SubRunContainer(const SkMatrix& initialPositionMatrix)
2243         : fInitialPositionMatrix{initialPositionMatrix} {}
2244 
flattenAllocSizeHint(SkWriteBuffer & buffer) const2245 void SubRunContainer::flattenAllocSizeHint(SkWriteBuffer& buffer) const {
2246     int unflattenSizeHint = 0;
2247     for (auto& subrun : fSubRuns) {
2248         unflattenSizeHint += subrun.unflattenSize();
2249     }
2250     buffer.writeInt(unflattenSizeHint);
2251 }
2252 
AllocSizeHintFromBuffer(SkReadBuffer & buffer)2253 int SubRunContainer::AllocSizeHintFromBuffer(SkReadBuffer& buffer) {
2254     int subRunsSizeHint = buffer.readInt();
2255 
2256     // Since the hint doesn't affect correctness, if it looks fishy just pick a reasonable
2257     // value.
2258     if (subRunsSizeHint < 0 || (1 << 16) < subRunsSizeHint) {
2259         subRunsSizeHint = 128;
2260     }
2261     return subRunsSizeHint;
2262 }
2263 
flattenRuns(SkWriteBuffer & buffer) const2264 void SubRunContainer::flattenRuns(SkWriteBuffer& buffer) const {
2265     buffer.writeMatrix(fInitialPositionMatrix);
2266     int subRunCount = 0;
2267     for ([[maybe_unused]] auto& subRun : fSubRuns) {
2268         subRunCount += 1;
2269     }
2270     buffer.writeInt(subRunCount);
2271     for (auto& subRun : fSubRuns) {
2272         subRun.flatten(buffer);
2273     }
2274 }
2275 
MakeFromBufferInAlloc(SkReadBuffer & buffer,const SkStrikeClient * client,SubRunAllocator * alloc)2276 SubRunContainerOwner SubRunContainer::MakeFromBufferInAlloc(SkReadBuffer& buffer,
2277                                                             const SkStrikeClient* client,
2278                                                             SubRunAllocator* alloc) {
2279     SkMatrix positionMatrix;
2280     buffer.readMatrix(&positionMatrix);
2281     if (!buffer.isValid()) { return nullptr; }
2282     SubRunContainerOwner container = alloc->makeUnique<SubRunContainer>(positionMatrix);
2283 
2284     int subRunCount = buffer.readInt();
2285     SkASSERT(subRunCount > 0);
2286     if (!buffer.validate(subRunCount > 0)) { return nullptr; }
2287     for (int i = 0; i < subRunCount; ++i) {
2288         auto subRunOwner = SubRun::MakeFromBuffer(
2289                 container->initialPosition(), buffer, alloc, client);
2290         if (!buffer.validate(subRunOwner != nullptr)) { return nullptr; }
2291         if (subRunOwner != nullptr) {
2292             container->fSubRuns.append(std::move(subRunOwner));
2293         }
2294     }
2295     return container;
2296 }
2297 
EstimateAllocSize(const GlyphRunList & glyphRunList)2298 size_t SubRunContainer::EstimateAllocSize(const GlyphRunList& glyphRunList) {
2299     // The difference in alignment from the per-glyph data to the SubRun;
2300     constexpr size_t alignDiff = alignof(DirectMaskSubRun) - alignof(SkPoint);
2301     constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
2302     size_t totalGlyphCount = glyphRunList.totalGlyphCount();
2303     // This is optimized for DirectMaskSubRun which is by far the most common case.
2304     return totalGlyphCount * sizeof(SkPoint)
2305            + GlyphVector::GlyphVectorSize(totalGlyphCount)
2306            + glyphRunList.runCount() * (sizeof(DirectMaskSubRun) + vertexDataToSubRunPadding)
2307            + sizeof(SubRunContainer);
2308 }
2309 
find_maximum_glyph_dimension(StrikeForGPU * strike,SkSpan<const SkGlyphID> glyphs)2310 SkScalar find_maximum_glyph_dimension(StrikeForGPU* strike, SkSpan<const SkGlyphID> glyphs) {
2311     StrikeMutationMonitor m{strike};
2312     SkScalar maxDimension = 0;
2313     for (SkGlyphID glyphID : glyphs) {
2314         SkGlyphDigest digest = strike->digestFor(kMask, SkPackedGlyphID{glyphID});
2315         maxDimension = std::max(static_cast<SkScalar>(digest.maxDimension()), maxDimension);
2316     }
2317 
2318     return maxDimension;
2319 }
2320 
2321 #if !defined(SK_DISABLE_SDF_TEXT)
prepare_for_SDFT_drawing(StrikeForGPU * strike,const SkMatrix & creationMatrix,SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)2322 SkRect prepare_for_SDFT_drawing(StrikeForGPU* strike,
2323                                 const SkMatrix& creationMatrix,
2324                                 SkDrawableGlyphBuffer* accepted,
2325                                 SkSourceGlyphBuffer* rejected) {
2326     SkGlyphRect boundingRect = skglyph::empty_rect();
2327     StrikeMutationMonitor m{strike};
2328     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted->input())) {
2329         if (!SkScalarsAreFinite(pos.x(), pos.y())) {
2330             continue;
2331         }
2332 
2333         SkGlyphDigest digest = strike->digestFor(kSDFT, packedID);
2334         switch (digest.actionFor(kSDFT)) {
2335             case GlyphAction::kAccept: {
2336                 SkPoint mappedPos = creationMatrix.mapPoint(pos);
2337                 const SkGlyphRect glyphBounds =
2338                     digest.bounds()
2339                         // The SDFT glyphs have 2-pixel wide padding that should
2340                         // not be used in calculating the source rectangle.
2341                         .inset(SK_DistanceFieldInset, SK_DistanceFieldInset)
2342                         .offset(mappedPos);
2343                 boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
2344                 accepted->accept(packedID, glyphBounds.leftTop(), digest.maskFormat());
2345                 break;
2346             }
2347             case GlyphAction::kReject:
2348                 rejected->reject(i);
2349             break;
2350             default:
2351                 break;
2352         }
2353     }
2354 
2355     return boundingRect.rect();
2356 }
2357 #endif
2358 
prepare_for_direct_mask_drawing(StrikeForGPU * strike,const SkMatrix & positionMatrix,SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)2359 SkRect prepare_for_direct_mask_drawing(StrikeForGPU* strike,
2360                                        const SkMatrix& positionMatrix,
2361                                        SkDrawableGlyphBuffer* accepted,
2362                                        SkSourceGlyphBuffer* rejected) {
2363     const SkIPoint mask = strike->roundingSpec().ignorePositionFieldMask;
2364     const SkPoint halfSampleFreq = strike->roundingSpec().halfAxisSampleFreq;
2365 
2366     // Build up the mapping from source space to device space. Add the rounding constant
2367     // halfSampleFreq, so we just need to floor to get the device result.
2368     SkMatrix positionMatrixWithRounding = positionMatrix;
2369     positionMatrixWithRounding.postTranslate(halfSampleFreq.x(), halfSampleFreq.y());
2370 
2371     SkGlyphRect boundingRect = skglyph::empty_rect();
2372     StrikeMutationMonitor m{strike};
2373     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted->input())) {
2374         if (!SkScalarsAreFinite(pos.x(), pos.y())) {
2375             continue;
2376         }
2377 
2378         const SkPoint mappedPos = positionMatrixWithRounding.mapPoint(pos);
2379         const SkGlyphID glyphID = packedID.glyphID();
2380         const SkPackedGlyphID packedGlyphID = SkPackedGlyphID{glyphID, mappedPos, mask};
2381         auto digest = strike->digestFor(kDirectMask, packedGlyphID);
2382         switch (digest.actionFor(kDirectMask)) {
2383             case GlyphAction::kAccept: {
2384                 const SkPoint roundedPos{SkScalarFloorToScalar(mappedPos.x()),
2385                                          SkScalarFloorToScalar(mappedPos.y())};
2386                 const SkGlyphRect glyphBounds = digest.bounds().offset(roundedPos);
2387                 boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
2388                 accepted->accept(packedGlyphID, glyphBounds.leftTop(), digest.maskFormat());
2389                 break;
2390             }
2391             case GlyphAction::kReject:
2392                 rejected->reject(i);
2393                 break;
2394             default:
2395                 break;
2396         }
2397     }
2398 
2399     return boundingRect.rect();
2400 }
2401 
prepare_for_mask_drawing(StrikeForGPU * strike,const SkMatrix & creationMatrix,SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)2402 SkRect prepare_for_mask_drawing(StrikeForGPU* strike,
2403                                 const SkMatrix& creationMatrix,
2404                                 SkDrawableGlyphBuffer* accepted,
2405                                 SkSourceGlyphBuffer* rejected) {
2406     SkGlyphRect boundingRect = skglyph::empty_rect();
2407     StrikeMutationMonitor m{strike};
2408     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted->input())) {
2409         if (!SkScalarsAreFinite(pos.x(), pos.y())) {
2410             continue;
2411         }
2412 
2413         const SkGlyphDigest digest = strike->digestFor(kMask, packedID);
2414         switch (digest.actionFor(kMask)) {
2415             case GlyphAction::kAccept: {
2416                 const SkPoint mappedPos = creationMatrix.mapPoint(pos);
2417                 const SkGlyphRect glyphBounds = digest.bounds().offset(mappedPos);
2418                 boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
2419                 accepted->accept(packedID, glyphBounds.leftTop(), digest.maskFormat());
2420                 break;
2421             }
2422             case GlyphAction::kReject:
2423                 rejected->reject(i);
2424                 break;
2425             default:
2426                 break;
2427         }
2428     }
2429 
2430     return boundingRect.rect();
2431 }
2432 
prepare_for_path_drawing(StrikeForGPU * strike,SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)2433 void prepare_for_path_drawing(StrikeForGPU* strike,
2434                               SkDrawableGlyphBuffer* accepted,
2435                               SkSourceGlyphBuffer* rejected) {
2436     StrikeMutationMonitor m{strike};
2437     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted->input())) {
2438         if (SkScalarsAreFinite(pos.x(), pos.y())) {
2439             switch (strike->digestFor(kPath, packedID).actionFor(kPath)) {
2440                 case GlyphAction::kAccept:
2441                     accepted->accept(packedID, pos);
2442                     break;
2443                 case GlyphAction::kReject:
2444                     rejected->reject(i);
2445                     break;
2446                 default:
2447                     break;
2448             }
2449         }
2450     }
2451 }
2452 
prepare_for_drawable_drawing(StrikeForGPU * strike,SkDrawableGlyphBuffer * accepted,SkSourceGlyphBuffer * rejected)2453 void prepare_for_drawable_drawing(StrikeForGPU* strike,
2454                                   SkDrawableGlyphBuffer* accepted,
2455                                   SkSourceGlyphBuffer* rejected) {
2456     StrikeMutationMonitor m{strike};
2457     for (auto [i, packedID, pos] : SkMakeEnumerate(accepted->input())) {
2458         if (SkScalarsAreFinite(pos.x(), pos.y())) {
2459             switch (strike->digestFor(kDrawable, packedID).actionFor(kDrawable)) {
2460                 case GlyphAction::kAccept:
2461                     accepted->accept(packedID, pos);
2462                     break;
2463                 case GlyphAction::kReject:
2464                     rejected->reject(i);
2465                     break;
2466                 default:
2467                     break;
2468             }
2469         }
2470     }
2471 }
2472 
MakeInAlloc(const GlyphRunList & glyphRunList,const SkMatrix & positionMatrix,const SkPaint & runPaint,SkStrikeDeviceInfo strikeDeviceInfo,StrikeForGPUCacheInterface * strikeCache,SubRunAllocator * alloc,SubRunCreationBehavior creationBehavior,const char * tag)2473 SubRunContainerOwner SubRunContainer::MakeInAlloc(
2474         const GlyphRunList& glyphRunList,
2475         const SkMatrix& positionMatrix,
2476         const SkPaint& runPaint,
2477         SkStrikeDeviceInfo strikeDeviceInfo,
2478         StrikeForGPUCacheInterface* strikeCache,
2479         SubRunAllocator* alloc,
2480         SubRunCreationBehavior creationBehavior,
2481         const char* tag) {
2482     SkASSERT(alloc != nullptr);
2483     SkASSERT(strikeDeviceInfo.fSDFTControl != nullptr);
2484 
2485     SubRunContainerOwner container = alloc->makeUnique<SubRunContainer>(positionMatrix);
2486     // If there is no SDFT description ignore all SubRuns.
2487     if (strikeDeviceInfo.fSDFTControl == nullptr) {
2488         return container;
2489     }
2490 
2491     const SkSurfaceProps deviceProps = strikeDeviceInfo.fSurfaceProps;
2492     const SkScalerContextFlags scalerContextFlags = strikeDeviceInfo.fScalerContextFlags;
2493 #if !defined(SK_DISABLE_SDF_TEXT)
2494     const SDFTControl SDFTControl = *strikeDeviceInfo.fSDFTControl;
2495     const SkScalar maxMaskSize = SDFTControl.maxSize();
2496 #else
2497     const SkScalar maxMaskSize = 256;
2498 #endif
2499 
2500     auto bufferScope = SkSubRunBuffers::EnsureBuffers(glyphRunList);
2501     auto [accepted, rejected] = bufferScope.buffers();
2502     SkPoint glyphRunListLocation = glyphRunList.sourceBounds().center();
2503 
2504     // Handle all the runs in the glyphRunList
2505     for (auto& glyphRun : glyphRunList) {
2506         rejected->setSource(glyphRun.source());
2507         const SkFont& runFont = glyphRun.font();
2508 
2509         SkScalar approximateDeviceTextSize =
2510                 // Since the positionMatrix has the origin prepended, use the plain
2511                 // sourceBounds from above.
2512                 SkFontPriv::ApproximateTransformedTextSize(runFont, positionMatrix,
2513                                                            glyphRunListLocation);
2514 
2515 
2516         // Atlas mask cases - SDFT and direct mask
2517         // Only consider using direct or SDFT drawing if not drawing hairlines and not too big.
2518         if ((runPaint.getStyle() != SkPaint::kStroke_Style || runPaint.getStrokeWidth() != 0) &&
2519                 approximateDeviceTextSize < maxMaskSize) {
2520 
2521 #if !defined(SK_DISABLE_SDF_TEXT)
2522             // SDFT case
2523             if (SDFTControl.isSDFT(approximateDeviceTextSize, runPaint, positionMatrix)) {
2524                 // Process SDFT - This should be the .009% case.
2525                 const auto& [strikeSpec, strikeToSourceScale, matrixRange] =
2526                         SkStrikeSpec::MakeSDFT(
2527                                 runFont, runPaint, deviceProps, positionMatrix,
2528                                 glyphRunListLocation, SDFTControl);
2529 
2530                 if (!SkScalarNearlyZero(strikeToSourceScale)) {
2531                     sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
2532 
2533                     // The creationMatrix needs to scale the strike data when inverted and
2534                     // multiplied by the positionMatrix. The final CTM should be:
2535                     //   [positionMatrix][scale by strikeToSourceScale],
2536                     // which should equal the following because of the transform during the vertex
2537                     // calculation,
2538                     //   [positionMatrix][creationMatrix]^-1.
2539                     // So, the creation matrix needs to be
2540                     //   [scale by 1/strikeToSourceScale].
2541                     SkMatrix creationMatrix =
2542                             SkMatrix::Scale(1.f/strikeToSourceScale, 1.f/strikeToSourceScale);
2543 
2544                     accepted->startSource(rejected->source());
2545 
2546                     SkRect creationBounds =
2547                         prepare_for_SDFT_drawing(strike.get(), creationMatrix, accepted, rejected);
2548                     rejected->flipRejectsToSource();
2549 
2550                     if (creationBehavior == kAddSubRuns && !accepted->empty()) {
2551                         container->fSubRuns.append(SDFTSubRun::Make(
2552                                 accepted->accepted(),
2553                                 runFont,
2554                                 strike->strikePromise(),
2555                                 creationMatrix,
2556                                 creationBounds,
2557                                 matrixRange,
2558                                 alloc));
2559                     }
2560                 }
2561             }
2562 #endif // !defined(SK_DISABLE_SDF_TEXT)
2563 
2564             // Direct Mask case
2565             // Handle all the directly mapped mask subruns.
2566             if (!rejected->source().empty() && !positionMatrix.hasPerspective()) {
2567                 // Process masks including ARGB - this should be the 99.99% case.
2568                 // This will handle medium size emoji that are sharing the run with SDFT drawn text.
2569                 // If things are too big they will be passed along to the drawing of last resort
2570                 // below.
2571                 SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(
2572                         runFont, runPaint, deviceProps, scalerContextFlags, positionMatrix);
2573 
2574                 sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
2575 
2576                 accepted->startSource(rejected->source());
2577                 SkRect bounds =
2578                     prepare_for_direct_mask_drawing(
2579                         strike.get(), positionMatrix, accepted, rejected);
2580                 rejected->flipRejectsToSource();
2581 
2582                 if (creationBehavior == kAddSubRuns && !accepted->empty()) {
2583                     auto addGlyphsWithSameFormat =
2584                             [&](const SkZip<SkPackedGlyphID, SkPoint>& acceptedGlyphsAndLocations,
2585                                 MaskFormat format) {
2586                                 container->fSubRuns.append(
2587                                         DirectMaskSubRun::Make(bounds,
2588                                                                acceptedGlyphsAndLocations,
2589                                                                container->initialPosition(),
2590                                                                strike->strikePromise(),
2591                                                                format,
2592                                                                alloc));
2593                             };
2594                     add_multi_mask_format(addGlyphsWithSameFormat,
2595                                           accepted->acceptedWithMaskFormat());
2596                 }
2597             }
2598         }
2599 
2600         // Drawable case
2601         // Handle all the drawable glyphs - usually large or perspective color glyphs.
2602         if (!rejected->source().empty()) {
2603             auto [strikeSpec, strikeToSourceScale] =
2604                     SkStrikeSpec::MakePath(runFont, runPaint, deviceProps, scalerContextFlags);
2605 
2606             if (!SkScalarNearlyZero(strikeToSourceScale)) {
2607                 sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
2608 
2609                 accepted->startSource(rejected->source());
2610                 prepare_for_drawable_drawing(strike.get(), accepted, rejected);
2611                 rejected->flipRejectsToSource();
2612 
2613                 if (creationBehavior == kAddSubRuns && !accepted->empty()) {
2614                     container->fSubRuns.append(make_drawable_sub_run<DrawableSubRun>(
2615                             accepted->accepted(),
2616                             strikeToSourceScale,
2617                             strike->strikePromise(),
2618                             alloc));
2619                 }
2620             }
2621         }
2622 
2623         // Path case
2624         // Handle path subruns. Mainly, large or large perspective glyphs with no color.
2625         if (!rejected->source().empty()) {
2626             auto [strikeSpec, strikeToSourceScale] =
2627                     SkStrikeSpec::MakePath(runFont, runPaint, deviceProps, scalerContextFlags);
2628 
2629             if (!SkScalarNearlyZero(strikeToSourceScale)) {
2630                 sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
2631 
2632                 accepted->startSource(rejected->source());
2633 
2634                 prepare_for_path_drawing(strike.get(), accepted, rejected);
2635                 rejected->flipRejectsToSource();
2636 
2637                 if (creationBehavior == kAddSubRuns && !accepted->empty()) {
2638                     container->fSubRuns.append(
2639                             PathSubRun::Make(accepted->accepted(),
2640                                              has_some_antialiasing(runFont),
2641                                              strikeToSourceScale,
2642                                              strike->strikePromise(),
2643                                              alloc));
2644                 }
2645             }
2646         }
2647 
2648         // Drawing of last resort case
2649         // Draw all the rest of the rejected glyphs from above. This scales out of the atlas to
2650         // the screen, so quality will suffer. This mainly handles large color or perspective
2651         // color not handled by Drawables.
2652         if (!rejected->source().empty() && !SkScalarNearlyZero(approximateDeviceTextSize)) {
2653             // Creation matrix will be changed below to meet the following criteria:
2654             // * No perspective - the font scaler and the strikes can't handle perspective masks.
2655             // * Fits atlas - creationMatrix will be conditioned so that the maximum glyph
2656             //   dimension for this run will be <  kMaxBilerpAtlasDimension.
2657             SkMatrix creationMatrix = positionMatrix;
2658 
2659             // Condition creationMatrix for perspective.
2660             if (creationMatrix.hasPerspective()) {
2661                 // Find a scale factor that reduces pixelation caused by keystoning.
2662                 SkPoint center = glyphRunList.sourceBounds().center();
2663                 SkScalar maxAreaScale = SkMatrixPriv::DifferentialAreaScale(creationMatrix, center);
2664                 SkScalar perspectiveFactor = 1;
2665                 if (SkScalarIsFinite(maxAreaScale) && !SkScalarNearlyZero(maxAreaScale)) {
2666                     perspectiveFactor = SkScalarSqrt(maxAreaScale);
2667                 }
2668 
2669                 // Masks can not be created in perspective. Create a non-perspective font with a
2670                 // scale that will support the perspective keystoning.
2671                 creationMatrix = SkMatrix::Scale(perspectiveFactor, perspectiveFactor);
2672             }
2673 
2674             // Reduce to make a one pixel border for the bilerp padding.
2675             static const constexpr SkScalar kMaxBilerpAtlasDimension =
2676                     SkGlyphDigest::kSkSideTooBigForAtlas - 2;
2677 
2678             // Get the raw glyph IDs to simulate device drawing to figure the maximum device
2679             // dimension.
2680             const SkSpan<const SkGlyphID> glyphs = rejected->source().get<0>();
2681 
2682             // maxGlyphDimension always returns an integer even though the return type is SkScalar.
2683             auto maxGlyphDimension = [&](const SkMatrix& m) {
2684                 const SkStrikeSpec strikeSpec = SkStrikeSpec::MakeTransformMask(
2685                         runFont, runPaint, deviceProps, scalerContextFlags, m);
2686                 const sk_sp<StrikeForGPU> gaugingStrike =
2687                         strikeSpec.findOrCreateScopedStrike(strikeCache);
2688                 const SkScalar maxDimension =
2689                         find_maximum_glyph_dimension(gaugingStrike.get(), glyphs);
2690                 if (maxDimension == 0) {
2691                     // Text Scalers don't create glyphs with a dimension larger than 65535. For very
2692                     // large sizes, this will cause all the dimensions to go to zero. Use 65535 as
2693                     // the dimension.
2694                     // TODO: There is a problem where a small character (say .) and a large
2695                     //  character (say M) are in the same run. If the run is scaled to be very
2696                     //  large, then the M may return 0 because its dimensions are > 65535, but
2697                     //  the small character produces regular result because its largest dimension
2698                     //  is < 65535. This will create an improper scale factor causing the M to be
2699                     //  too large to fit in the atlas. Tracked by skia:13714.
2700                     return 65535.0f;
2701                 }
2702                 return maxDimension;
2703             };
2704 
2705             // Condition the creationMatrix so that glyphs fit in the atlas.
2706             for (SkScalar maxDimension = maxGlyphDimension(creationMatrix);
2707                  maxDimension <= 0 || kMaxBilerpAtlasDimension < maxDimension;
2708                  maxDimension = maxGlyphDimension(creationMatrix))
2709             {
2710                 // The SkScalerContext has a limit of 65536 maximum dimension.
2711                 // reductionFactor will always be < 1 because
2712                 // maxDimension > kMaxBilerpAtlasDimension, and because maxDimension will always
2713                 // be an integer the reduction factor will always be at most 254 / 255.
2714                 SkScalar reductionFactor = kMaxBilerpAtlasDimension / maxDimension;
2715                 creationMatrix.postScale(reductionFactor, reductionFactor);
2716             }
2717 
2718             // Draw using the creationMatrix.
2719             SkStrikeSpec strikeSpec = SkStrikeSpec::MakeTransformMask(
2720                     runFont, runPaint, deviceProps, scalerContextFlags, creationMatrix);
2721             sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
2722 
2723             accepted->startSource(rejected->source());
2724             SkRect creationBounds =
2725                 prepare_for_mask_drawing(strike.get(), creationMatrix, accepted, rejected);
2726             rejected->flipRejectsToSource();
2727             SkASSERT(rejected->source().empty());
2728 
2729             if (creationBehavior == kAddSubRuns && !accepted->empty()) {
2730                 auto addGlyphsWithSameFormat =
2731                         [&](const SkZip<SkPackedGlyphID, SkPoint>& acceptedGlyphsAndLocations,
2732                             MaskFormat format) {
2733                             container->fSubRuns.append(
2734                                     TransformedMaskSubRun::Make(acceptedGlyphsAndLocations,
2735                                                                 container->initialPosition(),
2736                                                                 strike->strikePromise(),
2737                                                                 creationMatrix,
2738                                                                 creationBounds,
2739                                                                 format,
2740                                                                 alloc));
2741                         };
2742                 add_multi_mask_format(addGlyphsWithSameFormat,
2743                                       accepted->acceptedWithMaskFormat());
2744             }
2745         }
2746     }
2747 
2748     return container;
2749 }
2750 
2751 #if defined(SK_GANESH)
draw(SkCanvas * canvas,const GrClip * clip,const SkMatrixProvider & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,const SkRefCnt * subRunStorage,skgpu::v1::SurfaceDrawContext * sdc) const2752 void SubRunContainer::draw(SkCanvas* canvas,
2753                            const GrClip* clip,
2754                            const SkMatrixProvider& viewMatrix,
2755                            SkPoint drawOrigin,
2756                            const SkPaint& paint,
2757                            const SkRefCnt* subRunStorage,
2758                            skgpu::v1::SurfaceDrawContext* sdc) const {
2759     for (auto& subRun : fSubRuns) {
2760         subRun.draw(canvas, clip, viewMatrix, drawOrigin, paint, sk_ref_sp(subRunStorage), sdc);
2761     }
2762 }
2763 #endif  // defined(SK_GANESH)
2764 
2765 #if defined(SK_GRAPHITE)
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,const SkRefCnt * subRunStorage,skgpu::graphite::Device * device) const2766 void SubRunContainer::draw(SkCanvas* canvas,
2767                            SkPoint drawOrigin,
2768                            const SkPaint& paint,
2769                            const SkRefCnt* subRunStorage,
2770                            skgpu::graphite::Device* device) const {
2771     for (auto& subRun : fSubRuns) {
2772         subRun.draw(canvas, drawOrigin, paint, sk_ref_sp(subRunStorage), device);
2773     }
2774 }
2775 #endif
2776 
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const2777 bool SubRunContainer::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
2778     for (const SubRun& subRun : fSubRuns) {
2779         if (!subRun.canReuse(paint, positionMatrix)) {
2780             return false;
2781         }
2782     }
2783     return true;
2784 }
2785 }  // namespace sktext::gpu
2786