Home | History | Annotate | Download | only in core
      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