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