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/base/SkZip.h" 12 #include "src/core/SkEnumerate.h" 13 #include "src/core/SkGlyph.h" 14 15 #include <climits> 16 17 struct SkGlyphPositionRoundingSpec; 18 class SkPath; 19 class SkDrawable; 20 21 namespace sktext { 22 class StrikeForGPU; 23 } // namespace sktext 24 25 // SkSourceGlyphBuffer is the source of glyphs between the different stages of glyph drawing. 26 // It starts with the glyphs and positions from the SkGlyphRun as the first source. When glyphs 27 // are reject by a stage they become the source for the next stage. 28 class SkSourceGlyphBuffer { 29 public: 30 SkSourceGlyphBuffer() = default; 31 setSource(SkZip<const SkGlyphID,const SkPoint> source)32 void setSource(SkZip<const SkGlyphID, const SkPoint> source) { 33 this->~SkSourceGlyphBuffer(); 34 new (this) SkSourceGlyphBuffer{source}; 35 } 36 37 void reset(); 38 reject(size_t index)39 void reject(size_t index) { 40 SkASSERT(index < fSource.size()); 41 if (!this->sourceIsRejectBuffers()) { 42 // Need to expand the buffers for first use. All other reject sets will be fewer than 43 // this one. 44 auto [glyphID, pos] = fSource[index]; 45 fRejectedGlyphIDs.push_back(glyphID); 46 fRejectedPositions.push_back(pos); 47 fRejectSize++; 48 } else { 49 SkASSERT(fRejectSize < fRejects.size()); 50 fRejects[fRejectSize++] = fSource[index]; 51 } 52 } 53 flipRejectsToSource()54 SkZip<const SkGlyphID, const SkPoint> flipRejectsToSource() { 55 fRejects = SkMakeZip(fRejectedGlyphIDs, fRejectedPositions).first(fRejectSize); 56 fSource = fRejects; 57 fRejectSize = 0; 58 return fSource; 59 } 60 source()61 SkZip<const SkGlyphID, const SkPoint> source() const { return fSource; } 62 63 private: SkSourceGlyphBuffer(const SkZip<const SkGlyphID,const SkPoint> & source)64 SkSourceGlyphBuffer(const SkZip<const SkGlyphID, const SkPoint>& source) { 65 fSource = source; 66 } sourceIsRejectBuffers()67 bool sourceIsRejectBuffers() const { 68 return fSource.get<0>().data() == fRejectedGlyphIDs.data(); 69 } 70 71 SkZip<const SkGlyphID, const SkPoint> fSource; 72 size_t fRejectSize{0}; 73 74 SkZip<SkGlyphID, SkPoint> fRejects; 75 SkSTArray<4, SkGlyphID> fRejectedGlyphIDs; 76 SkSTArray<4, SkPoint> fRejectedPositions; 77 }; 78 79 // A buffer for converting SkPackedGlyph to SkGlyph*s. Initially the buffer contains 80 // SkPackedGlyphIDs, but those are used to lookup SkGlyph*s which are then copied over the 81 // SkPackedGlyphIDs. 82 class SkDrawableGlyphBuffer { 83 public: 84 void ensureSize(int size); 85 86 // Load the buffer with SkPackedGlyphIDs and positions at (0, 0) ready to finish positioning 87 // during drawing. 88 void startSource(const SkZip<const SkGlyphID, const SkPoint>& source); 89 90 SkString dumpInput() const; 91 92 // The input of SkPackedGlyphIDs input()93 SkZip<SkPackedGlyphID, SkPoint> input() { 94 SkASSERT(fPhase == kInput); 95 SkDEBUGCODE(fPhase = kProcess); 96 return SkZip<SkPackedGlyphID, SkPoint>{ 97 SkToSizeT(fInputSize), fPackedGlyphIDs.get(), fPositions}; 98 } 99 accept(SkPackedGlyphID glyphID,SkPoint position,SkMask::Format format)100 void accept(SkPackedGlyphID glyphID, SkPoint position, SkMask::Format format) { 101 SkASSERT(fPhase == kProcess); 102 fPositions[fAcceptedSize] = position; 103 fPackedGlyphIDs[fAcceptedSize] = glyphID; 104 fFormats[fAcceptedSize] = format; 105 fAcceptedSize++; 106 } 107 accept(SkPackedGlyphID glyphID,SkPoint position)108 void accept(SkPackedGlyphID glyphID, SkPoint position) { 109 SkASSERT(fPhase == kProcess); 110 fPositions[fAcceptedSize] = position; 111 fPackedGlyphIDs[fAcceptedSize] = glyphID; 112 fAcceptedSize++; 113 } 114 115 // The result after a series of `accept` of accepted SkGlyph* or SkPath*. accepted()116 SkZip<SkPackedGlyphID, SkPoint> accepted() { 117 SkASSERT(fPhase == kProcess); 118 SkDEBUGCODE(fPhase = kDraw); 119 return SkZip<SkPackedGlyphID, SkPoint>{ 120 SkToSizeT(fAcceptedSize), fPackedGlyphIDs.get(), fPositions}; 121 } 122 acceptedWithMaskFormat()123 SkZip<SkPackedGlyphID, SkPoint, SkMask::Format> acceptedWithMaskFormat() { 124 SkASSERT(fPhase == kProcess); 125 SkDEBUGCODE(fPhase = kDraw); 126 return SkZip<SkPackedGlyphID, SkPoint, SkMask::Format>{ 127 SkToSizeT(fAcceptedSize), fPackedGlyphIDs.get(), fPositions, fFormats}; 128 } 129 empty()130 bool empty() const { 131 SkASSERT(fPhase == kProcess || fPhase == kDraw); 132 return fAcceptedSize == 0; 133 } 134 135 void reset(); 136 137 template <typename Fn> forEachInput(Fn && fn)138 void forEachInput(Fn&& fn) { 139 for (auto [i, packedID, pos] : SkMakeEnumerate(this->input())) { 140 fn(i, packedID, pos); 141 } 142 } 143 144 private: 145 int fMaxSize{0}; 146 int fInputSize{0}; 147 int fAcceptedSize{0}; 148 skia_private::AutoTArray<SkPackedGlyphID> fPackedGlyphIDs; 149 skia_private::AutoTMalloc<SkPoint> fPositions; 150 skia_private::AutoTMalloc<SkMask::Format> fFormats; 151 152 #ifdef SK_DEBUG 153 enum { 154 kReset, 155 kInput, 156 kProcess, 157 kDraw 158 } fPhase{kReset}; 159 #endif 160 }; 161 #endif // SkGlyphBuffer_DEFINED 162