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