1 /*
2  * Copyright 2019 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 SkGlyphBuffer_DEFINED
9 #define SkGlyphBuffer_DEFINED
10 
11 #include "src/core/SkGlyph.h"
12 #include "src/core/SkZip.h"
13 
14 class SkStrikeForGPU;
15 struct SkGlyphPositionRoundingSpec;
16 
17 // A memory format that allows an SkPackedGlyphID, SkGlyph*, and SkPath* to occupy the same
18 // memory. This allows SkPackedGlyphIDs as input, and SkGlyph*/SkPath* as output using the same
19 // memory.
20 class SkGlyphVariant {
21 public:
SkGlyphVariant()22     SkGlyphVariant() : fV{nullptr} { }
23     SkGlyphVariant& operator= (SkPackedGlyphID packedID) {
24         fV.packedID = packedID;
25         SkDEBUGCODE(fTag = kPackedID);
26         return *this;
27     }
28     SkGlyphVariant& operator= (SkGlyph* glyph) {
29         fV.glyph = glyph;
30         SkDEBUGCODE(fTag = kGlyph);
31         return *this;
32 
33     }
34     SkGlyphVariant& operator= (const SkPath* path) {
35         fV.path = path;
36         SkDEBUGCODE(fTag = kPath);
37         return *this;
38     }
39 
glyph()40     SkGlyph* glyph() const {
41         SkASSERT(fTag == kGlyph);
42         return fV.glyph;
43     }
path()44     const SkPath* path() const {
45         SkASSERT(fTag == kPath);
46         return fV.path;
47     }
packedID()48     SkPackedGlyphID packedID() const {
49         SkASSERT(fTag == kPackedID);
50         return fV.packedID;
51     }
52 
SkPackedGlyphID()53     operator SkPackedGlyphID() const { return this->packedID(); }
54     operator SkGlyph*()        const { return this->glyph();    }
55     operator const SkPath*()   const { return this->path();     }
56 
57 private:
58     union {
59         SkGlyph* glyph;
60         const SkPath* path;
61         SkPackedGlyphID packedID;
62     } fV;
63 
64 #ifdef SK_DEBUG
65     enum {
66         kEmpty,
67         kPackedID,
68         kGlyph,
69         kPath
70     } fTag{kEmpty};
71 #endif
72 };
73 
74 // A buffer for converting SkPackedGlyph to SkGlyph* or SkPath*. Initially the buffer contains
75 // SkPackedGlyphIDs, but those are used to lookup SkGlyph*/SkPath* which are then copied over the
76 // SkPackedGlyphIDs.
77 class SkDrawableGlyphBuffer {
78 public:
79     void ensureSize(size_t size);
80 
81     // Load the buffer with SkPackedGlyphIDs and positions in source space.
82     void startSource(const SkZip<const SkGlyphID, const SkPoint>& source, SkPoint origin);
83 
84     // Load the buffer with SkPackedGlyphIDs and positions using the device transform.
85     void startDevice(
86             const SkZip<const SkGlyphID, const SkPoint>& source,
87             SkPoint origin, const SkMatrix& viewMatrix,
88             const SkGlyphPositionRoundingSpec& roundingSpec);
89 
90     // The input of SkPackedGlyphIDs
input()91     SkZip<SkGlyphVariant, SkPoint> input() {
92         SkASSERT(fPhase == kInput);
93         SkDEBUGCODE(fPhase = kProcess);
94         return SkZip<SkGlyphVariant, SkPoint>{fInputSize, fMultiBuffer, fPositions};
95     }
96 
97     // Store the glyph in the next drawable slot, using the position information located at index
98     // from.
push_back(SkGlyph * glyph,size_t from)99     void push_back(SkGlyph* glyph, size_t from) {
100         SkASSERT(fPhase == kProcess);
101         SkASSERT(fDrawableSize <= from);
102         fPositions[fDrawableSize] = fPositions[from];
103         fMultiBuffer[fDrawableSize] = glyph;
104         fDrawableSize++;
105     }
106 
107     // Store the path in the next drawable slot, using the position information located at index
108     // from.
push_back(const SkPath * path,size_t from)109     void push_back(const SkPath* path, size_t from) {
110         SkASSERT(fPhase == kProcess);
111         SkASSERT(fDrawableSize <= from);
112         fPositions[fDrawableSize] = fPositions[from];
113         fMultiBuffer[fDrawableSize] = path;
114         fDrawableSize++;
115     }
116 
117     // The result after a series of push_backs of drawable SkGlyph* or SkPath*.
drawable()118     SkZip<SkGlyphVariant, SkPoint> drawable() {
119         SkASSERT(fPhase == kProcess);
120         SkDEBUGCODE(fPhase = kDraw);
121         return SkZip<SkGlyphVariant, SkPoint>{fDrawableSize, fMultiBuffer, fPositions};
122     }
123 
124     void reset();
125 
126 private:
127     size_t fMaxSize{0};
128     size_t fInputSize{0};
129     size_t fDrawableSize{0};
130     SkAutoTMalloc<SkGlyphVariant> fMultiBuffer;
131     SkAutoTMalloc<SkPoint> fPositions;
132 
133 #ifdef SK_DEBUG
134     enum {
135         kReset,
136         kInput,
137         kProcess,
138         kDraw
139     } fPhase{kReset};
140 #endif
141 };
142 #endif  // SkGlyphBuffer_DEFINED
143