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" |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 | 360 |
361 SkTextBlobBuilder::~SkTextBlobBuilder() { | 361 SkTextBlobBuilder::~SkTextBlobBuilder() { |
362 if (nullptr != fStorage.get()) { | 362 if (nullptr != fStorage.get()) { |
363 // We are abandoning runs and must destruct the associated font data. | 363 // We are abandoning runs and must destruct the associated font data. |
364 // The easiest way to accomplish that is to use the blob destructor. | 364 // The easiest way to accomplish that is to use the blob destructor. |
365 build()->unref(); | 365 build()->unref(); |
366 } | 366 } |
367 } | 367 } |
368 | 368 |
369 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { | 369 SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { |
370 SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning()); | |
371 | |
372 SkRect bounds; | 370 SkRect bounds; |
373 SkPaint paint; | 371 SkPaint paint; |
374 run.font().applyToPaint(&paint); | 372 run.font().applyToPaint(&paint); |
375 paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &b
ounds); | 373 |
| 374 if (SkTextBlob::kDefault_Positioning == run.positioning()) { |
| 375 paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t)
, &bounds); |
| 376 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
| 377 } |
| 378 |
| 379 SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount()); |
| 380 paint.getTextWidths(run.glyphBuffer(), |
| 381 run.glyphCount() * sizeof(uint16_t), |
| 382 NULL, |
| 383 glyphBounds.get()); |
| 384 |
| 385 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || |
| 386 SkTextBlob::kHorizontal_Positioning == run.positioning()); |
| 387 // kFull_Positioning => [ x, y, x, y... ] |
| 388 // kHorizontal_Positioning => [ x, x, x... ] |
| 389 // (const y applied by runBounds.offset(run->offs
et()) later) |
| 390 const SkScalar horizontalConstY = 0; |
| 391 const SkScalar* glyphPosX = run.posBuffer(); |
| 392 const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Position
ing) ? |
| 393 glyphPosX + 1 : &horizonta
lConstY; |
| 394 const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning()); |
| 395 const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning
) ? |
| 396 posXInc : 0; |
| 397 |
| 398 bounds.setEmpty(); |
| 399 for (unsigned i = 0; i < run.glyphCount(); ++i) { |
| 400 bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY)); |
| 401 glyphPosX += posXInc; |
| 402 glyphPosY += posYInc; |
| 403 } |
| 404 |
| 405 SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run)); |
| 406 SkASSERT(run.positioning() == SkTextBlob::kHorizontal_Positioning || |
| 407 (void*)glyphPosY <= SkTextBlob::RunRecord::Next(&run)); |
376 | 408 |
377 return bounds.makeOffset(run.offset().x(), run.offset().y()); | 409 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
378 } | 410 } |
379 | 411 |
380 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run
) { | 412 SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run
) { |
381 SkASSERT(run.glyphCount() > 0); | 413 SkASSERT(run.glyphCount() > 0); |
382 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || | 414 SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || |
383 SkTextBlob::kHorizontal_Positioning == run.positioning()); | 415 SkTextBlob::kHorizontal_Positioning == run.positioning()); |
384 | 416 |
385 // First, compute the glyph position bbox. | 417 SkPaint paint; |
| 418 run.font().applyToPaint(&paint); |
| 419 const SkRect fontBounds = paint.getFontBounds(); |
| 420 if (fontBounds.isEmpty()) { |
| 421 // Empty font bounds are likely a font bug. TightBounds has a better ch
ance of |
| 422 // producing useful results in this case. |
| 423 return TightRunBounds(run); |
| 424 } |
| 425 |
| 426 // Compute the glyph position bbox. |
386 SkRect bounds; | 427 SkRect bounds; |
387 switch (run.positioning()) { | 428 switch (run.positioning()) { |
388 case SkTextBlob::kHorizontal_Positioning: { | 429 case SkTextBlob::kHorizontal_Positioning: { |
389 const SkScalar* glyphPos = run.posBuffer(); | 430 const SkScalar* glyphPos = run.posBuffer(); |
390 SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::
Next(&run)); | 431 SkASSERT((void*)(glyphPos + run.glyphCount()) <= SkTextBlob::RunRecord::
Next(&run)); |
391 | 432 |
392 SkScalar minX = *glyphPos; | 433 SkScalar minX = *glyphPos; |
393 SkScalar maxX = *glyphPos; | 434 SkScalar maxX = *glyphPos; |
394 for (unsigned i = 1; i < run.glyphCount(); ++i) { | 435 for (unsigned i = 1; i < run.glyphCount(); ++i) { |
395 SkScalar x = glyphPos[i]; | 436 SkScalar x = glyphPos[i]; |
396 minX = SkMinScalar(x, minX); | 437 minX = SkMinScalar(x, minX); |
397 maxX = SkMaxScalar(x, maxX); | 438 maxX = SkMaxScalar(x, maxX); |
398 } | 439 } |
399 | 440 |
400 bounds.setLTRB(minX, 0, maxX, 0); | 441 bounds.setLTRB(minX, 0, maxX, 0); |
401 } break; | 442 } break; |
402 case SkTextBlob::kFull_Positioning: { | 443 case SkTextBlob::kFull_Positioning: { |
403 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuf
fer()); | 444 const SkPoint* glyphPosPts = reinterpret_cast<const SkPoint*>(run.posBuf
fer()); |
404 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecor
d::Next(&run)); | 445 SkASSERT((void*)(glyphPosPts + run.glyphCount()) <= SkTextBlob::RunRecor
d::Next(&run)); |
405 | 446 |
406 bounds.setBounds(glyphPosPts, run.glyphCount()); | 447 bounds.setBounds(glyphPosPts, run.glyphCount()); |
407 } break; | 448 } break; |
408 default: | 449 default: |
409 SkFAIL("unsupported positioning mode"); | 450 SkFAIL("unsupported positioning mode"); |
410 } | 451 } |
411 | 452 |
412 // Expand by typeface glyph bounds. | 453 // Expand by typeface glyph bounds. |
413 SkPaint paint; | |
414 run.font().applyToPaint(&paint); | |
415 const SkRect fontBounds = paint.getFontBounds(); | |
416 bounds.fLeft += fontBounds.left(); | 454 bounds.fLeft += fontBounds.left(); |
417 bounds.fTop += fontBounds.top(); | 455 bounds.fTop += fontBounds.top(); |
418 bounds.fRight += fontBounds.right(); | 456 bounds.fRight += fontBounds.right(); |
419 bounds.fBottom += fontBounds.bottom(); | 457 bounds.fBottom += fontBounds.bottom(); |
420 | 458 |
421 // Offset by run position. | 459 // Offset by run position. |
422 return bounds.makeOffset(run.offset().x(), run.offset().y()); | 460 return bounds.makeOffset(run.offset().x(), run.offset().y()); |
423 } | 461 } |
424 | 462 |
425 void SkTextBlobBuilder::updateDeferredBounds() { | 463 void SkTextBlobBuilder::updateDeferredBounds() { |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 | 637 |
600 fStorageUsed = 0; | 638 fStorageUsed = 0; |
601 fStorageSize = 0; | 639 fStorageSize = 0; |
602 fRunCount = 0; | 640 fRunCount = 0; |
603 fLastRun = 0; | 641 fLastRun = 0; |
604 fBounds.setEmpty(); | 642 fBounds.setEmpty(); |
605 | 643 |
606 return blob; | 644 return blob; |
607 } | 645 } |
608 | 646 |
OLD | NEW |