From 64ed6861e2408965153c3c998a0f2c995e426aff Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Mon, 19 Jun 2017 01:43:04 +0300 Subject: [PATCH] Improve Text on a path layout rules conformance. Correct glyph point and delta x / y calculation and context handling. Remove incorrect whitespace from getLinePath method call. Correct the y coordinate of the text's origin when rendering glyphs into paths using getTextPath. Remove strange postTranslate transform. https://www.w3.org/TR/SVG11/text.html#TextOnAPath --- .../java/com/horcrux/svg/GlyphContext.java | 31 ++++++++++++------- .../java/com/horcrux/svg/TSpanShadowNode.java | 17 ++++------ .../java/com/horcrux/svg/TextShadowNode.java | 4 +++ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/android/src/main/java/com/horcrux/svg/GlyphContext.java b/android/src/main/java/com/horcrux/svg/GlyphContext.java index 4b5f4df4..cbd0838a 100644 --- a/android/src/main/java/com/horcrux/svg/GlyphContext.java +++ b/android/src/main/java/com/horcrux/svg/GlyphContext.java @@ -25,6 +25,7 @@ public class GlyphContext { private ArrayList mFontContext; private ArrayList mLocationContext; + private ArrayList mDeltaContext; private ArrayList> mDeltaXContext; private ArrayList> mDeltaYContext; private ArrayList mXContext; @@ -42,6 +43,7 @@ public class GlyphContext { mCurrentLocation = new PointF(); mFontContext = new ArrayList<>(); mLocationContext = new ArrayList<>(); + mDeltaContext = new ArrayList<>(); mDeltaXContext = new ArrayList<>(); mDeltaYContext = new ArrayList<>(); mXContext = new ArrayList<>(); @@ -59,6 +61,7 @@ public class GlyphContext { } mLocationContext.add(location); + mDeltaContext.add(new PointF(0, 0)); mFontContext.add(font); mDeltaXContext.add(getFloatArrayListFromReadableArray(deltaX)); mDeltaYContext.add(getFloatArrayListFromReadableArray(deltaY)); @@ -72,6 +75,7 @@ public class GlyphContext { float x = mXContext.get(mContextLength - 1); mFontContext.remove(mContextLength - 1); mLocationContext.remove(mContextLength - 1); + mDeltaContext.remove(mContextLength - 1); mDeltaXContext.remove(mContextLength - 1); mDeltaYContext.remove(mContextLength - 1); mXContext.remove(mContextLength - 1); @@ -87,23 +91,28 @@ public class GlyphContext { } public PointF getNextGlyphPoint(float offset, float glyphWidth) { - float dx = getNextDelta(mDeltaXContext); - mCurrentLocation.x += dx; - - float dy = getNextDelta(mDeltaYContext); - mCurrentLocation.y += dy; - - for (PointF point: mLocationContext) { - point.x += dx; - point.y += dy; - } - mXContext.set(mXContext.size() - 1, mCurrentLocation.x + offset + glyphWidth); return new PointF(mCurrentLocation.x + offset, mCurrentLocation.y); } + public PointF getNextGlyphDelta() { + float dx = getNextDelta(mDeltaXContext); + float dy = getNextDelta(mDeltaYContext); + + if (mContextLength > 0) { + for (PointF point: mDeltaContext) { + point.x += dx; + point.y += dy; + } + + return mDeltaContext.get(mContextLength - 1); + } + + return new PointF(dx, dy); + } + private float getNextDelta(ArrayList> deltaContext) { float value = 0; boolean valueSet = false; diff --git a/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java b/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java index 6a9ddc8e..f0a633a4 100644 --- a/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java @@ -78,7 +78,7 @@ public class TSpanShadowNode extends TextShadowNode { pushGlyphContext(); applyTextPropertiesToPaint(paint); - getLinePath(mContent + " ", paint, path); + getLinePath(mContent + "", paint, path); mCache = path; popGlyphContext(); @@ -99,13 +99,14 @@ public class TSpanShadowNode extends TextShadowNode { Path glyph = new Path(); float width = widths[index]; - paint.getTextPath(letter, 0, 1, 0, -paint.ascent(), glyph); + paint.getTextPath(letter, 0, 1, 0, 0, glyph); + PointF glyphDelta = getGlyphDeltaFromContext(); PointF glyphPoint = getGlyphPointFromContext(glyphPosition, width); glyphPosition += width; Matrix matrix = new Matrix(); if (mBezierTransformer != null) { - matrix = mBezierTransformer.getTransformAtDistance(glyphPoint.x); + matrix = mBezierTransformer.getTransformAtDistance(glyphPoint.x + glyphDelta.x); if (textPathHasReachedEnd()) { break; @@ -113,22 +114,16 @@ public class TSpanShadowNode extends TextShadowNode { continue; } + matrix.preTranslate(0, glyphDelta.y); matrix.postTranslate(0, glyphPoint.y); } else { - matrix.setTranslate(glyphPoint.x, glyphPoint.y); + matrix.setTranslate(glyphPoint.x + glyphDelta.x, glyphPoint.y + glyphDelta.y); } - glyph.transform(matrix); path.addPath(glyph); } - if (mBezierTransformer != null) { - Matrix matrix = new Matrix(); - matrix.postTranslate(0, paint.ascent() * 1.1f); - path.transform(matrix); - } - return path; } diff --git a/android/src/main/java/com/horcrux/svg/TextShadowNode.java b/android/src/main/java/com/horcrux/svg/TextShadowNode.java index b8be10d6..a38c855a 100644 --- a/android/src/main/java/com/horcrux/svg/TextShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/TextShadowNode.java @@ -200,6 +200,10 @@ public class TextShadowNode extends GroupShadowNode { return getTextRoot().getGlyphContext().getNextGlyphPoint(offset, glyphWidth); } + protected PointF getGlyphDeltaFromContext() { + return getTextRoot().getGlyphContext().getNextGlyphDelta(); + } + private Matrix getAlignMatrix(Path path) { RectF box = new RectF(); path.computeBounds(box, true);