Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/core/SkTextBlob.cpp

Issue 581173003: Souped-up SkTextBlob (reland) (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: minor cleanup Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkTextBlob.h" 8 #include "SkTextBlob.h"
9 9
10 #include "SkReadBuffer.h" 10 #include "SkReadBuffer.h"
11 #include "SkWriteBuffer.h" 11 #include "SkWriteBuffer.h"
12 12
13 SkTextBlob::SkTextBlob(uint16_t *glyphs, SkScalar *pos, const SkTArray<Run> *run s, 13 //
14 const SkRect& bounds) 14 // Textblob data is laid out into externally-managed storage as follows:
15 : fGlyphBuffer(glyphs) 15 //
16 , fPosBuffer(pos) 16 // -------------------------------------------------------------------------- ---
17 , fRuns(runs) 17 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
18 // -------------------------------------------------------------------------- ---
19 //
20 // Each run record describes a text blob run, and can be used to determine the (implicit)
21 // location of the following record.
22
23 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
24
25 class SkTextBlob::RunRecord {
26 public:
27 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphP ositioning pos)
28 : fCount(count)
29 , fOffset(offset)
30 , fFont(font)
31 , fPositioning(pos) {
32 SkDEBUGCODE(fMagic = kRunRecordMagic);
33 }
34
35 uint32_t glyphCount() const {
36 return fCount;
37 }
38
39 const SkPoint& offset() const {
40 return fOffset;
41 }
42
43 const SkPaint& font() const {
44 return fFont;
45 }
46
47 GlyphPositioning positioning() const {
48 return fPositioning;
49 }
50
51 uint16_t* glyphBuffer() const {
52 // Glyph are stored immediately following the record.
53 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
54 }
55
56 SkScalar* posBuffer() const {
57 // Position scalars follow the (aligned) glyph buffer.
58 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyp hBuffer()) +
59 SkAlign4(fCount * sizeof(uint16_t)));
60 }
61
62 static size_t StorageSize(int glyphCount, SkTextBlob::GlyphPositioning posit ioning) {
mtklein 2014/09/19 14:33:02 Let's use SkAlignPtr. RunRecord contains pointers
f(malita) 2014/09/19 15:42:36 Done.
63 // RunRecord object + (aligned) glyph buffer + position buffer
64 size_t size = sizeof(SkTextBlob::RunRecord)
65 + SkAlign4(glyphCount* sizeof(uint16_t))
66 + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(positionin g);
67
68 SkASSERT(SkIsAlign4(size));
69 return size;
70 }
71
72 static const RunRecord* First(const SkTextBlob* blob) {
73 // The first record (if present) is stored following the blob object.
74 return reinterpret_cast<const RunRecord*>(blob + 1);
75 }
76
77 static const RunRecord* Next(const RunRecord* run) {
78 return reinterpret_cast<const RunRecord*>(reinterpret_cast<const uint8_t *>(run)
79 + StorageSize(run->glyphCount(), run->positioning()));
80 }
81
82 void validate(uint8_t* storageTop) const {
83 SkASSERT(kRunRecordMagic == fMagic);
84 SkASSERT((uint8_t*)Next(this) <= storageTop);
85 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
86 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) == (SkScal ar*)Next(this));
87 }
88
89 private:
90 friend class SkTextBlobBuilder;
91
92 void grow(uint32_t count) {
93 SkScalar* initialPosBuffer = posBuffer();
94 uint32_t initialCount = fCount;
95 fCount += count;
96
97 // Move the initial pos scalars to their new location.
98 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning);
99 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this));
100
101 // memmove, as the buffers may overlap
102 memmove(posBuffer(), initialPosBuffer, copySize);
103 }
104
105 uint32_t fCount;
106 SkPoint fOffset;
107 SkPaint fFont;
108 GlyphPositioning fPositioning;
109
110 SkDEBUGCODE(unsigned fMagic;)
111 };
112
113 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds)
114 : fRunCount(runCount)
18 , fBounds(bounds) { 115 , fBounds(bounds) {
19 } 116 }
20 117
118 SkTextBlob::~SkTextBlob() {
119 const RunRecord* run = RunRecord::First(this);
120 for (int i = 0; i < fRunCount; ++i) {
121 const RunRecord* nextRun = RunRecord::Next(run);
122 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
123 run->~RunRecord();
124 run = nextRun;
125 }
126 }
127
128 void SkTextBlob::internal_dispose() const {
129 // SkTextBlobs use externally-managed storage.
130 this->internal_dispose_restore_refcnt_to_1();
131 this->~SkTextBlob();
132 sk_free(const_cast<SkTextBlob*>(this));
133 }
134
21 uint32_t SkTextBlob::uniqueID() const { 135 uint32_t SkTextBlob::uniqueID() const {
22 static int32_t gTextBlobGenerationID; // = 0; 136 static int32_t gTextBlobGenerationID; // = 0;
23 137
24 // loop in case our global wraps around, as we never want to return SK_Inval idGenID 138 // loop in case our global wraps around, as we never want to return SK_Inval idGenID
25 while (SK_InvalidGenID == fUniqueID) { 139 while (SK_InvalidGenID == fUniqueID) {
26 fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1; 140 fUniqueID = sk_atomic_inc(&gTextBlobGenerationID) + 1;
27 } 141 }
28 142
29 return fUniqueID; 143 return fUniqueID;
30 } 144 }
31 145
32 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
33 // GlyphPositioning values are directly mapped to scalars-per-glyph.
34 SkASSERT(pos <= 2);
35 return pos;
36 }
37
38 void SkTextBlob::flatten(SkWriteBuffer& buffer) const { 146 void SkTextBlob::flatten(SkWriteBuffer& buffer) const {
39 int runCount = (NULL == fRuns.get()) ? 0 : fRuns->count(); 147 int runCount = fRunCount;
40 148
41 buffer.write32(runCount); 149 buffer.write32(runCount);
42 buffer.writeRect(fBounds); 150 buffer.writeRect(fBounds);
43 151
44 SkPaint runPaint; 152 SkPaint runPaint;
45 RunIterator it(this); 153 RunIterator it(this);
46 while (!it.done()) { 154 while (!it.done()) {
47 SkASSERT(it.glyphCount() > 0); 155 SkASSERT(it.glyphCount() > 0);
48 156
49 buffer.write32(it.glyphCount()); 157 buffer.write32(it.glyphCount());
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bound s); 202 buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bound s);
95 break; 203 break;
96 case kFull_Positioning: 204 case kFull_Positioning:
97 buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds); 205 buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds);
98 break; 206 break;
99 default: 207 default:
100 return NULL; 208 return NULL;
101 } 209 }
102 210
103 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || 211 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) ||
104 !reader.readByteArray(buf->pos, glyphCount * sizeof(SkScalar) * Scal arsPerGlyph(pos))) { 212 !reader.readByteArray(buf->pos,
213 glyphCount * sizeof(SkScalar) * ScalarsPerGlyp h(pos))) {
105 return NULL; 214 return NULL;
106 } 215 }
107 } 216 }
108 217
109 return blobBuilder.build(); 218 return blobBuilder.build();
110 } 219 }
111 220
221 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
222 // GlyphPositioning values are directly mapped to scalars-per-glyph.
223 SkASSERT(pos <= 2);
224 return pos;
225 }
226
112 SkTextBlob::RunIterator::RunIterator(const SkTextBlob* blob) 227 SkTextBlob::RunIterator::RunIterator(const SkTextBlob* blob)
113 : fBlob(blob) 228 : fCurrentRun(RunRecord::First(blob))
114 , fIndex(0) { 229 , fRemainingRuns(blob->fRunCount) {
115 SkASSERT(blob); 230 SkDEBUGCODE(fStorageTop = (uint8_t*)blob + blob->fStorageSize;)
116 } 231 }
117 232
118 bool SkTextBlob::RunIterator::done() const { 233 bool SkTextBlob::RunIterator::done() const {
119 return NULL == fBlob->fRuns.get() || fIndex >= fBlob->fRuns->count(); 234 return fRemainingRuns <= 0;
120 } 235 }
121 236
122 void SkTextBlob::RunIterator::next() { 237 void SkTextBlob::RunIterator::next() {
123 SkASSERT(!this->done()); 238 SkASSERT(!this->done());
124 fIndex++; 239
240 if (!this->done()) {
241 SkDEBUGCODE(fCurrentRun->validate(fStorageTop);)
242 fCurrentRun = RunRecord::Next(fCurrentRun);
243 fRemainingRuns--;
244 }
125 } 245 }
126 246
127 uint32_t SkTextBlob::RunIterator::glyphCount() const { 247 uint32_t SkTextBlob::RunIterator::glyphCount() const {
128 SkASSERT(!this->done()); 248 SkASSERT(!this->done());
129 return (*fBlob->fRuns)[fIndex].count; 249 return fCurrentRun->glyphCount();
130 } 250 }
131 251
132 const uint16_t* SkTextBlob::RunIterator::glyphs() const { 252 const uint16_t* SkTextBlob::RunIterator::glyphs() const {
133 SkASSERT(!this->done()); 253 SkASSERT(!this->done());
134 return fBlob->fGlyphBuffer.get() + (*fBlob->fRuns)[fIndex].glyphStart; 254 return fCurrentRun->glyphBuffer();
135 } 255 }
136 256
137 const SkScalar* SkTextBlob::RunIterator::pos() const { 257 const SkScalar* SkTextBlob::RunIterator::pos() const {
138 SkASSERT(!this->done()); 258 SkASSERT(!this->done());
139 return fBlob->fPosBuffer.get() + (*fBlob->fRuns)[fIndex].posStart; 259 return fCurrentRun->posBuffer();
140 } 260 }
141 261
142 const SkPoint& SkTextBlob::RunIterator::offset() const { 262 const SkPoint& SkTextBlob::RunIterator::offset() const {
143 SkASSERT(!this->done()); 263 SkASSERT(!this->done());
144 return (*fBlob->fRuns)[fIndex].offset; 264 return fCurrentRun->offset();
145 } 265 }
146 266
147 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { 267 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const {
148 SkASSERT(!this->done()); 268 SkASSERT(!this->done());
149 return (*fBlob->fRuns)[fIndex].positioning; 269 return fCurrentRun->positioning();
150 } 270 }
151 271
152 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { 272 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const {
153 SkASSERT(!this->done()); 273 SkASSERT(!this->done());
154 274
155 const SkPaint& font = (*fBlob->fRuns)[fIndex].font; 275 const SkPaint& font = fCurrentRun->font();
156 276
157 paint->setTypeface(font.getTypeface()); 277 paint->setTypeface(font.getTypeface());
158 paint->setTextEncoding(font.getTextEncoding()); 278 paint->setTextEncoding(font.getTextEncoding());
159 paint->setTextSize(font.getTextSize()); 279 paint->setTextSize(font.getTextSize());
160 paint->setTextScaleX(font.getTextScaleX()); 280 paint->setTextScaleX(font.getTextScaleX());
161 paint->setTextSkewX(font.getTextSkewX()); 281 paint->setTextSkewX(font.getTextSkewX());
162 paint->setHinting(font.getHinting()); 282 paint->setHinting(font.getHinting());
163 283
164 uint32_t flagsMask = SkPaint::kAntiAlias_Flag 284 uint32_t flagsMask = SkPaint::kAntiAlias_Flag
165 | SkPaint::kUnderlineText_Flag 285 | SkPaint::kUnderlineText_Flag
166 | SkPaint::kStrikeThruText_Flag 286 | SkPaint::kStrikeThruText_Flag
167 | SkPaint::kFakeBoldText_Flag 287 | SkPaint::kFakeBoldText_Flag
168 | SkPaint::kLinearText_Flag 288 | SkPaint::kLinearText_Flag
169 | SkPaint::kSubpixelText_Flag 289 | SkPaint::kSubpixelText_Flag
170 | SkPaint::kDevKernText_Flag 290 | SkPaint::kDevKernText_Flag
171 | SkPaint::kLCDRenderText_Flag 291 | SkPaint::kLCDRenderText_Flag
172 | SkPaint::kEmbeddedBitmapText_Flag 292 | SkPaint::kEmbeddedBitmapText_Flag
173 | SkPaint::kAutoHinting_Flag 293 | SkPaint::kAutoHinting_Flag
174 | SkPaint::kVerticalText_Flag 294 | SkPaint::kVerticalText_Flag
175 | SkPaint::kGenA8FromLCD_Flag 295 | SkPaint::kGenA8FromLCD_Flag
176 | SkPaint::kDistanceFieldTextTEMP_Flag; 296 | SkPaint::kDistanceFieldTextTEMP_Flag;
177 paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsM ask)); 297 paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsM ask));
178 } 298 }
179 299
180 SkTextBlobBuilder::SkTextBlobBuilder(unsigned runs) 300 SkTextBlobBuilder::SkTextBlobBuilder()
181 : fRuns(NULL) 301 : fStorageSize(0)
182 , fDeferredBounds(false) { 302 , fStorageUsed(0)
183 303 , fRunCount(0)
184 if (runs > 0) { 304 , fDeferredBounds(false)
185 // if the number of runs is known, size our run storage accordingly. 305 , fLastRun(0) {
186 fRuns = SkNEW(SkTArray<SkTextBlob::Run>(runs));
187 }
188 fBounds.setEmpty(); 306 fBounds.setEmpty();
189 } 307 }
190 308
191 SkTextBlobBuilder::~SkTextBlobBuilder() { 309 SkTextBlobBuilder::~SkTextBlobBuilder() {
192 // unused runs 310 if (NULL != fStorage.get()) {
193 SkDELETE(fRuns); 311 // We are abandoning runs and must destruct the associated font data.
312 // The easiest way to accomplish that is to use the blob destructor.
313 build()->unref();
314 }
194 } 315 }
195 316
196 void SkTextBlobBuilder::updateDeferredBounds() { 317 void SkTextBlobBuilder::updateDeferredBounds() {
197 SkASSERT(!fDeferredBounds || (fRuns && !fRuns->empty())); 318 SkASSERT(!fDeferredBounds || fRunCount > 0);
198 319
199 if (!fDeferredBounds) { 320 if (!fDeferredBounds) {
200 return; 321 return;
201 } 322 }
202 323
203 // FIXME: measure the current run & union bounds 324 // FIXME: measure the current run & union bounds
204 fDeferredBounds = false; 325 fDeferredBounds = false;
205 } 326 }
206 327
207 void SkTextBlobBuilder::ensureRun(const SkPaint& font, SkTextBlob::GlyphPosition ing pos, 328 void SkTextBlobBuilder::reserve(size_t size) {
208 const SkPoint& offset) { 329 // We don't currently pre-allocate, but maybe someday...
209 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); 330 if (fStorageUsed + size <= fStorageSize) {
331 return;
332 }
210 333
211 if (NULL == fRuns) { 334 if (0 == fRunCount) {
212 fRuns = SkNEW(SkTArray<SkTextBlob::Run>()); 335 SkASSERT(NULL == fStorage.get());
336 SkASSERT(0 == fStorageSize);
337 SkASSERT(0 == fStorageUsed);
338
339 // the first allocation also includes blob storage
340 fStorageUsed += sizeof(SkTextBlob);
341 }
342
343 fStorageSize = fStorageUsed + size;
344 fStorage.realloc(fStorageSize);
mtklein 2014/09/19 14:33:02 // FYI: This relies on everything we store being r
f(malita) 2014/09/19 15:42:36 Done.
345 }
346
347 bool SkTextBlobBuilder::mergeRun(const SkPaint &font, SkTextBlob::GlyphPositioni ng positioning,
348 int count, SkPoint offset) {
349 if (0 == fLastRun) {
350 SkASSERT(0 == fRunCount);
351 return false;
352 }
353
354 SkASSERT(fLastRun >= sizeof(SkTextBlob));
355 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() +
356 fLastR un);
357 SkASSERT(run->glyphCount() > 0);
358
359 if (run->positioning() != positioning
360 || run->font() != font
361 || (run->glyphCount() + count < run->glyphCount())) {
362 return false;
213 } 363 }
214 364
215 // we can merge same-font/same-positioning runs in the following cases: 365 // we can merge same-font/same-positioning runs in the following cases:
216 // * fully positioned run following another fully positioned run 366 // * fully positioned run following another fully positioned run
217 // * horizontally postioned run following another horizontally positioned run with the same 367 // * horizontally postioned run following another horizontally positioned run with the same
218 // y-offset 368 // y-offset
219 if (!fRuns->empty() 369 if (SkTextBlob::kFull_Positioning != positioning
220 && fRuns->back().positioning == pos 370 && (SkTextBlob::kHorizontal_Positioning != positioning
221 && fRuns->back().font == font 371 || run->offset().y() != offset.y())) {
222 && (SkTextBlob::kFull_Positioning == fRuns->back().positioning 372 return false;
223 || (SkTextBlob::kHorizontal_Positioning == fRuns->back().positioning
224 && fRuns->back().offset.y() == offset.y()))){
225 return;
226 } 373 }
227 374
228 this->updateDeferredBounds(); 375 size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + co unt, positioning) -
376 SkTextBlob::RunRecord::StorageSize(run->glyphCount(), pos itioning);
377 this->reserve(sizeDelta);
229 378
230 // start a new run 379 // reserve may have realloced
231 SkTextBlob::Run& newRun = fRuns->push_back(); 380 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
232 newRun.count = 0; 381 uint32_t preMergeCount = run->glyphCount();
233 newRun.glyphStart = fGlyphBuffer.count(); 382 run->grow(count);
234 newRun.posStart = fPosBuffer.count(); 383
235 newRun.offset = offset; 384 // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
236 newRun.font = font; 385 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
237 newRun.positioning = pos; 386 fCurrentRunBuffer.pos = run->posBuffer()
387 + preMergeCount * SkTextBlob::ScalarsPerGlyph(position ing);
388
389 fStorageUsed += sizeDelta;
390
391 SkASSERT(fStorageUsed <= fStorageSize);
392 run->validate(fStorage.get() + fStorageUsed);
393
394 return true;
238 } 395 }
239 396
240 void SkTextBlobBuilder::allocInternal(const SkPaint &font, 397 void SkTextBlobBuilder::allocInternal(const SkPaint &font,
241 SkTextBlob::GlyphPositioning positioning, 398 SkTextBlob::GlyphPositioning positioning,
242 int count, SkPoint offset, const SkRect* b ounds) { 399 int count, SkPoint offset, const SkRect* b ounds) {
243 SkASSERT(count > 0); 400 SkASSERT(count > 0);
401 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding());
244 402
245 this->ensureRun(font, positioning, offset); 403 if (!this->mergeRun(font, positioning, count, offset)) {
404 updateDeferredBounds();
246 405
247 unsigned posScalarsPerGlyph = SkTextBlob::ScalarsPerGlyph(positioning); 406 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, positioning);
407 this->reserve(runSize);
248 408
249 fGlyphBuffer.append(count); 409 SkASSERT(fStorageUsed >= sizeof(SkTextBlob));
250 fPosBuffer.append(count * posScalarsPerGlyph); 410 SkASSERT(fStorageUsed + runSize <= fStorageSize);
251 411
252 SkASSERT(fRuns && !fRuns->empty()); 412 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
253 SkTextBlob::Run& run = fRuns->back(); 413 SkTextBlob::RunRecord(count, offset, fo nt, positioning);
254 414
255 run.count += count; 415 fCurrentRunBuffer.glyphs = run->glyphBuffer();
416 fCurrentRunBuffer.pos = run->posBuffer();
256 417
257 // The current run might have been merged, so the start offset may point to prev run data. 418 fLastRun = fStorageUsed;
258 // Start from the back (which always points to the end of the current run bu ffers) instead. 419 fStorageUsed += runSize;
259 fCurrentRunBuffer.glyphs = fGlyphBuffer.isEmpty() 420 fRunCount++;
260 ? NULL : fGlyphBuffer.end() - count; 421
261 SkASSERT(NULL == fCurrentRunBuffer.glyphs || fCurrentRunBuffer.glyphs >= fGl yphBuffer.begin()); 422 SkASSERT(fStorageUsed <= fStorageSize);
262 fCurrentRunBuffer.pos = fPosBuffer.isEmpty() 423 run->validate(fStorage.get() + fStorageUsed);
263 ? NULL : fPosBuffer.end() - count * posScalarsPerGlyph; 424 }
264 SkASSERT(NULL == fCurrentRunBuffer.pos || fCurrentRunBuffer.pos >= fPosBuffe r.begin());
265 425
266 if (!fDeferredBounds) { 426 if (!fDeferredBounds) {
267 if (bounds) { 427 if (bounds) {
268 fBounds.join(*bounds); 428 fBounds.join(*bounds);
269 } else { 429 } else {
270 fDeferredBounds = true; 430 fDeferredBounds = true;
271 } 431 }
272 } 432 }
273 } 433 }
274 434
(...skipping 15 matching lines...) Expand all
290 } 450 }
291 451
292 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint & font, int count, 452 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint & font, int count,
293 const SkRect *bounds) { 453 const SkRect *bounds) {
294 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Mak e(0, 0), bounds); 454 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Mak e(0, 0), bounds);
295 455
296 return fCurrentRunBuffer; 456 return fCurrentRunBuffer;
297 } 457 }
298 458
299 const SkTextBlob* SkTextBlobBuilder::build() { 459 const SkTextBlob* SkTextBlobBuilder::build() {
300 const SkTextBlob* blob; 460 SkASSERT((fRunCount > 0) == (NULL != fStorage.get()));
301 461
302 if (fGlyphBuffer.count() > 0) { 462 this->updateDeferredBounds();
303 // we have some glyphs, construct a real blob
304 SkASSERT(fRuns && !fRuns->empty());
305 463
306 this->updateDeferredBounds(); 464 if (0 == fRunCount) {
465 SkASSERT(NULL == fStorage.get());
466 fStorage.realloc(sizeof(SkTextBlob));
467 }
307 468
308 // ownership of all buffers is transferred to the blob 469 const SkTextBlob* blob = new (fStorage.detach()) SkTextBlob(fRunCount, fBoun ds);
309 blob = SkNEW_ARGS(SkTextBlob, (fGlyphBuffer.detach(), 470 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
310 fPosBuffer.detach(),
311 fRuns,
312 fBounds));
313 fRuns = NULL;
314 fBounds.setEmpty();
315 } else {
316 // empty blob
317 SkASSERT(NULL == fRuns || fRuns->empty());
318 SkASSERT(fBounds.isEmpty());
319 471
320 blob = SkNEW_ARGS(SkTextBlob, (NULL, NULL, NULL, SkRect::MakeEmpty())); 472 fStorageUsed = 0;
321 } 473 fStorageSize = 0;
474 fRunCount = 0;
475 fLastRun = 0;
476 fBounds.setEmpty();
322 477
323 return blob; 478 return blob;
324 } 479 }
325 480
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698