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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |