100d5c2c6523321d25b32905ff4822f083a4173eefmalita/*
200d5c2c6523321d25b32905ff4822f083a4173eefmalita * Copyright 2014 Google Inc.
300d5c2c6523321d25b32905ff4822f083a4173eefmalita *
400d5c2c6523321d25b32905ff4822f083a4173eefmalita * Use of this source code is governed by a BSD-style license that can be
500d5c2c6523321d25b32905ff4822f083a4173eefmalita * found in the LICENSE file.
600d5c2c6523321d25b32905ff4822f083a4173eefmalita */
700d5c2c6523321d25b32905ff4822f083a4173eefmalita
800d5c2c6523321d25b32905ff4822f083a4173eefmalita#include "SkTextBlob.h"
900d5c2c6523321d25b32905ff4822f083a4173eefmalita
10b7425173f96e93b090787e2386ba5f022b6c2869fmalita#include "SkReadBuffer.h"
11b7425173f96e93b090787e2386ba5f022b6c2869fmalita#include "SkWriteBuffer.h"
12b7425173f96e93b090787e2386ba5f022b6c2869fmalita
133c196def91726913a417e703ac482bb2dbbfff27fmalita//
143c196def91726913a417e703ac482bb2dbbfff27fmalita// Textblob data is laid out into externally-managed storage as follows:
153c196def91726913a417e703ac482bb2dbbfff27fmalita//
163c196def91726913a417e703ac482bb2dbbfff27fmalita//    -----------------------------------------------------------------------------
173c196def91726913a417e703ac482bb2dbbfff27fmalita//   | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
183c196def91726913a417e703ac482bb2dbbfff27fmalita//    -----------------------------------------------------------------------------
193c196def91726913a417e703ac482bb2dbbfff27fmalita//
203c196def91726913a417e703ac482bb2dbbfff27fmalita//  Each run record describes a text blob run, and can be used to determine the (implicit)
213c196def91726913a417e703ac482bb2dbbfff27fmalita//  location of the following record.
223c196def91726913a417e703ac482bb2dbbfff27fmalita
233c196def91726913a417e703ac482bb2dbbfff27fmalitaSkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
243c196def91726913a417e703ac482bb2dbbfff27fmalita
253c196def91726913a417e703ac482bb2dbbfff27fmalitaclass SkTextBlob::RunRecord {
263c196def91726913a417e703ac482bb2dbbfff27fmalitapublic:
273c196def91726913a417e703ac482bb2dbbfff27fmalita    RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
283c196def91726913a417e703ac482bb2dbbfff27fmalita        : fCount(count)
293c196def91726913a417e703ac482bb2dbbfff27fmalita        , fOffset(offset)
303c196def91726913a417e703ac482bb2dbbfff27fmalita        , fFont(font)
313c196def91726913a417e703ac482bb2dbbfff27fmalita        , fPositioning(pos) {
323c196def91726913a417e703ac482bb2dbbfff27fmalita        SkDEBUGCODE(fMagic = kRunRecordMagic);
333c196def91726913a417e703ac482bb2dbbfff27fmalita    }
343c196def91726913a417e703ac482bb2dbbfff27fmalita
353c196def91726913a417e703ac482bb2dbbfff27fmalita    uint32_t glyphCount() const {
363c196def91726913a417e703ac482bb2dbbfff27fmalita        return fCount;
373c196def91726913a417e703ac482bb2dbbfff27fmalita    }
383c196def91726913a417e703ac482bb2dbbfff27fmalita
393c196def91726913a417e703ac482bb2dbbfff27fmalita    const SkPoint& offset() const {
403c196def91726913a417e703ac482bb2dbbfff27fmalita        return fOffset;
413c196def91726913a417e703ac482bb2dbbfff27fmalita    }
423c196def91726913a417e703ac482bb2dbbfff27fmalita
433c196def91726913a417e703ac482bb2dbbfff27fmalita    const SkPaint& font() const {
443c196def91726913a417e703ac482bb2dbbfff27fmalita        return fFont;
453c196def91726913a417e703ac482bb2dbbfff27fmalita    }
463c196def91726913a417e703ac482bb2dbbfff27fmalita
473c196def91726913a417e703ac482bb2dbbfff27fmalita    GlyphPositioning positioning() const {
483c196def91726913a417e703ac482bb2dbbfff27fmalita        return fPositioning;
493c196def91726913a417e703ac482bb2dbbfff27fmalita    }
503c196def91726913a417e703ac482bb2dbbfff27fmalita
513c196def91726913a417e703ac482bb2dbbfff27fmalita    uint16_t* glyphBuffer() const {
523c196def91726913a417e703ac482bb2dbbfff27fmalita        // Glyph are stored immediately following the record.
533c196def91726913a417e703ac482bb2dbbfff27fmalita        return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
543c196def91726913a417e703ac482bb2dbbfff27fmalita    }
553c196def91726913a417e703ac482bb2dbbfff27fmalita
563c196def91726913a417e703ac482bb2dbbfff27fmalita    SkScalar* posBuffer() const {
573c196def91726913a417e703ac482bb2dbbfff27fmalita        // Position scalars follow the (aligned) glyph buffer.
583c196def91726913a417e703ac482bb2dbbfff27fmalita        return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyphBuffer()) +
593c196def91726913a417e703ac482bb2dbbfff27fmalita                                           SkAlign4(fCount * sizeof(uint16_t)));
603c196def91726913a417e703ac482bb2dbbfff27fmalita    }
613c196def91726913a417e703ac482bb2dbbfff27fmalita
623c196def91726913a417e703ac482bb2dbbfff27fmalita    static size_t StorageSize(int glyphCount, SkTextBlob::GlyphPositioning positioning) {
633c196def91726913a417e703ac482bb2dbbfff27fmalita        // RunRecord object + (aligned) glyph buffer + position buffer
643c196def91726913a417e703ac482bb2dbbfff27fmalita        return SkAlignPtr(sizeof(SkTextBlob::RunRecord)
653c196def91726913a417e703ac482bb2dbbfff27fmalita                        + SkAlign4(glyphCount* sizeof(uint16_t))
663c196def91726913a417e703ac482bb2dbbfff27fmalita                        + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(positioning));
673c196def91726913a417e703ac482bb2dbbfff27fmalita    }
683c196def91726913a417e703ac482bb2dbbfff27fmalita
693c196def91726913a417e703ac482bb2dbbfff27fmalita    static const RunRecord* First(const SkTextBlob* blob) {
703c196def91726913a417e703ac482bb2dbbfff27fmalita        // The first record (if present) is stored following the blob object.
713c196def91726913a417e703ac482bb2dbbfff27fmalita        return reinterpret_cast<const RunRecord*>(blob + 1);
723c196def91726913a417e703ac482bb2dbbfff27fmalita    }
733c196def91726913a417e703ac482bb2dbbfff27fmalita
743c196def91726913a417e703ac482bb2dbbfff27fmalita    static const RunRecord* Next(const RunRecord* run) {
753c196def91726913a417e703ac482bb2dbbfff27fmalita        return reinterpret_cast<const RunRecord*>(reinterpret_cast<const uint8_t*>(run)
763c196def91726913a417e703ac482bb2dbbfff27fmalita            + StorageSize(run->glyphCount(), run->positioning()));
773c196def91726913a417e703ac482bb2dbbfff27fmalita    }
783c196def91726913a417e703ac482bb2dbbfff27fmalita
793c196def91726913a417e703ac482bb2dbbfff27fmalita    void validate(uint8_t* storageTop) const {
803c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(kRunRecordMagic == fMagic);
813c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT((uint8_t*)Next(this) <= storageTop);
823c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
833c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScalar*)Next(this));
843c196def91726913a417e703ac482bb2dbbfff27fmalita    }
853c196def91726913a417e703ac482bb2dbbfff27fmalita
863c196def91726913a417e703ac482bb2dbbfff27fmalitaprivate:
873c196def91726913a417e703ac482bb2dbbfff27fmalita    friend class SkTextBlobBuilder;
883c196def91726913a417e703ac482bb2dbbfff27fmalita
893c196def91726913a417e703ac482bb2dbbfff27fmalita    void grow(uint32_t count) {
903c196def91726913a417e703ac482bb2dbbfff27fmalita        SkScalar* initialPosBuffer = posBuffer();
913c196def91726913a417e703ac482bb2dbbfff27fmalita        uint32_t initialCount = fCount;
923c196def91726913a417e703ac482bb2dbbfff27fmalita        fCount += count;
933c196def91726913a417e703ac482bb2dbbfff27fmalita
943c196def91726913a417e703ac482bb2dbbfff27fmalita        // Move the initial pos scalars to their new location.
953c196def91726913a417e703ac482bb2dbbfff27fmalita        size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPositioning);
963c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this));
973c196def91726913a417e703ac482bb2dbbfff27fmalita
983c196def91726913a417e703ac482bb2dbbfff27fmalita        // memmove, as the buffers may overlap
993c196def91726913a417e703ac482bb2dbbfff27fmalita        memmove(posBuffer(), initialPosBuffer, copySize);
1003c196def91726913a417e703ac482bb2dbbfff27fmalita    }
1013c196def91726913a417e703ac482bb2dbbfff27fmalita
1023c196def91726913a417e703ac482bb2dbbfff27fmalita    uint32_t         fCount;
1033c196def91726913a417e703ac482bb2dbbfff27fmalita    SkPoint          fOffset;
1043c196def91726913a417e703ac482bb2dbbfff27fmalita    SkPaint          fFont;
1053c196def91726913a417e703ac482bb2dbbfff27fmalita    GlyphPositioning fPositioning;
1063c196def91726913a417e703ac482bb2dbbfff27fmalita
1073c196def91726913a417e703ac482bb2dbbfff27fmalita    SkDEBUGCODE(unsigned fMagic;)
1083c196def91726913a417e703ac482bb2dbbfff27fmalita};
1093c196def91726913a417e703ac482bb2dbbfff27fmalita
1103c196def91726913a417e703ac482bb2dbbfff27fmalitaSkTextBlob::SkTextBlob(int runCount, const SkRect& bounds)
1113c196def91726913a417e703ac482bb2dbbfff27fmalita    : fRunCount(runCount)
11200d5c2c6523321d25b32905ff4822f083a4173eefmalita    , fBounds(bounds) {
11300d5c2c6523321d25b32905ff4822f083a4173eefmalita}
11400d5c2c6523321d25b32905ff4822f083a4173eefmalita
1153c196def91726913a417e703ac482bb2dbbfff27fmalitaSkTextBlob::~SkTextBlob() {
1163c196def91726913a417e703ac482bb2dbbfff27fmalita    const RunRecord* run = RunRecord::First(this);
1173c196def91726913a417e703ac482bb2dbbfff27fmalita    for (int i = 0; i < fRunCount; ++i) {
1183c196def91726913a417e703ac482bb2dbbfff27fmalita        const RunRecord* nextRun = RunRecord::Next(run);
1193c196def91726913a417e703ac482bb2dbbfff27fmalita        SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
1203c196def91726913a417e703ac482bb2dbbfff27fmalita        run->~RunRecord();
1213c196def91726913a417e703ac482bb2dbbfff27fmalita        run = nextRun;
1223c196def91726913a417e703ac482bb2dbbfff27fmalita    }
1233c196def91726913a417e703ac482bb2dbbfff27fmalita}
1243c196def91726913a417e703ac482bb2dbbfff27fmalita
1253c196def91726913a417e703ac482bb2dbbfff27fmalitavoid SkTextBlob::internal_dispose() const {
1263c196def91726913a417e703ac482bb2dbbfff27fmalita    // SkTextBlobs use externally-managed storage.
1273c196def91726913a417e703ac482bb2dbbfff27fmalita    this->internal_dispose_restore_refcnt_to_1();
1283c196def91726913a417e703ac482bb2dbbfff27fmalita    this->~SkTextBlob();
1293c196def91726913a417e703ac482bb2dbbfff27fmalita    sk_free(const_cast<SkTextBlob*>(this));
1303c196def91726913a417e703ac482bb2dbbfff27fmalita}
1313c196def91726913a417e703ac482bb2dbbfff27fmalita
13200d5c2c6523321d25b32905ff4822f083a4173eefmalitauint32_t SkTextBlob::uniqueID() const {
13300d5c2c6523321d25b32905ff4822f083a4173eefmalita    static int32_t  gTextBlobGenerationID; // = 0;
13400d5c2c6523321d25b32905ff4822f083a4173eefmalita
13500d5c2c6523321d25b32905ff4822f083a4173eefmalita    // loop in case our global wraps around, as we never want to return SK_InvalidGenID
13600d5c2c6523321d25b32905ff4822f083a4173eefmalita    while (SK_InvalidGenID == fUniqueID) {
13700d5c2c6523321d25b32905ff4822f083a4173eefmalita        fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1;
13800d5c2c6523321d25b32905ff4822f083a4173eefmalita    }
13900d5c2c6523321d25b32905ff4822f083a4173eefmalita
14000d5c2c6523321d25b32905ff4822f083a4173eefmalita    return fUniqueID;
14100d5c2c6523321d25b32905ff4822f083a4173eefmalita}
14200d5c2c6523321d25b32905ff4822f083a4173eefmalita
143b7425173f96e93b090787e2386ba5f022b6c2869fmalitavoid SkTextBlob::flatten(SkWriteBuffer& buffer) const {
1443c196def91726913a417e703ac482bb2dbbfff27fmalita    int runCount = fRunCount;
145b7425173f96e93b090787e2386ba5f022b6c2869fmalita
146b7425173f96e93b090787e2386ba5f022b6c2869fmalita    buffer.write32(runCount);
147b7425173f96e93b090787e2386ba5f022b6c2869fmalita    buffer.writeRect(fBounds);
148b7425173f96e93b090787e2386ba5f022b6c2869fmalita
149b7425173f96e93b090787e2386ba5f022b6c2869fmalita    SkPaint runPaint;
150b7425173f96e93b090787e2386ba5f022b6c2869fmalita    RunIterator it(this);
151b7425173f96e93b090787e2386ba5f022b6c2869fmalita    while (!it.done()) {
152b7425173f96e93b090787e2386ba5f022b6c2869fmalita        SkASSERT(it.glyphCount() > 0);
153b7425173f96e93b090787e2386ba5f022b6c2869fmalita
154b7425173f96e93b090787e2386ba5f022b6c2869fmalita        buffer.write32(it.glyphCount());
155b7425173f96e93b090787e2386ba5f022b6c2869fmalita        buffer.write32(it.positioning());
156b7425173f96e93b090787e2386ba5f022b6c2869fmalita        buffer.writePoint(it.offset());
157b7425173f96e93b090787e2386ba5f022b6c2869fmalita        // This should go away when switching to SkFont
158b7425173f96e93b090787e2386ba5f022b6c2869fmalita        it.applyFontToPaint(&runPaint);
159b7425173f96e93b090787e2386ba5f022b6c2869fmalita        buffer.writePaint(runPaint);
160b7425173f96e93b090787e2386ba5f022b6c2869fmalita
161b7425173f96e93b090787e2386ba5f022b6c2869fmalita        buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
162b7425173f96e93b090787e2386ba5f022b6c2869fmalita        buffer.writeByteArray(it.pos(),
163b7425173f96e93b090787e2386ba5f022b6c2869fmalita            it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning()));
164b7425173f96e93b090787e2386ba5f022b6c2869fmalita
165b7425173f96e93b090787e2386ba5f022b6c2869fmalita        it.next();
166b7425173f96e93b090787e2386ba5f022b6c2869fmalita        SkDEBUGCODE(runCount--);
167b7425173f96e93b090787e2386ba5f022b6c2869fmalita    }
168b7425173f96e93b090787e2386ba5f022b6c2869fmalita    SkASSERT(0 == runCount);
169b7425173f96e93b090787e2386ba5f022b6c2869fmalita}
170b7425173f96e93b090787e2386ba5f022b6c2869fmalita
171b7425173f96e93b090787e2386ba5f022b6c2869fmalitaconst SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) {
172b7425173f96e93b090787e2386ba5f022b6c2869fmalita    int runCount = reader.read32();
173b7425173f96e93b090787e2386ba5f022b6c2869fmalita    if (runCount < 0) {
174b7425173f96e93b090787e2386ba5f022b6c2869fmalita        return NULL;
175b7425173f96e93b090787e2386ba5f022b6c2869fmalita    }
176b7425173f96e93b090787e2386ba5f022b6c2869fmalita
177b7425173f96e93b090787e2386ba5f022b6c2869fmalita    SkRect bounds;
178b7425173f96e93b090787e2386ba5f022b6c2869fmalita    reader.readRect(&bounds);
179b7425173f96e93b090787e2386ba5f022b6c2869fmalita
180b7425173f96e93b090787e2386ba5f022b6c2869fmalita    SkTextBlobBuilder blobBuilder;
181b7425173f96e93b090787e2386ba5f022b6c2869fmalita    for (int i = 0; i < runCount; ++i) {
182b7425173f96e93b090787e2386ba5f022b6c2869fmalita        int glyphCount = reader.read32();
183b7425173f96e93b090787e2386ba5f022b6c2869fmalita        GlyphPositioning pos = static_cast<GlyphPositioning>(reader.read32());
184b7425173f96e93b090787e2386ba5f022b6c2869fmalita        if (glyphCount <= 0 || pos > kFull_Positioning) {
185b7425173f96e93b090787e2386ba5f022b6c2869fmalita            return NULL;
186b7425173f96e93b090787e2386ba5f022b6c2869fmalita        }
187b7425173f96e93b090787e2386ba5f022b6c2869fmalita
188b7425173f96e93b090787e2386ba5f022b6c2869fmalita        SkPoint offset;
189b7425173f96e93b090787e2386ba5f022b6c2869fmalita        reader.readPoint(&offset);
190b7425173f96e93b090787e2386ba5f022b6c2869fmalita        SkPaint font;
191b7425173f96e93b090787e2386ba5f022b6c2869fmalita        reader.readPaint(&font);
192b7425173f96e93b090787e2386ba5f022b6c2869fmalita
193b7425173f96e93b090787e2386ba5f022b6c2869fmalita        const SkTextBlobBuilder::RunBuffer* buf = NULL;
194b7425173f96e93b090787e2386ba5f022b6c2869fmalita        switch (pos) {
195b7425173f96e93b090787e2386ba5f022b6c2869fmalita        case kDefault_Positioning:
196b7425173f96e93b090787e2386ba5f022b6c2869fmalita            buf = &blobBuilder.allocRun(font, glyphCount, offset.x(), offset.y(), &bounds);
197b7425173f96e93b090787e2386ba5f022b6c2869fmalita            break;
198b7425173f96e93b090787e2386ba5f022b6c2869fmalita        case kHorizontal_Positioning:
199b7425173f96e93b090787e2386ba5f022b6c2869fmalita            buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bounds);
200b7425173f96e93b090787e2386ba5f022b6c2869fmalita            break;
201b7425173f96e93b090787e2386ba5f022b6c2869fmalita        case kFull_Positioning:
202b7425173f96e93b090787e2386ba5f022b6c2869fmalita            buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds);
203b7425173f96e93b090787e2386ba5f022b6c2869fmalita            break;
204b7425173f96e93b090787e2386ba5f022b6c2869fmalita        default:
205b7425173f96e93b090787e2386ba5f022b6c2869fmalita            return NULL;
206b7425173f96e93b090787e2386ba5f022b6c2869fmalita        }
207b7425173f96e93b090787e2386ba5f022b6c2869fmalita
208b7425173f96e93b090787e2386ba5f022b6c2869fmalita        if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) ||
2093c196def91726913a417e703ac482bb2dbbfff27fmalita            !reader.readByteArray(buf->pos,
2103c196def91726913a417e703ac482bb2dbbfff27fmalita                                  glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(pos))) {
211b7425173f96e93b090787e2386ba5f022b6c2869fmalita            return NULL;
212b7425173f96e93b090787e2386ba5f022b6c2869fmalita        }
213b7425173f96e93b090787e2386ba5f022b6c2869fmalita    }
214b7425173f96e93b090787e2386ba5f022b6c2869fmalita
215b7425173f96e93b090787e2386ba5f022b6c2869fmalita    return blobBuilder.build();
216b7425173f96e93b090787e2386ba5f022b6c2869fmalita}
217b7425173f96e93b090787e2386ba5f022b6c2869fmalita
2183c196def91726913a417e703ac482bb2dbbfff27fmalitaunsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
2193c196def91726913a417e703ac482bb2dbbfff27fmalita    // GlyphPositioning values are directly mapped to scalars-per-glyph.
2203c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT(pos <= 2);
2213c196def91726913a417e703ac482bb2dbbfff27fmalita    return pos;
2223c196def91726913a417e703ac482bb2dbbfff27fmalita}
2233c196def91726913a417e703ac482bb2dbbfff27fmalita
22400d5c2c6523321d25b32905ff4822f083a4173eefmalitaSkTextBlob::RunIterator::RunIterator(const SkTextBlob* blob)
2253c196def91726913a417e703ac482bb2dbbfff27fmalita    : fCurrentRun(RunRecord::First(blob))
2263c196def91726913a417e703ac482bb2dbbfff27fmalita    , fRemainingRuns(blob->fRunCount) {
2273c196def91726913a417e703ac482bb2dbbfff27fmalita    SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
22800d5c2c6523321d25b32905ff4822f083a4173eefmalita}
22900d5c2c6523321d25b32905ff4822f083a4173eefmalita
23000d5c2c6523321d25b32905ff4822f083a4173eefmalitabool SkTextBlob::RunIterator::done() const {
2313c196def91726913a417e703ac482bb2dbbfff27fmalita    return fRemainingRuns <= 0;
23200d5c2c6523321d25b32905ff4822f083a4173eefmalita}
23300d5c2c6523321d25b32905ff4822f083a4173eefmalita
23400d5c2c6523321d25b32905ff4822f083a4173eefmalitavoid SkTextBlob::RunIterator::next() {
23500d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
2363c196def91726913a417e703ac482bb2dbbfff27fmalita
2373c196def91726913a417e703ac482bb2dbbfff27fmalita    if (!this->done()) {
2383c196def91726913a417e703ac482bb2dbbfff27fmalita        SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
2393c196def91726913a417e703ac482bb2dbbfff27fmalita        fCurrentRun = RunRecord::Next(fCurrentRun);
2403c196def91726913a417e703ac482bb2dbbfff27fmalita        fRemainingRuns--;
2413c196def91726913a417e703ac482bb2dbbfff27fmalita    }
24200d5c2c6523321d25b32905ff4822f083a4173eefmalita}
24300d5c2c6523321d25b32905ff4822f083a4173eefmalita
24400d5c2c6523321d25b32905ff4822f083a4173eefmalitauint32_t SkTextBlob::RunIterator::glyphCount() const {
24500d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
2463c196def91726913a417e703ac482bb2dbbfff27fmalita    return fCurrentRun->glyphCount();
24700d5c2c6523321d25b32905ff4822f083a4173eefmalita}
24800d5c2c6523321d25b32905ff4822f083a4173eefmalita
24900d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst uint16_t* SkTextBlob::RunIterator::glyphs() const {
25000d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
2513c196def91726913a417e703ac482bb2dbbfff27fmalita    return fCurrentRun->glyphBuffer();
25200d5c2c6523321d25b32905ff4822f083a4173eefmalita}
25300d5c2c6523321d25b32905ff4822f083a4173eefmalita
25400d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst SkScalar* SkTextBlob::RunIterator::pos() const {
25500d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
2563c196def91726913a417e703ac482bb2dbbfff27fmalita    return fCurrentRun->posBuffer();
25700d5c2c6523321d25b32905ff4822f083a4173eefmalita}
25800d5c2c6523321d25b32905ff4822f083a4173eefmalita
25900d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst SkPoint& SkTextBlob::RunIterator::offset() const {
26000d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
2613c196def91726913a417e703ac482bb2dbbfff27fmalita    return fCurrentRun->offset();
26200d5c2c6523321d25b32905ff4822f083a4173eefmalita}
26300d5c2c6523321d25b32905ff4822f083a4173eefmalita
26437ecbaffd1f9f6841aa562aa31a824d109d52988fmalitaSkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const {
26500d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
2663c196def91726913a417e703ac482bb2dbbfff27fmalita    return fCurrentRun->positioning();
26700d5c2c6523321d25b32905ff4822f083a4173eefmalita}
26800d5c2c6523321d25b32905ff4822f083a4173eefmalita
26937ecbaffd1f9f6841aa562aa31a824d109d52988fmalitavoid SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const {
27000d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(!this->done());
27137ecbaffd1f9f6841aa562aa31a824d109d52988fmalita
2723c196def91726913a417e703ac482bb2dbbfff27fmalita    const SkPaint& font = fCurrentRun->font();
27337ecbaffd1f9f6841aa562aa31a824d109d52988fmalita
27437ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setTypeface(font.getTypeface());
27537ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setTextEncoding(font.getTextEncoding());
27637ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setTextSize(font.getTextSize());
27737ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setTextScaleX(font.getTextScaleX());
27837ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setTextSkewX(font.getTextSkewX());
27937ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setHinting(font.getHinting());
28037ecbaffd1f9f6841aa562aa31a824d109d52988fmalita
28137ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    uint32_t flagsMask = SkPaint::kAntiAlias_Flag
28237ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kUnderlineText_Flag
28337ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kStrikeThruText_Flag
28437ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kFakeBoldText_Flag
28537ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kLinearText_Flag
28637ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kSubpixelText_Flag
28737ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kDevKernText_Flag
28837ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kLCDRenderText_Flag
28937ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kEmbeddedBitmapText_Flag
29037ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kAutoHinting_Flag
29137ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kVerticalText_Flag
29237ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kGenA8FromLCD_Flag
29337ecbaffd1f9f6841aa562aa31a824d109d52988fmalita                       | SkPaint::kDistanceFieldTextTEMP_Flag;
29437ecbaffd1f9f6841aa562aa31a824d109d52988fmalita    paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsMask));
29500d5c2c6523321d25b32905ff4822f083a4173eefmalita}
29600d5c2c6523321d25b32905ff4822f083a4173eefmalita
2973c196def91726913a417e703ac482bb2dbbfff27fmalitaSkTextBlobBuilder::SkTextBlobBuilder()
2983c196def91726913a417e703ac482bb2dbbfff27fmalita    : fStorageSize(0)
2993c196def91726913a417e703ac482bb2dbbfff27fmalita    , fStorageUsed(0)
3003c196def91726913a417e703ac482bb2dbbfff27fmalita    , fRunCount(0)
3013c196def91726913a417e703ac482bb2dbbfff27fmalita    , fDeferredBounds(false)
3023c196def91726913a417e703ac482bb2dbbfff27fmalita    , fLastRun(0) {
30300d5c2c6523321d25b32905ff4822f083a4173eefmalita    fBounds.setEmpty();
30400d5c2c6523321d25b32905ff4822f083a4173eefmalita}
30500d5c2c6523321d25b32905ff4822f083a4173eefmalita
30600d5c2c6523321d25b32905ff4822f083a4173eefmalitaSkTextBlobBuilder::~SkTextBlobBuilder() {
3073c196def91726913a417e703ac482bb2dbbfff27fmalita    if (NULL != fStorage.get()) {
3083c196def91726913a417e703ac482bb2dbbfff27fmalita        // We are abandoning runs and must destruct the associated font data.
3093c196def91726913a417e703ac482bb2dbbfff27fmalita        // The easiest way to accomplish that is to use the blob destructor.
3103c196def91726913a417e703ac482bb2dbbfff27fmalita        build()->unref();
3113c196def91726913a417e703ac482bb2dbbfff27fmalita    }
31200d5c2c6523321d25b32905ff4822f083a4173eefmalita}
31300d5c2c6523321d25b32905ff4822f083a4173eefmalita
31400d5c2c6523321d25b32905ff4822f083a4173eefmalitavoid SkTextBlobBuilder::updateDeferredBounds() {
3153c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT(!fDeferredBounds || fRunCount > 0);
31600d5c2c6523321d25b32905ff4822f083a4173eefmalita
31700d5c2c6523321d25b32905ff4822f083a4173eefmalita    if (!fDeferredBounds) {
31800d5c2c6523321d25b32905ff4822f083a4173eefmalita        return;
31900d5c2c6523321d25b32905ff4822f083a4173eefmalita    }
32000d5c2c6523321d25b32905ff4822f083a4173eefmalita
32100d5c2c6523321d25b32905ff4822f083a4173eefmalita    // FIXME: measure the current run & union bounds
32200d5c2c6523321d25b32905ff4822f083a4173eefmalita    fDeferredBounds = false;
32300d5c2c6523321d25b32905ff4822f083a4173eefmalita}
32400d5c2c6523321d25b32905ff4822f083a4173eefmalita
3253c196def91726913a417e703ac482bb2dbbfff27fmalitavoid SkTextBlobBuilder::reserve(size_t size) {
3263c196def91726913a417e703ac482bb2dbbfff27fmalita    // We don't currently pre-allocate, but maybe someday...
3273c196def91726913a417e703ac482bb2dbbfff27fmalita    if (fStorageUsed + size <= fStorageSize) {
3283c196def91726913a417e703ac482bb2dbbfff27fmalita        return;
3293c196def91726913a417e703ac482bb2dbbfff27fmalita    }
3303c196def91726913a417e703ac482bb2dbbfff27fmalita
3313c196def91726913a417e703ac482bb2dbbfff27fmalita    if (0 == fRunCount) {
3323c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(NULL == fStorage.get());
3333c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(0 == fStorageSize);
3343c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(0 == fStorageUsed);
33513645ea0ea87038ebd71be3bd6d53b313069a9e4fmalita
3363c196def91726913a417e703ac482bb2dbbfff27fmalita        // the first allocation also includes blob storage
3373c196def91726913a417e703ac482bb2dbbfff27fmalita        fStorageUsed += sizeof(SkTextBlob);
3383c196def91726913a417e703ac482bb2dbbfff27fmalita    }
3393c196def91726913a417e703ac482bb2dbbfff27fmalita
3403c196def91726913a417e703ac482bb2dbbfff27fmalita    fStorageSize = fStorageUsed + size;
3413c196def91726913a417e703ac482bb2dbbfff27fmalita    // FYI: This relies on everything we store being relocatable, particularly SkPaint.
3423c196def91726913a417e703ac482bb2dbbfff27fmalita    fStorage.realloc(fStorageSize);
3433c196def91726913a417e703ac482bb2dbbfff27fmalita}
3443c196def91726913a417e703ac482bb2dbbfff27fmalita
3453c196def91726913a417e703ac482bb2dbbfff27fmalitabool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioning positioning,
3463c196def91726913a417e703ac482bb2dbbfff27fmalita                                 int count, SkPoint offset) {
3473c196def91726913a417e703ac482bb2dbbfff27fmalita    if (0 == fLastRun) {
3483c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(0 == fRunCount);
3493c196def91726913a417e703ac482bb2dbbfff27fmalita        return false;
3503c196def91726913a417e703ac482bb2dbbfff27fmalita    }
3513c196def91726913a417e703ac482bb2dbbfff27fmalita
3523c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT(fLastRun >= sizeof(SkTextBlob));
3533c196def91726913a417e703ac482bb2dbbfff27fmalita    SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
3543c196def91726913a417e703ac482bb2dbbfff27fmalita                                                                          fLastRun);
3553c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT(run->glyphCount() > 0);
3563c196def91726913a417e703ac482bb2dbbfff27fmalita
3573c196def91726913a417e703ac482bb2dbbfff27fmalita    if (run->positioning() != positioning
3583c196def91726913a417e703ac482bb2dbbfff27fmalita        || run->font() != font
3593c196def91726913a417e703ac482bb2dbbfff27fmalita        || (run->glyphCount() + count < run->glyphCount())) {
3603c196def91726913a417e703ac482bb2dbbfff27fmalita        return false;
36100d5c2c6523321d25b32905ff4822f083a4173eefmalita    }
36200d5c2c6523321d25b32905ff4822f083a4173eefmalita
36300d5c2c6523321d25b32905ff4822f083a4173eefmalita    // we can merge same-font/same-positioning runs in the following cases:
36400d5c2c6523321d25b32905ff4822f083a4173eefmalita    //   * fully positioned run following another fully positioned run
36500d5c2c6523321d25b32905ff4822f083a4173eefmalita    //   * horizontally postioned run following another horizontally positioned run with the same
36600d5c2c6523321d25b32905ff4822f083a4173eefmalita    //     y-offset
3673c196def91726913a417e703ac482bb2dbbfff27fmalita    if (SkTextBlob::kFull_Positioning != positioning
3683c196def91726913a417e703ac482bb2dbbfff27fmalita        && (SkTextBlob::kHorizontal_Positioning != positioning
3693c196def91726913a417e703ac482bb2dbbfff27fmalita            || run->offset().y() != offset.y())) {
3703c196def91726913a417e703ac482bb2dbbfff27fmalita        return false;
37100d5c2c6523321d25b32905ff4822f083a4173eefmalita    }
37200d5c2c6523321d25b32905ff4822f083a4173eefmalita
3733c196def91726913a417e703ac482bb2dbbfff27fmalita    size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + count, positioning) -
3743c196def91726913a417e703ac482bb2dbbfff27fmalita                       SkTextBlob::RunRecord::StorageSize(run->glyphCount(), positioning);
3753c196def91726913a417e703ac482bb2dbbfff27fmalita    this->reserve(sizeDelta);
3763c196def91726913a417e703ac482bb2dbbfff27fmalita
3773c196def91726913a417e703ac482bb2dbbfff27fmalita    // reserve may have realloced
3783c196def91726913a417e703ac482bb2dbbfff27fmalita    run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
3793c196def91726913a417e703ac482bb2dbbfff27fmalita    uint32_t preMergeCount = run->glyphCount();
3803c196def91726913a417e703ac482bb2dbbfff27fmalita    run->grow(count);
38100d5c2c6523321d25b32905ff4822f083a4173eefmalita
3823c196def91726913a417e703ac482bb2dbbfff27fmalita    // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
3833c196def91726913a417e703ac482bb2dbbfff27fmalita    fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
3843c196def91726913a417e703ac482bb2dbbfff27fmalita    fCurrentRunBuffer.pos = run->posBuffer()
3853c196def91726913a417e703ac482bb2dbbfff27fmalita                          + preMergeCount * SkTextBlob::ScalarsPerGlyph(positioning);
3863c196def91726913a417e703ac482bb2dbbfff27fmalita
3873c196def91726913a417e703ac482bb2dbbfff27fmalita    fStorageUsed += sizeDelta;
3883c196def91726913a417e703ac482bb2dbbfff27fmalita
3893c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT(fStorageUsed <= fStorageSize);
3903c196def91726913a417e703ac482bb2dbbfff27fmalita    run->validate(fStorage.get() + fStorageUsed);
3913c196def91726913a417e703ac482bb2dbbfff27fmalita
3923c196def91726913a417e703ac482bb2dbbfff27fmalita    return true;
39300d5c2c6523321d25b32905ff4822f083a4173eefmalita}
39400d5c2c6523321d25b32905ff4822f083a4173eefmalita
39500d5c2c6523321d25b32905ff4822f083a4173eefmalitavoid SkTextBlobBuilder::allocInternal(const SkPaint &font,
39600d5c2c6523321d25b32905ff4822f083a4173eefmalita                                      SkTextBlob::GlyphPositioning positioning,
39700d5c2c6523321d25b32905ff4822f083a4173eefmalita                                      int count, SkPoint offset, const SkRect* bounds) {
39800d5c2c6523321d25b32905ff4822f083a4173eefmalita    SkASSERT(count > 0);
3993c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding());
40000d5c2c6523321d25b32905ff4822f083a4173eefmalita
4013c196def91726913a417e703ac482bb2dbbfff27fmalita    if (!this->mergeRun(font, positioning, count, offset)) {
4023c196def91726913a417e703ac482bb2dbbfff27fmalita        updateDeferredBounds();
40300d5c2c6523321d25b32905ff4822f083a4173eefmalita
4043c196def91726913a417e703ac482bb2dbbfff27fmalita        size_t runSize = SkTextBlob::RunRecord::StorageSize(count, positioning);
4053c196def91726913a417e703ac482bb2dbbfff27fmalita        this->reserve(runSize);
40600d5c2c6523321d25b32905ff4822f083a4173eefmalita
4073c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(fStorageUsed >= sizeof(SkTextBlob));
4083c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(fStorageUsed + runSize <= fStorageSize);
40900d5c2c6523321d25b32905ff4822f083a4173eefmalita
4103c196def91726913a417e703ac482bb2dbbfff27fmalita        SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
4113c196def91726913a417e703ac482bb2dbbfff27fmalita                                         SkTextBlob::RunRecord(count, offset, font, positioning);
41200d5c2c6523321d25b32905ff4822f083a4173eefmalita
4133c196def91726913a417e703ac482bb2dbbfff27fmalita        fCurrentRunBuffer.glyphs = run->glyphBuffer();
4143c196def91726913a417e703ac482bb2dbbfff27fmalita        fCurrentRunBuffer.pos = run->posBuffer();
41500d5c2c6523321d25b32905ff4822f083a4173eefmalita
4163c196def91726913a417e703ac482bb2dbbfff27fmalita        fLastRun = fStorageUsed;
4173c196def91726913a417e703ac482bb2dbbfff27fmalita        fStorageUsed += runSize;
4183c196def91726913a417e703ac482bb2dbbfff27fmalita        fRunCount++;
4193c196def91726913a417e703ac482bb2dbbfff27fmalita
4203c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(fStorageUsed <= fStorageSize);
4213c196def91726913a417e703ac482bb2dbbfff27fmalita        run->validate(fStorage.get() + fStorageUsed);
4223c196def91726913a417e703ac482bb2dbbfff27fmalita    }
42300d5c2c6523321d25b32905ff4822f083a4173eefmalita
42400d5c2c6523321d25b32905ff4822f083a4173eefmalita    if (!fDeferredBounds) {
42549f085dddff10473b6ebf832a974288300224e60bsalomon        if (bounds) {
42600d5c2c6523321d25b32905ff4822f083a4173eefmalita            fBounds.join(*bounds);
42700d5c2c6523321d25b32905ff4822f083a4173eefmalita        } else {
42800d5c2c6523321d25b32905ff4822f083a4173eefmalita            fDeferredBounds = true;
42900d5c2c6523321d25b32905ff4822f083a4173eefmalita        }
43000d5c2c6523321d25b32905ff4822f083a4173eefmalita    }
43100d5c2c6523321d25b32905ff4822f083a4173eefmalita}
43200d5c2c6523321d25b32905ff4822f083a4173eefmalita
43300d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkPaint& font, int count,
43400d5c2c6523321d25b32905ff4822f083a4173eefmalita                                                                SkScalar x, SkScalar y,
43500d5c2c6523321d25b32905ff4822f083a4173eefmalita                                                                const SkRect* bounds) {
43600d5c2c6523321d25b32905ff4822f083a4173eefmalita    this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, SkPoint::Make(x, y), bounds);
43700d5c2c6523321d25b32905ff4822f083a4173eefmalita
43800d5c2c6523321d25b32905ff4822f083a4173eefmalita    return fCurrentRunBuffer;
43900d5c2c6523321d25b32905ff4822f083a4173eefmalita}
44000d5c2c6523321d25b32905ff4822f083a4173eefmalita
44100d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkPaint& font, int count,
44200d5c2c6523321d25b32905ff4822f083a4173eefmalita                                                                    SkScalar y,
44300d5c2c6523321d25b32905ff4822f083a4173eefmalita                                                                    const SkRect* bounds) {
44400d5c2c6523321d25b32905ff4822f083a4173eefmalita    this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, SkPoint::Make(0, y),
44500d5c2c6523321d25b32905ff4822f083a4173eefmalita                        bounds);
44600d5c2c6523321d25b32905ff4822f083a4173eefmalita
44700d5c2c6523321d25b32905ff4822f083a4173eefmalita    return fCurrentRunBuffer;
44800d5c2c6523321d25b32905ff4822f083a4173eefmalita}
44900d5c2c6523321d25b32905ff4822f083a4173eefmalita
45000d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint& font, int count,
45100d5c2c6523321d25b32905ff4822f083a4173eefmalita                                                                   const SkRect *bounds) {
45200d5c2c6523321d25b32905ff4822f083a4173eefmalita    this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Make(0, 0), bounds);
45300d5c2c6523321d25b32905ff4822f083a4173eefmalita
45400d5c2c6523321d25b32905ff4822f083a4173eefmalita    return fCurrentRunBuffer;
45500d5c2c6523321d25b32905ff4822f083a4173eefmalita}
45600d5c2c6523321d25b32905ff4822f083a4173eefmalita
45700d5c2c6523321d25b32905ff4822f083a4173eefmalitaconst SkTextBlob* SkTextBlobBuilder::build() {
4583c196def91726913a417e703ac482bb2dbbfff27fmalita    SkASSERT((fRunCount > 0) == (NULL != fStorage.get()));
4593c196def91726913a417e703ac482bb2dbbfff27fmalita
4603c196def91726913a417e703ac482bb2dbbfff27fmalita    this->updateDeferredBounds();
4613c196def91726913a417e703ac482bb2dbbfff27fmalita
4623c196def91726913a417e703ac482bb2dbbfff27fmalita    if (0 == fRunCount) {
4633c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(NULL == fStorage.get());
4643c196def91726913a417e703ac482bb2dbbfff27fmalita        fStorageUsed = sizeof(SkTextBlob);
4653c196def91726913a417e703ac482bb2dbbfff27fmalita        fStorage.realloc(fStorageUsed);
46600d5c2c6523321d25b32905ff4822f083a4173eefmalita    }
46700d5c2c6523321d25b32905ff4822f083a4173eefmalita
4683c196def91726913a417e703ac482bb2dbbfff27fmalita    SkDEBUGCODE(
4693c196def91726913a417e703ac482bb2dbbfff27fmalita        size_t validateSize = sizeof(SkTextBlob);
4703c196def91726913a417e703ac482bb2dbbfff27fmalita        const SkTextBlob::RunRecord* run =
4713c196def91726913a417e703ac482bb2dbbfff27fmalita            SkTextBlob::RunRecord::First(reinterpret_cast<const SkTextBlob*>(fStorage.get()));
4723c196def91726913a417e703ac482bb2dbbfff27fmalita        for (int i = 0; i < fRunCount; ++i) {
4733c196def91726913a417e703ac482bb2dbbfff27fmalita            validateSize += SkTextBlob::RunRecord::StorageSize(run->fCount, run->fPositioning);
4743c196def91726913a417e703ac482bb2dbbfff27fmalita            run->validate(fStorage.get() + fStorageUsed);
4753c196def91726913a417e703ac482bb2dbbfff27fmalita            run = SkTextBlob::RunRecord::Next(run);
4763c196def91726913a417e703ac482bb2dbbfff27fmalita        }
4773c196def91726913a417e703ac482bb2dbbfff27fmalita        SkASSERT(validateSize == fStorageUsed);
4783c196def91726913a417e703ac482bb2dbbfff27fmalita    )
4793c196def91726913a417e703ac482bb2dbbfff27fmalita
4803c196def91726913a417e703ac482bb2dbbfff27fmalita    const SkTextBlob* blob = new (fStorage.detach()) SkTextBlob(fRunCount, fBounds);
4813c196def91726913a417e703ac482bb2dbbfff27fmalita    SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
4823c196def91726913a417e703ac482bb2dbbfff27fmalita
4833c196def91726913a417e703ac482bb2dbbfff27fmalita    fStorageUsed = 0;
4843c196def91726913a417e703ac482bb2dbbfff27fmalita    fStorageSize = 0;
4853c196def91726913a417e703ac482bb2dbbfff27fmalita    fRunCount = 0;
4863c196def91726913a417e703ac482bb2dbbfff27fmalita    fLastRun = 0;
4873c196def91726913a417e703ac482bb2dbbfff27fmalita    fBounds.setEmpty();
4883c196def91726913a417e703ac482bb2dbbfff27fmalita
48900d5c2c6523321d25b32905ff4822f083a4173eefmalita    return blob;
49000d5c2c6523321d25b32905ff4822f083a4173eefmalita}
49100d5c2c6523321d25b32905ff4822f083a4173eefmalita
492