• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SkEnumerate.h"
12 #include "src/core/SkGlyph.h"
13 #include "src/core/SkZip.h"
14 
15 class SkStrikeForGPU;
16 struct SkGlyphPositionRoundingSpec;
17 
18 // SkSourceGlyphBuffer is the source of glyphs between the different stages of character drawing.
19 // It starts with the glyphs and positions from the SkGlyphRun as the first source. When glyphs
20 // are reject by a stage they become the source for the next stage.
21 class SkSourceGlyphBuffer {
22 public:
23     SkSourceGlyphBuffer() = default;
24 
setSource(SkZip<const SkGlyphID,const SkPoint> source)25     void setSource(SkZip<const SkGlyphID, const SkPoint> source) {
26         this->~SkSourceGlyphBuffer();
27         new (this) SkSourceGlyphBuffer{source};
28     }
29 
30     void reset();
31 
reject(size_t index)32     void reject(size_t index) {
33         SkASSERT(index < fSource.size());
34         if (!this->sourceIsRejectBuffers()) {
35             // Need to expand the buffers for first use. All other reject sets will be fewer than
36             // this one.
37             auto [glyphID, pos] = fSource[index];
38             fRejectedGlyphIDs.push_back(glyphID);
39             fRejectedPositions.push_back(pos);
40             fRejectSize++;
41         } else {
42             SkASSERT(fRejectSize < fRejects.size());
43             fRejects[fRejectSize++] = fSource[index];
44         }
45     }
46 
reject(size_t index,int rejectedMaxDimension)47     void reject(size_t index, int rejectedMaxDimension) {
48         fRejectedMaxDimension = std::max(fRejectedMaxDimension, rejectedMaxDimension);
49         this->reject(index);
50     }
51 
flipRejectsToSource()52     SkZip<const SkGlyphID, const SkPoint> flipRejectsToSource() {
53         fRejects = SkMakeZip(fRejectedGlyphIDs, fRejectedPositions).first(fRejectSize);
54         fSource = fRejects;
55         fRejectSize = 0;
56         fSourceMaxDimension = fRejectedMaxDimension;
57         fRejectedMaxDimension = 0;
58         return fSource;
59     }
60 
source()61     SkZip<const SkGlyphID, const SkPoint> source() const { return fSource; }
62 
rejectedMaxDimension()63     int rejectedMaxDimension() const { return fSourceMaxDimension; }
64 
65 private:
SkSourceGlyphBuffer(const SkZip<const SkGlyphID,const SkPoint> & source)66     SkSourceGlyphBuffer(const SkZip<const SkGlyphID, const SkPoint>& source) {
67         fSource = source;
68     }
sourceIsRejectBuffers()69     bool sourceIsRejectBuffers() const {
70         return fSource.get<0>().data() == fRejectedGlyphIDs.data();
71     }
72 
73     SkZip<const SkGlyphID, const SkPoint> fSource;
74     size_t fRejectSize{0};
75     int fSourceMaxDimension{0};
76     int fRejectedMaxDimension{0};
77     SkZip<SkGlyphID, SkPoint> fRejects;
78     SkSTArray<4, SkGlyphID> fRejectedGlyphIDs;
79     SkSTArray<4, SkPoint> fRejectedPositions;
80 };
81 
82 // A memory format that allows an SkPackedGlyphID, SkGlyph*, and SkPath* to occupy the same
83 // memory. This allows SkPackedGlyphIDs as input, and SkGlyph*/SkPath* as output using the same
84 // memory.
85 class SkGlyphVariant {
86 public:
SkGlyphVariant()87     SkGlyphVariant() : fV{nullptr} { }
88     SkGlyphVariant& operator= (SkPackedGlyphID packedID) {
89         fV.packedID = packedID;
90         SkDEBUGCODE(fTag = kPackedID);
91         return *this;
92     }
93     SkGlyphVariant& operator= (SkGlyph* glyph) {
94         fV.glyph = glyph;
95         SkDEBUGCODE(fTag = kGlyph);
96         return *this;
97 
98     }
99     SkGlyphVariant& operator= (const SkPath* path) {
100         fV.path = path;
101         SkDEBUGCODE(fTag = kPath);
102         return *this;
103     }
104 
glyph()105     SkGlyph* glyph() const {
106         SkASSERT(fTag == kGlyph);
107         return fV.glyph;
108     }
path()109     const SkPath* path() const {
110         SkASSERT(fTag == kPath);
111         return fV.path;
112     }
packedID()113     SkPackedGlyphID packedID() const {
114         SkASSERT(fTag == kPackedID);
115         return fV.packedID;
116     }
117 
SkPackedGlyphID()118     operator SkPackedGlyphID() const { return this->packedID(); }
119     operator SkGlyph*()        const { return this->glyph();    }
120     operator const SkPath*()   const { return this->path();     }
121 
122 private:
123     union {
124         SkGlyph* glyph;
125         const SkPath* path;
126         SkPackedGlyphID packedID;
127     } fV;
128 
129 #ifdef SK_DEBUG
130     enum {
131         kEmpty,
132         kPackedID,
133         kGlyph,
134         kPath
135     } fTag{kEmpty};
136 #endif
137 };
138 
139 // A buffer for converting SkPackedGlyph to SkGlyph* or SkPath*. Initially the buffer contains
140 // SkPackedGlyphIDs, but those are used to lookup SkGlyph*/SkPath* which are then copied over the
141 // SkPackedGlyphIDs.
142 class SkDrawableGlyphBuffer {
143 public:
144     void ensureSize(size_t size);
145 
146     // Load the buffer with SkPackedGlyphIDs and positions in source space.
147     void startSource(const SkZip<const SkGlyphID, const SkPoint>& source, SkPoint origin);
148 
149     // Use the original glyphIDs and positions.
150     void startPaths(const SkZip<const SkGlyphID, const SkPoint>& source);
151 
152     // Load the buffer with SkPackedGlyphIDs and positions using the device transform.
153     void startDevice(
154             const SkZip<const SkGlyphID, const SkPoint>& source,
155             SkPoint origin, const SkMatrix& viewMatrix,
156             const SkGlyphPositionRoundingSpec& roundingSpec);
157 
158     // The input of SkPackedGlyphIDs
input()159     SkZip<SkGlyphVariant, SkPoint> input() {
160         SkASSERT(fPhase == kInput);
161         SkDEBUGCODE(fPhase = kProcess);
162         return SkZip<SkGlyphVariant, SkPoint>{fInputSize, fMultiBuffer, fPositions};
163     }
164 
165     // Store the glyph in the next drawable slot, using the position information located at index
166     // from.
push_back(SkGlyph * glyph,size_t from)167     void push_back(SkGlyph* glyph, size_t from) {
168         SkASSERT(fPhase == kProcess);
169         SkASSERT(fDrawableSize <= from);
170         fPositions[fDrawableSize] = fPositions[from];
171         fMultiBuffer[fDrawableSize] = glyph;
172         fDrawableSize++;
173     }
174 
175     // Store the path in the next drawable slot, using the position information located at index
176     // from.
push_back(const SkPath * path,size_t from)177     void push_back(const SkPath* path, size_t from) {
178         SkASSERT(fPhase == kProcess);
179         SkASSERT(fDrawableSize <= from);
180         fPositions[fDrawableSize] = fPositions[from];
181         fMultiBuffer[fDrawableSize] = path;
182         fDrawableSize++;
183     }
184 
185     // The result after a series of push_backs of drawable SkGlyph* or SkPath*.
drawable()186     SkZip<SkGlyphVariant, SkPoint> drawable() {
187         SkASSERT(fPhase == kProcess);
188         SkDEBUGCODE(fPhase = kDraw);
189         return SkZip<SkGlyphVariant, SkPoint>{fDrawableSize, fMultiBuffer, fPositions};
190     }
191 
192     void reset();
193 
194     template <typename Fn>
forEachGlyphID(Fn && fn)195     void forEachGlyphID(Fn&& fn) {
196         for (auto [i, packedID, pos] : SkMakeEnumerate(this->input())) {
197             fn(i, packedID.packedID(), pos);
198         }
199     }
200 
201 private:
202     size_t fMaxSize{0};
203     size_t fInputSize{0};
204     size_t fDrawableSize{0};
205     SkAutoTMalloc<SkGlyphVariant> fMultiBuffer;
206     SkAutoTMalloc<SkPoint> fPositions;
207 
208 #ifdef SK_DEBUG
209     enum {
210         kReset,
211         kInput,
212         kProcess,
213         kDraw
214     } fPhase{kReset};
215 #endif
216 };
217 #endif  // SkGlyphBuffer_DEFINED
218