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 "SkTextBlobRunIterator.h" 9 10 #include "SkReadBuffer.h" 11 #include "SkSafeMath.h" 12 #include "SkTypeface.h" 13 #include "SkWriteBuffer.h" 14 15 #include <limits> 16 17 #if SK_SUPPORT_GPU 18 #include "text/GrTextBlobCache.h" 19 #endif 20 21 namespace { 22 23 // TODO(fmalita): replace with SkFont. 24 class RunFont : SkNoncopyable { 25 public: 26 RunFont(const SkPaint& paint) 27 : fSize(paint.getTextSize()) 28 , fScaleX(paint.getTextScaleX()) 29 , fTypeface(SkSafeRef(paint.getTypeface())) 30 , fSkewX(paint.getTextSkewX()) 31 , fAlign(paint.getTextAlign()) 32 , fHinting(paint.getHinting()) 33 , fFlags(paint.getFlags() & kFlagsMask) { } 34 35 void applyToPaint(SkPaint* paint) const { 36 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 37 paint->setTypeface(fTypeface); 38 paint->setTextSize(fSize); 39 paint->setTextScaleX(fScaleX); 40 paint->setTextSkewX(fSkewX); 41 paint->setTextAlign(static_cast<SkPaint::Align>(fAlign)); 42 paint->setHinting(static_cast<SkPaint::Hinting>(fHinting)); 43 44 paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags); 45 } 46 47 bool operator==(const RunFont& other) const { 48 return fTypeface == other.fTypeface 49 && fSize == other.fSize 50 && fScaleX == other.fScaleX 51 && fSkewX == other.fSkewX 52 && fAlign == other.fAlign 53 && fHinting == other.fHinting 54 && fFlags == other.fFlags; 55 } 56 57 bool operator!=(const RunFont& other) const { 58 return !(*this == other); 59 } 60 61 uint32_t flags() const { return fFlags; } 62 63 private: 64 const static uint32_t kFlagsMask = 65 SkPaint::kAntiAlias_Flag | 66 SkPaint::kFakeBoldText_Flag | 67 SkPaint::kLinearText_Flag | 68 SkPaint::kSubpixelText_Flag | 69 SkPaint::kDevKernText_Flag | 70 SkPaint::kLCDRenderText_Flag | 71 SkPaint::kEmbeddedBitmapText_Flag | 72 SkPaint::kAutoHinting_Flag | 73 SkPaint::kVerticalText_Flag | 74 SkPaint::kGenA8FromLCD_Flag; 75 76 SkScalar fSize; 77 SkScalar fScaleX; 78 79 // Keep this sk_sp off the first position, to avoid interfering with SkNoncopyable 80 // empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694). 81 sk_sp<SkTypeface> fTypeface; 82 SkScalar fSkewX; 83 84 static_assert(SkPaint::kAlignCount < 4, "insufficient_align_bits"); 85 uint32_t fAlign : 2; 86 static_assert(SkPaint::kFull_Hinting < 4, "insufficient_hinting_bits"); 87 uint32_t fHinting : 2; 88 static_assert((kFlagsMask & 0xffff) == kFlagsMask, "insufficient_flags_bits"); 89 uint32_t fFlags : 16; 90 91 typedef SkNoncopyable INHERITED; 92 }; 93 94 struct RunFontStorageEquivalent { 95 SkScalar fSize, fScaleX; 96 void* fTypeface; 97 SkScalar fSkewX; 98 uint32_t fFlags; 99 }; 100 static_assert(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), "runfont_should_stay_packed"); 101 102 } // anonymous namespace 103 104 // 105 // Textblob data is laid out into externally-managed storage as follows: 106 // 107 // ----------------------------------------------------------------------------- 108 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... 109 // ----------------------------------------------------------------------------- 110 // 111 // Each run record describes a text blob run, and can be used to determine the (implicit) 112 // location of the following record. 113 // 114 // Extended Textblob runs have more data after the Pos[] array: 115 // 116 // ------------------------------------------------------------------------- 117 // ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ... 118 // ------------------------------------------------------------------------- 119 // 120 // To determine the length of the extended run data, the TextSize must be read. 121 // 122 // Extended Textblob runs may be mixed with non-extended runs. 123 124 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) 125 126 namespace { 127 struct RunRecordStorageEquivalent { 128 RunFont fFont; 129 SkPoint fOffset; 130 uint32_t fCount; 131 uint32_t fFlags; 132 SkDEBUGCODE(unsigned fMagic;) 133 }; 134 } 135 136 class SkTextBlob::RunRecord { 137 public: 138 RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos) 139 : fFont(font) 140 , fCount(count) 141 , fOffset(offset) 142 , fFlags(pos) { 143 SkASSERT(static_cast<unsigned>(pos) <= Flags::kPositioning_Mask); 144 145 SkDEBUGCODE(fMagic = kRunRecordMagic); 146 if (textSize > 0) { 147 fFlags |= kExtended_Flag; 148 *this->textSizePtr() = textSize; 149 } 150 } 151 152 uint32_t glyphCount() const { 153 return fCount; 154 } 155 156 const SkPoint& offset() const { 157 return fOffset; 158 } 159 160 const RunFont& font() const { 161 return fFont; 162 } 163 164 GlyphPositioning positioning() const { 165 return static_cast<GlyphPositioning>(fFlags & kPositioning_Mask); 166 } 167 168 uint16_t* glyphBuffer() const { 169 static_assert(SkIsAlignPtr(sizeof(RunRecord)), ""); 170 // Glyphs are stored immediately following the record. 171 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); 172 } 173 174 SkScalar* posBuffer() const { 175 // Position scalars follow the (aligned) glyph buffer. 176 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) + 177 SkAlign4(fCount * sizeof(uint16_t))); 178 } 179 180 uint32_t textSize() const { return isExtended() ? *this->textSizePtr() : 0; } 181 182 uint32_t* clusterBuffer() const { 183 // clusters follow the textSize. 184 return isExtended() ? 1 + this->textSizePtr() : nullptr; 185 } 186 187 char* textBuffer() const { 188 return isExtended() 189 ? reinterpret_cast<char*>(this->clusterBuffer() + fCount) 190 : nullptr; 191 } 192 193 static size_t StorageSize(uint32_t glyphCount, uint32_t textSize, 194 SkTextBlob::GlyphPositioning positioning, 195 SkSafeMath* safe) { 196 static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment"); 197 198 auto glyphSize = safe->mul(glyphCount, sizeof(uint16_t)), 199 posSize = safe->mul(PosCount(glyphCount, positioning, safe), sizeof(SkScalar)); 200 201 // RunRecord object + (aligned) glyph buffer + position buffer 202 auto size = sizeof(SkTextBlob::RunRecord); 203 size = safe->add(size, safe->alignUp(glyphSize, 4)); 204 size = safe->add(size, posSize); 205 206 if (textSize) { // Extended run. 207 size = safe->add(size, sizeof(uint32_t)); 208 size = safe->add(size, safe->mul(glyphCount, sizeof(uint32_t))); 209 size = safe->add(size, textSize); 210 } 211 212 return safe->alignUp(size, sizeof(void*)); 213 } 214 215 static const RunRecord* First(const SkTextBlob* blob) { 216 // The first record (if present) is stored following the blob object. 217 return reinterpret_cast<const RunRecord*>(blob + 1); 218 } 219 220 static const RunRecord* Next(const RunRecord* run) { 221 return SkToBool(run->fFlags & kLast_Flag) ? nullptr : NextUnchecked(run); 222 } 223 224 void validate(const uint8_t* storageTop) const { 225 SkASSERT(kRunRecordMagic == fMagic); 226 SkASSERT((uint8_t*)NextUnchecked(this) <= storageTop); 227 228 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); 229 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(positioning()) 230 <= (SkScalar*)NextUnchecked(this)); 231 if (isExtended()) { 232 SkASSERT(textSize() > 0); 233 SkASSERT(textSizePtr() < (uint32_t*)NextUnchecked(this)); 234 SkASSERT(clusterBuffer() < (uint32_t*)NextUnchecked(this)); 235 SkASSERT(textBuffer() + textSize() <= (char*)NextUnchecked(this)); 236 } 237 static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEquivalent), 238 "runrecord_should_stay_packed"); 239 } 240 241 private: 242 friend class SkTextBlobBuilder; 243 244 enum Flags { 245 kPositioning_Mask = 0x03, // bits 0-1 reserved for positioning 246 kLast_Flag = 0x04, // set for the last blob run 247 kExtended_Flag = 0x08, // set for runs with text/cluster info 248 }; 249 250 static const RunRecord* NextUnchecked(const RunRecord* run) { 251 SkSafeMath safe; 252 auto res = reinterpret_cast<const RunRecord*>( 253 reinterpret_cast<const uint8_t*>(run) 254 + StorageSize(run->glyphCount(), run->textSize(), run->positioning(), &safe)); 255 SkASSERT(safe); 256 return res; 257 } 258 259 static size_t PosCount(uint32_t glyphCount, 260 SkTextBlob::GlyphPositioning positioning, 261 SkSafeMath* safe) { 262 return safe->mul(glyphCount, ScalarsPerGlyph(positioning)); 263 } 264 265 uint32_t* textSizePtr() const { 266 // textSize follows the position buffer. 267 SkASSERT(isExtended()); 268 SkSafeMath safe; 269 auto res = (uint32_t*)(&this->posBuffer()[PosCount(fCount, positioning(), &safe)]); 270 SkASSERT(safe); 271 return res; 272 } 273 274 void grow(uint32_t count) { 275 SkScalar* initialPosBuffer = posBuffer(); 276 uint32_t initialCount = fCount; 277 fCount += count; 278 279 // Move the initial pos scalars to their new location. 280 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning()); 281 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)NextUnchecked(this)); 282 283 // memmove, as the buffers may overlap 284 memmove(posBuffer(), initialPosBuffer, copySize); 285 } 286 287 bool isExtended() const { 288 return fFlags & kExtended_Flag; 289 } 290 291 RunFont fFont; 292 uint32_t fCount; 293 SkPoint fOffset; 294 uint32_t fFlags; 295 296 SkDEBUGCODE(unsigned fMagic;) 297 }; 298 299 static int32_t gNextID = 1; 300 static int32_t next_id() { 301 int32_t id; 302 do { 303 id = sk_atomic_inc(&gNextID); 304 } while (id == SK_InvalidGenID); 305 return id; 306 } 307 308 SkTextBlob::SkTextBlob(const SkRect& bounds) 309 : fBounds(bounds) 310 , fUniqueID(next_id()) 311 , fCacheID(SK_InvalidUniqueID) {} 312 313 SkTextBlob::~SkTextBlob() { 314 #if SK_SUPPORT_GPU 315 if (SK_InvalidUniqueID != fCacheID.load()) { 316 GrTextBlobCache::PostPurgeBlobMessage(fUniqueID, fCacheID); 317 } 318 #endif 319 320 const auto* run = RunRecord::First(this); 321 do { 322 const auto* nextRun = RunRecord::Next(run); 323 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) 324 run->~RunRecord(); 325 run = nextRun; 326 } while (run); 327 } 328 329 namespace { 330 331 union PositioningAndExtended { 332 int32_t intValue; 333 struct { 334 SkTextBlob::GlyphPositioning positioning; 335 uint8_t extended; 336 uint16_t padding; 337 }; 338 }; 339 340 static_assert(sizeof(PositioningAndExtended) == sizeof(int32_t), ""); 341 342 } // namespace 343 344 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { 345 // GlyphPositioning values are directly mapped to scalars-per-glyph. 346 SkASSERT(pos <= 2); 347 return pos; 348 } 349 350 SkTextBlobRunIterator::SkTextBlobRunIterator(const SkTextBlob* blob) 351 : fCurrentRun(SkTextBlob::RunRecord::First(blob)) { 352 SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;) 353 } 354 355 bool SkTextBlobRunIterator::done() const { 356 return !fCurrentRun; 357 } 358 359 void SkTextBlobRunIterator::next() { 360 SkASSERT(!this->done()); 361 362 if (!this->done()) { 363 SkDEBUGCODE(fCurrentRun->validate(fStorageTop);) 364 fCurrentRun = SkTextBlob::RunRecord::Next(fCurrentRun); 365 } 366 } 367 368 uint32_t SkTextBlobRunIterator::glyphCount() const { 369 SkASSERT(!this->done()); 370 return fCurrentRun->glyphCount(); 371 } 372 373 const uint16_t* SkTextBlobRunIterator::glyphs() const { 374 SkASSERT(!this->done()); 375 return fCurrentRun->glyphBuffer(); 376 } 377 378 const SkScalar* SkTextBlobRunIterator::pos() const { 379 SkASSERT(!this->done()); 380 return fCurrentRun->posBuffer(); 381 } 382 383 const SkPoint& SkTextBlobRunIterator::offset() const { 384 SkASSERT(!this->done()); 385 return fCurrentRun->offset(); 386 } 387 388 SkTextBlob::GlyphPositioning SkTextBlobRunIterator::positioning() const { 389 SkASSERT(!this->done()); 390 return fCurrentRun->positioning(); 391 } 392 393 void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const { 394 SkASSERT(!this->done()); 395 396 fCurrentRun->font().applyToPaint(paint); 397 } 398 399 uint32_t* SkTextBlobRunIterator::clusters() const { 400 SkASSERT(!this->done()); 401 return fCurrentRun->clusterBuffer(); 402 } 403 uint32_t SkTextBlobRunIterator::textSize() const { 404 SkASSERT(!this->done()); 405 return fCurrentRun->textSize(); 406 } 407 char* SkTextBlobRunIterator::text() const { 408 SkASSERT(!this->done()); 409 return fCurrentRun->textBuffer(); 410 } 411 412 413 bool SkTextBlobRunIterator::isLCD() const { 414 return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag); 415 } 416 417 SkTextBlobBuilder::SkTextBlobBuilder() 418 : fStorageSize(0) 419 , fStorageUsed(0) 420 , fRunCount(0) 421 , fDeferredBounds(false) 422 , fLastRun(0) { 423 fBounds.setEmpty(); 424 } 425 426 SkTextBlobBuilder::~SkTextBlobBuilder() { 427 if (nullptr != fStorage.get()) { 428 // We are abandoning runs and must destruct the associated font data. 429 // The easiest way to accomplish that is to use the blob destructor. 430 this->make(); 431 } 432 } 433 434 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { 435 SkRect bounds; 436 SkPaint paint; 437 run.font().applyToPaint(&paint); 438 439 if (SkTextBlob::kDefault_Positioning == run.positioning()) { 440 paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds); 441 return bounds.makeOffset(run.offset().x(), run.offset().y()); 442 } 443 444 SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount()); 445 paint.getTextWidths(run.glyphBuffer(), 446 run.glyphCount() * sizeof(uint16_t), 447 nullptr, 448 glyphBounds.get()); 449 450 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || 451 SkTextBlob::kHorizontal_Positioning == run.positioning()); 452 // kFull_Positioning => [ x, y, x, y... ] 453 // kHorizontal_Positioning => [ x, x, x... ] 454 // (const y applied by runBounds.offset(run->offset()) later) 455 const SkScalar horizontalConstY = 0; 456 const SkScalar* glyphPosX = run.posBuffer(); 457 const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ? 458 glyphPosX + 1 : &horizontalConstY; 459 const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning()); 460 const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ? 461 posXInc : 0; 462 463 bounds.setEmpty(); 464 for (unsigned i = 0; i < run.glyphCount(); ++i) { 465 bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY)); 466 glyphPosX += posXInc; 467 glyphPosY += posYInc; 468 } 469 470 SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run)); 471 472 return bounds.makeOffset(run.offset().x(), run.offset().y()); 473 } 474 475 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) { 476 SkASSERT(run.glyphCount() > 0); 477 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || 478 SkTextBlob::kHorizontal_Positioning == run.positioning()); 479 480 SkPaint paint; 481 run.font().applyToPaint(&paint); 482 const SkRect fontBounds = paint.getFontBounds(); 483 if (fontBounds.isEmpty()) { 484 // Empty font bounds are likely a font bug. TightBounds has a better chance of 485 // producing useful results in this case. 486 return TightRunBounds(run); 487 } 488 489 // Compute the glyph position bbox. 490 SkRect bounds; 491 switch (run.positioning()) { 492 case SkTextBlob::kHorizontal_Positioning: { 493 const SkScalar* glyphPos = run.posBuffer(); 494 SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run)); 495 496 SkScalar minX = *glyphPos; 497 SkScalar maxX = *glyphPos; 498 for (unsigned i = 1; i < run.glyphCount(); ++i) { 499 SkScalar x = glyphPos[i]; 500 minX = SkMinScalar(x, minX); 501 maxX = SkMaxScalar(x, maxX); 502 } 503 504 bounds.setLTRB(minX, 0, maxX, 0); 505 } break; 506 case SkTextBlob::kFull_Positioning: { 507 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuffer()); 508 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecord::Next(&run)); 509 510 bounds.setBounds(glyphPosPts, run.glyphCount()); 511 } break; 512 default: 513 SK_ABORT("unsupported positioning mode"); 514 } 515 516 // Expand by typeface glyph bounds. 517 bounds.fLeft += fontBounds.left(); 518 bounds.fTop += fontBounds.top(); 519 bounds.fRight += fontBounds.right(); 520 bounds.fBottom += fontBounds.bottom(); 521 522 // Offset by run position. 523 return bounds.makeOffset(run.offset().x(), run.offset().y()); 524 } 525 526 void SkTextBlobBuilder::updateDeferredBounds() { 527 SkASSERT(!fDeferredBounds || fRunCount > 0); 528 529 if (!fDeferredBounds) { 530 return; 531 } 532 533 SkASSERT(fLastRun >= sizeof(SkTextBlob)); 534 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + 535 fLastRun); 536 537 // FIXME: we should also use conservative bounds for kDefault_Positioning. 538 SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ? 539 TightRunBounds(*run) : ConservativeRunBounds(*run); 540 fBounds.join(runBounds); 541 fDeferredBounds = false; 542 } 543 544 void SkTextBlobBuilder::reserve(size_t size) { 545 SkSafeMath safe; 546 547 // We don't currently pre-allocate, but maybe someday... 548 if (safe.add(fStorageUsed, size) <= fStorageSize && safe) { 549 return; 550 } 551 552 if (0 == fRunCount) { 553 SkASSERT(nullptr == fStorage.get()); 554 SkASSERT(0 == fStorageSize); 555 SkASSERT(0 == fStorageUsed); 556 557 // the first allocation also includes blob storage 558 fStorageUsed = sizeof(SkTextBlob); 559 } 560 561 fStorageSize = safe.add(fStorageUsed, size); 562 563 // FYI: This relies on everything we store being relocatable, particularly SkPaint. 564 // Also, this is counting on the underlying realloc to throw when passed max(). 565 fStorage.realloc(safe ? fStorageSize : std::numeric_limits<size_t>::max()); 566 } 567 568 bool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioning positioning, 569 uint32_t count, SkPoint offset) { 570 if (0 == fLastRun) { 571 SkASSERT(0 == fRunCount); 572 return false; 573 } 574 575 SkASSERT(fLastRun >= sizeof(SkTextBlob)); 576 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + 577 fLastRun); 578 SkASSERT(run->glyphCount() > 0); 579 580 if (run->textSize() != 0) { 581 return false; 582 } 583 584 if (run->positioning() != positioning 585 || run->font() != font 586 || (run->glyphCount() + count < run->glyphCount())) { 587 return false; 588 } 589 590 // we can merge same-font/same-positioning runs in the following cases: 591 // * fully positioned run following another fully positioned run 592 // * horizontally postioned run following another horizontally positioned run with the same 593 // y-offset 594 if (SkTextBlob::kFull_Positioning != positioning 595 && (SkTextBlob::kHorizontal_Positioning != positioning 596 || run->offset().y() != offset.y())) { 597 return false; 598 } 599 600 SkSafeMath safe; 601 size_t sizeDelta = 602 SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, 0, positioning, &safe) - 603 SkTextBlob::RunRecord::StorageSize(run->glyphCount() , 0, positioning, &safe); 604 if (!safe) { 605 return false; 606 } 607 608 this->reserve(sizeDelta); 609 610 // reserve may have realloced 611 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); 612 uint32_t preMergeCount = run->glyphCount(); 613 run->grow(count); 614 615 // Callers expect the buffers to point at the newly added slice, ant not at the beginning. 616 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount; 617 fCurrentRunBuffer.pos = run->posBuffer() 618 + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning); 619 620 fStorageUsed += sizeDelta; 621 622 SkASSERT(fStorageUsed <= fStorageSize); 623 run->validate(fStorage.get() + fStorageUsed); 624 625 return true; 626 } 627 628 void SkTextBlobBuilder::allocInternal(const SkPaint &font, 629 SkTextBlob::GlyphPositioning positioning, 630 int count, int textSize, SkPoint offset, 631 const SkRect* bounds) { 632 if (count <= 0 || textSize < 0 || font.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { 633 fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr }; 634 return; 635 } 636 637 if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) { 638 this->updateDeferredBounds(); 639 640 SkSafeMath safe; 641 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, positioning, &safe); 642 if (!safe) { 643 fCurrentRunBuffer = { nullptr, nullptr, nullptr, nullptr }; 644 return; 645 } 646 647 this->reserve(runSize); 648 649 SkASSERT(fStorageUsed >= sizeof(SkTextBlob)); 650 SkASSERT(fStorageUsed + runSize <= fStorageSize); 651 652 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed) 653 SkTextBlob::RunRecord(count, textSize, offset, font, positioning); 654 fCurrentRunBuffer.glyphs = run->glyphBuffer(); 655 fCurrentRunBuffer.pos = run->posBuffer(); 656 fCurrentRunBuffer.utf8text = run->textBuffer(); 657 fCurrentRunBuffer.clusters = run->clusterBuffer(); 658 659 fLastRun = fStorageUsed; 660 fStorageUsed += runSize; 661 fRunCount++; 662 663 SkASSERT(fStorageUsed <= fStorageSize); 664 run->validate(fStorage.get() + fStorageUsed); 665 } 666 SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text); 667 SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters); 668 if (!fDeferredBounds) { 669 if (bounds) { 670 fBounds.join(*bounds); 671 } else { 672 fDeferredBounds = true; 673 } 674 } 675 } 676 677 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkPaint& font, int count, 678 SkScalar x, SkScalar y, 679 int textByteCount, 680 SkString lang, 681 const SkRect* bounds) { 682 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, textByteCount, SkPoint::Make(x, y), bounds); 683 return fCurrentRunBuffer; 684 } 685 686 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const SkPaint& font, int count, 687 SkScalar y, 688 int textByteCount, 689 SkString lang, 690 const SkRect* bounds) { 691 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, textByteCount, SkPoint::Make(0, y), 692 bounds); 693 694 return fCurrentRunBuffer; 695 } 696 697 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkPaint& font, int count, 698 int textByteCount, 699 SkString lang, 700 const SkRect *bounds) { 701 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, textByteCount, SkPoint::Make(0, 0), bounds); 702 703 return fCurrentRunBuffer; 704 } 705 706 sk_sp<SkTextBlob> SkTextBlobBuilder::make() { 707 if (!fRunCount) { 708 // We don't instantiate empty blobs. 709 SkASSERT(!fStorage.get()); 710 SkASSERT(fStorageUsed == 0); 711 SkASSERT(fStorageSize == 0); 712 SkASSERT(fLastRun == 0); 713 SkASSERT(fBounds.isEmpty()); 714 return nullptr; 715 } 716 717 this->updateDeferredBounds(); 718 719 // Tag the last run as such. 720 auto* lastRun = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); 721 lastRun->fFlags |= SkTextBlob::RunRecord::kLast_Flag; 722 723 SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fBounds); 724 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;) 725 726 SkDEBUGCODE( 727 SkSafeMath safe; 728 size_t validateSize = sizeof(SkTextBlob); 729 for (const auto* run = SkTextBlob::RunRecord::First(blob); run; 730 run = SkTextBlob::RunRecord::Next(run)) { 731 validateSize += SkTextBlob::RunRecord::StorageSize( 732 run->fCount, run->textSize(), run->positioning(), &safe); 733 run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed); 734 fRunCount--; 735 } 736 SkASSERT(validateSize == fStorageUsed); 737 SkASSERT(fRunCount == 0); 738 SkASSERT(safe); 739 ) 740 741 fStorageUsed = 0; 742 fStorageSize = 0; 743 fRunCount = 0; 744 fLastRun = 0; 745 fBounds.setEmpty(); 746 747 return sk_sp<SkTextBlob>(blob); 748 } 749 750 /////////////////////////////////////////////////////////////////////////////////////////////////// 751 752 void SkTextBlob::flatten(SkWriteBuffer& buffer) const { 753 buffer.writeRect(fBounds); 754 755 SkPaint runPaint; 756 SkTextBlobRunIterator it(this); 757 while (!it.done()) { 758 SkASSERT(it.glyphCount() > 0); 759 760 buffer.write32(it.glyphCount()); 761 PositioningAndExtended pe; 762 pe.intValue = 0; 763 pe.positioning = it.positioning(); 764 SkASSERT((int32_t)it.positioning() == pe.intValue); // backwards compat. 765 766 uint32_t textSize = it.textSize(); 767 pe.extended = textSize > 0; 768 buffer.write32(pe.intValue); 769 if (pe.extended) { 770 buffer.write32(textSize); 771 } 772 buffer.writePoint(it.offset()); 773 // This should go away when switching to SkFont 774 it.applyFontToPaint(&runPaint); 775 buffer.writePaint(runPaint); 776 777 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t)); 778 buffer.writeByteArray(it.pos(), 779 it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning())); 780 if (pe.extended) { 781 buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCount()); 782 buffer.writeByteArray(it.text(), it.textSize()); 783 } 784 785 it.next(); 786 } 787 788 // Marker for the last run (0 is not a valid glyph count). 789 buffer.write32(0); 790 } 791 792 sk_sp<SkTextBlob> SkTextBlob::MakeFromBuffer(SkReadBuffer& reader) { 793 SkRect bounds; 794 reader.readRect(&bounds); 795 796 SkTextBlobBuilder blobBuilder; 797 for (;;) { 798 int glyphCount = reader.read32(); 799 if (glyphCount == 0) { 800 // End-of-runs marker. 801 break; 802 } 803 804 PositioningAndExtended pe; 805 pe.intValue = reader.read32(); 806 GlyphPositioning pos = pe.positioning; 807 if (glyphCount <= 0 || pos > kFull_Positioning) { 808 return nullptr; 809 } 810 int textSize = pe.extended ? reader.read32() : 0; 811 if (textSize < 0) { 812 return nullptr; 813 } 814 815 SkPoint offset; 816 reader.readPoint(&offset); 817 SkPaint font; 818 reader.readPaint(&font); 819 820 if (!reader.isValid()) { 821 return nullptr; 822 } 823 824 const SkTextBlobBuilder::RunBuffer* buf = nullptr; 825 switch (pos) { 826 case kDefault_Positioning: 827 buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset.y(), 828 textSize, SkString(), &bounds); 829 break; 830 case kHorizontal_Positioning: 831 buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(), 832 textSize, SkString(), &bounds); 833 break; 834 case kFull_Positioning: 835 buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, SkString(), &bounds); 836 break; 837 default: 838 return nullptr; 839 } 840 841 if (!buf->glyphs || 842 !buf->pos || 843 (pe.extended && (!buf->clusters || !buf->utf8text))) { 844 return nullptr; 845 } 846 847 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || 848 !reader.readByteArray(buf->pos, 849 glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(pos))) { 850 return nullptr; 851 } 852 853 if (pe.extended) { 854 if (!reader.readByteArray(buf->clusters, glyphCount * sizeof(uint32_t)) || 855 !reader.readByteArray(buf->utf8text, textSize)) { 856 return nullptr; 857 } 858 } 859 } 860 861 return blobBuilder.make(); 862 } 863 864 sk_sp<SkData> SkTextBlob::serialize(const SkSerialProcs& procs) const { 865 SkBinaryWriteBuffer buffer; 866 buffer.setSerialProcs(procs); 867 this->flatten(buffer); 868 869 size_t total = buffer.bytesWritten(); 870 sk_sp<SkData> data = SkData::MakeUninitialized(total); 871 buffer.writeToMemory(data->writable_data()); 872 return data; 873 } 874 875 sk_sp<SkData> SkTextBlob::serialize() const { 876 return this->serialize(SkSerialProcs()); 877 } 878 879 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length, 880 const SkDeserialProcs& procs) { 881 SkReadBuffer buffer(data, length); 882 buffer.setDeserialProcs(procs); 883 return SkTextBlob::MakeFromBuffer(buffer); 884 } 885 886 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length) { 887 return SkTextBlob::Deserialize(data, length, SkDeserialProcs()); 888 } 889 890 /////////////////////////////////////////////////////////////////////////////////////////////////// 891 892 namespace { 893 struct CatalogState { 894 SkTypefaceCatalogerProc fProc; 895 void* fCtx; 896 }; 897 898 sk_sp<SkData> catalog_typeface_proc(SkTypeface* face, void* ctx) { 899 CatalogState* state = static_cast<CatalogState*>(ctx); 900 state->fProc(face, state->fCtx); 901 uint32_t id = face->uniqueID(); 902 return SkData::MakeWithCopy(&id, sizeof(uint32_t)); 903 } 904 } 905 906 sk_sp<SkData> SkTextBlob::serialize(SkTypefaceCatalogerProc proc, void* ctx) const { 907 CatalogState state = { proc, ctx }; 908 SkSerialProcs procs; 909 procs.fTypefaceProc = catalog_typeface_proc; 910 procs.fTypefaceCtx = &state; 911 return this->serialize(procs); 912 } 913 914 namespace { 915 struct ResolverState { 916 SkTypefaceResolverProc fProc; 917 void* fCtx; 918 }; 919 920 sk_sp<SkTypeface> resolver_typeface_proc(const void* data, size_t length, void* ctx) { 921 if (length != 4) { 922 return nullptr; 923 } 924 925 ResolverState* state = static_cast<ResolverState*>(ctx); 926 uint32_t id; 927 memcpy(&id, data, length); 928 return state->fProc(id, state->fCtx); 929 } 930 } 931 932 sk_sp<SkTextBlob> SkTextBlob::Deserialize(const void* data, size_t length, 933 SkTypefaceResolverProc proc, void* ctx) { 934 ResolverState state = { proc, ctx }; 935 SkDeserialProcs procs; 936 procs.fTypefaceProc = resolver_typeface_proc; 937 procs.fTypefaceCtx = &state; 938 return Deserialize(data, length, procs); 939 } 940