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

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

Issue 2084533004: SkTextBlob: Begin implementing Extended TextBlob API (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-06-24 (Friday) 17:22:15 EDT Created 4 years, 5 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 "SkTextBlobRunIterator.h" 8 #include "SkTextBlobRunIterator.h"
9 9
10 #include "SkReadBuffer.h" 10 #include "SkReadBuffer.h"
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 uint32_t fFlags; 93 uint32_t fFlags;
94 }; 94 };
95 static_assert(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), "runfont_shou ld_stay_packed"); 95 static_assert(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), "runfont_shou ld_stay_packed");
96 96
97 } // anonymous namespace 97 } // anonymous namespace
98 98
99 // 99 //
100 // Textblob data is laid out into externally-managed storage as follows: 100 // Textblob data is laid out into externally-managed storage as follows:
101 // 101 //
102 // -------------------------------------------------------------------------- --- 102 // -------------------------------------------------------------------------- ---
103 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... 103 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ...
f(malita) 2016/06/27 20:21:55 We should also update this layout diagram w/ text
hal.canary 2016/06/28 15:39:12 Done.
104 // -------------------------------------------------------------------------- --- 104 // -------------------------------------------------------------------------- ---
105 // 105 //
106 // Each run record describes a text blob run, and can be used to determine the (implicit) 106 // Each run record describes a text blob run, and can be used to determine the (implicit)
107 // location of the following record. 107 // location of the following record.
108 108
109 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) 109 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
110 110
111 class SkTextBlob::RunRecord { 111 class SkTextBlob::RunRecord {
112 public: 112 public:
113 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphP ositioning pos) 113 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphP ositioning pos, bool extended)
114 : fFont(font) 114 : fFont(font)
115 , fCount(count) 115 , fCount(count)
116 , fOffset(offset) 116 , fOffset(offset)
117 , fPositioning(pos) { 117 , fPositioning(pos)
118 , fExtended(extended) {
118 SkDEBUGCODE(fMagic = kRunRecordMagic); 119 SkDEBUGCODE(fMagic = kRunRecordMagic);
119 } 120 }
120 121
121 uint32_t glyphCount() const { 122 uint32_t glyphCount() const {
122 return fCount; 123 return fCount;
123 } 124 }
124 125
125 const SkPoint& offset() const { 126 const SkPoint& offset() const {
126 return fOffset; 127 return fOffset;
127 } 128 }
128 129
129 const RunFont& font() const { 130 const RunFont& font() const {
130 return fFont; 131 return fFont;
131 } 132 }
132 133
133 GlyphPositioning positioning() const { 134 GlyphPositioning positioning() const {
134 return fPositioning; 135 return fPositioning;
135 } 136 }
136 137
137 uint16_t* glyphBuffer() const { 138 uint16_t* glyphBuffer() const {
139 static_assert(SkIsAlignPtr(sizeof(RunRecord)), "");
138 // Glyph are stored immediately following the record. 140 // Glyph are stored immediately following the record.
f(malita) 2016/06/27 20:21:55 nit: "Glyphs", while we're here
hal.canary 2016/06/28 15:39:13 Done.
139 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); 141 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1);
140 } 142 }
141 143
142 SkScalar* posBuffer() const { 144 SkScalar* posBuffer() const {
143 // Position scalars follow the (aligned) glyph buffer. 145 // Position scalars follow the (aligned) glyph buffer.
144 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyp hBuffer()) + 146 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyp hBuffer()) +
145 SkAlign4(fCount * sizeof(uint16_t))); 147 SkAlign4(fCount * sizeof(uint16_t)));
146 } 148 }
147 149
148 static size_t StorageSize(int glyphCount, SkTextBlob::GlyphPositioning posit ioning) { 150 uint32_t textSize() const {
f(malita) 2016/06/27 20:21:55 maybe uint32_t* textSizePtr() for reuse?
hal.canary 2016/06/28 15:39:12 Done.
151 // textSize follows the position buffer.
152 if (!fExtended) { return 0; }
153 return *(uint32_t*)(&this->posBuffer()[ScalarsPerGlyph(fPositioning) * f Count]);
f(malita) 2016/06/27 20:21:55 nit: reinterpret_cast instead of old-style cast?
hal.canary 2016/06/28 15:39:12 Done.
154 }
155
156 void setTextSize(uint32_t size) {
f(malita) 2016/06/27 20:21:55 I think we can get rid of the setter, see suggesti
hal.canary 2016/06/28 15:39:12 Done.
157 SkASSERT(fExtended);
158 *(uint32_t*)(&this->posBuffer()[ScalarsPerGlyph(fPositioning) * fCount]) = size;
f(malita) 2016/06/27 20:21:55 nit: reinterpret_cast
hal.canary 2016/06/28 15:39:12 Done.
159
160 }
161 uint32_t* clusterBuffer() const {
162 // clusters follow the textSize.
163 if (!fExtended) { return nullptr; }
164 return (uint32_t*)(&this->posBuffer()[ScalarsPerGlyph(fPositioning) * fC ount]) + 1;
f(malita) 2016/06/27 20:21:55 return textSizePtr() + 1 ?
hal.canary 2016/06/28 15:39:12 Done.
165 }
166
167 char* textBuffer() const {
168 if (!fExtended) { return nullptr; }
169 return (char*)((uint32_t*)(&this->posBuffer()[ScalarsPerGlyph(fPositioni ng) * fCount]) + 1 + fCount);
f(malita) 2016/06/27 20:21:55 return reinterpret_cast<char*>(clusterBuffer() + f
hal.canary 2016/06/28 15:39:13 Done.
170 }
171
172 static size_t StorageSize(int glyphCount, int textSize, SkTextBlob::GlyphPos itioning positioning) {
149 // RunRecord object + (aligned) glyph buffer + position buffer 173 // RunRecord object + (aligned) glyph buffer + position buffer
150 return SkAlignPtr(sizeof(SkTextBlob::RunRecord) 174 if (0 == textSize) {
151 + SkAlign4(glyphCount* sizeof(uint16_t)) 175 return SkAlignPtr(sizeof(SkTextBlob::RunRecord)
152 + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(positi oning)); 176 + SkAlign4(glyphCount* sizeof(uint16_t))
177 + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph( positioning));
178 } else {
179 return SkAlignPtr(sizeof(SkTextBlob::RunRecord)
180 + SkAlign4(glyphCount* sizeof(uint16_t))
181 + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph( positioning)
182 + sizeof(uint32_t)
183 + sizeof(uint32_t) * glyphCount
184 + textSize);
185 }
f(malita) 2016/06/27 20:21:55 nit: maybe somewhat DRY-er size_t size = ...;
hal.canary 2016/06/28 15:39:12 Done.
153 } 186 }
154 187
155 static const RunRecord* First(const SkTextBlob* blob) { 188 static const RunRecord* First(const SkTextBlob* blob) {
156 // The first record (if present) is stored following the blob object. 189 // The first record (if present) is stored following the blob object.
157 return reinterpret_cast<const RunRecord*>(blob + 1); 190 return reinterpret_cast<const RunRecord*>(blob + 1);
158 } 191 }
159 192
160 static const RunRecord* Next(const RunRecord* run) { 193 static const RunRecord* Next(const RunRecord* run) {
161 return reinterpret_cast<const RunRecord*>(reinterpret_cast<const uint8_t *>(run) 194 return reinterpret_cast<const RunRecord*>(
162 + StorageSize(run->glyphCount(), run->positioning())); 195 reinterpret_cast<const uint8_t*>(run)
196 + StorageSize(run->glyphCount(), run->textSize(), run->positioni ng()));
163 } 197 }
164 198
165 void validate(const uint8_t* storageTop) const { 199 void validate(const uint8_t* storageTop) const {
166 SkASSERT(kRunRecordMagic == fMagic); 200 SkASSERT(kRunRecordMagic == fMagic);
167 SkASSERT((uint8_t*)Next(this) <= storageTop); 201 SkASSERT((uint8_t*)Next(this) <= storageTop);
202
168 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); 203 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer());
169 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScal ar*)Next(this)); 204 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScal ar*)Next(this));
f(malita) 2016/06/27 20:21:55 We should also add asserts for the new buffers.
hal.canary 2016/06/28 15:39:12 Done.
170 } 205 }
171 206
172 private: 207 private:
173 friend class SkTextBlobBuilder; 208 friend class SkTextBlobBuilder;
174 209
175 void grow(uint32_t count) { 210 void grow(uint32_t count) {
176 SkScalar* initialPosBuffer = posBuffer(); 211 SkScalar* initialPosBuffer = posBuffer();
177 uint32_t initialCount = fCount; 212 uint32_t initialCount = fCount;
178 fCount += count; 213 fCount += count;
179 214
180 // Move the initial pos scalars to their new location. 215 // Move the initial pos scalars to their new location.
181 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning); 216 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning);
182 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); 217 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this));
183 218
184 // memmove, as the buffers may overlap 219 // memmove, as the buffers may overlap
185 memmove(posBuffer(), initialPosBuffer, copySize); 220 memmove(posBuffer(), initialPosBuffer, copySize);
186 } 221 }
187 222
188 RunFont fFont; 223 RunFont fFont;
189 uint32_t fCount; 224 uint32_t fCount;
190 SkPoint fOffset; 225 SkPoint fOffset;
191 GlyphPositioning fPositioning; 226 GlyphPositioning fPositioning;
227 bool fExtended;
192 228
193 SkDEBUGCODE(unsigned fMagic;) 229 SkDEBUGCODE(unsigned fMagic;)
194 }; 230 };
f(malita) 2016/06/27 20:21:55 Similar to RunFont above: namespace { struct Run
hal.canary 2016/06/28 15:39:12 Done.
195 231
196 static int32_t gNextID = 1; 232 static int32_t gNextID = 1;
197 static int32_t next_id() { 233 static int32_t next_id() {
198 int32_t id; 234 int32_t id;
199 do { 235 do {
200 id = sk_atomic_inc(&gNextID); 236 id = sk_atomic_inc(&gNextID);
201 } while (id == SK_InvalidGenID); 237 } while (id == SK_InvalidGenID);
202 return id; 238 return id;
203 } 239 }
204 240
205 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds) 241 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds)
206 : fRunCount(runCount) 242 : fRunCount(runCount)
207 , fBounds(bounds) 243 , fBounds(bounds)
208 , fUniqueID(next_id()) { 244 , fUniqueID(next_id()) {
245 #ifdef SK_DEBUG
246 static_assert(sizeof(SkTextBlob::RunRecord) == SkAlignPtr(sizeof(void*) + 29 + 4), "");
247 #else
248 static_assert(sizeof(SkTextBlob::RunRecord) == SkAlignPtr(sizeof(void*) + 29), "");
249 #endif
f(malita) 2016/06/27 20:21:55 Not needed with RunRecordStorageEquivalent above.
hal.canary 2016/06/28 15:39:12 Done.
209 } 250 }
210 251
211 SkTextBlob::~SkTextBlob() { 252 SkTextBlob::~SkTextBlob() {
212 const RunRecord* run = RunRecord::First(this); 253 const RunRecord* run = RunRecord::First(this);
213 for (int i = 0; i < fRunCount; ++i) { 254 for (int i = 0; i < fRunCount; ++i) {
214 const RunRecord* nextRun = RunRecord::Next(run); 255 const RunRecord* nextRun = RunRecord::Next(run);
215 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) 256 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);)
216 run->~RunRecord(); 257 run->~RunRecord();
217 run = nextRun; 258 run = nextRun;
218 } 259 }
219 } 260 }
220 261
262 namespace {
263 union PositioningAndExtended {
264 int32_t intValue;
265 struct {
266 SkTextBlob::GlyphPositioning positioning;
267 bool extended;
268 uint16_t padding;
269 };
270 };
271 } // namespace
272
221 void SkTextBlob::flatten(SkWriteBuffer& buffer) const { 273 void SkTextBlob::flatten(SkWriteBuffer& buffer) const {
222 int runCount = fRunCount; 274 int runCount = fRunCount;
223 275
224 buffer.write32(runCount); 276 buffer.write32(runCount);
225 buffer.writeRect(fBounds); 277 buffer.writeRect(fBounds);
226 278
227 SkPaint runPaint; 279 SkPaint runPaint;
228 SkTextBlobRunIterator it(this); 280 SkTextBlobRunIterator it(this);
229 while (!it.done()) { 281 while (!it.done()) {
230 SkASSERT(it.glyphCount() > 0); 282 SkASSERT(it.glyphCount() > 0);
231 283
232 buffer.write32(it.glyphCount()); 284 buffer.write32(it.glyphCount());
233 buffer.write32(it.positioning()); 285 PositioningAndExtended pe;
286 pe.intValue = 0;
287 pe.positioning = it.positioning();
288 SkASSERT((int32_t)it.positioning() == pe.intValue); // backwards compat .
289 pe.extended = it.isExtended();
290 buffer.write32(pe.intValue);
291 if (pe.extended) {
292 buffer.write32(it.textSize());
293 }
234 buffer.writePoint(it.offset()); 294 buffer.writePoint(it.offset());
235 // This should go away when switching to SkFont 295 // This should go away when switching to SkFont
236 it.applyFontToPaint(&runPaint); 296 it.applyFontToPaint(&runPaint);
237 buffer.writePaint(runPaint); 297 buffer.writePaint(runPaint);
238 298
239 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t)); 299 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t));
240 buffer.writeByteArray(it.pos(), 300 buffer.writeByteArray(it.pos(),
241 it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning( ))); 301 it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning( )));
302 if (pe.extended) {
303 buffer.writeByteArray(it.clusterBuffer(), sizeof(uint32_t) * it.glyp hCount());
304 buffer.writeByteArray(it.textBuffer(), it.textSize());
305 }
242 306
243 it.next(); 307 it.next();
244 SkDEBUGCODE(runCount--); 308 SkDEBUGCODE(runCount--);
245 } 309 }
246 SkASSERT(0 == runCount); 310 SkASSERT(0 == runCount);
247 } 311 }
248 312
249 const SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) { 313 const SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) {
250 int runCount = reader.read32(); 314 int runCount = reader.read32();
251 if (runCount < 0) { 315 if (runCount < 0) {
252 return nullptr; 316 return nullptr;
253 } 317 }
254 318
255 SkRect bounds; 319 SkRect bounds;
256 reader.readRect(&bounds); 320 reader.readRect(&bounds);
257 321
258 SkTextBlobBuilder blobBuilder; 322 SkTextBlobBuilder blobBuilder;
259 for (int i = 0; i < runCount; ++i) { 323 for (int i = 0; i < runCount; ++i) {
260 int glyphCount = reader.read32(); 324 int glyphCount = reader.read32();
261 GlyphPositioning pos = static_cast<GlyphPositioning>(reader.read32()); 325
326 PositioningAndExtended pe;
327 pe.intValue = reader.read32();
328 GlyphPositioning pos = pe.positioning;
262 if (glyphCount <= 0 || pos > kFull_Positioning) { 329 if (glyphCount <= 0 || pos > kFull_Positioning) {
263 return nullptr; 330 return nullptr;
264 } 331 }
332 uint32_t textSize = pe.extended ? (uint32_t)reader.read32() : 0;
265 333
266 SkPoint offset; 334 SkPoint offset;
267 reader.readPoint(&offset); 335 reader.readPoint(&offset);
268 SkPaint font; 336 SkPaint font;
269 reader.readPaint(&font); 337 reader.readPaint(&font);
270 338
271 const SkTextBlobBuilder::RunBuffer* buf = nullptr; 339 const SkTextBlobBuilder::RunBuffer* buf = nullptr;
272 switch (pos) { 340 switch (pos) {
273 case kDefault_Positioning: 341 case kDefault_Positioning:
274 buf = &blobBuilder.allocRun(font, glyphCount, offset.x(), offset.y() , &bounds); 342 buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset .y(),
343 textSize, SkString(), &bounds);
275 break; 344 break;
276 case kHorizontal_Positioning: 345 case kHorizontal_Positioning:
277 buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bound s); 346 buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(),
347 textSize, SkString(), &bounds);
278 break; 348 break;
279 case kFull_Positioning: 349 case kFull_Positioning:
280 buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds); 350 buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, SkStr ing(), &bounds);
281 break; 351 break;
282 default: 352 default:
283 return nullptr; 353 return nullptr;
284 } 354 }
285 355
286 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || 356 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) ||
287 !reader.readByteArray(buf->pos, 357 !reader.readByteArray(buf->pos,
288 glyphCount * sizeof(SkScalar) * ScalarsPerGlyp h(pos))) { 358 glyphCount * sizeof(SkScalar) * ScalarsPerGlyp h(pos))) {
289 return nullptr; 359 return nullptr;
290 } 360 }
361
362 if (pe.extended) {
363 if (!reader.readByteArray(buf->clusters, glyphCount * sizeof(uint32_ t)) ||
364 !reader.readByteArray(buf->utf8text, textSize)) {
365 return nullptr;
366 }
367 }
291 } 368 }
292 369
293 return blobBuilder.build(); 370 return blobBuilder.build();
294 } 371 }
295 372
296 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { 373 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) {
297 // GlyphPositioning values are directly mapped to scalars-per-glyph. 374 // GlyphPositioning values are directly mapped to scalars-per-glyph.
298 SkASSERT(pos <= 2); 375 SkASSERT(pos <= 2);
299 return pos; 376 return pos;
300 } 377 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 SkASSERT(!this->done()); 420 SkASSERT(!this->done());
344 return fCurrentRun->positioning(); 421 return fCurrentRun->positioning();
345 } 422 }
346 423
347 void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const { 424 void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const {
348 SkASSERT(!this->done()); 425 SkASSERT(!this->done());
349 426
350 fCurrentRun->font().applyToPaint(paint); 427 fCurrentRun->font().applyToPaint(paint);
351 } 428 }
352 429
430 bool SkTextBlobRunIterator::isExtended() const {
431 SkASSERT(!this->done());
432 return fCurrentRun->textSize() > 0;
433 }
434 uint32_t* SkTextBlobRunIterator::clusterBuffer() const {
435 SkASSERT(!this->done());
436 return fCurrentRun->clusterBuffer();
437 }
438 uint32_t SkTextBlobRunIterator::textSize() const {
439 SkASSERT(!this->done());
440 return fCurrentRun->textSize();
441 }
442 char* SkTextBlobRunIterator::textBuffer() const {
443 SkASSERT(!this->done());
444 return fCurrentRun->textBuffer();
445 }
446
447
353 bool SkTextBlobRunIterator::isLCD() const { 448 bool SkTextBlobRunIterator::isLCD() const {
354 return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag); 449 return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag);
355 } 450 }
356 451
357 SkTextBlobBuilder::SkTextBlobBuilder() 452 SkTextBlobBuilder::SkTextBlobBuilder()
358 : fStorageSize(0) 453 : fStorageSize(0)
359 , fStorageUsed(0) 454 , fStorageUsed(0)
360 , fRunCount(0) 455 , fRunCount(0)
361 , fDeferredBounds(false) 456 , fDeferredBounds(false)
362 , fLastRun(0) { 457 , fLastRun(0) {
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 if (0 == fLastRun) { 601 if (0 == fLastRun) {
507 SkASSERT(0 == fRunCount); 602 SkASSERT(0 == fRunCount);
508 return false; 603 return false;
509 } 604 }
510 605
511 SkASSERT(fLastRun >= sizeof(SkTextBlob)); 606 SkASSERT(fLastRun >= sizeof(SkTextBlob));
512 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() + 607 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() +
513 fLastR un); 608 fLastR un);
514 SkASSERT(run->glyphCount() > 0); 609 SkASSERT(run->glyphCount() > 0);
515 610
611 if (run->textSize() != 0) {
612 return false;
613 }
614
516 if (run->positioning() != positioning 615 if (run->positioning() != positioning
517 || run->font() != font 616 || run->font() != font
518 || (run->glyphCount() + count < run->glyphCount())) { 617 || (run->glyphCount() + count < run->glyphCount())) {
519 return false; 618 return false;
520 } 619 }
521 620
522 // we can merge same-font/same-positioning runs in the following cases: 621 // we can merge same-font/same-positioning runs in the following cases:
523 // * fully positioned run following another fully positioned run 622 // * fully positioned run following another fully positioned run
524 // * horizontally postioned run following another horizontally positioned run with the same 623 // * horizontally postioned run following another horizontally positioned run with the same
525 // y-offset 624 // y-offset
526 if (SkTextBlob::kFull_Positioning != positioning 625 if (SkTextBlob::kFull_Positioning != positioning
527 && (SkTextBlob::kHorizontal_Positioning != positioning 626 && (SkTextBlob::kHorizontal_Positioning != positioning
528 || run->offset().y() != offset.y())) { 627 || run->offset().y() != offset.y())) {
529 return false; 628 return false;
530 } 629 }
531 630
532 size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + co unt, positioning) - 631 size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + co unt, 0, positioning) -
533 SkTextBlob::RunRecord::StorageSize(run->glyphCount(), pos itioning); 632 SkTextBlob::RunRecord::StorageSize(run->glyphCount(), 0, positioning);
534 this->reserve(sizeDelta); 633 this->reserve(sizeDelta);
535 634
536 // reserve may have realloced 635 // reserve may have realloced
537 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); 636 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun);
538 uint32_t preMergeCount = run->glyphCount(); 637 uint32_t preMergeCount = run->glyphCount();
539 run->grow(count); 638 run->grow(count);
540 639
541 // Callers expect the buffers to point at the newly added slice, ant not at the beginning. 640 // Callers expect the buffers to point at the newly added slice, ant not at the beginning.
542 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount; 641 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount;
543 fCurrentRunBuffer.pos = run->posBuffer() 642 fCurrentRunBuffer.pos = run->posBuffer()
544 + preMergeCount * SkTextBlob::ScalarsPerGlyph(position ing); 643 + preMergeCount * SkTextBlob::ScalarsPerGlyph(position ing);
545 644
546 fStorageUsed += sizeDelta; 645 fStorageUsed += sizeDelta;
547 646
548 SkASSERT(fStorageUsed <= fStorageSize); 647 SkASSERT(fStorageUsed <= fStorageSize);
549 run->validate(fStorage.get() + fStorageUsed); 648 run->validate(fStorage.get() + fStorageUsed);
550 649
551 return true; 650 return true;
552 } 651 }
553 652
554 void SkTextBlobBuilder::allocInternal(const SkPaint &font, 653 void SkTextBlobBuilder::allocInternal(const SkPaint &font,
555 SkTextBlob::GlyphPositioning positioning, 654 SkTextBlob::GlyphPositioning positioning,
556 int count, SkPoint offset, const SkRect* b ounds) { 655 int count, int textSize, SkPoint offset, c onst SkRect* bounds) {
557 SkASSERT(count > 0); 656 SkASSERT(count > 0);
657 SkASSERT(textSize >= 0);
558 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); 658 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding());
559 659
560 if (!this->mergeRun(font, positioning, count, offset)) { 660 if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) {
561 this->updateDeferredBounds(); 661 this->updateDeferredBounds();
562 662
563 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, positioning); 663 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, pos itioning);
564 this->reserve(runSize); 664 this->reserve(runSize);
565 665
566 SkASSERT(fStorageUsed >= sizeof(SkTextBlob)); 666 SkASSERT(fStorageUsed >= sizeof(SkTextBlob));
567 SkASSERT(fStorageUsed + runSize <= fStorageSize); 667 SkASSERT(fStorageUsed + runSize <= fStorageSize);
568 668
569 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed) 669 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed)
570 SkTextBlob::RunRecord(count, offset, fo nt, positioning); 670 SkTextBlob::RunRecord(count, offset, font, positioning, textSize > 0);
571 671 if (textSize > 0) {
672 run->setTextSize(textSize);
f(malita) 2016/06/27 20:21:55 Why not pass textSize to the RunRecord ctor? Then
hal.canary 2016/06/28 15:39:13 Done.
673 }
572 fCurrentRunBuffer.glyphs = run->glyphBuffer(); 674 fCurrentRunBuffer.glyphs = run->glyphBuffer();
573 fCurrentRunBuffer.pos = run->posBuffer(); 675 fCurrentRunBuffer.pos = run->posBuffer();
676 fCurrentRunBuffer.utf8text = run->textBuffer();
677 fCurrentRunBuffer.clusters = run->clusterBuffer();
574 678
575 fLastRun = fStorageUsed; 679 fLastRun = fStorageUsed;
576 fStorageUsed += runSize; 680 fStorageUsed += runSize;
577 fRunCount++; 681 fRunCount++;
578 682
579 SkASSERT(fStorageUsed <= fStorageSize); 683 SkASSERT(fStorageUsed <= fStorageSize);
580 run->validate(fStorage.get() + fStorageUsed); 684 run->validate(fStorage.get() + fStorageUsed);
685 } else {
686 fCurrentRunBuffer.utf8text = nullptr;
687 fCurrentRunBuffer.clusters = nullptr;
f(malita) 2016/06/27 20:21:55 I don't think we need to clear these: textSize ==
hal.canary 2016/06/28 15:39:12 Done.
581 } 688 }
582 689
583 if (!fDeferredBounds) { 690 if (!fDeferredBounds) {
584 if (bounds) { 691 if (bounds) {
585 fBounds.join(*bounds); 692 fBounds.join(*bounds);
586 } else { 693 } else {
587 fDeferredBounds = true; 694 fDeferredBounds = true;
588 } 695 }
589 } 696 }
590 } 697 }
591 698
592 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkPaint& f ont, int count, 699 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkPain t& font, int count,
593 SkScalar x, SkSc alar y, 700 SkScalar x, SkScalar y,
594 const SkRect* bo unds) { 701 int textByte Count,
595 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, SkPoint:: Make(x, y), bounds); 702 SkString lan g,
596 703 const SkRect * bounds) {
704 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, textByteC ount, SkPoint::Make(x, y), bounds);
597 return fCurrentRunBuffer; 705 return fCurrentRunBuffer;
598 } 706 }
599 707
600 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkPain t& font, int count, 708 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const Sk Paint& font, int count,
601 SkScalar y, 709 SkScalar y,
602 const SkRect * bounds) { 710 int text ByteCount,
603 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, SkPoin t::Make(0, y), 711 SkString lang,
712 const Sk Rect* bounds) {
713 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, textBy teCount, SkPoint::Make(0, y),
604 bounds); 714 bounds);
605 715
606 return fCurrentRunBuffer; 716 return fCurrentRunBuffer;
607 } 717 }
608 718
609 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint & font, int count, 719 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkP aint& font, int count,
610 const SkRect *bounds) { 720 int textB yteCount,
611 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Mak e(0, 0), bounds); 721 SkString lang,
722 const SkR ect *bounds) {
723 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, textByteCount , SkPoint::Make(0, 0), bounds);
612 724
613 return fCurrentRunBuffer; 725 return fCurrentRunBuffer;
614 } 726 }
615 727
616 const SkTextBlob* SkTextBlobBuilder::build() { 728 const SkTextBlob* SkTextBlobBuilder::build() {
617 SkASSERT((fRunCount > 0) == (nullptr != fStorage.get())); 729 SkASSERT((fRunCount > 0) == (nullptr != fStorage.get()));
618 730
619 this->updateDeferredBounds(); 731 this->updateDeferredBounds();
620 732
621 if (0 == fRunCount) { 733 if (0 == fRunCount) {
622 SkASSERT(nullptr == fStorage.get()); 734 SkASSERT(nullptr == fStorage.get());
623 fStorageUsed = sizeof(SkTextBlob); 735 fStorageUsed = sizeof(SkTextBlob);
624 fStorage.realloc(fStorageUsed); 736 fStorage.realloc(fStorageUsed);
625 } 737 }
626 738
627 const SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fRunCount, fBou nds); 739 const SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fRunCount, fBou nds);
628 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;) 740 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;)
629 741
630 SkDEBUGCODE( 742 SkDEBUGCODE(
631 size_t validateSize = sizeof(SkTextBlob); 743 size_t validateSize = sizeof(SkTextBlob);
632 const SkTextBlob::RunRecord* run = SkTextBlob::RunRecord::First(blob); 744 const SkTextBlob::RunRecord* run = SkTextBlob::RunRecord::First(blob);
633 for (int i = 0; i < fRunCount; ++i) { 745 for (int i = 0; i < fRunCount; ++i) {
634 validateSize += SkTextBlob::RunRecord::StorageSize(run->fCount, run- >fPositioning); 746 validateSize += SkTextBlob::RunRecord::StorageSize(
747 run->fCount, run->textSize(), run->fPositioning);
635 run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed) ; 748 run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed) ;
636 run = SkTextBlob::RunRecord::Next(run); 749 run = SkTextBlob::RunRecord::Next(run);
637 } 750 }
638 SkASSERT(validateSize == fStorageUsed); 751 SkASSERT(validateSize == fStorageUsed);
639 ) 752 )
640 753
641 fStorageUsed = 0; 754 fStorageUsed = 0;
642 fStorageSize = 0; 755 fStorageSize = 0;
643 fRunCount = 0; 756 fRunCount = 0;
644 fLastRun = 0; 757 fLastRun = 0;
645 fBounds.setEmpty(); 758 fBounds.setEmpty();
646 759
647 return blob; 760 return blob;
648 } 761 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698