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