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

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

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

Powered by Google App Engine
This is Rietveld 408576698