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