From b0b45d35e4f30c1f42b6a910dc7f90e1a88de70c Mon Sep 17 00:00:00 2001 From: fmalita Date: Fri, 9 Oct 2015 14:46:28 -0700 Subject: [PATCH] [TextBlob] Fall back to TightRunBounds when the font bounds are empty Empty font bounds are likely an indication of a font bug. As a best effort, we can use TightRunBounds in this easily detectable case. Since TightRunBounds only supports kDefault_Positioning currently, the CL also reinstates handling of kFull_Positioning and kHorizontal_Positioning (removed in http://crrev.com/858153007). BUG=507022 R=reed@google.com,bungeman@google.com Review URL: https://codereview.chromium.org/1399123002 --- src/core/SkTextBlob.cpp | 52 +++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp index a49ff25101..2ccf26b1c6 100644 --- a/src/core/SkTextBlob.cpp +++ b/src/core/SkTextBlob.cpp @@ -367,12 +367,44 @@ SkTextBlobBuilder::~SkTextBlobBuilder() { } SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) { - SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning()); - SkRect bounds; SkPaint paint; run.font().applyToPaint(&paint); - paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds); + + if (SkTextBlob::kDefault_Positioning == run.positioning()) { + paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds); + return bounds.makeOffset(run.offset().x(), run.offset().y()); + } + + SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount()); + paint.getTextWidths(run.glyphBuffer(), + run.glyphCount() * sizeof(uint16_t), + NULL, + glyphBounds.get()); + + SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || + SkTextBlob::kHorizontal_Positioning == run.positioning()); + // kFull_Positioning => [ x, y, x, y... ] + // kHorizontal_Positioning => [ x, x, x... ] + // (const y applied by runBounds.offset(run->offset()) later) + const SkScalar horizontalConstY = 0; + const SkScalar* glyphPosX = run.posBuffer(); + const SkScalar* glyphPosY = (run.positioning() == SkTextBlob::kFull_Positioning) ? + glyphPosX + 1 : &horizontalConstY; + const unsigned posXInc = SkTextBlob::ScalarsPerGlyph(run.positioning()); + const unsigned posYInc = (run.positioning() == SkTextBlob::kFull_Positioning) ? + posXInc : 0; + + bounds.setEmpty(); + for (unsigned i = 0; i < run.glyphCount(); ++i) { + bounds.join(glyphBounds[i].makeOffset(*glyphPosX, *glyphPosY)); + glyphPosX += posXInc; + glyphPosY += posYInc; + } + + SkASSERT((void*)glyphPosX <= SkTextBlob::RunRecord::Next(&run)); + SkASSERT(run.positioning() == SkTextBlob::kHorizontal_Positioning || + (void*)glyphPosY <= SkTextBlob::RunRecord::Next(&run)); return bounds.makeOffset(run.offset().x(), run.offset().y()); } @@ -382,7 +414,16 @@ SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() || SkTextBlob::kHorizontal_Positioning == run.positioning()); - // First, compute the glyph position bbox. + SkPaint paint; + run.font().applyToPaint(&paint); + const SkRect fontBounds = paint.getFontBounds(); + if (fontBounds.isEmpty()) { + // Empty font bounds are likely a font bug. TightBounds has a better chance of + // producing useful results in this case. + return TightRunBounds(run); + } + + // Compute the glyph position bbox. SkRect bounds; switch (run.positioning()) { case SkTextBlob::kHorizontal_Positioning: { @@ -410,9 +451,6 @@ SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run } // Expand by typeface glyph bounds. - SkPaint paint; - run.font().applyToPaint(&paint); - const SkRect fontBounds = paint.getFontBounds(); bounds.fLeft += fontBounds.left(); bounds.fTop += fontBounds.top(); bounds.fRight += fontBounds.right();