aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2015-01-28 10:56:06 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-01-28 10:56:06 -0800
commit3dc40ac9f968eee95eef5e8ee811e0640691df0f (patch)
treec40e195fcaee3cf58f1a8ef25c957a99c0fa353b /src
parentcb30bf63b5e24ce53d959fbbae320d77d69e3d2c (diff)
Conservative SkTextBlob bounds.
Compute cheaper/more conservative text blob bounds based on the typeface maximum glyph bbox. BUG=chromium:451401 R=reed@google.com,bungeman@google.com Review URL: https://codereview.chromium.org/886473002
Diffstat (limited to 'src')
-rw-r--r--src/core/SkTextBlob.cpp110
1 files changed, 77 insertions, 33 deletions
diff --git a/src/core/SkTextBlob.cpp b/src/core/SkTextBlob.cpp
index 0b81cb6572..2293c2256f 100644
--- a/src/core/SkTextBlob.cpp
+++ b/src/core/SkTextBlob.cpp
@@ -8,6 +8,7 @@
#include "SkTextBlob.h"
#include "SkReadBuffer.h"
+#include "SkTypeface.h"
#include "SkWriteBuffer.h"
//
@@ -304,6 +305,74 @@ SkTextBlobBuilder::~SkTextBlobBuilder() {
}
}
+SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) {
+ SkRect bounds;
+
+ if (SkTextBlob::kDefault_Positioning == run.positioning()) {
+ run.font().measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds);
+ return bounds;
+ }
+
+ SkASSERT(SkTextBlob::kFull_Positioning == run.positioning() ||
+ SkTextBlob::kHorizontal_Positioning == run.positioning());
+
+ SkAutoSTArray<16, SkRect> glyphBounds(run.glyphCount());
+ run.font().getTextWidths(run.glyphBuffer(),
+ run.glyphCount() * sizeof(uint16_t),
+ NULL,
+ glyphBounds.get());
+
+ bounds = SkRect::MakeEmpty();
+ SkScalar* glyphPos = run.posBuffer();
+ for (unsigned i = 0; i < run.glyphCount(); ++i) {
+ if (SkTextBlob::kFull_Positioning == run.positioning()) {
+ // [ x, y, x, y... ]
+ glyphBounds[i].offset(glyphPos[0], glyphPos[1]);
+ SkASSERT(2 == SkTextBlob::ScalarsPerGlyph(run.positioning()));
+ glyphPos += 2;
+ } else {
+ // [ x, x, x... ], const y applied by runBounds.offset(run->offset()) later.
+ glyphBounds[i].offset(glyphPos[0], 0);
+ SkASSERT(1 == SkTextBlob::ScalarsPerGlyph(run.positioning()));
+ glyphPos += 1;
+ }
+
+ bounds.join(glyphBounds[i]);
+ }
+
+ SkASSERT((void*)glyphPos <= SkTextBlob::RunRecord::Next(&run));
+
+ return bounds.makeOffset(run.offset().x(), run.offset().y());
+}
+
+SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run) {
+ const SkScalar* glyphPos = run.posBuffer();
+ int posScalars = SkTextBlob::ScalarsPerGlyph(run.positioning());
+
+ SkASSERT(1 == posScalars || 2 == posScalars);
+ SkASSERT(run.glyphCount() > 0);
+ SkASSERT((void*)(glyphPos + run.glyphCount() * posScalars) <=
+ SkTextBlob::RunRecord::Next(&run));
+
+ // First, compute the glyph position bbox.
+ SkRect bounds = SkRect::MakeXYWH(glyphPos[0], (2 == posScalars) ? glyphPos[1] : 0, 0, 0);
+ for (unsigned i = 1; i < run.glyphCount(); ++i) {
+ SkScalar xpos = glyphPos[i * posScalars];
+ SkScalar ypos = (2 == posScalars) ? glyphPos[i * posScalars + 1] : 0;
+ bounds.growToInclude(xpos, ypos);
+ }
+
+ // Expand by typeface glyph bounds.
+ const SkRect fontBounds = run.font().getFontBounds();
+ bounds.fLeft += fontBounds.left();
+ bounds.fTop += fontBounds.top();
+ bounds.fRight += fontBounds.right();
+ bounds.fBottom += fontBounds.bottom();
+
+ // Offset by run position.
+ return bounds.makeOffset(run.offset().x(), run.offset().y());
+}
+
void SkTextBlobBuilder::updateDeferredBounds() {
SkASSERT(!fDeferredBounds || fRunCount > 0);
@@ -316,42 +385,17 @@ void SkTextBlobBuilder::updateDeferredBounds() {
fLastRun);
SkASSERT(SkPaint::kGlyphID_TextEncoding == run->font().getTextEncoding());
- SkRect runBounds = SkRect::MakeEmpty();
+ SkRect runBounds;
+#ifdef SK_SUPPORT_LEGACY_BLOB_BOUNDS
+ runBounds = TightRunBounds(*run);
+#else
+ // FIXME: conservative bounds for default positioning?
if (SkTextBlob::kDefault_Positioning == run->positioning()) {
- run->font().measureText(run->glyphBuffer(),
- run->glyphCount() * sizeof(uint16_t),
- &runBounds);
+ runBounds = TightRunBounds(*run);
} else {
- SkASSERT(SkTextBlob::kFull_Positioning == run->positioning() ||
- SkTextBlob::kHorizontal_Positioning == run->positioning());
-
- SkAutoSTArray<16, SkRect> glyphBounds(run->glyphCount());
- run->font().getTextWidths(run->glyphBuffer(),
- run->glyphCount() * sizeof(uint16_t),
- NULL,
- glyphBounds.get());
-
- SkScalar* glyphOffset = run->posBuffer();
- for (unsigned i = 0; i < run->glyphCount(); ++i) {
- if (SkTextBlob::kFull_Positioning == run->positioning()) {
- // [ x, y, x, y... ]
- glyphBounds[i].offset(glyphOffset[0], glyphOffset[1]);
- SkASSERT(2 == SkTextBlob::ScalarsPerGlyph(run->positioning()));
- glyphOffset += 2;
- } else {
- // [ x, x, x... ], const y applied by runBounds.offset(run->offset()) later.
- glyphBounds[i].offset(glyphOffset[0], 0);
- SkASSERT(1 == SkTextBlob::ScalarsPerGlyph(run->positioning()));
- glyphOffset += 1;
- }
-
- runBounds.join(glyphBounds[i]);
- }
-
- SkASSERT((void*)glyphOffset <= SkTextBlob::RunRecord::Next(run));
+ runBounds = ConservativeRunBounds(*run);
}
-
- runBounds.offset(run->offset());
+#endif
fBounds.join(runBounds);
fDeferredBounds = false;