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