• 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/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