OLD | NEW |
---|---|
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 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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[] | ... |
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 // | |
109 // Extended Textblob runs have more data after the Pos[] array: | |
110 // | |
111 // ------------------------------------------------------------------------- | |
112 // ... | RunRecord | Glyphs[] | Pos[] | TextSize | Clusters[] | Text[] | ... | |
113 // ------------------------------------------------------------------------- | |
114 // | |
115 // To determine the length of the extended run data, the TextSize must be read. | |
116 // | |
117 // Extended Textblob runs may be mixed with non-extended runs. | |
108 | 118 |
109 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) | 119 SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;) |
110 | 120 |
121 namespace { | |
122 struct RunRecordStorageEquivalent { | |
123 RunFont fFont; | |
124 SkPoint fOffset; | |
125 uint32_t fCount; | |
126 uint32_t fFlags; | |
127 SkDEBUGCODE(unsigned fMagic;) | |
128 }; | |
129 } | |
130 | |
111 class SkTextBlob::RunRecord { | 131 class SkTextBlob::RunRecord { |
112 public: | 132 public: |
113 RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphP ositioning pos) | 133 RunRecord(uint32_t count, uint32_t textSize, const SkPoint& offset, const S kPaint& font, GlyphPositioning pos) |
114 : fFont(font) | 134 : fFont(font) |
115 , fCount(count) | 135 , fCount(count) |
116 , fOffset(offset) | 136 , fOffset(offset) |
117 , fPositioning(pos) { | 137 , fPositioning(pos) |
138 , fExtended(textSize > 0) { | |
118 SkDEBUGCODE(fMagic = kRunRecordMagic); | 139 SkDEBUGCODE(fMagic = kRunRecordMagic); |
140 if (textSize > 0) { | |
141 *this->textSizePtr() = textSize; | |
142 } | |
119 } | 143 } |
120 | 144 |
121 uint32_t glyphCount() const { | 145 uint32_t glyphCount() const { |
122 return fCount; | 146 return fCount; |
123 } | 147 } |
124 | 148 |
125 const SkPoint& offset() const { | 149 const SkPoint& offset() const { |
126 return fOffset; | 150 return fOffset; |
127 } | 151 } |
128 | 152 |
129 const RunFont& font() const { | 153 const RunFont& font() const { |
130 return fFont; | 154 return fFont; |
131 } | 155 } |
132 | 156 |
133 GlyphPositioning positioning() const { | 157 GlyphPositioning positioning() const { |
134 return fPositioning; | 158 return fPositioning; |
135 } | 159 } |
136 | 160 |
137 uint16_t* glyphBuffer() const { | 161 uint16_t* glyphBuffer() const { |
138 // Glyph are stored immediately following the record. | 162 static_assert(SkIsAlignPtr(sizeof(RunRecord)), ""); |
163 // Glyphs are stored immediately following the record. | |
139 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); | 164 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); |
140 } | 165 } |
141 | 166 |
142 SkScalar* posBuffer() const { | 167 SkScalar* posBuffer() const { |
143 // Position scalars follow the (aligned) glyph buffer. | 168 // Position scalars follow the (aligned) glyph buffer. |
144 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyp hBuffer()) + | 169 return reinterpret_cast<SkScalar*>(reinterpret_cast<uint8_t*>(this->glyp hBuffer()) + |
145 SkAlign4(fCount * sizeof(uint16_t))); | 170 SkAlign4(fCount * sizeof(uint16_t))); |
146 } | 171 } |
147 | 172 |
148 static size_t StorageSize(int glyphCount, SkTextBlob::GlyphPositioning posit ioning) { | 173 uint32_t textSize() const { return fExtended ? *this->textSizePtr() : 0; } |
174 | |
175 void setTextSize(uint32_t size) { | |
f(malita)
2016/06/28 15:57:44
We can delete the setter now.
| |
176 SkASSERT(fExtended); | |
177 *this->textSizePtr() = size; | |
178 } | |
179 | |
180 uint32_t* clusterBuffer() const { | |
181 // clusters follow the textSize. | |
182 return fExtended ? 1 + this->textSizePtr() : nullptr; | |
183 } | |
184 | |
185 char* textBuffer() const { | |
186 if (!fExtended) { return nullptr; } | |
187 return reinterpret_cast<char*>(this->clusterBuffer() + fCount); | |
188 } | |
189 | |
190 static size_t StorageSize(int glyphCount, int textSize, | |
191 SkTextBlob::GlyphPositioning positioning) { | |
192 static_assert(SkIsAlign4(sizeof(SkScalar)), "SkScalar size alignment"); | |
149 // RunRecord object + (aligned) glyph buffer + position buffer | 193 // RunRecord object + (aligned) glyph buffer + position buffer |
150 return SkAlignPtr(sizeof(SkTextBlob::RunRecord) | 194 size_t size = sizeof(SkTextBlob::RunRecord) |
151 + SkAlign4(glyphCount* sizeof(uint16_t)) | 195 + SkAlign4(glyphCount* sizeof(uint16_t)) |
152 + glyphCount * sizeof(SkScalar) * ScalarsPerGlyph(positi oning)); | 196 + PosCount(glyphCount, positioning) * sizeof(SkScalar); |
197 if (textSize > 0) { // Extended run. | |
198 size += sizeof(uint32_t) | |
199 + sizeof(uint32_t) * glyphCount | |
200 + textSize; | |
201 } | |
202 return SkAlignPtr(size); | |
153 } | 203 } |
154 | 204 |
155 static const RunRecord* First(const SkTextBlob* blob) { | 205 static const RunRecord* First(const SkTextBlob* blob) { |
156 // The first record (if present) is stored following the blob object. | 206 // The first record (if present) is stored following the blob object. |
157 return reinterpret_cast<const RunRecord*>(blob + 1); | 207 return reinterpret_cast<const RunRecord*>(blob + 1); |
158 } | 208 } |
159 | 209 |
160 static const RunRecord* Next(const RunRecord* run) { | 210 static const RunRecord* Next(const RunRecord* run) { |
161 return reinterpret_cast<const RunRecord*>(reinterpret_cast<const uint8_t *>(run) | 211 return reinterpret_cast<const RunRecord*>( |
162 + StorageSize(run->glyphCount(), run->positioning())); | 212 reinterpret_cast<const uint8_t*>(run) |
213 + StorageSize(run->glyphCount(), run->textSize(), run->positioni ng())); | |
163 } | 214 } |
164 | 215 |
165 void validate(const uint8_t* storageTop) const { | 216 void validate(const uint8_t* storageTop) const { |
166 SkASSERT(kRunRecordMagic == fMagic); | 217 SkASSERT(kRunRecordMagic == fMagic); |
167 SkASSERT((uint8_t*)Next(this) <= storageTop); | 218 SkASSERT((uint8_t*)Next(this) <= storageTop); |
219 | |
168 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); | 220 SkASSERT(glyphBuffer() + fCount <= (uint16_t*)posBuffer()); |
169 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScal ar*)Next(this)); | 221 SkASSERT(posBuffer() + fCount * ScalarsPerGlyph(fPositioning) <= (SkScal ar*)Next(this)); |
222 if (fExtended) { | |
223 SkASSERT(textSize() > 0); | |
224 SkASSERT(textSizePtr() < (uint32_t*)Next(this)); | |
225 SkASSERT(clusterBuffer() < (uint32_t*)Next(this)); | |
226 SkASSERT(textBuffer() + textSize() <= (char*)Next(this)); | |
227 } | |
228 static_assert(sizeof(SkTextBlob::RunRecord) == sizeof(RunRecordStorageEq uivalent), | |
229 "runrecord_should_stay_packed"); | |
170 } | 230 } |
171 | 231 |
172 private: | 232 private: |
173 friend class SkTextBlobBuilder; | 233 friend class SkTextBlobBuilder; |
174 | 234 |
235 static size_t PosCount(int glyphCount, | |
236 SkTextBlob::GlyphPositioning positioning) { | |
237 return glyphCount * ScalarsPerGlyph(positioning); | |
238 } | |
239 | |
240 uint32_t* textSizePtr() const { | |
241 // textSize follows the position buffer. | |
242 SkASSERT(fExtended); | |
243 return (uint32_t*)(&this->posBuffer()[PosCount(fCount, fPositioning)]); | |
244 } | |
245 | |
175 void grow(uint32_t count) { | 246 void grow(uint32_t count) { |
176 SkScalar* initialPosBuffer = posBuffer(); | 247 SkScalar* initialPosBuffer = posBuffer(); |
177 uint32_t initialCount = fCount; | 248 uint32_t initialCount = fCount; |
178 fCount += count; | 249 fCount += count; |
179 | 250 |
180 // Move the initial pos scalars to their new location. | 251 // Move the initial pos scalars to their new location. |
181 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning); | 252 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning); |
182 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); | 253 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); |
183 | 254 |
184 // memmove, as the buffers may overlap | 255 // memmove, as the buffers may overlap |
185 memmove(posBuffer(), initialPosBuffer, copySize); | 256 memmove(posBuffer(), initialPosBuffer, copySize); |
186 } | 257 } |
187 | 258 |
188 RunFont fFont; | 259 RunFont fFont; |
189 uint32_t fCount; | 260 uint32_t fCount; |
190 SkPoint fOffset; | 261 SkPoint fOffset; |
191 GlyphPositioning fPositioning; | 262 GlyphPositioning fPositioning; |
263 bool fExtended; | |
192 | 264 |
193 SkDEBUGCODE(unsigned fMagic;) | 265 SkDEBUGCODE(unsigned fMagic;) |
194 }; | 266 }; |
195 | 267 |
196 static int32_t gNextID = 1; | 268 static int32_t gNextID = 1; |
197 static int32_t next_id() { | 269 static int32_t next_id() { |
198 int32_t id; | 270 int32_t id; |
199 do { | 271 do { |
200 id = sk_atomic_inc(&gNextID); | 272 id = sk_atomic_inc(&gNextID); |
201 } while (id == SK_InvalidGenID); | 273 } while (id == SK_InvalidGenID); |
202 return id; | 274 return id; |
203 } | 275 } |
204 | 276 |
205 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds) | 277 SkTextBlob::SkTextBlob(int runCount, const SkRect& bounds) |
206 : fRunCount(runCount) | 278 : fRunCount(runCount) |
207 , fBounds(bounds) | 279 , fBounds(bounds) |
208 , fUniqueID(next_id()) { | 280 , fUniqueID(next_id()) { |
209 } | 281 } |
210 | 282 |
211 SkTextBlob::~SkTextBlob() { | 283 SkTextBlob::~SkTextBlob() { |
212 const RunRecord* run = RunRecord::First(this); | 284 const RunRecord* run = RunRecord::First(this); |
213 for (int i = 0; i < fRunCount; ++i) { | 285 for (int i = 0; i < fRunCount; ++i) { |
214 const RunRecord* nextRun = RunRecord::Next(run); | 286 const RunRecord* nextRun = RunRecord::Next(run); |
215 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) | 287 SkDEBUGCODE(run->validate((uint8_t*)this + fStorageSize);) |
216 run->~RunRecord(); | 288 run->~RunRecord(); |
217 run = nextRun; | 289 run = nextRun; |
218 } | 290 } |
219 } | 291 } |
220 | 292 |
293 namespace { | |
294 union PositioningAndExtended { | |
295 int32_t intValue; | |
296 struct { | |
297 SkTextBlob::GlyphPositioning positioning; | |
298 bool extended; | |
299 uint16_t padding; | |
300 }; | |
301 }; | |
302 } // namespace | |
303 | |
221 void SkTextBlob::flatten(SkWriteBuffer& buffer) const { | 304 void SkTextBlob::flatten(SkWriteBuffer& buffer) const { |
222 int runCount = fRunCount; | 305 int runCount = fRunCount; |
223 | 306 |
224 buffer.write32(runCount); | 307 buffer.write32(runCount); |
225 buffer.writeRect(fBounds); | 308 buffer.writeRect(fBounds); |
226 | 309 |
227 SkPaint runPaint; | 310 SkPaint runPaint; |
228 SkTextBlobRunIterator it(this); | 311 SkTextBlobRunIterator it(this); |
229 while (!it.done()) { | 312 while (!it.done()) { |
230 SkASSERT(it.glyphCount() > 0); | 313 SkASSERT(it.glyphCount() > 0); |
231 | 314 |
232 buffer.write32(it.glyphCount()); | 315 buffer.write32(it.glyphCount()); |
233 buffer.write32(it.positioning()); | 316 PositioningAndExtended pe; |
317 pe.intValue = 0; | |
318 pe.positioning = it.positioning(); | |
319 SkASSERT((int32_t)it.positioning() == pe.intValue); // backwards compat . | |
320 | |
321 uint32_t textSize = it.textSize(); | |
322 pe.extended = textSize > 0; | |
323 buffer.write32(pe.intValue); | |
324 if (pe.extended) { | |
325 buffer.write32(textSize); | |
326 } | |
234 buffer.writePoint(it.offset()); | 327 buffer.writePoint(it.offset()); |
235 // This should go away when switching to SkFont | 328 // This should go away when switching to SkFont |
236 it.applyFontToPaint(&runPaint); | 329 it.applyFontToPaint(&runPaint); |
237 buffer.writePaint(runPaint); | 330 buffer.writePaint(runPaint); |
238 | 331 |
239 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t)); | 332 buffer.writeByteArray(it.glyphs(), it.glyphCount() * sizeof(uint16_t)); |
240 buffer.writeByteArray(it.pos(), | 333 buffer.writeByteArray(it.pos(), |
241 it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning( ))); | 334 it.glyphCount() * sizeof(SkScalar) * ScalarsPerGlyph(it.positioning( ))); |
335 if (pe.extended) { | |
336 buffer.writeByteArray(it.clusters(), sizeof(uint32_t) * it.glyphCoun t()); | |
337 buffer.writeByteArray(it.text(), it.textSize()); | |
338 } | |
242 | 339 |
243 it.next(); | 340 it.next(); |
244 SkDEBUGCODE(runCount--); | 341 SkDEBUGCODE(runCount--); |
245 } | 342 } |
246 SkASSERT(0 == runCount); | 343 SkASSERT(0 == runCount); |
247 } | 344 } |
248 | 345 |
249 const SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) { | 346 const SkTextBlob* SkTextBlob::CreateFromBuffer(SkReadBuffer& reader) { |
250 int runCount = reader.read32(); | 347 int runCount = reader.read32(); |
251 if (runCount < 0) { | 348 if (runCount < 0) { |
252 return nullptr; | 349 return nullptr; |
253 } | 350 } |
254 | 351 |
255 SkRect bounds; | 352 SkRect bounds; |
256 reader.readRect(&bounds); | 353 reader.readRect(&bounds); |
257 | 354 |
258 SkTextBlobBuilder blobBuilder; | 355 SkTextBlobBuilder blobBuilder; |
259 for (int i = 0; i < runCount; ++i) { | 356 for (int i = 0; i < runCount; ++i) { |
260 int glyphCount = reader.read32(); | 357 int glyphCount = reader.read32(); |
261 GlyphPositioning pos = static_cast<GlyphPositioning>(reader.read32()); | 358 |
359 PositioningAndExtended pe; | |
360 pe.intValue = reader.read32(); | |
361 GlyphPositioning pos = pe.positioning; | |
262 if (glyphCount <= 0 || pos > kFull_Positioning) { | 362 if (glyphCount <= 0 || pos > kFull_Positioning) { |
263 return nullptr; | 363 return nullptr; |
264 } | 364 } |
365 uint32_t textSize = pe.extended ? (uint32_t)reader.read32() : 0; | |
265 | 366 |
266 SkPoint offset; | 367 SkPoint offset; |
267 reader.readPoint(&offset); | 368 reader.readPoint(&offset); |
268 SkPaint font; | 369 SkPaint font; |
269 reader.readPaint(&font); | 370 reader.readPaint(&font); |
270 | 371 |
271 const SkTextBlobBuilder::RunBuffer* buf = nullptr; | 372 const SkTextBlobBuilder::RunBuffer* buf = nullptr; |
272 switch (pos) { | 373 switch (pos) { |
273 case kDefault_Positioning: | 374 case kDefault_Positioning: |
274 buf = &blobBuilder.allocRun(font, glyphCount, offset.x(), offset.y() , &bounds); | 375 buf = &blobBuilder.allocRunText(font, glyphCount, offset.x(), offset .y(), |
376 textSize, SkString(), &bounds); | |
275 break; | 377 break; |
276 case kHorizontal_Positioning: | 378 case kHorizontal_Positioning: |
277 buf = &blobBuilder.allocRunPosH(font, glyphCount, offset.y(), &bound s); | 379 buf = &blobBuilder.allocRunTextPosH(font, glyphCount, offset.y(), |
380 textSize, SkString(), &bounds); | |
278 break; | 381 break; |
279 case kFull_Positioning: | 382 case kFull_Positioning: |
280 buf = &blobBuilder.allocRunPos(font, glyphCount, &bounds); | 383 buf = &blobBuilder.allocRunTextPos(font, glyphCount, textSize, SkStr ing(), &bounds); |
281 break; | 384 break; |
282 default: | 385 default: |
283 return nullptr; | 386 return nullptr; |
284 } | 387 } |
285 | 388 |
286 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || | 389 if (!reader.readByteArray(buf->glyphs, glyphCount * sizeof(uint16_t)) || |
287 !reader.readByteArray(buf->pos, | 390 !reader.readByteArray(buf->pos, |
288 glyphCount * sizeof(SkScalar) * ScalarsPerGlyp h(pos))) { | 391 glyphCount * sizeof(SkScalar) * ScalarsPerGlyp h(pos))) { |
289 return nullptr; | 392 return nullptr; |
290 } | 393 } |
394 | |
395 if (pe.extended) { | |
396 if (!reader.readByteArray(buf->clusters, glyphCount * sizeof(uint32_ t)) || | |
397 !reader.readByteArray(buf->utf8text, textSize)) { | |
398 return nullptr; | |
399 } | |
400 } | |
291 } | 401 } |
292 | 402 |
293 return blobBuilder.build(); | 403 return blobBuilder.build(); |
294 } | 404 } |
295 | 405 |
296 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { | 406 unsigned SkTextBlob::ScalarsPerGlyph(GlyphPositioning pos) { |
297 // GlyphPositioning values are directly mapped to scalars-per-glyph. | 407 // GlyphPositioning values are directly mapped to scalars-per-glyph. |
298 SkASSERT(pos <= 2); | 408 SkASSERT(pos <= 2); |
299 return pos; | 409 return pos; |
300 } | 410 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
343 SkASSERT(!this->done()); | 453 SkASSERT(!this->done()); |
344 return fCurrentRun->positioning(); | 454 return fCurrentRun->positioning(); |
345 } | 455 } |
346 | 456 |
347 void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const { | 457 void SkTextBlobRunIterator::applyFontToPaint(SkPaint* paint) const { |
348 SkASSERT(!this->done()); | 458 SkASSERT(!this->done()); |
349 | 459 |
350 fCurrentRun->font().applyToPaint(paint); | 460 fCurrentRun->font().applyToPaint(paint); |
351 } | 461 } |
352 | 462 |
463 uint32_t* SkTextBlobRunIterator::clusters() const { | |
464 SkASSERT(!this->done()); | |
465 return fCurrentRun->clusterBuffer(); | |
466 } | |
467 uint32_t SkTextBlobRunIterator::textSize() const { | |
468 SkASSERT(!this->done()); | |
469 return fCurrentRun->textSize(); | |
470 } | |
471 char* SkTextBlobRunIterator::text() const { | |
472 SkASSERT(!this->done()); | |
473 return fCurrentRun->textBuffer(); | |
474 } | |
475 | |
476 | |
353 bool SkTextBlobRunIterator::isLCD() const { | 477 bool SkTextBlobRunIterator::isLCD() const { |
354 return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag); | 478 return SkToBool(fCurrentRun->font().flags() & SkPaint::kLCDRenderText_Flag); |
355 } | 479 } |
356 | 480 |
357 SkTextBlobBuilder::SkTextBlobBuilder() | 481 SkTextBlobBuilder::SkTextBlobBuilder() |
358 : fStorageSize(0) | 482 : fStorageSize(0) |
359 , fStorageUsed(0) | 483 , fStorageUsed(0) |
360 , fRunCount(0) | 484 , fRunCount(0) |
361 , fDeferredBounds(false) | 485 , fDeferredBounds(false) |
362 , fLastRun(0) { | 486 , fLastRun(0) { |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
506 if (0 == fLastRun) { | 630 if (0 == fLastRun) { |
507 SkASSERT(0 == fRunCount); | 631 SkASSERT(0 == fRunCount); |
508 return false; | 632 return false; |
509 } | 633 } |
510 | 634 |
511 SkASSERT(fLastRun >= sizeof(SkTextBlob)); | 635 SkASSERT(fLastRun >= sizeof(SkTextBlob)); |
512 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() + | 636 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() + |
513 fLastR un); | 637 fLastR un); |
514 SkASSERT(run->glyphCount() > 0); | 638 SkASSERT(run->glyphCount() > 0); |
515 | 639 |
640 if (run->textSize() != 0) { | |
641 return false; | |
642 } | |
643 | |
516 if (run->positioning() != positioning | 644 if (run->positioning() != positioning |
517 || run->font() != font | 645 || run->font() != font |
518 || (run->glyphCount() + count < run->glyphCount())) { | 646 || (run->glyphCount() + count < run->glyphCount())) { |
519 return false; | 647 return false; |
520 } | 648 } |
521 | 649 |
522 // we can merge same-font/same-positioning runs in the following cases: | 650 // we can merge same-font/same-positioning runs in the following cases: |
523 // * fully positioned run following another fully positioned run | 651 // * fully positioned run following another fully positioned run |
524 // * horizontally postioned run following another horizontally positioned run with the same | 652 // * horizontally postioned run following another horizontally positioned run with the same |
525 // y-offset | 653 // y-offset |
526 if (SkTextBlob::kFull_Positioning != positioning | 654 if (SkTextBlob::kFull_Positioning != positioning |
527 && (SkTextBlob::kHorizontal_Positioning != positioning | 655 && (SkTextBlob::kHorizontal_Positioning != positioning |
528 || run->offset().y() != offset.y())) { | 656 || run->offset().y() != offset.y())) { |
529 return false; | 657 return false; |
530 } | 658 } |
531 | 659 |
532 size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + co unt, positioning) - | 660 size_t sizeDelta = SkTextBlob::RunRecord::StorageSize(run->glyphCount() + co unt, 0, positioning) - |
533 SkTextBlob::RunRecord::StorageSize(run->glyphCount(), pos itioning); | 661 SkTextBlob::RunRecord::StorageSize(run->glyphCount(), 0, positioning); |
534 this->reserve(sizeDelta); | 662 this->reserve(sizeDelta); |
535 | 663 |
536 // reserve may have realloced | 664 // reserve may have realloced |
537 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); | 665 run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() + fLastRun); |
538 uint32_t preMergeCount = run->glyphCount(); | 666 uint32_t preMergeCount = run->glyphCount(); |
539 run->grow(count); | 667 run->grow(count); |
540 | 668 |
541 // Callers expect the buffers to point at the newly added slice, ant not at the beginning. | 669 // Callers expect the buffers to point at the newly added slice, ant not at the beginning. |
542 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount; | 670 fCurrentRunBuffer.glyphs = run->glyphBuffer() + preMergeCount; |
543 fCurrentRunBuffer.pos = run->posBuffer() | 671 fCurrentRunBuffer.pos = run->posBuffer() |
544 + preMergeCount * SkTextBlob::ScalarsPerGlyph(position ing); | 672 + preMergeCount * SkTextBlob::ScalarsPerGlyph(position ing); |
545 | 673 |
546 fStorageUsed += sizeDelta; | 674 fStorageUsed += sizeDelta; |
547 | 675 |
548 SkASSERT(fStorageUsed <= fStorageSize); | 676 SkASSERT(fStorageUsed <= fStorageSize); |
549 run->validate(fStorage.get() + fStorageUsed); | 677 run->validate(fStorage.get() + fStorageUsed); |
550 | 678 |
551 return true; | 679 return true; |
552 } | 680 } |
553 | 681 |
554 void SkTextBlobBuilder::allocInternal(const SkPaint &font, | 682 void SkTextBlobBuilder::allocInternal(const SkPaint &font, |
555 SkTextBlob::GlyphPositioning positioning, | 683 SkTextBlob::GlyphPositioning positioning, |
556 int count, SkPoint offset, const SkRect* b ounds) { | 684 int count, int textSize, SkPoint offset, c onst SkRect* bounds) { |
557 SkASSERT(count > 0); | 685 SkASSERT(count > 0); |
686 SkASSERT(textSize >= 0); | |
558 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); | 687 SkASSERT(SkPaint::kGlyphID_TextEncoding == font.getTextEncoding()); |
559 | 688 if (textSize != 0 || !this->mergeRun(font, positioning, count, offset)) { |
560 if (!this->mergeRun(font, positioning, count, offset)) { | |
561 this->updateDeferredBounds(); | 689 this->updateDeferredBounds(); |
562 | 690 |
563 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, positioning); | 691 size_t runSize = SkTextBlob::RunRecord::StorageSize(count, textSize, pos itioning); |
564 this->reserve(runSize); | 692 this->reserve(runSize); |
565 | 693 |
566 SkASSERT(fStorageUsed >= sizeof(SkTextBlob)); | 694 SkASSERT(fStorageUsed >= sizeof(SkTextBlob)); |
567 SkASSERT(fStorageUsed + runSize <= fStorageSize); | 695 SkASSERT(fStorageUsed + runSize <= fStorageSize); |
568 | 696 |
569 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed) | 697 SkTextBlob::RunRecord* run = new (fStorage.get() + fStorageUsed) |
570 SkTextBlob::RunRecord(count, offset, fo nt, positioning); | 698 SkTextBlob::RunRecord(count, textSize, offset, font, positioning); |
571 | |
572 fCurrentRunBuffer.glyphs = run->glyphBuffer(); | 699 fCurrentRunBuffer.glyphs = run->glyphBuffer(); |
573 fCurrentRunBuffer.pos = run->posBuffer(); | 700 fCurrentRunBuffer.pos = run->posBuffer(); |
701 fCurrentRunBuffer.utf8text = run->textBuffer(); | |
702 fCurrentRunBuffer.clusters = run->clusterBuffer(); | |
574 | 703 |
575 fLastRun = fStorageUsed; | 704 fLastRun = fStorageUsed; |
576 fStorageUsed += runSize; | 705 fStorageUsed += runSize; |
577 fRunCount++; | 706 fRunCount++; |
578 | 707 |
579 SkASSERT(fStorageUsed <= fStorageSize); | 708 SkASSERT(fStorageUsed <= fStorageSize); |
580 run->validate(fStorage.get() + fStorageUsed); | 709 run->validate(fStorage.get() + fStorageUsed); |
581 } | 710 } |
582 | 711 SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.utf8text); |
712 SkASSERT(textSize > 0 || nullptr == fCurrentRunBuffer.clusters); | |
583 if (!fDeferredBounds) { | 713 if (!fDeferredBounds) { |
584 if (bounds) { | 714 if (bounds) { |
585 fBounds.join(*bounds); | 715 fBounds.join(*bounds); |
586 } else { | 716 } else { |
587 fDeferredBounds = true; | 717 fDeferredBounds = true; |
588 } | 718 } |
589 } | 719 } |
590 } | 720 } |
591 | 721 |
592 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRun(const SkPaint& f ont, int count, | 722 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunText(const SkPain t& font, int count, |
593 SkScalar x, SkSc alar y, | 723 SkScalar x, SkScalar y, |
594 const SkRect* bo unds) { | 724 int textByte Count, |
595 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, SkPoint:: Make(x, y), bounds); | 725 SkString lan g, |
596 | 726 const SkRect * bounds) { |
727 this->allocInternal(font, SkTextBlob::kDefault_Positioning, count, textByteC ount, SkPoint::Make(x, y), bounds); | |
597 return fCurrentRunBuffer; | 728 return fCurrentRunBuffer; |
598 } | 729 } |
599 | 730 |
600 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPosH(const SkPain t& font, int count, | 731 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPosH(const Sk Paint& font, int count, |
601 SkScalar y, | 732 SkScalar y, |
602 const SkRect * bounds) { | 733 int text ByteCount, |
603 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, SkPoin t::Make(0, y), | 734 SkString lang, |
735 const Sk Rect* bounds) { | |
736 this->allocInternal(font, SkTextBlob::kHorizontal_Positioning, count, textBy teCount, SkPoint::Make(0, y), | |
604 bounds); | 737 bounds); |
605 | 738 |
606 return fCurrentRunBuffer; | 739 return fCurrentRunBuffer; |
607 } | 740 } |
608 | 741 |
609 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunPos(const SkPaint & font, int count, | 742 const SkTextBlobBuilder::RunBuffer& SkTextBlobBuilder::allocRunTextPos(const SkP aint& font, int count, |
610 const SkRect *bounds) { | 743 int textB yteCount, |
611 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, SkPoint::Mak e(0, 0), bounds); | 744 SkString lang, |
745 const SkR ect *bounds) { | |
746 this->allocInternal(font, SkTextBlob::kFull_Positioning, count, textByteCount , SkPoint::Make(0, 0), bounds); | |
612 | 747 |
613 return fCurrentRunBuffer; | 748 return fCurrentRunBuffer; |
614 } | 749 } |
615 | 750 |
616 const SkTextBlob* SkTextBlobBuilder::build() { | 751 const SkTextBlob* SkTextBlobBuilder::build() { |
617 SkASSERT((fRunCount > 0) == (nullptr != fStorage.get())); | 752 SkASSERT((fRunCount > 0) == (nullptr != fStorage.get())); |
618 | 753 |
619 this->updateDeferredBounds(); | 754 this->updateDeferredBounds(); |
620 | 755 |
621 if (0 == fRunCount) { | 756 if (0 == fRunCount) { |
622 SkASSERT(nullptr == fStorage.get()); | 757 SkASSERT(nullptr == fStorage.get()); |
623 fStorageUsed = sizeof(SkTextBlob); | 758 fStorageUsed = sizeof(SkTextBlob); |
624 fStorage.realloc(fStorageUsed); | 759 fStorage.realloc(fStorageUsed); |
625 } | 760 } |
626 | 761 |
627 const SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fRunCount, fBou nds); | 762 const SkTextBlob* blob = new (fStorage.release()) SkTextBlob(fRunCount, fBou nds); |
628 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;) | 763 SkDEBUGCODE(const_cast<SkTextBlob*>(blob)->fStorageSize = fStorageSize;) |
629 | 764 |
630 SkDEBUGCODE( | 765 SkDEBUGCODE( |
631 size_t validateSize = sizeof(SkTextBlob); | 766 size_t validateSize = sizeof(SkTextBlob); |
632 const SkTextBlob::RunRecord* run = SkTextBlob::RunRecord::First(blob); | 767 const SkTextBlob::RunRecord* run = SkTextBlob::RunRecord::First(blob); |
633 for (int i = 0; i < fRunCount; ++i) { | 768 for (int i = 0; i < fRunCount; ++i) { |
634 validateSize += SkTextBlob::RunRecord::StorageSize(run->fCount, run- >fPositioning); | 769 validateSize += SkTextBlob::RunRecord::StorageSize( |
770 run->fCount, run->textSize(), run->fPositioning); | |
635 run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed) ; | 771 run->validate(reinterpret_cast<const uint8_t*>(blob) + fStorageUsed) ; |
636 run = SkTextBlob::RunRecord::Next(run); | 772 run = SkTextBlob::RunRecord::Next(run); |
637 } | 773 } |
638 SkASSERT(validateSize == fStorageUsed); | 774 SkASSERT(validateSize == fStorageUsed); |
639 ) | 775 ) |
640 | 776 |
641 fStorageUsed = 0; | 777 fStorageUsed = 0; |
642 fStorageSize = 0; | 778 fStorageSize = 0; |
643 fRunCount = 0; | 779 fRunCount = 0; |
644 fLastRun = 0; | 780 fLastRun = 0; |
645 fBounds.setEmpty(); | 781 fBounds.setEmpty(); |
646 | 782 |
647 return blob; | 783 return blob; |
648 } | 784 } |
OLD | NEW |