1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef SkGlyphBuffer_DEFINED
9cb93a386Sopenharmony_ci#define SkGlyphBuffer_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "src/core/SkEnumerate.h"
12cb93a386Sopenharmony_ci#include "src/core/SkGlyph.h"
13cb93a386Sopenharmony_ci#include "src/core/SkZip.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciclass SkStrikeForGPU;
16cb93a386Sopenharmony_cistruct SkGlyphPositionRoundingSpec;
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci// SkSourceGlyphBuffer is the source of glyphs between the different stages of character drawing.
19cb93a386Sopenharmony_ci// It starts with the glyphs and positions from the SkGlyphRun as the first source. When glyphs
20cb93a386Sopenharmony_ci// are reject by a stage they become the source for the next stage.
21cb93a386Sopenharmony_ciclass SkSourceGlyphBuffer {
22cb93a386Sopenharmony_cipublic:
23cb93a386Sopenharmony_ci    SkSourceGlyphBuffer() = default;
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ci    void setSource(SkZip<const SkGlyphID, const SkPoint> source) {
26cb93a386Sopenharmony_ci        this->~SkSourceGlyphBuffer();
27cb93a386Sopenharmony_ci        new (this) SkSourceGlyphBuffer{source};
28cb93a386Sopenharmony_ci    }
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci    void reset();
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci    void reject(size_t index) {
33cb93a386Sopenharmony_ci        SkASSERT(index < fSource.size());
34cb93a386Sopenharmony_ci        if (!this->sourceIsRejectBuffers()) {
35cb93a386Sopenharmony_ci            // Need to expand the buffers for first use. All other reject sets will be fewer than
36cb93a386Sopenharmony_ci            // this one.
37cb93a386Sopenharmony_ci            auto [glyphID, pos] = fSource[index];
38cb93a386Sopenharmony_ci            fRejectedGlyphIDs.push_back(glyphID);
39cb93a386Sopenharmony_ci            fRejectedPositions.push_back(pos);
40cb93a386Sopenharmony_ci            fRejectSize++;
41cb93a386Sopenharmony_ci        } else {
42cb93a386Sopenharmony_ci            SkASSERT(fRejectSize < fRejects.size());
43cb93a386Sopenharmony_ci            fRejects[fRejectSize++] = fSource[index];
44cb93a386Sopenharmony_ci        }
45cb93a386Sopenharmony_ci    }
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci    void reject(size_t index, int rejectedMaxDimension) {
48cb93a386Sopenharmony_ci        fRejectedMaxDimension = std::max(fRejectedMaxDimension, rejectedMaxDimension);
49cb93a386Sopenharmony_ci        this->reject(index);
50cb93a386Sopenharmony_ci    }
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    SkZip<const SkGlyphID, const SkPoint> flipRejectsToSource() {
53cb93a386Sopenharmony_ci        fRejects = SkMakeZip(fRejectedGlyphIDs, fRejectedPositions).first(fRejectSize);
54cb93a386Sopenharmony_ci        fSource = fRejects;
55cb93a386Sopenharmony_ci        fRejectSize = 0;
56cb93a386Sopenharmony_ci        fSourceMaxDimension = fRejectedMaxDimension;
57cb93a386Sopenharmony_ci        fRejectedMaxDimension = 0;
58cb93a386Sopenharmony_ci        return fSource;
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    SkZip<const SkGlyphID, const SkPoint> source() const { return fSource; }
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    int rejectedMaxDimension() const { return fSourceMaxDimension; }
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ciprivate:
66cb93a386Sopenharmony_ci    SkSourceGlyphBuffer(const SkZip<const SkGlyphID, const SkPoint>& source) {
67cb93a386Sopenharmony_ci        fSource = source;
68cb93a386Sopenharmony_ci    }
69cb93a386Sopenharmony_ci    bool sourceIsRejectBuffers() const {
70cb93a386Sopenharmony_ci        return fSource.get<0>().data() == fRejectedGlyphIDs.data();
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci    SkZip<const SkGlyphID, const SkPoint> fSource;
74cb93a386Sopenharmony_ci    size_t fRejectSize{0};
75cb93a386Sopenharmony_ci    int fSourceMaxDimension{0};
76cb93a386Sopenharmony_ci    int fRejectedMaxDimension{0};
77cb93a386Sopenharmony_ci    SkZip<SkGlyphID, SkPoint> fRejects;
78cb93a386Sopenharmony_ci    SkSTArray<4, SkGlyphID> fRejectedGlyphIDs;
79cb93a386Sopenharmony_ci    SkSTArray<4, SkPoint> fRejectedPositions;
80cb93a386Sopenharmony_ci};
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci// A memory format that allows an SkPackedGlyphID, SkGlyph*, and SkPath* to occupy the same
83cb93a386Sopenharmony_ci// memory. This allows SkPackedGlyphIDs as input, and SkGlyph*/SkPath* as output using the same
84cb93a386Sopenharmony_ci// memory.
85cb93a386Sopenharmony_ciclass SkGlyphVariant {
86cb93a386Sopenharmony_cipublic:
87cb93a386Sopenharmony_ci    SkGlyphVariant() : fV{nullptr} { }
88cb93a386Sopenharmony_ci    SkGlyphVariant& operator= (SkPackedGlyphID packedID) {
89cb93a386Sopenharmony_ci        fV.packedID = packedID;
90cb93a386Sopenharmony_ci        SkDEBUGCODE(fTag = kPackedID);
91cb93a386Sopenharmony_ci        return *this;
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci    SkGlyphVariant& operator= (SkGlyph* glyph) {
94cb93a386Sopenharmony_ci        fV.glyph = glyph;
95cb93a386Sopenharmony_ci        SkDEBUGCODE(fTag = kGlyph);
96cb93a386Sopenharmony_ci        return *this;
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    }
99cb93a386Sopenharmony_ci    SkGlyphVariant& operator= (const SkPath* path) {
100cb93a386Sopenharmony_ci        fV.path = path;
101cb93a386Sopenharmony_ci        SkDEBUGCODE(fTag = kPath);
102cb93a386Sopenharmony_ci        return *this;
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    SkGlyph* glyph() const {
106cb93a386Sopenharmony_ci        SkASSERT(fTag == kGlyph);
107cb93a386Sopenharmony_ci        return fV.glyph;
108cb93a386Sopenharmony_ci    }
109cb93a386Sopenharmony_ci    const SkPath* path() const {
110cb93a386Sopenharmony_ci        SkASSERT(fTag == kPath);
111cb93a386Sopenharmony_ci        return fV.path;
112cb93a386Sopenharmony_ci    }
113cb93a386Sopenharmony_ci    SkPackedGlyphID packedID() const {
114cb93a386Sopenharmony_ci        SkASSERT(fTag == kPackedID);
115cb93a386Sopenharmony_ci        return fV.packedID;
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    operator SkPackedGlyphID() const { return this->packedID(); }
119cb93a386Sopenharmony_ci    operator SkGlyph*()        const { return this->glyph();    }
120cb93a386Sopenharmony_ci    operator const SkPath*()   const { return this->path();     }
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ciprivate:
123cb93a386Sopenharmony_ci    union {
124cb93a386Sopenharmony_ci        SkGlyph* glyph;
125cb93a386Sopenharmony_ci        const SkPath* path;
126cb93a386Sopenharmony_ci        SkPackedGlyphID packedID;
127cb93a386Sopenharmony_ci    } fV;
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci#ifdef SK_DEBUG
130cb93a386Sopenharmony_ci    enum {
131cb93a386Sopenharmony_ci        kEmpty,
132cb93a386Sopenharmony_ci        kPackedID,
133cb93a386Sopenharmony_ci        kGlyph,
134cb93a386Sopenharmony_ci        kPath
135cb93a386Sopenharmony_ci    } fTag{kEmpty};
136cb93a386Sopenharmony_ci#endif
137cb93a386Sopenharmony_ci};
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci// A buffer for converting SkPackedGlyph to SkGlyph* or SkPath*. Initially the buffer contains
140cb93a386Sopenharmony_ci// SkPackedGlyphIDs, but those are used to lookup SkGlyph*/SkPath* which are then copied over the
141cb93a386Sopenharmony_ci// SkPackedGlyphIDs.
142cb93a386Sopenharmony_ciclass SkDrawableGlyphBuffer {
143cb93a386Sopenharmony_cipublic:
144cb93a386Sopenharmony_ci    void ensureSize(size_t size);
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    // Load the buffer with SkPackedGlyphIDs and positions at (0, 0) ready to finish positioning
147cb93a386Sopenharmony_ci    // during drawing.
148cb93a386Sopenharmony_ci    void startSource(const SkZip<const SkGlyphID, const SkPoint>& source);
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci    // Load the buffer with SkPackedGlyphIDs and positions using the device transform.
151cb93a386Sopenharmony_ci    void startBitmapDevice(
152cb93a386Sopenharmony_ci            const SkZip<const SkGlyphID, const SkPoint>& source,
153cb93a386Sopenharmony_ci            SkPoint origin, const SkMatrix& viewMatrix,
154cb93a386Sopenharmony_ci            const SkGlyphPositionRoundingSpec& roundingSpec);
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    // Load the buffer with SkPackedGlyphIDs, calculating positions so they can be constant.
157cb93a386Sopenharmony_ci    //
158cb93a386Sopenharmony_ci    // The positions are calculated integer positions in devices space, and the mapping of the
159cb93a386Sopenharmony_ci    // the source origin through the initial matrix is returned. It is given that these positions
160cb93a386Sopenharmony_ci    // are only reused when the blob is translated by an integral amount. Thus the shifted
161cb93a386Sopenharmony_ci    // positions are given by the following equation where (ix, iy) is the integer positions of
162cb93a386Sopenharmony_ci    // the glyph, initialMappedOrigin is (0,0) in source mapped to the device using the initial
163cb93a386Sopenharmony_ci    // matrix, and newMappedOrigin is (0,0) in source mapped to the device using the current
164cb93a386Sopenharmony_ci    // drawing matrix.
165cb93a386Sopenharmony_ci    //
166cb93a386Sopenharmony_ci    //    (ix', iy') = (ix, iy) + round(newMappedOrigin - initialMappedOrigin)
167cb93a386Sopenharmony_ci    //
168cb93a386Sopenharmony_ci    // In theory, newMappedOrigin - initialMappedOrigin should be integer, but the vagaries of
169cb93a386Sopenharmony_ci    // floating point don't guarantee that, so force it to integer.
170cb93a386Sopenharmony_ci    void startGPUDevice(
171cb93a386Sopenharmony_ci            const SkZip<const SkGlyphID, const SkPoint>& source,
172cb93a386Sopenharmony_ci            const SkMatrix& drawMatrix,
173cb93a386Sopenharmony_ci            const SkGlyphPositionRoundingSpec& roundingSpec);
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci    SkString dumpInput() const;
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_ci    // The input of SkPackedGlyphIDs
178cb93a386Sopenharmony_ci    SkZip<SkGlyphVariant, SkPoint> input() {
179cb93a386Sopenharmony_ci        SkASSERT(fPhase == kInput);
180cb93a386Sopenharmony_ci        SkDEBUGCODE(fPhase = kProcess);
181cb93a386Sopenharmony_ci        return SkZip<SkGlyphVariant, SkPoint>{fInputSize, fMultiBuffer.get(), fPositions};
182cb93a386Sopenharmony_ci    }
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    // Store the glyph in the next drawable slot, using the position information located at index
185cb93a386Sopenharmony_ci    // from.
186cb93a386Sopenharmony_ci    void push_back(SkGlyph* glyph, size_t from) {
187cb93a386Sopenharmony_ci        SkASSERT(fPhase == kProcess);
188cb93a386Sopenharmony_ci        SkASSERT(fDrawableSize <= from);
189cb93a386Sopenharmony_ci        fPositions[fDrawableSize] = fPositions[from];
190cb93a386Sopenharmony_ci        fMultiBuffer[fDrawableSize] = glyph;
191cb93a386Sopenharmony_ci        fDrawableSize++;
192cb93a386Sopenharmony_ci    }
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci    // Store the path in the next drawable slot, using the position information located at index
195cb93a386Sopenharmony_ci    // from.
196cb93a386Sopenharmony_ci    void push_back(const SkPath* path, size_t from) {
197cb93a386Sopenharmony_ci        SkASSERT(fPhase == kProcess);
198cb93a386Sopenharmony_ci        SkASSERT(fDrawableSize <= from);
199cb93a386Sopenharmony_ci        fPositions[fDrawableSize] = fPositions[from];
200cb93a386Sopenharmony_ci        fMultiBuffer[fDrawableSize] = path;
201cb93a386Sopenharmony_ci        fDrawableSize++;
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci    // The result after a series of push_backs of drawable SkGlyph* or SkPath*.
205cb93a386Sopenharmony_ci    SkZip<SkGlyphVariant, SkPoint> drawable() {
206cb93a386Sopenharmony_ci        SkASSERT(fPhase == kProcess);
207cb93a386Sopenharmony_ci        SkDEBUGCODE(fPhase = kDraw);
208cb93a386Sopenharmony_ci        return SkZip<SkGlyphVariant, SkPoint>{fDrawableSize, fMultiBuffer.get(), fPositions};
209cb93a386Sopenharmony_ci    }
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_ci    bool drawableIsEmpty() const {
212cb93a386Sopenharmony_ci        SkASSERT(fPhase == kProcess || fPhase == kDraw);
213cb93a386Sopenharmony_ci        return fDrawableSize == 0;
214cb93a386Sopenharmony_ci    }
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci    void reset();
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    template <typename Fn>
219cb93a386Sopenharmony_ci    void forEachGlyphID(Fn&& fn) {
220cb93a386Sopenharmony_ci        for (auto [i, packedID, pos] : SkMakeEnumerate(this->input())) {
221cb93a386Sopenharmony_ci            fn(i, packedID.packedID(), pos);
222cb93a386Sopenharmony_ci        }
223cb93a386Sopenharmony_ci    }
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ciprivate:
226cb93a386Sopenharmony_ci    size_t fMaxSize{0};
227cb93a386Sopenharmony_ci    size_t fInputSize{0};
228cb93a386Sopenharmony_ci    size_t fDrawableSize{0};
229cb93a386Sopenharmony_ci    SkAutoTArray<SkGlyphVariant> fMultiBuffer;
230cb93a386Sopenharmony_ci    SkAutoTMalloc<SkPoint> fPositions;
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci#ifdef SK_DEBUG
233cb93a386Sopenharmony_ci    enum {
234cb93a386Sopenharmony_ci        kReset,
235cb93a386Sopenharmony_ci        kInput,
236cb93a386Sopenharmony_ci        kProcess,
237cb93a386Sopenharmony_ci        kDraw
238cb93a386Sopenharmony_ci    } fPhase{kReset};
239cb93a386Sopenharmony_ci#endif
240cb93a386Sopenharmony_ci};
241cb93a386Sopenharmony_ci#endif  // SkGlyphBuffer_DEFINED
242