OLD | NEW |
(Empty) | |
| 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 "SkTextBlob.h" |
| 9 |
| 10 SkTextBlob::SkTextBlob(const uint16_t *glyphs, const SkScalar *pos, const SkTArr
ay<Run> *runs, |
| 11 const SkRect& bounds) |
| 12 : fGlyphBuffer(glyphs) |
| 13 , fPosBuffer(pos) |
| 14 , fRuns(runs) |
| 15 , fBounds(bounds) { |
| 16 } |
| 17 |
| 18 SkTextBlob::~SkTextBlob() { |
| 19 sk_free(const_cast<uint16_t*>(fGlyphBuffer)); |
| 20 sk_free(const_cast<SkScalar*>(fPosBuffer)); |
| 21 SkDELETE(fRuns); |
| 22 } |
| 23 |
| 24 uint32_t SkTextBlob::uniqueID() const { |
| 25 static int32_t gTextBlobGenerationID; // = 0; |
| 26 |
| 27 // loop in case our global wraps around, as we never want to return SK_Inval
idGenID |
| 28 while (SK_InvalidGenID == fUniqueID) { |
| 29 fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1; |
| 30 } |
| 31 |
| 32 return fUniqueID; |
| 33 } |
| 34 |
| 35 const SkTextBlob::RunInfo SkTextBlob::runInfo(unsigned runIndex) const { |
| 36 SkASSERT(NULL != fRuns && runIndex < (unsigned)fRuns->count()); |
| 37 |
| 38 const Run& run = (*fRuns)[runIndex]; |
| 39 return RunInfo(run.count, run.positioning, fGlyphBuffer + run.glyphStart, |
| 40 fPosBuffer + run.posStart, &run.font); |
| 41 } |
| 42 |
| 43 SkTextBlobBuilder::SkTextBlobBuilder(unsigned runs) |
| 44 : fRuns(NULL) |
| 45 , fDeferredRunBounds(false) { |
| 46 |
| 47 if (runs > 0) { |
| 48 // if the number of runs is known, size our run storage accordingly. |
| 49 fRuns = SkNEW(SkTArray<SkTextBlob::Run>(runs)); |
| 50 } |
| 51 fBounds.setEmpty(); |
| 52 } |
| 53 |
| 54 SkTextBlobBuilder::~SkTextBlobBuilder() { |
| 55 // unused runs |
| 56 SkDELETE(fRuns); |
| 57 } |
| 58 |
| 59 void SkTextBlobBuilder::updateRunBounds() { |
| 60 if (!fDeferredRunBounds) { |
| 61 // Run bounds are up to date. |
| 62 return; |
| 63 } |
| 64 |
| 65 SkASSERT(NULL != fRuns && !fRuns->empty()); |
| 66 |
| 67 // FIXME: compute run bounds. |
| 68 SkRect runBounds = SkRect::MakeEmpty(); |
| 69 |
| 70 fBounds.join(runBounds); |
| 71 fDeferredRunBounds = false; |
| 72 } |
| 73 |
| 74 void SkTextBlobBuilder::ensureRun(const SkPaint& font, SkTextBlob::Positioning p
os, |
| 75 unsigned count, const SkRect* runBounds) { |
| 76 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); |
| 77 |
| 78 if (NULL == fRuns) { |
| 79 fRuns = SkNEW(SkTArray<SkTextBlob::Run>()); |
| 80 } |
| 81 |
| 82 // same-font/same-positioning runs are merged |
| 83 if (fRuns->empty() || fRuns->back().positioning != pos || fRuns->back().font
!= font) { |
| 84 // former run bounds may need updating |
| 85 updateRunBounds(); |
| 86 |
| 87 // start a new run |
| 88 SkTextBlob::Run& newRun = fRuns->push_back(); |
| 89 newRun.count = 0; |
| 90 newRun.glyphStart = fGlyphBuffer.count(); |
| 91 newRun.posStart = fPosBuffer.count(); |
| 92 newRun.font = font; |
| 93 newRun.positioning = pos; |
| 94 } |
| 95 |
| 96 // reserve buffer storage upfront if the glyph count is known |
| 97 if (count > 0) { |
| 98 fGlyphBuffer.setReserve(fGlyphBuffer.count() + count); |
| 99 SkASSERT(pos <= 2); |
| 100 fPosBuffer.setReserve(fPosBuffer.count() + count * pos); |
| 101 } |
| 102 |
| 103 fDeferredRunBounds |= (NULL == runBounds); |
| 104 // when in deferred bounds mode, we'll compute the bounds at a later time. |
| 105 if (!fDeferredRunBounds) { |
| 106 fBounds.join(*runBounds); |
| 107 } |
| 108 } |
| 109 |
| 110 const SkTextBlob* SkTextBlobBuilder::build() { |
| 111 const SkTextBlob* leBlob; |
| 112 |
| 113 if (fGlyphBuffer.count() > 0) { |
| 114 // we have some glyphs, construct a real blob |
| 115 SkASSERT(NULL != fRuns && !fRuns->empty()); |
| 116 |
| 117 // last run may require deferred bounds computation |
| 118 updateRunBounds(); |
| 119 |
| 120 // ownership of all buffers is transferred to the blob |
| 121 leBlob = SkNEW_ARGS(SkTextBlob, (fGlyphBuffer.detach(), |
| 122 fPosBuffer.detach(), |
| 123 fRuns, |
| 124 fBounds)); |
| 125 fRuns = NULL; |
| 126 fBounds.setEmpty(); |
| 127 } else { |
| 128 // empty blob |
| 129 SkASSERT(NULL == fRuns || fRuns->empty()); |
| 130 SkASSERT(fBounds.isEmpty()); |
| 131 |
| 132 leBlob = SkNEW_ARGS(SkTextBlob, (NULL, NULL, NULL, SkRect::MakeEmpty()))
; |
| 133 } |
| 134 |
| 135 return leBlob; |
| 136 } |
| 137 |
| 138 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kDefault_Positioning>::addGlyph(u
int16_t glyph) { |
| 139 SkASSERT(NULL != fBlobBuilder->fRuns); |
| 140 SkASSERT(fBlobBuilder->fRuns->count() > 0); |
| 141 SkASSERT(fBlobBuilder->fRuns->back().positioning == SkTextBlob::kDefault_Pos
itioning); |
| 142 |
| 143 *fBlobBuilder->fGlyphBuffer.append() = glyph; |
| 144 |
| 145 fBlobBuilder->fRuns->back().count += 1; |
| 146 } |
| 147 |
| 148 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kDefault_Positioning>::addGlyphs( |
| 149 const uint16_t glyphs[], size_t count) { |
| 150 |
| 151 for (size_t i = 0; i < count; ++i) { |
| 152 this->addGlyph(glyphs[i]); |
| 153 } |
| 154 } |
| 155 |
| 156 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kHorizontal_Positioning>::addGlyp
h(uint16_t glyph, |
| 157 Sk
Scalar x) { |
| 158 SkASSERT(NULL != fBlobBuilder->fRuns); |
| 159 SkASSERT(fBlobBuilder->fRuns->count() > 0); |
| 160 SkASSERT(fBlobBuilder->fRuns->back().positioning == SkTextBlob::kHorizontal_
Positioning); |
| 161 |
| 162 *fBlobBuilder->fGlyphBuffer.append() = glyph; |
| 163 *fBlobBuilder->fPosBuffer.append() = x; |
| 164 |
| 165 fBlobBuilder->fRuns->back().count += 1; |
| 166 } |
| 167 |
| 168 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kHorizontal_Positioning>::addGlyp
hs( |
| 169 const uint16_t glyphs[], const SkScalar xPos[], size_t count) { |
| 170 |
| 171 for (size_t i = 0; i < count; ++i) { |
| 172 this->addGlyph(glyphs[i], xPos[i]); |
| 173 } |
| 174 } |
| 175 |
| 176 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyph(uint
16_t glyph, |
| 177 SkS
calar x, |
| 178 SkS
calar y) { |
| 179 SkASSERT(NULL != fBlobBuilder->fRuns); |
| 180 SkASSERT(fBlobBuilder->fRuns->count() > 0); |
| 181 SkASSERT(fBlobBuilder->fRuns->back().positioning == SkTextBlob::kFull_Positi
oning); |
| 182 |
| 183 *fBlobBuilder->fGlyphBuffer.append() = glyph; |
| 184 *fBlobBuilder->fPosBuffer.append() = x; |
| 185 *fBlobBuilder->fPosBuffer.append() = y; |
| 186 |
| 187 fBlobBuilder->fRuns->back().count += 1; |
| 188 } |
| 189 |
| 190 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyph(uint
16_t glyph, |
| 191 SkPo
int pos) { |
| 192 this->addGlyph(glyph, pos.x(), pos.y()); |
| 193 } |
| 194 |
| 195 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyphs( |
| 196 const uint16_t glyphs[], const SkScalar xPos[], const SkScalar yPos[], s
ize_t count) { |
| 197 |
| 198 for (size_t i = 0; i < count; ++i) { |
| 199 this->addGlyph(glyphs[i], xPos[i], yPos[i]); |
| 200 } |
| 201 } |
| 202 |
| 203 void SkTextBlobBuilder::RunBuilder<SkTextBlob::kFull_Positioning>::addGlyphs( |
| 204 const uint16_t glyphs[], const SkPoint pos[], size_t count) { |
| 205 |
| 206 for (size_t i = 0; i < count; ++i) { |
| 207 this->addGlyph(glyphs[i], pos[i].x(), pos[i].y()); |
| 208 } |
| 209 } |
OLD | NEW |