1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrTextBlob_DEFINED
9#define GrTextBlob_DEFINED
10
11#include <limits>
12
13#include "include/core/SkPoint3.h"
14#include "include/core/SkRefCnt.h"
15#include "src/core/SkGlyphRunPainter.h"
16#include "src/core/SkIPoint16.h"
17#include "src/core/SkMaskFilterBase.h"
18#include "src/core/SkOpts.h"
19#include "src/core/SkRectPriv.h"
20#include "src/core/SkStrikeSpec.h"
21#include "src/core/SkTLazy.h"
22#include "src/gpu/GrColor.h"
23#include "src/gpu/GrDrawOpAtlas.h"
24#include "src/gpu/ops/GrMeshDrawOp.h"
25#include "src/gpu/text/GrStrikeCache.h"
26
27class GrAtlasManager;
28class GrAtlasTextOp;
29class GrDeferredUploadTarget;
30class GrDrawOp;
31class GrGlyph;
32class GrStrikeCache;
33class GrSubRun;
34
35class SkMatrixProvider;
36class SkSurfaceProps;
37class SkTextBlob;
38class SkTextBlobRunIterator;
39
40
41// A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
42// on the GPU. These are initially created with valid positions and colors, but invalid
43// texture coordinates.
44//
45// A GrTextBlob contains a number of SubRuns that are created in the blob's arena. Each SubRun
46// tracks its own GrGlyph* and vertex data. The memory is organized in the arena in the following
47// way so that the pointers for the GrGlyph* and vertex data are known before creating the SubRun.
48//
49// GrGlyph*... | vertexData... | SubRun | GrGlyph*... | vertexData... | SubRun etc.
50//
51// In these classes, I'm trying to follow the convention about matrices and origins.
52// * draw Matrix|Origin - describes the current draw command.
53// * initial Matrix|Origin - describes the matrix and origin the GrTextBlob was created with.
54// * current Matrix|Origin - describes the matrix and origin that are currently in the SubRun's
55// vertex data.
56//
57//
58class GrTextBlob final : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface {
59public:
60 struct Key {
61 Key();
62 uint32_t fUniqueID;
63 // Color may affect the gamma of the mask we generate, but in a fairly limited way.
64 // Each color is assigned to on of a fixed number of buckets based on its
65 // luminance. For each luminance bucket there is a "canonical color" that
66 // represents the bucket. This functionality is currently only supported for A8
67 SkColor fCanonicalColor;
68 SkPaint::Style fStyle;
69 SkPixelGeometry fPixelGeometry;
70 bool fHasBlur;
71 uint32_t fScalerContextFlags;
72
73 bool operator==(const Key& other) const;
74 };
75
76 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob);
77
78 // Change memory management to handle the data after GrTextBlob, but in the same allocation
79 // of memory. Only allow placement new.
80 void operator delete(void* p);
81 void* operator new(size_t);
82 void* operator new(size_t, void* p);
83
84 ~GrTextBlob() override;
85
86 // Make an empty GrTextBlob, with all the invariants set to make the right decisions when
87 // adding SubRuns.
88 static sk_sp<GrTextBlob> Make(const SkGlyphRunList& glyphRunList,
89 const SkMatrix& drawMatrix);
90
91 // Key manipulation functions
92 void setupKey(const GrTextBlob::Key& key,
93 const SkMaskFilterBase::BlurRec& blurRec,
94 const SkPaint& paint);
95 static const Key& GetKey(const GrTextBlob& blob);
96 static uint32_t Hash(const Key& key);
97
98 bool hasDistanceField() const;
99 bool hasBitmap() const;
100 bool hasPerspective() const;
101
102 void setHasDistanceField();
103 void setHasBitmap();
104 void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax);
105
106 bool canReuse(const SkPaint& paint, const SkMaskFilterBase::BlurRec& blurRec,
107 const SkMatrix& drawMatrix, SkPoint drawOrigin);
108
109 const Key& key() const;
110 size_t size() const;
111
112 template<typename AddSingleMaskFormat>
113 void addMultiMaskFormat(
114 AddSingleMaskFormat addSingle,
115 const SkZip<SkGlyphVariant, SkPoint>& drawables,
116 const SkStrikeSpec& strikeSpec,
117 SkPoint residual);
118
119 const SkTInternalLList<GrSubRun>& subRunList() const { return fSubRunList; }
120
121private:
122 enum TextType {
123 kHasDistanceField_TextType = 0x1,
124 kHasBitmap_TextType = 0x2,
125 };
126
127 struct StrokeInfo {
128 SkScalar fFrameWidth;
129 SkScalar fMiterLimit;
130 SkPaint::Join fJoin;
131 };
132
133 GrTextBlob(size_t allocSize,
134 const SkMatrix& drawMatrix,
135 SkPoint origin,
136 SkColor initialLuminance);
137
138 void insertSubRun(GrSubRun* subRun);
139
140 // Methods to satisfy SkGlyphRunPainterInterface
141 void processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
142 const SkStrikeSpec& strikeSpec,
143 SkPoint residual) override;
144 void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables,
145 const SkFont& runFont,
146 const SkStrikeSpec& strikeSpec) override;
147 void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables,
148 const SkStrikeSpec& strikeSpec,
149 const SkFont& runFont,
150 SkScalar minScale,
151 SkScalar maxScale) override;
152 void processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables,
153 const SkStrikeSpec& strikeSpec) override;
154
155 // Overall size of this struct plus vertices and glyphs at the end.
156 const size_t fSize;
157
158 // The initial view matrix. This is used for moving additional draws of this
159 // same text blob. We record the initial view matrix and initial offsets(x,y), because we
160 // record vertex bounds relative to these numbers. When blobs are reused with new matrices,
161 // we need to return to source space so we can update the vertex bounds appropriately.
162 const SkMatrix fInitialMatrix;
163
164 // Initial position of this blob. Used for calculating position differences when reusing this
165 // blob.
166 const SkPoint fInitialOrigin;
167
168 const SkColor fInitialLuminance;
169
170 SkMaskFilterBase::BlurRec fBlurRec;
171 StrokeInfo fStrokeInfo;
172 Key fKey;
173
174 // We can reuse distance field text, but only if the new view matrix would not result in
175 // a mip change. Because there can be multiple runs in a blob, we track the overall
176 // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
177 SkScalar fMaxMinScale{-SK_ScalarMax};
178 SkScalar fMinMaxScale{SK_ScalarMax};
179
180 uint8_t fTextType{0};
181
182 SkTInternalLList<GrSubRun> fSubRunList;
183 SkArenaAlloc fAlloc;
184};
185
186// -- GrSubRun -------------------------------------------------------------------------------------
187class GrSubRun {
188public:
189 virtual ~GrSubRun() = default;
190 virtual void draw(const GrClip* clip,
191 const SkMatrixProvider& viewMatrix,
192 const SkGlyphRunList& glyphRunList,
193 GrRenderTargetContext* rtc) const = 0;
194
195private:
196 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrSubRun);
197};
198
199// -- GrPathSubRun ---------------------------------------------------------------------------------
200class GrPathSubRun final : public GrSubRun {
201 struct PathGlyph;
202
203public:
204 GrPathSubRun(bool isAntiAliased, const SkStrikeSpec& strikeSpec, SkSpan<PathGlyph> paths);
205
206 void draw(const GrClip* clip,
207 const SkMatrixProvider& viewMatrix,
208 const SkGlyphRunList& glyphRunList,
209 GrRenderTargetContext* rtc) const override;
210
211 static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
212 bool isAntiAliased,
213 const SkStrikeSpec& strikeSpec,
214 SkArenaAlloc* alloc);
215
216private:
217 struct PathGlyph {
218 PathGlyph(const SkPath& path, SkPoint origin);
219 SkPath fPath;
220 SkPoint fOrigin;
221 };
222
223 const bool fIsAntiAliased;
224 const SkStrikeSpec fStrikeSpec;
225 const SkSpan<const PathGlyph> fPaths;
226};
227
228// -- GrAtlasSubRun --------------------------------------------------------------------------------
229class GrAtlasSubRun : public GrSubRun {
230public:
231 static constexpr int kVerticesPerGlyph = 4;
232 virtual size_t vertexStride() const = 0;
233 virtual int glyphCount() const = 0;
234
235 virtual std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
236 makeAtlasTextOp(const GrClip* clip,
237 const SkMatrixProvider& viewMatrix,
238 const SkGlyphRunList& glyphRunList,
239 GrRenderTargetContext* rtc) const = 0;
240 virtual void fillVertexData(
241 void* vertexDst, int offset, int count,
242 GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin,
243 SkIRect clip) const = 0;
244
245 virtual void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache* cache) = 0;
246
247 // This call is not thread safe. It should only be called from GrDrawOp::onPrepare which
248 // is single threaded.
249 virtual std::tuple<bool, int> regenerateAtlas(
250 int begin, int end, GrMeshDrawOp::Target* target) const = 0;
251
252protected:
253 struct AtlasPt {
254 uint16_t u;
255 uint16_t v;
256 };
257
258 // Normal text mask, SDFT, or color.
259 struct Mask2DVertex {
260 SkPoint devicePos;
261 GrColor color;
262 AtlasPt atlasPos;
263 };
264 struct ARGB2DVertex {
265 ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
266 SkPoint devicePos;
267 AtlasPt atlasPos;
268 };
269
270 // Perspective SDFT or SDFT forced to 3D or perspective color.
271 struct Mask3DVertex {
272 SkPoint3 devicePos;
273 GrColor color;
274 AtlasPt atlasPos;
275 };
276 struct ARGB3DVertex {
277 ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {}
278 SkPoint3 devicePos;
279 AtlasPt atlasPos;
280 };
281};
282
283// -- GrGlyphVector --------------------------------------------------------------------------------
284class GrGlyphVector {
285 union Variant {
286 // Initially, filled with packed id, but changed to GrGlyph* in the onPrepare stage.
287 SkPackedGlyphID packedGlyphID;
288 GrGlyph* grGlyph;
289 };
290
291public:
292 static GrGlyphVector Make(
293 const SkStrikeSpec& spec, SkSpan<SkGlyphVariant> glyphs, SkArenaAlloc* alloc);
294 SkSpan<const GrGlyph*> glyphs() const;
295
296 SkScalar strikeToSourceRatio() const { return fStrikeSpec.strikeToSourceRatio(); }
297
298 void packedGlyphIDToGrGlyph(GrStrikeCache* cache);
299
300 std::tuple<bool, int> regenerateAtlas(
301 int begin, int end,
302 GrMaskFormat maskFormat,
303 int srcPadding,
304 GrMeshDrawOp::Target *target,
305 bool bilerpPadding = false);
306
307 static size_t GlyphVectorSize(size_t count) {
308 return sizeof(Variant) * count;
309 }
310
311private:
312 GrGlyphVector(const SkStrikeSpec& spec, SkSpan<Variant> glyphs);
313
314 const SkStrikeSpec fStrikeSpec;
315 SkSpan<Variant> fGlyphs;
316 sk_sp<GrTextStrike> fStrike{nullptr};
317 uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration};
318 GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken;
319};
320
321// -- GrDirectMaskSubRun ---------------------------------------------------------------------------
322class GrDirectMaskSubRun final : public GrAtlasSubRun {
323public:
324 using VertexData = SkIPoint;
325
326 GrDirectMaskSubRun(GrMaskFormat format,
327 SkPoint residual,
328 GrTextBlob* blob,
329 const SkRect& bounds,
330 SkSpan<const VertexData> vertexData,
331 GrGlyphVector glyphs);
332
333 static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
334 const SkStrikeSpec& strikeSpec,
335 GrMaskFormat format,
336 SkPoint residual,
337 GrTextBlob* blob,
338 SkArenaAlloc* alloc);
339
340 void draw(const GrClip* clip,
341 const SkMatrixProvider& viewMatrix,
342 const SkGlyphRunList& glyphRunList,
343 GrRenderTargetContext* rtc) const override;
344
345 size_t vertexStride() const override;
346
347 int glyphCount() const override;
348
349 std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
350 makeAtlasTextOp(const GrClip* clip,
351 const SkMatrixProvider& viewMatrix,
352 const SkGlyphRunList& glyphRunList,
353 GrRenderTargetContext* rtc) const override;
354
355 void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override;
356
357 std::tuple<bool, int>
358 regenerateAtlas(int begin, int end, GrMeshDrawOp::Target* target) const override;
359
360 void fillVertexData(void* vertexDst, int offset, int count, GrColor color,
361 const SkMatrix& drawMatrix, SkPoint drawOrigin,
362 SkIRect clip) const override;
363private:
364
365 // The rectangle that surrounds all the glyph bounding boxes in device space.
366 SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
367
368 const GrMaskFormat fMaskFormat;
369 const SkPoint fResidual;
370 GrTextBlob* const fBlob;
371 // The vertex bounds in device space. The bounds are the joined rectangles of all the glyphs.
372 const SkRect fVertexBounds;
373 const SkSpan<const VertexData> fVertexData;
374
375 // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
376 // be single threaded.
377 mutable GrGlyphVector fGlyphs;
378};
379
380// -- GrTransformedMaskSubRun ----------------------------------------------------------------------
381class GrTransformedMaskSubRun final : public GrAtlasSubRun {
382public:
383 struct VertexData {
384 const SkPoint pos;
385 // The rectangle of the glyphs in strike space. But, for kDirectMask this also implies a
386 // device space rect.
387 GrIRect16 rect;
388 };
389
390 // SubRun for masks
391 GrTransformedMaskSubRun(GrMaskFormat format,
392 GrTextBlob* blob,
393 const SkRect& bounds,
394 SkSpan<const VertexData> vertexData,
395 GrGlyphVector glyphs);
396
397 static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
398 const SkStrikeSpec& strikeSpec,
399 GrMaskFormat format,
400 SkPoint residual,
401 GrTextBlob* blob,
402 SkArenaAlloc* alloc);
403
404 void draw(const GrClip* clip,
405 const SkMatrixProvider& viewMatrix,
406 const SkGlyphRunList& glyphRunList,
407 GrRenderTargetContext* rtc) const override;
408
409 std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
410 makeAtlasTextOp(const GrClip* clip,
411 const SkMatrixProvider& viewMatrix,
412 const SkGlyphRunList& glyphRunList,
413 GrRenderTargetContext* rtc) const override;
414
415 void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override;
416
417 std::tuple<bool, int> regenerateAtlas(
418 int begin, int end, GrMeshDrawOp::Target* target) const override;
419
420 void fillVertexData(
421 void* vertexDst, int offset, int count,
422 GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin,
423 SkIRect clip) const override;
424
425 size_t vertexStride() const override;
426 int glyphCount() const override;
427
428private:
429 bool hasW() const;
430 // The rectangle that surrounds all the glyph bounding boxes in device space.
431 SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
432
433 const GrMaskFormat fMaskFormat;
434 GrTextBlob* fBlob;
435
436 // The bounds in source space. The bounds are the joined rectangles of all the glyphs.
437 const SkRect fVertexBounds;
438 const SkSpan<const VertexData> fVertexData;
439
440 // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
441 // be single threaded.
442 mutable GrGlyphVector fGlyphs;
443};
444
445// -- GrSDFTSubRun ---------------------------------------------------------------------------------
446// Hold data to draw Scaled Distance Field Text sub runs.
447class GrSDFTSubRun final : public GrAtlasSubRun {
448public:
449 struct VertexData {
450 const SkPoint pos;
451 // The rectangle of the glyphs in strike space.
452 GrIRect16 rect;
453 };
454
455 GrSDFTSubRun(GrMaskFormat format,
456 GrTextBlob* blob,
457 SkRect vertexBounds,
458 SkSpan<const VertexData> vertexData,
459 GrGlyphVector glyphs,
460 bool useLCDText,
461 bool antiAliased);
462
463 static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables,
464 const SkFont& runFont,
465 const SkStrikeSpec& strikeSpec,
466 GrTextBlob* blob,
467 SkArenaAlloc* alloc);
468
469 void draw(const GrClip* clip,
470 const SkMatrixProvider& viewMatrix,
471 const SkGlyphRunList& glyphRunList,
472 GrRenderTargetContext* rtc) const override;
473
474 std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>>
475 makeAtlasTextOp(const GrClip* clip,
476 const SkMatrixProvider& viewMatrix,
477 const SkGlyphRunList& glyphRunList,
478 GrRenderTargetContext* rtc) const override;
479
480 void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override;
481
482 std::tuple<bool, int> regenerateAtlas(
483 int begin, int end, GrMeshDrawOp::Target* target) const override;
484
485 void fillVertexData(
486 void* vertexDst, int offset, int count,
487 GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin,
488 SkIRect clip) const override;
489
490 size_t vertexStride() const override;
491 int glyphCount() const override;
492
493private:
494 bool hasW() const;
495
496 // The rectangle that surrounds all the glyph bounding boxes in device space.
497 SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const;
498
499 const GrMaskFormat fMaskFormat;
500 GrTextBlob* fBlob;
501
502 // The bounds in source space. The bounds are the joined rectangles of all the glyphs.
503 const SkRect fVertexBounds;
504 const SkSpan<const VertexData> fVertexData;
505
506 // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
507 // be single threaded.
508 mutable GrGlyphVector fGlyphs;
509
510 const bool fUseLCDText;
511 const bool fAntiAliased;
512};
513
514#endif // GrTextBlob_DEFINED
515