1 /* 2 * Copyright 2018 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 SkTextBlobPriv_DEFINED 9 #define SkTextBlobPriv_DEFINED 10 11 #include "include/core/SkColorFilter.h" 12 #include "include/core/SkFont.h" 13 #include "include/core/SkImageFilter.h" 14 #include "include/core/SkMaskFilter.h" 15 #include "include/core/SkPathEffect.h" 16 #include "include/core/SkShader.h" 17 #include "include/core/SkTextBlob.h" 18 #include "include/core/SkTypeface.h" 19 #include "src/base/SkSafeMath.h" 20 #include "src/core/SkPaintPriv.h" 21 22 class SkReadBuffer; 23 class SkWriteBuffer; 24 25 class SkTextBlobPriv { 26 public: 27 /** 28 * Serialize to a buffer. 29 */ 30 static void Flatten(const SkTextBlob& , SkWriteBuffer&); 31 32 /** 33 * Recreate an SkTextBlob that was serialized into a buffer. 34 * 35 * @param SkReadBuffer Serialized blob data. 36 * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is 37 * invalid. 38 */ 39 static sk_sp<SkTextBlob> MakeFromBuffer(SkReadBuffer&); 40 41 static bool HasRSXForm(const SkTextBlob& blob); 42 }; 43 44 // 45 // Textblob data is laid out into externally-managed storage as follows: 46 // 47 // ----------------------------------------------------------------------------- 48 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... 49 // ----------------------------------------------------------------------------- 50 // 51 // Each run record describes a text blob run, and can be used to determine the (implicit) 52 // location of the following record. 53 // 54 // Extended Textblob runs have more data after the Pos[] array: 55 // 56 // ------------------------------------------------------------------------- 57 // ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ... 58 // ------------------------------------------------------------------------- 59 // 60 // To determine the length of the extended run data, the TextSize must be read. 61 // 62 // Extended Textblob runs may be mixed with non-extended runs. 63 64 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) 65 66 class SkTextBlob::RunRecord { 67 public: RunRecord(uint32_t count,uint32_t textSize,const SkPoint & offset,const SkFont & font,GlyphPositioning pos)68 RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkFont& font, GlyphPositioning pos) 69 : fFont(font) 70 , fCount(count) 71 , fOffset(offset) 72 , fFlags(pos) { 73 SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask); 74 75 SkDEBUGCODE(fMagic = kRunRecordMagic); 76 if (textSize > 0) { 77 fFlags |= kExtended_Flag; 78 *this->textSizePtr() = textSize; 79 } 80 } 81 glyphCount()82 uint32_t glyphCount() const { 83 return fCount; 84 } 85 offset()86 const SkPoint& offset() const { 87 return fOffset; 88 } 89 font()90 const SkFont& font() const { 91 return fFont; 92 } 93 positioning()94 GlyphPositioning positioning() const { 95 return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask); 96 } 97 glyphBuffer()98 uint16_t* glyphBuffer() const { 99 static_assert(SkIsAlignPtr(sizeof(RunRecord)), ""); 100 // Glyphs are stored immediately following the record. 101 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); 102 } 103 104 // can be aliased with pointBuffer() or xformBuffer() posBuffer()105 SkScalar* posBuffer() const { 106 // Position scalars follow the (aligned) glyph buffer. 107 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) + 108 SkAlign4(fCount * sizeof(uint16_t))); 109 } 110 111 // alias for posBuffer() pointBuffer()112 SkPoint* pointBuffer() const { 113 SkASSERT(this->positioning() == (GlyphPositioning)2); 114 return reinterpret_cast<SkPoint*>(this->posBuffer()); 115 } 116 117 // alias for posBuffer() xformBuffer()118 SkRSXform* xformBuffer() const { 119 SkASSERT(this->positioning() == (GlyphPositioning)3); 120 return reinterpret_cast<SkRSXform*>(this->posBuffer()); 121 } 122 textSize()123 uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; } 124 clusterBuffer()125 uint32_t* clusterBuffer() const { 126 // clusters follow the textSize. 127 return isExtended() ? 1 + this->textSizePtr() : nullptr; 128 } 129 textBuffer()130 char* textBuffer() const { 131 return isExtended() 132 ? reinterpret_cast<char*>(this->clusterBuffer() + fCount) 133 : nullptr; 134 } 135 isLastRun()136 bool isLastRun() const { return SkToBool(fFlags & kLast_Flag); } 137 138 static size_t StorageSize(uint32_t glyphCount, uint32_t textSize, 139 SkTextBlob::GlyphPositioning positioning, 140 SkSafeMath* safe); 141 142 static const RunRecord* First(const SkTextBlob* blob); 143 144 static const RunRecord* Next(const RunRecord* run); 145 146 void validate(const uint8_t* storageTop) const; 147 148 private: 149 friend class SkTextBlobBuilder; 150 151 enum Flags { 152 kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning 153 kLast_Flag = 0x04, // set for the last blob run 154 kExtended_Flag = 0x08, // set for runs with text/cluster info 155 }; 156 157 static const RunRecord* NextUnchecked(const RunRecord* run); 158 159 static size_t PosCount(uint32_t glyphCount, 160 SkTextBlob::GlyphPositioning positioning, 161 SkSafeMath* safe); 162 163 uint32_t* textSizePtr() const; 164 165 void grow(uint32_t count); 166 isExtended()167 bool isExtended() const { 168 return fFlags & kExtended_Flag; 169 } 170 171 SkFont fFont; 172 uint32_t fCount; 173 SkPoint fOffset; 174 uint32_t fFlags; 175 176 SkDEBUGCODE(unsigned fMagic;) 177 }; 178 179 /** 180 * Iterate through all of the text runs of the text blob. For example: 181 * for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) { 182 * ..... 183 * } 184 */ 185 class SK_SPI SkTextBlobRunIterator { 186 public: 187 SkTextBlobRunIterator(const SkTextBlob* blob); 188 189 enum GlyphPositioning : uint8_t { 190 kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph. 191 kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph. 192 kFull_Positioning = 2, // Point positioning -- two scalars per glyph. 193 kRSXform_Positioning = 3, // RSXform positioning -- four scalars per glyph. 194 }; 195 done()196 bool done() const { 197 return !fCurrentRun; 198 } 199 void next(); 200 glyphCount()201 uint32_t glyphCount() const { 202 SkASSERT(!this->done()); 203 return fCurrentRun->glyphCount(); 204 } glyphs()205 const uint16_t* glyphs() const { 206 SkASSERT(!this->done()); 207 return fCurrentRun->glyphBuffer(); 208 } pos()209 const SkScalar* pos() const { 210 SkASSERT(!this->done()); 211 return fCurrentRun->posBuffer(); 212 } 213 // alias for pos() points()214 const SkPoint* points() const { 215 return fCurrentRun->pointBuffer(); 216 } 217 // alias for pos() xforms()218 const SkRSXform* xforms() const { 219 return fCurrentRun->xformBuffer(); 220 } offset()221 const SkPoint& offset() const { 222 SkASSERT(!this->done()); 223 return fCurrentRun->offset(); 224 } font()225 const SkFont& font() const { 226 SkASSERT(!this->done()); 227 return fCurrentRun->font(); 228 } 229 GlyphPositioning positioning() const; 230 unsigned scalarsPerGlyph() const; clusters()231 uint32_t* clusters() const { 232 SkASSERT(!this->done()); 233 return fCurrentRun->clusterBuffer(); 234 } textSize()235 uint32_t textSize() const { 236 SkASSERT(!this->done()); 237 return fCurrentRun->textSize(); 238 } text()239 char* text() const { 240 SkASSERT(!this->done()); 241 return fCurrentRun->textBuffer(); 242 } 243 244 bool isLCD() const; 245 246 private: 247 const SkTextBlob::RunRecord* fCurrentRun; 248 249 SkDEBUGCODE(const uint8_t* fStorageTop;) 250 }; 251 252 #endif // SkTextBlobPriv_DEFINED 253