| Index: src/core/SkTextBlob.cpp
|
| diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..690d8f45533e5aac20c5772d79c1fbbc80310b2a
|
| --- /dev/null
|
| +++ b/src/core/SkTextBlob.cpp
|
| @@ -0,0 +1,209 @@
|
| +/*
|
| + * Copyright 2014 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#include "SkTextBlob.h"
|
| +
|
| +SkTextBlob::SkTextBlob(const uint16_t *glyphs, const SkScalar *pos, const SkTArray<Run> *runs,
|
| + const SkRect& bounds)
|
| + : fGlyphBuffer(glyphs)
|
| + , fPosBuffer(pos)
|
| + , fRuns(runs)
|
| + , fBounds(bounds) {
|
| +}
|
| +
|
| +SkTextBlob::~SkTextBlob() {
|
| + sk_free(const_cast<uint16_t*>(fGlyphBuffer));
|
| + sk_free(const_cast<SkScalar*>(fPosBuffer));
|
| + SkDELETE(fRuns);
|
| +}
|
| +
|
| +uint32_t SkTextBlob::uniqueID() const {
|
| + static int32_t gTextBlobGenerationID; // = 0;
|
| +
|
| + // loop in case our global wraps around, as we never want to return SK_InvalidGenID
|
| + while (SK_InvalidGenID == fUniqueID) {
|
| + fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1;
|
| + }
|
| +
|
| + return fUniqueID;
|
| +}
|
| +
|
| +const SkTextBlob::RunInfo SkTextBlob::runInfo(unsigned runIndex) const {
|
| + SkASSERT(NULL != fRuns && runIndex < (unsigned)fRuns->count());
|
| +
|
| + const Run& run = (*fRuns)[runIndex];
|
| + return RunInfo(run.count, run.positioning, fGlyphBuffer + run.glyphStart,
|
| + fPosBuffer + run.posStart, &run.font);
|
| +}
|
| +
|
| +SkTextBlobBuilder::SkTextBlobBuilder(unsigned runs)
|
| + : fRuns(NULL)
|
| + , fDeferredRunBounds(false) {
|
| +
|
| + if (runs > 0) {
|
| + // if the number of runs is known, size our run storage accordingly.
|
| + fRuns = SkNEW(SkTArray<SkTextBlob::Run>(runs));
|
| + }
|
| + fBounds.setEmpty();
|
| +}
|
| +
|
| +SkTextBlobBuilder::~SkTextBlobBuilder() {
|
| + // unused runs
|
| + SkDELETE(fRuns);
|
| +}
|
| +
|
| +void SkTextBlobBuilder::updateRunBounds() {
|
| + if (!fDeferredRunBounds) {
|
| + // Run bounds are up to date.
|
| + return;
|
| + }
|
| +
|
| + SkASSERT(NULL != fRuns && !fRuns->empty());
|
| +
|
| + // FIXME: compute run bounds.
|
| + SkRect runBounds = SkRect::MakeEmpty();
|
| +
|
| + fBounds.join(runBounds);
|
| + fDeferredRunBounds = false;
|
| +}
|
| +
|
| +void SkTextBlobBuilder::ensureRun(const SkPaint& font, SkTextBlob::Positioning pos,
|
| + unsigned count, const SkRect* runBounds) {
|
| + SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding());
|
| +
|
| + if (NULL == fRuns) {
|
| + fRuns = SkNEW(SkTArray<SkTextBlob::Run>());
|
| + }
|
| +
|
| + // same-font/same-positioning runs are merged
|
| + if (fRuns->empty() || fRuns->back().positioning != pos || fRuns->back().font != font) {
|
| + // former run bounds may need updating
|
| + updateRunBounds();
|
| +
|
| + // start a new run
|
| + SkTextBlob::Run& newRun = fRuns->push_back();
|
| + newRun.count = 0;
|
| + newRun.glyphStart = fGlyphBuffer.count();
|
| + newRun.posStart = fPosBuffer.count();
|
| + newRun.font = font;
|
| + newRun.positioning = pos;
|
| + }
|
| +
|
| + // reserve buffer storage upfront if the glyph count is known
|
| + if (count > 0) {
|
| + fGlyphBuffer.setReserve(fGlyphBuffer.count() + count);
|
| + SkASSERT(pos <= 2);
|
| + fPosBuffer.setReserve(fPosBuffer.count() + count * pos);
|
| + }
|
| +
|
| + fDeferredRunBounds |= (NULL == runBounds);
|
| + // when in deferred bounds mode, we'll compute the bounds at a later time.
|
| + if (!fDeferredRunBounds) {
|
| + fBounds.join(*runBounds);
|
| + }
|
| +}
|
| +
|
| +const SkTextBlob* SkTextBlobBuilder::build() {
|
| + const SkTextBlob* leBlob;
|
| +
|
| + if (fGlyphBuffer.count() > 0) {
|
| + // we have some glyphs, construct a real blob
|
| + SkASSERT(NULL != fRuns && !fRuns->empty());
|
| +
|
| + // last run may require deferred bounds computation
|
| + updateRunBounds();
|
| +
|
| + // ownership of all buffers is transferred to the blob
|
| + leBlob = SkNEW_ARGS(SkTextBlob, (fGlyphBuffer.detach(),
|
| + fPosBuffer.detach(),
|
| + fRuns,
|
| + fBounds));
|
| + fRuns = NULL;
|
| + fBounds.setEmpty();
|
| + } else {
|
| + // empty blob
|
| + SkASSERT(NULL == fRuns || fRuns->empty());
|
| + SkASSERT(fBounds.isEmpty());
|
| +
|
| + leBlob = SkNEW_ARGS(SkTextBlob, (NULL, NULL, NULL, SkRect::MakeEmpty()));
|
| + }
|
| +
|
| + return leBlob;
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kDefault_Positioning>::addGlyph(uint16_t glyph) {
|
| + SkASSERT(NULL != fBlobBuilder->fRuns);
|
| + SkASSERT(fBlobBuilder->fRuns->count() > 0);
|
| + SkASSERT(fBlobBuilder->fRuns->back().positioning == SkTextBlob::kDefault_Positioning);
|
| +
|
| + *fBlobBuilder->fGlyphBuffer.append() = glyph;
|
| +
|
| + fBlobBuilder->fRuns->back().count += 1;
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kDefault_Positioning>::addGlyphs(
|
| + const uint16_t glyphs[], size_t count) {
|
| +
|
| + for (size_t i = 0; i < count; ++i) {
|
| + this->addGlyph(glyphs[i]);
|
| + }
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kHorizontal_Positioning>::addGlyph(uint16_t glyph,
|
| + SkScalar x) {
|
| + SkASSERT(NULL != fBlobBuilder->fRuns);
|
| + SkASSERT(fBlobBuilder->fRuns->count() > 0);
|
| + SkASSERT(fBlobBuilder->fRuns->back().positioning == SkTextBlob::kHorizontal_Positioning);
|
| +
|
| + *fBlobBuilder->fGlyphBuffer.append() = glyph;
|
| + *fBlobBuilder->fPosBuffer.append() = x;
|
| +
|
| + fBlobBuilder->fRuns->back().count += 1;
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kHorizontal_Positioning>::addGlyphs(
|
| + const uint16_t glyphs[], const SkScalar xPos[], size_t count) {
|
| +
|
| + for (size_t i = 0; i < count; ++i) {
|
| + this->addGlyph(glyphs[i], xPos[i]);
|
| + }
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyph(uint16_t glyph,
|
| + SkScalar x,
|
| + SkScalar y) {
|
| + SkASSERT(NULL != fBlobBuilder->fRuns);
|
| + SkASSERT(fBlobBuilder->fRuns->count() > 0);
|
| + SkASSERT(fBlobBuilder->fRuns->back().positioning == SkTextBlob::kFull_Positioning);
|
| +
|
| + *fBlobBuilder->fGlyphBuffer.append() = glyph;
|
| + *fBlobBuilder->fPosBuffer.append() = x;
|
| + *fBlobBuilder->fPosBuffer.append() = y;
|
| +
|
| + fBlobBuilder->fRuns->back().count += 1;
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyph(uint16_t glyph,
|
| + SkPoint pos) {
|
| + this->addGlyph(glyph, pos.x(), pos.y());
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyphs(
|
| + const uint16_t glyphs[], const SkScalar xPos[], const SkScalar yPos[], size_t count) {
|
| +
|
| + for (size_t i = 0; i < count; ++i) {
|
| + this->addGlyph(glyphs[i], xPos[i], yPos[i]);
|
| + }
|
| +}
|
| +
|
| +void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyphs(
|
| + const uint16_t glyphs[], const SkPoint pos[], size_t count) {
|
| +
|
| + for (size_t i = 0; i < count; ++i) {
|
| + this->addGlyph(glyphs[i], pos[i].x(), pos[i].y());
|
| + }
|
| +}
|
|
|