diff --git a/android/src/main/java/com/horcrux/svg/GlyphPathBag.java b/android/src/main/java/com/horcrux/svg/GlyphPathBag.java new file mode 100644 index 00000000..0b411dd3 --- /dev/null +++ b/android/src/main/java/com/horcrux/svg/GlyphPathBag.java @@ -0,0 +1,48 @@ +package com.horcrux.svg; + +import android.graphics.Paint; +import android.graphics.Path; + +import java.util.ArrayList; + +class GlyphPathBag { + private ArrayList paths = new ArrayList<>(); + private int[][] data = new int[255][]; + Paint paint; + + GlyphPathBag(Paint paint) { + this.paint = paint; + // Make indexed-by-one, to allow zero to represent non-cached + paths.add(new Path()); + } + + Path getOrCreateAndCache(char ch, String current) { + int index = getIndex(ch); + Path cached; + + if (index != 0) { + cached = paths.get(index); + } else { + cached = new Path(); + paint.getTextPath(current, 0, 1, 0, 0, cached); + + int[] bin = data[ch >> 8]; + if (bin == null) { + bin = data[ch >> 8] = new int[255]; + } + bin[ch & 0xFF] = paths.size(); + + paths.add(cached); + } + + Path glyph = new Path(); + glyph.addPath(cached); + return glyph; + } + + private int getIndex(char ch) { + int[] bin = data[ch >> 8]; + if (bin == null) return 0; + return bin[ch & 0xFF]; + } +} diff --git a/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java b/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java index b50435ed..f9467afa 100644 --- a/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java @@ -98,6 +98,7 @@ class TSpanShadowNode extends TextShadowNode { GlyphContext gc = getTextRootGlyphContext(); FontData font = gc.getFont(); applyTextPropertiesToPaint(paint, font); + GlyphPathBag bag = new GlyphPathBag(paint); /* Determine the startpoint-on-the-path for the first glyph using attribute ‘startOffset’ @@ -127,7 +128,6 @@ class TSpanShadowNode extends TextShadowNode { double distance = 0; PathMeasure pm = null; - double renderMethodScaling = 1; if (textPath != null) { pm = new PathMeasure(textPath.getPath(), false); distance = pm.getLength(); @@ -142,12 +142,10 @@ class TSpanShadowNode extends TextShadowNode { // https://svgwg.org/svg2-draft/text.html#TextPathElementSpacingAttribute } */ - final TextPathMethod method = textPath.getMethod(); - if (method == TextPathMethod.stretch) { - renderMethodScaling = distance / textMeasure; - } } + double renderMethodScaling = getRenderMethodScaling(textMeasure, distance); + /* * * Three properties affect the space between characters and words: @@ -427,8 +425,7 @@ class TSpanShadowNode extends TextShadowNode { mid.preRotate((float) r); - Path glyph = new Path(); - paint.getTextPath(current, 0, 1, 0, 0, glyph); + Path glyph = bag.getOrCreateAndCache(currentChar, current); glyph.transform(mid); path.addPath(glyph); } @@ -436,6 +433,13 @@ class TSpanShadowNode extends TextShadowNode { return path; } + private double getRenderMethodScaling(double textMeasure, double distance) { + if (textPath != null && textPath.getMethod() == TextPathMethod.stretch) { + return distance / textMeasure; + } + return 1; + } + private double getAbsoluteStartOffset(double distance, double size, String startOffset) { return PropHelper.fromRelative(startOffset, distance, 0, mScale, size); }