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 "SkTextBlob.h" | 8 #include "SkTextBlob.h" |
| 9 | 9 |
| 10 #include "SkReadBuffer.h" | 10 #include "SkReadBuffer.h" |
| 11 #include "SkTypeface.h" | 11 #include "SkTypeface.h" |
| 12 #include "SkWriteBuffer.h" | 12 #include "SkWriteBuffer.h" |
| 13 | 13 |
| 14 namespace { | |
| 15 | |
| 16 // TODO(fmalita): replace with SkFont. | |
| 17 class RunFont : SkNoncopyable { | |
| 18 public: | |
| 19 RunFont(const SkPaint& paint) | |
| 20 : fSize(paint.getTextSize()) | |
| 21 , fScaleX(paint.getTextScaleX()) | |
| 22 , fTypeface(SkSafeRef(paint.getTypeface())) | |
| 23 , fSkewX(paint.getTextSkewX()) | |
| 24 , fHinting(paint.getHinting()) | |
| 25 , fFlags(paint.getFlags() & kFlagsMask) { } | |
| 26 | |
| 27 void applyToPaint(SkPaint* paint) const { | |
| 28 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
| 29 paint->setTypeface(fTypeface.get()); | |
| 30 paint->setTextSize(fSize); | |
| 31 paint->setTextScaleX(fScaleX); | |
| 32 paint->setTextSkewX(fSkewX); | |
| 33 paint->setHinting(static_cast<SkPaint::Hinting>(fHinting)); | |
| 34 | |
| 35 paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags); | |
| 36 } | |
| 37 | |
| 38 bool operator==(const RunFont& other) const { | |
| 39 return fTypeface == other.fTypeface | |
| 40 && fSize == other.fSize | |
| 41 && fScaleX == other.fScaleX | |
| 42 && fSkewX == other.fSkewX | |
| 43 && fHinting == other.fHinting | |
| 44 && fFlags == other.fFlags; | |
| 45 } | |
| 46 | |
| 47 bool operator!=(const RunFont& other) const { | |
| 48 return !(*this == other); | |
| 49 } | |
| 50 private: | |
| 51 const static uint32_t kFlagsMask = | |
| 52 SkPaint::kAntiAlias_Flag | | |
| 53 SkPaint::kUnderlineText_Flag | | |
| 54 SkPaint::kStrikeThruText_Flag | | |
| 55 SkPaint::kFakeBoldText_Flag | | |
| 56 SkPaint::kLinearText_Flag | | |
| 57 SkPaint::kSubpixelText_Flag | | |
| 58 SkPaint::kDevKernText_Flag | | |
| 59 SkPaint::kLCDRenderText_Flag | | |
| 60 SkPaint::kEmbeddedBitmapText_Flag | | |
| 61 SkPaint::kAutoHinting_Flag | | |
| 62 SkPaint::kVerticalText_Flag | | |
| 63 SkPaint::kGenA8FromLCD_Flag | | |
| 64 SkPaint::kDistanceFieldTextTEMP_Flag; | |
| 65 | |
| 66 SkScalar fSize; | |
| 67 SkScalar fScaleX; | |
| 68 | |
| 69 // Keep this SkAutoTUnref off the first position, to avoid interfering with | |
| 70 // SkNoncopyable empty baseclass optimization. | |
|
reed1
2015/04/09 14:44:49
Can we link to a bug here, to describe this empty
f(malita)
2015/04/09 15:25:47
Done.
| |
| 71 SkAutoTUnref<SkTypeface> fTypeface; | |
| 72 SkScalar fSkewX; | |
| 73 | |
| 74 SK_COMPILE_ASSERT(SkPaint::kFull_Hinting < 4, insufficient_hinting_bits); | |
| 75 uint32_t fHinting : 2; | |
| 76 SK_COMPILE_ASSERT((kFlagsMask & 0xffff) == kFlagsMask, insufficient_flags_bi ts); | |
| 77 uint32_t fFlags : 16; | |
| 78 | |
| 79 typedef SkNoncopyable INHERITED; | |
| 80 }; | |
| 81 | |
| 82 struct RunFontStorageEquivalent { | |
| 83 void* ptr; | |
|
reed1
2015/04/09 14:44:49
Can this be reordered to look like the field-order
f(malita)
2015/04/09 15:25:47
Done.
| |
| 84 SkScalar scalars[3]; | |
| 85 uint32_t flags; | |
| 86 }; | |
| 87 SK_COMPILE_ASSERT(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), runfont_s hould_stay_packed); | |
| 88 | |
| 89 } // anonymous namespace | |
| 90 | |
| 14 // | 91 // |
| 15 // Textblob data is laid out into externally-managed storage as follows: | 92 // Textblob data is laid out into externally-managed storage as follows: |
| 16 // | 93 // |
| 17 // -------------------------------------------------------------------------- --- | 94 // -------------------------------------------------------------------------- --- |
| 18 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... | 95 // | SkTextBlob | RunRecord | Glyphs[] | Pos[] | RunRecord | Glyphs[] | Pos[] | ... |
| 19 // -------------------------------------------------------------------------- --- | 96 // -------------------------------------------------------------------------- --- |
| 20 // | 97 // |
| 21 // Each run record describes a text blob run, and can be used to determine the (implicit) | 98 // Each run record describes a text blob run, and can be used to determine the (implicit) |
| 22 // location of the following record. | 99 // location of the following record. |
| 23 | 100 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 34 } | 111 } |
| 35 | 112 |
| 36 uint32_t glyphCount() const { | 113 uint32_t glyphCount() const { |
| 37 return fCount; | 114 return fCount; |
| 38 } | 115 } |
| 39 | 116 |
| 40 const SkPoint& offset() const { | 117 const SkPoint& offset() const { |
| 41 return fOffset; | 118 return fOffset; |
| 42 } | 119 } |
| 43 | 120 |
| 44 const SkPaint& font() const { | 121 const RunFont& font() const { |
| 45 return fFont; | 122 return fFont; |
| 46 } | 123 } |
| 47 | 124 |
| 48 GlyphPositioning positioning() const { | 125 GlyphPositioning positioning() const { |
| 49 return fPositioning; | 126 return fPositioning; |
| 50 } | 127 } |
| 51 | 128 |
| 52 uint16_t* glyphBuffer() const { | 129 uint16_t* glyphBuffer() const { |
| 53 // Glyph are stored immediately following the record. | 130 // Glyph are stored immediately following the record. |
| 54 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); | 131 return reinterpret_cast<uint16_t*>(const_cast<RunRecord*>(this) + 1); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 95 // Move the initial pos scalars to their new location. | 172 // Move the initial pos scalars to their new location. |
| 96 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning); | 173 size_t copySize = initialCount * sizeof(SkScalar) * ScalarsPerGlyph(fPos itioning); |
| 97 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); | 174 SkASSERT((uint8_t*)posBuffer() + copySize <= (uint8_t*)Next(this)); |
| 98 | 175 |
| 99 // memmove, as the buffers may overlap | 176 // memmove, as the buffers may overlap |
| 100 memmove(posBuffer(), initialPosBuffer, copySize); | 177 memmove(posBuffer(), initialPosBuffer, copySize); |
| 101 } | 178 } |
| 102 | 179 |
| 103 uint32_t fCount; | 180 uint32_t fCount; |
| 104 SkPoint fOffset; | 181 SkPoint fOffset; |
| 105 SkPaint fFont; | 182 RunFont fFont; |
|
reed1
2015/04/09 14:44:49
Can/should this field be first, for alignment, sin
f(malita)
2015/04/09 15:25:48
Good catch, I think that shaves another 8 bytes of
| |
| 106 GlyphPositioning fPositioning; | 183 GlyphPositioning fPositioning; |
| 107 | 184 |
| 108 SkDEBUGCODE(unsigned fMagic;) | 185 SkDEBUGCODE(unsigned fMagic;) |
| 109 }; | 186 }; |
| 110 | 187 |
| 111 static int32_t gNextID = 1; | 188 static int32_t gNextID = 1; |
| 112 static int32_t next_id() { | 189 static int32_t next_id() { |
| 113 int32_t id; | 190 int32_t id; |
| 114 do { | 191 do { |
| 115 id = sk_atomic_inc(&gNextID); | 192 id = sk_atomic_inc(&gNextID); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 } | 332 } |
| 256 | 333 |
| 257 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { | 334 SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const { |
| 258 SkASSERT(!this->done()); | 335 SkASSERT(!this->done()); |
| 259 return fCurrentRun->positioning(); | 336 return fCurrentRun->positioning(); |
| 260 } | 337 } |
| 261 | 338 |
| 262 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { | 339 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const { |
| 263 SkASSERT(!this->done()); | 340 SkASSERT(!this->done()); |
| 264 | 341 |
| 265 const SkPaint& font = fCurrentRun->font(); | 342 fCurrentRun->font().applyToPaint(paint); |
| 266 | |
| 267 paint->setTypeface(font.getTypeface()); | |
| 268 paint->setTextEncoding(font.getTextEncoding()); | |
| 269 paint->setTextSize(font.getTextSize()); | |
| 270 paint->setTextScaleX(font.getTextScaleX()); | |
| 271 paint->setTextSkewX(font.getTextSkewX()); | |
| 272 paint->setHinting(font.getHinting()); | |
| 273 | |
| 274 uint32_t flagsMask = SkPaint::kAntiAlias_Flag | |
| 275 | SkPaint::kUnderlineText_Flag | |
| 276 | SkPaint::kStrikeThruText_Flag | |
| 277 | SkPaint::kFakeBoldText_Flag | |
| 278 | SkPaint::kLinearText_Flag | |
| 279 | SkPaint::kSubpixelText_Flag | |
| 280 | SkPaint::kDevKernText_Flag | |
| 281 | SkPaint::kLCDRenderText_Flag | |
| 282 | SkPaint::kEmbeddedBitmapText_Flag | |
| 283 | SkPaint::kAutoHinting_Flag | |
| 284 | SkPaint::kVerticalText_Flag | |
| 285 | SkPaint::kGenA8FromLCD_Flag | |
| 286 | SkPaint::kDistanceFieldTextTEMP_Flag; | |
| 287 paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsM ask)); | |
| 288 } | 343 } |
| 289 | 344 |
| 290 SkTextBlobBuilder::SkTextBlobBuilder() | 345 SkTextBlobBuilder::SkTextBlobBuilder() |
| 291 : fStorageSize(0) | 346 : fStorageSize(0) |
| 292 , fStorageUsed(0) | 347 , fStorageUsed(0) |
| 293 , fRunCount(0) | 348 , fRunCount(0) |
| 294 , fDeferredBounds(false) | 349 , fDeferredBounds(false) |
| 295 , fLastRun(0) { | 350 , fLastRun(0) { |
| 296 fBounds.setEmpty(); | 351 fBounds.setEmpty(); |
| 297 } | 352 } |
| 298 | 353 |
| 299 SkTextBlobBuilder::~SkTextBlobBuilder() { | 354 SkTextBlobBuilder::~SkTextBlobBuilder() { |
| 300 if (NULL != fStorage.get()) { | 355 if (NULL != fStorage.get()) { |
| 301 // We are abandoning runs and must destruct the associated font data. | 356 // We are abandoning runs and must destruct the associated font data. |
| 302 // The easiest way to accomplish that is to use the blob destructor. | 357 // The easiest way to accomplish that is to use the blob destructor. |
| 303 build()->unref(); | 358 build()->unref(); |
| 304 } | 359 } |
| 305 } | 360 } |
| 306 | 361 |
| 307 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { | 362 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { |
| 308 SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning()); | 363 SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning()); |
| 309 | 364 |
| 310 SkRect bounds; | 365 SkRect bounds; |
| 311 run.font().measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t ), &bounds); | 366 SkPaint paint; |
| 367 run.font().applyToPaint(&paint); | |
| 368 paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &b ounds); | |
| 312 | 369 |
| 313 return bounds.makeOffset(run.offset().x(), run.offset().y()); | 370 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
| 314 } | 371 } |
| 315 | 372 |
| 316 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run ) { | 373 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run ) { |
| 317 SkASSERT(run.glyphCount() > 0); | 374 SkASSERT(run.glyphCount() > 0); |
| 318 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || | 375 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || |
| 319 SkTextBlob::kHorizontal_Positioning == run.positioning()); | 376 SkTextBlob::kHorizontal_Positioning == run.positioning()); |
| 320 | 377 |
| 321 // First, compute the glyph position bbox. | 378 // First, compute the glyph position bbox. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 339 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuf fer()); | 396 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuf fer()); |
| 340 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecor d::Next(&run)); | 397 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecor d::Next(&run)); |
| 341 | 398 |
| 342 bounds.setBounds(glyphPosPts, run.glyphCount()); | 399 bounds.setBounds(glyphPosPts, run.glyphCount()); |
| 343 } break; | 400 } break; |
| 344 default: | 401 default: |
| 345 SkFAIL("unsupported positioning mode"); | 402 SkFAIL("unsupported positioning mode"); |
| 346 } | 403 } |
| 347 | 404 |
| 348 // Expand by typeface glyph bounds. | 405 // Expand by typeface glyph bounds. |
| 349 const SkRect fontBounds = run.font().getFontBounds(); | 406 SkPaint paint; |
| 407 run.font().applyToPaint(&paint); | |
| 408 const SkRect fontBounds = paint.getFontBounds(); | |
| 350 bounds.fLeft += fontBounds.left(); | 409 bounds.fLeft += fontBounds.left(); |
| 351 bounds.fTop += fontBounds.top(); | 410 bounds.fTop += fontBounds.top(); |
| 352 bounds.fRight += fontBounds.right(); | 411 bounds.fRight += fontBounds.right(); |
| 353 bounds.fBottom += fontBounds.bottom(); | 412 bounds.fBottom += fontBounds.bottom(); |
| 354 | 413 |
| 355 // Offset by run position. | 414 // Offset by run position. |
| 356 return bounds.makeOffset(run.offset().x(), run.offset().y()); | 415 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
| 357 } | 416 } |
| 358 | 417 |
| 359 void SkTextBlobBuilder::updateDeferredBounds() { | 418 void SkTextBlobBuilder::updateDeferredBounds() { |
| 360 SkASSERT(!fDeferredBounds || fRunCount > 0); | 419 SkASSERT(!fDeferredBounds || fRunCount > 0); |
| 361 | 420 |
| 362 if (!fDeferredBounds) { | 421 if (!fDeferredBounds) { |
| 363 return; | 422 return; |
| 364 } | 423 } |
| 365 | 424 |
| 366 SkASSERT(fLastRun >= sizeof(SkTextBlob)); | 425 SkASSERT(fLastRun >= sizeof(SkTextBlob)); |
| 367 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() + | 426 SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStora ge.get() + |
| 368 fLastR un); | 427 fLastR un); |
| 369 SkASSERT(SkPaint::kGlyphID_TextEncoding == run->font().getTextEncoding()); | |
| 370 | 428 |
| 371 // FIXME: we should also use conservative bounds for kDefault_Positioning. | 429 // FIXME: we should also use conservative bounds for kDefault_Positioning. |
| 372 SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ? | 430 SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ? |
| 373 TightRunBounds(*run) : ConservativeRunBounds(*run); | 431 TightRunBounds(*run) : ConservativeRunBounds(*run); |
| 374 fBounds.join(runBounds); | 432 fBounds.join(runBounds); |
| 375 fDeferredBounds = false; | 433 fDeferredBounds = false; |
| 376 } | 434 } |
| 377 | 435 |
| 378 void SkTextBlobBuilder::reserve(size_t size) { | 436 void SkTextBlobBuilder::reserve(size_t size) { |
| 379 // We don't currently pre-allocate, but maybe someday... | 437 // We don't currently pre-allocate, but maybe someday... |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 535 | 593 |
| 536 fStorageUsed = 0; | 594 fStorageUsed = 0; |
| 537 fStorageSize = 0; | 595 fStorageSize = 0; |
| 538 fRunCount = 0; | 596 fRunCount = 0; |
| 539 fLastRun = 0; | 597 fLastRun = 0; |
| 540 fBounds.setEmpty(); | 598 fBounds.setEmpty(); |
| 541 | 599 |
| 542 return blob; | 600 return blob; |
| 543 } | 601 } |
| 544 | 602 |
| OLD | NEW |