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 at (0, 0) ready to finish positioning 147 // during drawing. 148 void startSource(const SkZip<const SkGlyphID, const SkPoint>& source); 149 150 // Load the buffer with SkPackedGlyphIDs and positions using the device transform. 151 void startBitmapDevice( 152 const SkZip<const SkGlyphID, const SkPoint>& source, 153 SkPoint origin, const SkMatrix& viewMatrix, 154 const SkGlyphPositionRoundingSpec& roundingSpec); 155 156 // Load the buffer with SkPackedGlyphIDs, calculating positions so they can be constant. 157 // 158 // The positions are calculated integer positions in devices space, and the mapping of the 159 // the source origin through the initial matrix is returned. It is given that these positions 160 // are only reused when the blob is translated by an integral amount. Thus the shifted 161 // positions are given by the following equation where (ix, iy) is the integer positions of 162 // the glyph, initialMappedOrigin is (0,0) in source mapped to the device using the initial 163 // matrix, and newMappedOrigin is (0,0) in source mapped to the device using the current 164 // drawing matrix. 165 // 166 // (ix', iy') = (ix, iy) + round(newMappedOrigin - initialMappedOrigin) 167 // 168 // In theory, newMappedOrigin - initialMappedOrigin should be integer, but the vagaries of 169 // floating point don't guarantee that, so force it to integer. 170 void startGPUDevice( 171 const SkZip<const SkGlyphID, const SkPoint>& source, 172 const SkMatrix& drawMatrix, 173 const SkGlyphPositionRoundingSpec& roundingSpec); 174 175 SkString dumpInput() const; 176 177 // The input of SkPackedGlyphIDs input()178 SkZip<SkGlyphVariant, SkPoint> input() { 179 SkASSERT(fPhase == kInput); 180 SkDEBUGCODE(fPhase = kProcess); 181 return SkZip<SkGlyphVariant, SkPoint>{fInputSize, fMultiBuffer.get(), fPositions}; 182 } 183 184 // Store the glyph in the next drawable slot, using the position information located at index 185 // from. push_back(SkGlyph * glyph,size_t from)186 void push_back(SkGlyph* glyph, size_t from) { 187 SkASSERT(fPhase == kProcess); 188 SkASSERT(fDrawableSize <= from); 189 fPositions[fDrawableSize] = fPositions[from]; 190 fMultiBuffer[fDrawableSize] = glyph; 191 fDrawableSize++; 192 } 193 194 // Store the path in the next drawable slot, using the position information located at index 195 // from. push_back(const SkPath * path,size_t from)196 void push_back(const SkPath* path, size_t from) { 197 SkASSERT(fPhase == kProcess); 198 SkASSERT(fDrawableSize <= from); 199 fPositions[fDrawableSize] = fPositions[from]; 200 fMultiBuffer[fDrawableSize] = path; 201 fDrawableSize++; 202 } 203 204 // The result after a series of push_backs of drawable SkGlyph* or SkPath*. drawable()205 SkZip<SkGlyphVariant, SkPoint> drawable() { 206 SkASSERT(fPhase == kProcess); 207 SkDEBUGCODE(fPhase = kDraw); 208 return SkZip<SkGlyphVariant, SkPoint>{fDrawableSize, fMultiBuffer.get(), fPositions}; 209 } 210 drawableIsEmpty()211 bool drawableIsEmpty() const { 212 SkASSERT(fPhase == kProcess || fPhase == kDraw); 213 return fDrawableSize == 0; 214 } 215 216 void reset(); 217 218 template <typename Fn> forEachGlyphID(Fn && fn)219 void forEachGlyphID(Fn&& fn) { 220 for (auto [i, packedID, pos] : SkMakeEnumerate(this->input())) { 221 fn(i, packedID.packedID(), pos); 222 } 223 } 224 225 private: 226 size_t fMaxSize{0}; 227 size_t fInputSize{0}; 228 size_t fDrawableSize{0}; 229 SkAutoTArray<SkGlyphVariant> fMultiBuffer; 230 SkAutoTMalloc<SkPoint> fPositions; 231 232 #ifdef SK_DEBUG 233 enum { 234 kReset, 235 kInput, 236 kProcess, 237 kDraw 238 } fPhase{kReset}; 239 #endif 240 }; 241 #endif // SkGlyphBuffer_DEFINED 242