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()); |
+ } |
+} |