Chromium Code Reviews| 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 |