diff --git a/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java b/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java index 0a426c7b..83f153e3 100644 --- a/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/TSpanShadowNode.java @@ -368,10 +368,11 @@ class TSpanShadowNode extends TextShadowNode { final double descenderDepth = fm.descent; final double totalHeight = top + bottom; double baselineShift = 0; - if (mAlignmentBaseline != null) { + AlignmentBaseline baseline = getAlignmentBaseline(); + if (baseline != null) { // TODO alignment-baseline, test / verify behavior // TODO get per glyph baselines from font baseline table, for high-precision alignment - switch (mAlignmentBaseline) { + switch (baseline) { // https://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling default: case baseline: @@ -386,7 +387,7 @@ class TSpanShadowNode extends TextShadowNode { // Match the bottom of the box to the bottom of the parent’s content area. // text-after-edge = text-bottom // text-after-edge = descender depth - baselineShift = descenderDepth; + baselineShift = -descenderDepth; break; case alphabetic: @@ -398,7 +399,7 @@ class TSpanShadowNode extends TextShadowNode { case ideographic: // Match the box’s ideographic character face under-side baseline to that of its parent. // ideographic = descender depth - baselineShift = descenderDepth; + baselineShift = -descenderDepth; break; case middle: @@ -423,7 +424,7 @@ class TSpanShadowNode extends TextShadowNode { // There are no obvious formulas to calculate the position of these baselines. // At the time of writing FOP puts the hanging baseline at 80% of the ascender // height and the mathematical baseline at 50%. - baselineShift = ascenderHeight / 2; + baselineShift = 0.5 * ascenderHeight; break; case hanging: @@ -608,7 +609,7 @@ class TSpanShadowNode extends TextShadowNode { mid.preScale((float) scaledDirection, (float) side); mid.postTranslate(0, (float) y); } else { - mid.setTranslate((float) startPoint, (float) (y + dy)); + mid.setTranslate((float) startPoint, (float) (y + dy + baselineShift)); } mid.preRotate((float) r); diff --git a/android/src/main/java/com/horcrux/svg/TextShadowNode.java b/android/src/main/java/com/horcrux/svg/TextShadowNode.java index c2acd0ee..0aef68ba 100644 --- a/android/src/main/java/com/horcrux/svg/TextShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/TextShadowNode.java @@ -15,6 +15,7 @@ import android.graphics.Path; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.annotations.ReactProp; import javax.annotation.Nullable; @@ -47,7 +48,7 @@ class TextShadowNode extends GroupShadowNode { @ReactProp(name = "alignmentBaseline") public void setMethod(@Nullable String alignment) { - mAlignmentBaseline = AlignmentBaseline.valueOf(alignment); + mAlignmentBaseline = AlignmentBaseline.getEnum(alignment); markUpdated(); } @@ -106,6 +107,23 @@ class TextShadowNode extends GroupShadowNode { return groupPath; } + AlignmentBaseline getAlignmentBaseline() { + if (mAlignmentBaseline == null) { + ReactShadowNode parent = this.getParent(); + while (parent != null) { + if (parent instanceof TextShadowNode) { + TextShadowNode node = (TextShadowNode)parent; + final AlignmentBaseline baseline = node.mAlignmentBaseline; + if (baseline != null) { + return baseline; + } + } + parent = parent.getParent(); + } + } + return mAlignmentBaseline; + } + void releaseCachedPath() { traverseChildren(new NodeRunnable() { public void run(VirtualNode node) {