1 /* 2 * Copyright 2014 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 #include "SkTextBlob.h" 9 10 #include "SkReadBuffer.h" 11 #include "SkWriteBuffer.h" 12 13 // 14 // Textblob data is laid out into externally-managed storage as follows: 15 // 16 // ----------------------------------------------------------------------------- 17 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... 18 // ----------------------------------------------------------------------------- 19 // 20 // Each run record describes a text blob run, and can be used to determine the (implicit) 21 // location of the following record. 22 23 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) 24 25 class SkTextBlob::RunRecord { 26 public: 27 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos) 28 : fCount(count) 29 , fOffset(offset) 30 , fFont(font) 31 , fPositioning(pos) { 32 SkDEBUGCODE(fMagic = kRunRecordMagic); 33 } 34 35 uint32_t glyphCount() const { 36 return fCount; 37 } 38 39 const SkPoint& offset() const { 40 return fOffset; 41 } 42 43 const SkPaint& font() const { 44 return fFont; 45 } 46 47 GlyphPositioning positioning() const { 48 return fPositioning; 49 } 50 51 uint16_t* glyphBuffer() const { 52 // Glyph are stored immediately following the record. 53 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); 54 } 55 56 SkScalar* posBuffer() const { 57 // Position scalars follow the (aligned) glyph buffer. 58 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) + 59 SkAlign4(fCount * sizeof(uint16_t))); 60 } 61 62 static size_t StorageSize(int glyphCount, SkTextBlob::GlyphPositioning positioning) { 63 // RunRecord object + (aligned) glyph buffer + position buffer 64 return SkAlignPtr(sizeof(SkTextBlob::RunRecord) 65 + SkAlign4(glyphCount* sizeof(uint16_t)) 66 + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning)); 67 } 68 69 static const RunRecord* First(const SkTextBlob* blob) { 70 // The first record (if present) is stored following the blob object. 71 return reinterpret_cast<const RunRecord*>(blob + 1); 72 } 73 74 static const RunRecord* Next(const RunRecord* run) { 75 return reinterpret_cast<const RunRecord*>(reinterpret_cast<const uint8_t*>(run) 76 + StorageSize(run->glyphCount(), run->positioning())); 77 } 78 79 void validate(uint8_t* storageTop) const { 80 SkASSERT(kRunRecordMagic == fMagic); 81 SkASSERT((uint8_t*)Next(this) <= storageTop); 82 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); 83 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScalar*)Next(this)); 84 } 85 86 private: 87 friend class SkTextBlobBuilder; 88 89 void grow(uint32_t count) { 90 SkScalar* initialPosBuffer = posBuffer(); 91 uint32_t initialCount = fCount; 92 fCount += count; 93 94 // Move the initial pos scalars to their new location. 95 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPositioning); 96 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); 97 98 // memmove, as the buffers may overlap 99 memmove(posBuffer(), initialPosBuffer, copySize); 100 } 101 102 uint32_t fCount; 103 SkPoint fOffset; 104 SkPaint fFont; 105 GlyphPositioning fPositioning; 106 107 SkDEBUGCODE(unsigned fMagic;) 108 }; 109 110 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds) 111 : fRunCount(runCount) 112 , fBounds(bounds) { 113 } 114 115 SkTextBlob::~SkTextBlob() { 116 const RunRecord* run = RunRecord::First(this); 117 for (int i = 0; i < fRunCount; ++i) { 118 const RunRecord* nextRun = RunRecord::Next(run); 119 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) 120 run->~RunRecord(); 121 run = nextRun; 122 } 123 } 124 125 void SkTextBlob::internal_dispose() const { 126 // SkTextBlobs use externally-managed storage. 127 this->internal_dispose_restore_refcnt_to_1(); 128 this->~SkTextBlob(); 129 sk_free(const_cast<SkTextBlob*>(this)); 130 } 131 132 uint32_t SkTextBlob::uniqueID() const { 133 static int32_t gTextBlobGenerationID; // = 0; 134 135 // loop in case our global wraps around, as we never want to return SK_InvalidGenID 136 while (SK_InvalidGenID == fUniqueID) { 137 fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1; 138 } 139 140 return fUniqueID; 141 } 142 143 void SkTextBlob::flatten(SkWriteBuffer& buffer) const { 144 int runCount = fRunCount; 145 146 buffer.write32(runCount); 147 buffer.writeRect(fBounds); 148 149 SkPaint runPaint; 150 RunIterator it(this); 151 while (!it.done()) { 152 SkASSERT(it.glyphCount() > 0); 153 154 buffer.write32(it.glyphCount()); 155 buffer.write32(it.positioning()); 156 buffer.writePoint(it.offset()); 157 // This should go away when switching to SkFont 158 it.applyFontToPaint(&runPaint); 159 buffer.writePaint(runPaint); 160 161 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t)); 162 buffer.writeByteArray(it.pos(), 163 it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning())); 164 165 it.next(); 166 SkDEBUGCODE(runCount--); 167 } 168 SkASSERT(0 == runCount); 169 } 170 171 const SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) { 172 int runCount = reader.read32(); 173 if (runCount < 0) { 174 return NULL; 175 } 176 177 SkRect bounds; 178 reader.readRect(&bounds); 179 180 SkTextBlobBuilder blobBuilder; 181 for (int i = 0; i < runCount; ++i) { 182 int glyphCount = reader.read32(); 183 GlyphPositioning pos = static_cast<GlyphPositioning>(reader.read32()); 184 if (glyphCount <= 0 || pos > kFull_Positioning) { 185 return NULL; 186 } 187 188 SkPoint offset; 189 reader.readPoint(&offset); 190 SkPaint font; 191 reader.readPaint(&font); 192 193 const SkTextBlobBuilder::RunBuffer* buf = NULL; 194 switch (pos) { 195 case kDefault_Positioning: 196 buf = &blobBuilder.allocRun(font, glyphCount, offset.x(), offset.y(), &bounds); 197 break; 198 case kHorizontal_Positioning: 199 buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bounds); 200 break; 201 case kFull_Positioning: 202 buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds); 203 break; 204 default: 205 return NULL; 206 } 207 208 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || 209 !reader.readByteArray(buf->pos, 210 glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(pos))) { 211 return NULL; 212 } 213 } 214 215 return blobBuilder.build(); 216 } 217 218 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { 219 // GlyphPositioning values are directly mapped to scalars-per-glyph. 220 SkASSERT(pos <= 2); 221 return pos; 222 } 223 224 SkTextBlob::RunIterator::RunIterator(const SkTextBlob* blob) 225 : fCurrentRun(RunRecord::First(blob)) 226 , fRemainingRuns(blob->fRunCount) { 227 SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;) 228 } 229 230 bool SkTextBlob::RunIterator::done() const { 231 return fRemainingRuns <= 0; 232 } 233 234 void SkTextBlob::RunIterator::next() { 235 SkASSERT(!this->done()); 236 237 if (!this->done()) { 238 SkDEBUGCODE(fCurrentRun->validate(fStorageTop);) 239 fCurrentRun = RunRecord::Next(fCurrentRun); 240 fRemainingRuns--; 241 } 242 } 243 244 uint32_t SkTextBlob::RunIterator::glyphCount() const { 245 SkASSERT(!this->done()); 246 return fCurrentRun->glyphCount(); 247 } 248 249 const uint16_t* SkTextBlob::RunIterator::glyphs() const { 250 SkASSERT(!this->done()); 251 return fCurrentRun->glyphBuffer(); 252 } 253 254 const SkScalar* SkTextBlob::RunIterator::pos() const { 255 SkASSERT(!this->done()); 256 return fCurrentRun->posBuffer(); 257 } 258 259 const SkPoint& SkTextBlob::RunIterator::offset() const { 260 SkASSERT(!this->done()); 261 return fCurrentRun->offset(); 262 } 263 264 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { 265 SkASSERT(!this->done()); 266 return fCurrentRun->positioning(); 267 } 268 269 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { 270 SkASSERT(!this->done()); 271 272 const SkPaint& font = fCurrentRun->font(); 273 274 paint->setTypeface(font.getTypeface()); 275 paint->setTextEncoding(font.getTextEncoding()); 276 paint->setTextSize(font.getTextSize()); 277 paint->setTextScaleX(font.getTextScaleX()); 278 paint->setTextSkewX(font.getTextSkewX()); 279 paint->setHinting(font.getHinting()); 280 281 uint32_t flagsMask = SkPaint::kAntiAlias_Flag 282 | SkPaint::kUnderlineText_Flag 283 | SkPaint::kStrikeThruText_Flag 284 | SkPaint::kFakeBoldText_Flag 285 | SkPaint::kLinearText_Flag 286 | SkPaint::kSubpixelText_Flag 287 | SkPaint::kDevKernText_Flag 288 | SkPaint::kLCDRenderText_Flag 289 | SkPaint::kEmbeddedBitmapText_Flag 290 | SkPaint::kAutoHinting_Flag 291 | SkPaint::kVerticalText_Flag 292 | SkPaint::kGenA8FromLCD_Flag 293 | SkPaint::kDistanceFieldTextTEMP_Flag; 294 paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsMask)); 295 } 296 297 SkTextBlobBuilder::SkTextBlobBuilder() 298 : fStorageSize(0) 299 , fStorageUsed(0) 300 , fRunCount(0) 301 , fDeferredBounds(false) 302 , fLastRun(0) { 303 fBounds.setEmpty(); 304 } 305 306 SkTextBlobBuilder::~SkTextBlobBuilder() { 307 if (NULL != fStorage.get()) { 308 // We are abandoning runs and must destruct the associated font data. 309 // The easiest way to accomplish that is to use the blob destructor. 310 build()->unref(); 311 } 312 } 313 314 void SkTextBlobBuilder::updateDeferredBounds() { 315 SkASSERT(!fDeferredBounds || fRunCount > 0); 316 317 if (!fDeferredBounds) { 318 return; 319 } 320 321 // FIXME: measure the current run & union bounds 322 fDeferredBounds = false; 323 } 324 325 void SkTextBlobBuilder::reserve(size_t size) { 326 // We don't currently pre-allocate, but maybe someday... 327 if (fStorageUsed + size <= fStorageSize) { 328 return; 329 } 330 331 if (0 == fRunCount) { 332 SkASSERT(NULL == fStorage.get()); 333 SkASSERT(0 == fStorageSize); 334 SkASSERT(0 == fStorageUsed); 335 336 // the first allocation also includes blob storage 337 fStorageUsed += sizeof(SkTextBlob); 338 } 339 340 fStorageSize = fStorageUsed + size; 341 // FYI: This relies on everything we store being relocatable, particularly SkPaint. 342 fStorage.realloc(fStorageSize); 343 } 344 345 bool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioning positioning, 346 int count, SkPoint offset) { 347 if (0 == fLastRun) { 348 SkASSERT(0 == fRunCount); 349 return false; 350 } 351 352 SkASSERT(fLastRun >= sizeof(SkTextBlob)); 353 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + 354 fLastRun); 355 SkASSERT(run->glyphCount() > 0); 356 357 if (run->positioning() != positioning 358 || run->font() != font 359 || (run->glyphCount() + count < run->glyphCount())) { 360 return false; 361 } 362 363 // we can merge same-font/same-positioning runs in the following cases: 364 // * fully positioned run following another fully positioned run 365 // * horizontally postioned run following another horizontally positioned run with the same 366 // y-offset 367 if (SkTextBlob::kFull_Positioning != positioning 368 && (SkTextBlob::kHorizontal_Positioning != positioning 369 || run->offset().y() != offset.y())) { 370 return false; 371 } 372 373 size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, positioning) - 374 SkTextBlob::RunRecord::StorageSize(run->glyphCount(), positioning); 375 this->reserve(sizeDelta); 376 377 // reserve may have realloced 378 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); 379 uint32_t preMergeCount = run->glyphCount(); 380 run->grow(count); 381 382 // Callers expect the buffers to point at the newly added slice, ant not at the beginning. 383 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount; 384 fCurrentRunBuffer.pos = run->posBuffer() 385 + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning); 386 387 fStorageUsed += sizeDelta; 388 389 SkASSERT(fStorageUsed <= fStorageSize); 390 run->validate(fStorage.get() + fStorageUsed); 391 392 return true; 393 } 394 395 void SkTextBlobBuilder::allocInternal(const SkPaint &font, 396 SkTextBlob::GlyphPositioning positioning, 397 int count, SkPoint offset, const SkRect* bounds) { 398 SkASSERT(count > 0); 399 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); 400 401 if (!this->mergeRun(font, positioning, count, offset)) { 402 updateDeferredBounds(); 403 404 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, positioning); 405 this->reserve(runSize); 406 407 SkASSERT(fStorageUsed >= sizeof(SkTextBlob)); 408 SkASSERT(fStorageUsed + runSize <= fStorageSize); 409 410 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed) 411 SkTextBlob::RunRecord(count, offset, font, positioning); 412 413 fCurrentRunBuffer.glyphs = run->glyphBuffer(); 414 fCurrentRunBuffer.pos = run->posBuffer(); 415 416 fLastRun = fStorageUsed; 417 fStorageUsed += runSize; 418 fRunCount++; 419 420 SkASSERT(fStorageUsed <= fStorageSize); 421 run->validate(fStorage.get() + fStorageUsed); 422 } 423 424 if (!fDeferredBounds) { 425 if (bounds) { 426 fBounds.join(*bounds); 427 } else { 428 fDeferredBounds = true; 429 } 430 } 431 } 432 433 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkPaint& font, int count, 434 SkScalar x, SkScalar y, 435 const SkRect* bounds) { 436 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, SkPoint::Make(x, y), bounds); 437 438 return fCurrentRunBuffer; 439 } 440 441 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkPaint& font, int count, 442 SkScalar y, 443 const SkRect* bounds) { 444 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, SkPoint::Make(0, y), 445 bounds); 446 447 return fCurrentRunBuffer; 448 } 449 450 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint& font, int count, 451 const SkRect *bounds) { 452 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Make(0, 0), bounds); 453 454 return fCurrentRunBuffer; 455 } 456 457 const SkTextBlob* SkTextBlobBuilder::build() { 458 SkASSERT((fRunCount > 0) == (NULL != fStorage.get())); 459 460 this->updateDeferredBounds(); 461 462 if (0 == fRunCount) { 463 SkASSERT(NULL == fStorage.get()); 464 fStorageUsed = sizeof(SkTextBlob); 465 fStorage.realloc(fStorageUsed); 466 } 467 468 SkDEBUGCODE( 469 size_t validateSize = sizeof(SkTextBlob); 470 const SkTextBlob::RunRecord* run = 471 SkTextBlob::RunRecord::First(reinterpret_cast<const SkTextBlob*>(fStorage.get())); 472 for (int i = 0; i < fRunCount; ++i) { 473 validateSize += SkTextBlob::RunRecord::StorageSize(run->fCount, run->fPositioning); 474 run->validate(fStorage.get() + fStorageUsed); 475 run = SkTextBlob::RunRecord::Next(run); 476 } 477 SkASSERT(validateSize == fStorageUsed); 478 ) 479 480 const SkTextBlob* blob = new (fStorage.detach()) SkTextBlob(fRunCount, fBounds); 481 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;) 482 483 fStorageUsed = 0; 484 fStorageSize = 0; 485 fRunCount = 0; 486 fLastRun = 0; 487 fBounds.setEmpty(); 488 489 return blob; 490 } 491 492