summaryrefslogtreecommitdiffstats
path: root/core/jni/android/graphics/TextLayoutCache.cpp
diff options
context:
space:
mode:
authorRaph Levien <raph@google.com>2012-07-17 16:39:49 -0700
committerRaph Levien <raph@google.com>2012-07-17 18:11:28 -0700
commit2301d32f7e2ba584abc31ac177dde754385d3c04 (patch)
tree59529375dac20ebbea7d90665d1b7c265367aa41 /core/jni/android/graphics/TextLayoutCache.cpp
parent1deb589bf566a4c5cc8d450f55d5623b9580cfac (diff)
downloadframeworks_base-2301d32f7e2ba584abc31ac177dde754385d3c04.zip
frameworks_base-2301d32f7e2ba584abc31ac177dde754385d3c04.tar.gz
frameworks_base-2301d32f7e2ba584abc31ac177dde754385d3c04.tar.bz2
Software-only implementation of glyph positioning (bug 5443796)
This patch implements glyph positioning in the Skia-based renderer. Note that it depends on a fix for bug 6833339 being in place (correct calculation of advance widths under skew and scale transforms), otherwise there will be regressions. Careful attention was paid to correct results in a wide variety of conditions: alignments, text decorations, scale, skew, etc. Many of these are exercised in the test app attached to bug 6833339. Note that this patch also changes slightly the way that the total advance is calculated - the running is accumulated and passed through to computeRunValues(), so that the x positions of each glyph can be set according to the total advance of all glyphs (in all runs) appearing before (plus, of course, the offset for mark positioning). After committing this patch, text rendering will no longer match between the software and hardware rendering cases. Implementing positioning in the hardware renderer will resolve that, and fully implement bug 5443796. Change-Id: Ie0f7835d48bc120475a19afbfe159aa5304fcaa8
Diffstat (limited to 'core/jni/android/graphics/TextLayoutCache.cpp')
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp72
1 files changed, 52 insertions, 20 deletions
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 2bdba87..37747bf 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -308,11 +308,12 @@ TextLayoutValue::TextLayoutValue(size_t contextCount) :
// Give a hint for advances and glyphs vectors size
mAdvances.setCapacity(contextCount);
mGlyphs.setCapacity(contextCount);
+ mPos.setCapacity(contextCount * 2);
}
size_t TextLayoutValue::getSize() const {
return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() +
- sizeof(jchar) * mGlyphs.capacity();
+ sizeof(jchar) * mGlyphs.capacity() + sizeof(jfloat) * mPos.capacity();
}
void TextLayoutValue::setElapsedTime(uint32_t time) {
@@ -329,13 +330,9 @@ TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) {
mFontRec.klass = &harfbuzzSkiaClass;
mFontRec.userData = 0;
- // The values which harfbuzzSkiaClass returns are already scaled to
- // pixel units, so we just set all these to one to disable further
- // scaling.
- mFontRec.x_ppem = 1;
- mFontRec.y_ppem = 1;
- mFontRec.x_scale = 1;
- mFontRec.y_scale = 1;
+ // Note that the scaling values (x_ and y_ppem, x_ and y_scale) will be set
+ // below, when the paint transform and em unit of the actual shaping font
+ // are known.
memset(&mShaperItem, 0, sizeof(mShaperItem));
@@ -360,7 +357,7 @@ void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* pain
size_t start, size_t count, size_t contextCount, int dirFlags) {
computeValues(paint, chars, start, count, contextCount, dirFlags,
- &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs);
+ &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
#if DEBUG_ADVANCES
ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
contextCount, value->mTotalAdvance);
@@ -370,9 +367,9 @@ void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* pain
void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
- Vector<jchar>* const outGlyphs) {
+ Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
+ *outTotalAdvance = 0;
if (!count) {
- *outTotalAdvance = 0;
return;
}
@@ -437,6 +434,7 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
ALOGW("Visual run is not valid");
outGlyphs->clear();
outAdvances->clear();
+ outPos->clear();
*outTotalAdvance = 0;
isRTL = (paraDir == 1);
useSingleRun = true;
@@ -459,15 +457,13 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
lengthRun = endRun - startRun;
isRTL = (runDir == UBIDI_RTL);
- jfloat runTotalAdvance = 0;
#if DEBUG_GLYPHS
ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
i, startRun, lengthRun, isRTL);
#endif
computeRunValues(paint, chars + startRun, lengthRun, isRTL,
- outAdvances, &runTotalAdvance, outGlyphs);
+ outAdvances, outTotalAdvance, outGlyphs, outPos);
- *outTotalAdvance += runTotalAdvance;
}
}
} else {
@@ -490,7 +486,7 @@ void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
"-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
#endif
computeRunValues(paint, chars + start, count, isRTL,
- outAdvances, outTotalAdvance, outGlyphs);
+ outAdvances, outTotalAdvance, outGlyphs, outPos);
}
#if DEBUG_GLYPHS
@@ -512,10 +508,9 @@ static void logGlyphs(HB_ShaperItem shaperItem) {
void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars,
size_t count, bool isRTL,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
- Vector<jchar>* const outGlyphs) {
+ Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
if (!count) {
// We cannot shape an empty run.
- *outTotalAdvance = 0;
return;
}
@@ -615,7 +610,8 @@ void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars
// Define shaping paint properties
mShapingPaint.setTextSize(paint->getTextSize());
- mShapingPaint.setTextSkewX(paint->getTextSkewX());
+ float skewX = paint->getTextSkewX();
+ mShapingPaint.setTextSkewX(skewX);
mShapingPaint.setTextScaleX(paint->getTextScaleX());
mShapingPaint.setFlags(paint->getFlags());
mShapingPaint.setHinting(paint->getHinting());
@@ -624,7 +620,7 @@ void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars
// into the shaperItem
ssize_t indexFontRun = isRTL ? mShaperItem.stringLength - 1 : 0;
unsigned numCodePoints = 0;
- jfloat totalAdvance = 0;
+ jfloat totalAdvance = *outTotalAdvance;
while ((isRTL) ?
hb_utf16_script_run_prev(&numCodePoints, &mShaperItem.item, mShaperItem.string,
mShaperItem.stringLength, &indexFontRun):
@@ -692,7 +688,6 @@ void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars
currentAdvance = HBFixedToFloat(mShaperItem.advances[i]);
totalFontRunAdvance += currentAdvance;
}
- totalAdvance += totalFontRunAdvance;
#if DEBUG_ADVANCES
ALOGD("Returned advances");
@@ -717,6 +712,30 @@ void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars
outGlyphs->add(glyph);
}
}
+
+ // Get glyph positions (and reverse them in place if RTL)
+ if (outPos) {
+ size_t countGlyphs = mShaperItem.num_glyphs;
+ jfloat x = totalAdvance;
+ for (size_t i = 0; i < countGlyphs; i++) {
+ size_t index = (!isRTL) ? i : countGlyphs - 1 - i;
+ float xo = HBFixedToFloat(mShaperItem.offsets[index].x);
+ float yo = HBFixedToFloat(mShaperItem.offsets[index].y);
+ // Apply skewX component of transform to position offsets. Note
+ // that scale has already been applied through x_ and y_scale
+ // set in the mFontRec.
+ outPos->add(x + xo + yo * skewX);
+ outPos->add(yo);
+#ifdef DEBUG_GLYPHS
+ ALOGD(" -- hb adv[%d] = %f, log_cluster[%d] = %d",
+ index, HBFixedToFloat(mShaperItem.advances[index]),
+ index, mShaperItem.log_clusters[index]);
+#endif
+ x += HBFixedToFloat(mShaperItem.advances[index]);
+ }
+ }
+
+ totalAdvance += totalFontRunAdvance;
}
*outTotalAdvance = totalAdvance;
@@ -807,6 +826,19 @@ size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
mShapingPaint.setTypeface(typeface);
mShaperItem.face = getCachedHBFace(typeface);
+ int textSize = paint->getTextSize();
+ float scaleX = paint->getTextScaleX();
+ mFontRec.x_ppem = floor(scaleX * textSize + 0.5);
+ mFontRec.y_ppem = textSize;
+ uint32_t unitsPerEm = SkFontHost::GetUnitsPerEm(typeface->uniqueID());
+ // x_ and y_scale are the conversion factors from font design space
+ // (unitsPerEm) to 1/64th of device pixels in 16.16 format.
+ const int kDevicePixelFraction = 64;
+ const int kMultiplyFor16Dot16 = 1 << 16;
+ float emScale = kDevicePixelFraction * kMultiplyFor16Dot16 / (float)unitsPerEm;
+ mFontRec.x_scale = emScale * scaleX * textSize;
+ mFontRec.y_scale = emScale * textSize;
+
#if DEBUG_GLYPHS
ALOGD("Run typeface = %p, uniqueID = %d, hb_face = %p",
typeface, typeface->uniqueID(), mShaperItem.face);