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 "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