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