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 22class SkReadBuffer; 23class SkWriteBuffer; 24 25class SkTextBlobPriv { 26public: 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 62SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) 63 64class SkTextBlob::RunRecord { 65public: 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 80 uint32_t glyphCount() const { 81 return fCount; 82 } 83 84 const SkPoint& offset() const { 85 return fOffset; 86 } 87 88 const SkFont& font() const { 89 return fFont; 90 } 91 92 GlyphPositioning positioning() const { 93 return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask); 94 } 95 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() 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() 110 SkPoint* pointBuffer() const { 111 SkASSERT(this->positioning() == (GlyphPositioning)2); 112 return reinterpret_cast<SkPoint*>(this->posBuffer()); 113 } 114 115 // alias for posBuffer() 116 SkRSXform* xformBuffer() const { 117 SkASSERT(this->positioning() == (GlyphPositioning)3); 118 return reinterpret_cast<SkRSXform*>(this->posBuffer()); 119 } 120 121 uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; } 122 123 uint32_t* clusterBuffer() const { 124 // clusters follow the textSize. 125 return isExtended() ? 1 + this->textSizePtr() : nullptr; 126 } 127 128 char* textBuffer() const { 129 return isExtended() 130 ? reinterpret_cast<char*>(this->clusterBuffer() + fCount) 131 : nullptr; 132 } 133 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 146private: 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 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 */ 183class SK_API SkTextBlobRunIterator { 184public: 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 194 bool done() const { 195 return !fCurrentRun; 196 } 197 void next(); 198 199 uint32_t glyphCount() const { 200 SkASSERT(!this->done()); 201 return fCurrentRun->glyphCount(); 202 } 203 const uint16_t* glyphs() const { 204 SkASSERT(!this->done()); 205 return fCurrentRun->glyphBuffer(); 206 } 207 const SkScalar* pos() const { 208 SkASSERT(!this->done()); 209 return fCurrentRun->posBuffer(); 210 } 211 // alias for pos() 212 const SkPoint* points() const { 213 return fCurrentRun->pointBuffer(); 214 } 215 // alias for pos() 216 const SkRSXform* xforms() const { 217 return fCurrentRun->xformBuffer(); 218 } 219 const SkPoint& offset() const { 220 SkASSERT(!this->done()); 221 return fCurrentRun->offset(); 222 } 223 const SkFont& font() const { 224 SkASSERT(!this->done()); 225 return fCurrentRun->font(); 226 } 227 GlyphPositioning positioning() const; 228 unsigned scalarsPerGlyph() const; 229 uint32_t* clusters() const { 230 SkASSERT(!this->done()); 231 return fCurrentRun->clusterBuffer(); 232 } 233 uint32_t textSize() const { 234 SkASSERT(!this->done()); 235 return fCurrentRun->textSize(); 236 } 237 char* text() const { 238 SkASSERT(!this->done()); 239 return fCurrentRun->textBuffer(); 240 } 241 242 bool isLCD() const; 243 244private: 245 const SkTextBlob::RunRecord* fCurrentRun; 246 247 SkDEBUGCODE(uint8_t* fStorageTop;) 248}; 249 250#endif // SkTextBlobPriv_DEFINED 251