diff options
author | Raph Levien <raph@google.com> | 2012-07-18 08:40:19 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-07-18 08:40:19 -0700 |
commit | 57bdd3d3782ceeba38dd862b7de73d47793bee93 (patch) | |
tree | f327c8061bb11a931bc197464e3b21b8c46708ea /core/jni | |
parent | db8d60fca3c8f4ba1a4027adf7ea40e4c1f956a3 (diff) | |
parent | 2301d32f7e2ba584abc31ac177dde754385d3c04 (diff) | |
download | frameworks_base-57bdd3d3782ceeba38dd862b7de73d47793bee93.zip frameworks_base-57bdd3d3782ceeba38dd862b7de73d47793bee93.tar.gz frameworks_base-57bdd3d3782ceeba38dd862b7de73d47793bee93.tar.bz2 |
Merge "Software-only implementation of glyph positioning (bug 5443796)"
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/android/graphics/Canvas.cpp | 51 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayoutCache.cpp | 72 | ||||
-rw-r--r-- | core/jni/android/graphics/TextLayoutCache.h | 11 |
3 files changed, 111 insertions, 23 deletions
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 6b74705..5c27602 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -766,8 +766,46 @@ public: if (value == NULL) { return; } - doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint); + SkPaint::Align align = paint->getTextAlign(); + if (align == SkPaint::kCenter_Align) { + x -= 0.5 * value->getTotalAdvance(); + } else if (align == SkPaint::kRight_Align) { + x -= value->getTotalAdvance(); + } + paint->setTextAlign(SkPaint::kLeft_Align); + doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint); + doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint); + paint->setTextAlign(align); + } + +// Same values used by Skia +#define kStdStrikeThru_Offset (-6.0f / 21.0f) +#define kStdUnderline_Offset (1.0f / 9.0f) +#define kStdUnderline_Thickness (1.0f / 18.0f) + +static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) { + uint32_t flags = paint->getFlags(); + if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { + SkScalar left = SkFloatToScalar(x); + SkScalar right = SkFloatToScalar(x + length); + float textSize = paint->getTextSize(); + float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); + if (flags & SkPaint::kUnderlineText_Flag) { + SkScalar top = SkFloatToScalar(y + textSize * kStdUnderline_Offset + - 0.5f * strokeWidth); + SkScalar bottom = SkFloatToScalar(y + textSize * kStdUnderline_Offset + + 0.5f * strokeWidth); + canvas->drawRectCoords(left, top, right, bottom, *paint); + } + if (flags & SkPaint::kStrikeThruText_Flag) { + SkScalar top = SkFloatToScalar(y + textSize * kStdStrikeThru_Offset + - 0.5f * strokeWidth); + SkScalar bottom = SkFloatToScalar(y + textSize * kStdStrikeThru_Offset + + 0.5f * strokeWidth); + canvas->drawRectCoords(left, top, right, bottom, *paint); + } } +} static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) { @@ -775,6 +813,17 @@ public: canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint); } + static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray, + int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) { + SkPoint* posPtr = new SkPoint[count]; + for (int indx = 0; indx < count; indx++) { + posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]); + posPtr[indx].fY = SkFloatToScalar(y + posArray[indx * 2 + 1]); + } + canvas->drawPosText(glyphArray, count << 1, posPtr, *paint); + delete[] posPtr; + } + static void drawTextRun___CIIIIFFIPaint( JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index, int count, int contextIndex, int contextCount, 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); diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h index 0b25e93..96ba34a 100644 --- a/core/jni/android/graphics/TextLayoutCache.h +++ b/core/jni/android/graphics/TextLayoutCache.h @@ -130,6 +130,8 @@ public: inline jfloat getTotalAdvance() const { return mTotalAdvance; } inline const jchar* getGlyphs() const { return mGlyphs.array(); } inline size_t getGlyphsCount() const { return mGlyphs.size(); } + inline const jfloat* getPos() const { return mPos.array(); } + inline size_t getPosCount() const { return mPos.size(); } /** * Advances vector @@ -147,6 +149,11 @@ public: Vector<jchar> mGlyphs; /** + * Pos vector (2 * i is x pos, 2 * i + 1 is y pos, same as drawPosText) + */ + Vector<jfloat> mPos; + + /** * Get the size of the Cache entry */ size_t getSize() const; @@ -224,12 +231,12 @@ private: void 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); void 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); SkTypeface* getCachedTypeface(SkTypeface** typeface, HB_Script script, SkTypeface::Style style); HB_Face getCachedHBFace(SkTypeface* typeface); |