[Android] Attempt to fix text-anchor subtree advance/extent calculation

Related to
https://github.com/react-native-community/react-native-svg/issues/600
https://github.com/react-native-community/react-native-svg/issues/570
This commit is contained in:
Mikael Sand
2019-02-09 22:51:22 +02:00
parent 04fc2cdce5
commit 60a7b1fd53
2 changed files with 89 additions and 1 deletions
@@ -21,6 +21,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Build;
import android.view.View;
import android.view.ViewParent;
import com.facebook.react.bridge.ReactContext;
@@ -106,6 +107,50 @@ class TSpanView extends TextView {
return mPath;
}
double getSubtreeTextChunksTotalAdvance(Paint paint) {
double advance = 0;
if (mContent == null) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof TextView) {
TextView text = (TextView)child;
advance += text.getSubtreeTextChunksTotalAdvance(paint);
}
}
return advance;
}
String line = mContent;
final int length = line.length();
if (length == 0) {
return advance;
}
GlyphContext gc = getTextRootGlyphContext();
FontData font = gc.getFont();
applyTextPropertiesToPaint(paint, font);
double letterSpacing = font.letterSpacing;
final boolean allowOptionalLigatures = letterSpacing == 0 &&
font.fontVariantLigatures == FontVariantLigatures.normal;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
String required = "'rlig', 'liga', 'clig', 'calt', 'locl', 'ccmp', 'mark', 'mkmk',";
String defaultFeatures = required + "'kern', ";
if (allowOptionalLigatures) {
String additionalLigatures = "'hlig', 'cala', ";
paint.setFontFeatureSettings(defaultFeatures + additionalLigatures + font.fontFeatureSettings);
} else {
String disableDiscretionaryLigatures = "'liga' 0, 'clig' 0, 'dlig' 0, 'hlig' 0, 'cala' 0, ";
paint.setFontFeatureSettings(defaultFeatures + disableDiscretionaryLigatures + font.fontFeatureSettings);
}
}
return paint.measureText(line);
}
@SuppressWarnings("ConstantConditions")
private Path getLinePath(String line, Paint paint, Canvas canvas) {
final int length = line.length();
@@ -311,8 +356,10 @@ class TSpanView extends TextView {
attributes, such as a dx attribute value on a tspan element.
*/
final TextAnchor textAnchor = font.textAnchor;
final double textMeasure = paint.measureText(line);
TextView anchorRoot = getTextAnchorRoot();
final double textMeasure = anchorRoot.getSubtreeTextChunksTotalAdvance(paint);
double offset = getTextAnchorOffset(textAnchor, textMeasure);
applyTextPropertiesToPaint(paint, font);
int side = 1;
double startOfRendering = 0;
@@ -14,6 +14,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Region;
import android.view.View;
import android.view.ViewParent;
import com.facebook.react.bridge.Dynamic;
@@ -38,6 +39,7 @@ class TextView extends GroupView {
@Nullable ArrayList<SVGLength> mRotate;
@Nullable ArrayList<SVGLength> mDeltaX;
@Nullable ArrayList<SVGLength> mDeltaY;
double cachedAdvance = Double.NaN;
public TextView(ReactContext reactContext) {
super(reactContext);
@@ -48,6 +50,7 @@ class TextView extends GroupView {
if (mPath == null) {
return;
}
cachedAdvance = Double.NaN;
super.invalidate();
clearChildCache();
}
@@ -207,4 +210,42 @@ class TextView extends GroupView {
boolean isTextNode = !(this instanceof TextPathView) && !(this instanceof TSpanView);
getTextRootGlyphContext().pushContext(isTextNode, this, mFont, mPositionX, mPositionY, mDeltaX, mDeltaY, mRotate);
}
TextView getTextAnchorRoot() {
GlyphContext gc = getTextRootGlyphContext();
FontData font = gc.getFont();
TextProperties.TextAnchor textAnchor = font.textAnchor;
if (textAnchor == TextProperties.TextAnchor.start) {
return 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();
}
}
return this;
}
double getSubtreeTextChunksTotalAdvance(Paint paint) {
if (!Double.isNaN(cachedAdvance)) {
return cachedAdvance;
}
double advance = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof TextView) {
TextView text = (TextView)child;
advance += text.getSubtreeTextChunksTotalAdvance(paint);
}
}
cachedAdvance = advance;
return advance;
}
}