From d5fa136a0fd7bffcd05c4c406caa8c26ebf39bf1 Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Sun, 10 Feb 2019 01:47:46 +0200 Subject: [PATCH] Fix text-anchor subtree advance/extent calculation for letter-spacing Related to https://github.com/react-native-community/react-native-svg/issues/570 --- .../java/com/horcrux/svg/GlyphContext.java | 2 +- .../main/java/com/horcrux/svg/TSpanView.java | 7 ++++-- .../main/java/com/horcrux/svg/TextView.java | 24 +++++++------------ ios/Text/RNSVGTSpan.m | 21 ++++++++-------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/android/src/main/java/com/horcrux/svg/GlyphContext.java b/android/src/main/java/com/horcrux/svg/GlyphContext.java index 890f2869..d42bff93 100644 --- a/android/src/main/java/com/horcrux/svg/GlyphContext.java +++ b/android/src/main/java/com/horcrux/svg/GlyphContext.java @@ -19,7 +19,7 @@ import javax.annotation.Nullable; class GlyphContext { // Current stack (one per node push/pop) - private final ArrayList mFontContext = new ArrayList<>(); + final ArrayList mFontContext = new ArrayList<>(); // Unique input attribute lists (only added if node sets a value) private final ArrayList mXsContext = new ArrayList<>(); diff --git a/android/src/main/java/com/horcrux/svg/TSpanView.java b/android/src/main/java/com/horcrux/svg/TSpanView.java index 2695425e..9103c215 100644 --- a/android/src/main/java/com/horcrux/svg/TSpanView.java +++ b/android/src/main/java/com/horcrux/svg/TSpanView.java @@ -146,6 +146,7 @@ class TSpanView extends TextView { String disableDiscretionaryLigatures = "'liga' 0, 'clig' 0, 'dlig' 0, 'hlig' 0, 'cala' 0, "; paint.setFontFeatureSettings(defaultFeatures + disableDiscretionaryLigatures + font.fontFeatureSettings); } + paint.setLetterSpacing((float)(letterSpacing / (font.fontSize * mScale))); } return paint.measureText(line); @@ -610,7 +611,7 @@ class TSpanView extends TextView { // this will just retrieve the bounding rect for 'x' paint.getTextBounds("x", 0, 1, bounds); int xHeight = bounds.height(); - baselineShift = xHeight / 2; + baselineShift = xHeight / 2.0; break; case central: @@ -738,7 +739,6 @@ class TSpanView extends TextView { final Matrix end = new Matrix(); final float[] startPointMatrixData = new float[9]; - final float[] midPointMatrixData = new float[9]; final float[] endPointMatrixData = new float[9]; emoji.clear(); @@ -1008,6 +1008,9 @@ class TSpanView extends TextView { paint.setTypeface(typeface); paint.setTextSize((float) fontSize); paint.setTextAlign(Paint.Align.LEFT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + paint.setLetterSpacing(0); + } // Do these have any effect for anyone? Not for me (@msand) at least. // paint.setUnderlineText(underlineText); diff --git a/android/src/main/java/com/horcrux/svg/TextView.java b/android/src/main/java/com/horcrux/svg/TextView.java index d1600851..5d17f772 100644 --- a/android/src/main/java/com/horcrux/svg/TextView.java +++ b/android/src/main/java/com/horcrux/svg/TextView.java @@ -213,23 +213,17 @@ class TextView extends GroupView { TextView getTextAnchorRoot() { GlyphContext gc = getTextRootGlyphContext(); - FontData font = gc.getFont(); - TextProperties.TextAnchor textAnchor = font.textAnchor; - if (textAnchor == TextProperties.TextAnchor.start) { - return this; - } + ArrayList font = gc.mFontContext; + TextView node = this; ViewParent parent = this.getParent(); - if (parent instanceof TextView) { - TextView parentText = (TextView)parent; - GlyphContext parentGc = parentText.getGlyphContext(); - FontData parentFont = parentGc.getFont(); - if (parentFont.textAnchor == TextProperties.TextAnchor.start) { - return this; - } else { - return parentText.getTextAnchorRoot(); + for (int i = font.size() - 1; i >= 0; i--) { + if (!(parent instanceof TextView) || font.get(i).textAnchor == TextProperties.TextAnchor.start) { + return node; } + node = (TextView) parent; + parent = node.getParent(); } - return this; + return node; } double getSubtreeTextChunksTotalAdvance(Paint paint) { @@ -240,7 +234,7 @@ class TextView extends GroupView { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof TextView) { - TextView text = (TextView)child; + TextView text = (TextView) child; advance += text.getSubtreeTextChunksTotalAdvance(paint); } } diff --git a/ios/Text/RNSVGTSpan.m b/ios/Text/RNSVGTSpan.m index d52f780a..a219f89f 100644 --- a/ios/Text/RNSVGTSpan.m +++ b/ios/Text/RNSVGTSpan.m @@ -121,7 +121,7 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; RNSVGFontData* font = [gc getFont]; CGFloat letterSpacing = font->letterSpacing; - bool autoKerning = !font->manualKerning; + CGFloat kerning = font->kerning; bool allowOptionalLigatures = letterSpacing == 0 && font->fontVariantLigatures == RNSVGFontVariantLigaturesNormal; @@ -133,19 +133,18 @@ static CGFloat RNSVGTSpan_radToDeg = 180 / (CGFloat)M_PI; if (fontRef != nil) { attrs[NSFontAttributeName] = (__bridge id)fontRef; } - if (!autoKerning) { - NSNumber *noAutoKern = [NSNumber numberWithFloat:0.0f]; + float kern = (float)(letterSpacing + kerning); + NSNumber *kernAttr = [NSNumber numberWithFloat:kern]; #if DTCORETEXT_SUPPORT_NS_ATTRIBUTES - if (___useiOS6Attributes) - { - [attrs setObject:noAutoKern forKey:NSKernAttributeName]; - } - else + if (___useiOS6Attributes) + { + [attrs setObject:kernAttr forKey:NSKernAttributeName]; + } + else #endif - { - [attrs setObject:noAutoKern forKey:(id)kCTKernAttributeName]; - } + { + [attrs setObject:kernAttr forKey:(id)kCTKernAttributeName]; } attributes = (__bridge CFDictionaryRef)attrs;