Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ public class GlyphLayout implements TextSpanLayout {
private static final AttributedCharacterIterator.Attribute BASELINE_SHIFT
= GVTAttributedCharacterIterator.TextAttribute.BASELINE_SHIFT;

private static final AttributedCharacterIterator.Attribute DOMINANT_BASELINE
= GVTAttributedCharacterIterator.TextAttribute.DOMINANT_BASELINE;

private static final AttributedCharacterIterator.Attribute ALIGNMENT_BASELINE
= GVTAttributedCharacterIterator.TextAttribute.ALIGNMENT_BASELINE;

private static final AttributedCharacterIterator.Attribute WRITING_MODE
= GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE;

Expand All @@ -153,6 +159,8 @@ public class GlyphLayout implements TextSpanLayout {
runAtts.add(DY);
runAtts.add(ROTATION);
runAtts.add(BASELINE_SHIFT);
runAtts.add(DOMINANT_BASELINE);
runAtts.add(ALIGNMENT_BASELINE);
}

protected static Set szAtts = new HashSet();
Expand Down Expand Up @@ -1084,6 +1092,8 @@ protected void doExplicitGlyphLayout() {

Float x=null, y=null, dx=null, dy=null, rotation=null;
Object baseline=null;
String dominantBl=null;
String alignmentBl=null;

float shift_x_pos = 0;
float shift_y_pos = 0;
Expand All @@ -1102,6 +1112,8 @@ protected void doExplicitGlyphLayout() {
dy = (Float) aci.getAttribute(DY);
rotation = (Float) aci.getAttribute(ROTATION);
baseline = aci.getAttribute(BASELINE_SHIFT);
dominantBl = (String) aci.getAttribute(DOMINANT_BASELINE);
alignmentBl = (String) aci.getAttribute(ALIGNMENT_BASELINE);
}

GVTGlyphMetrics gm = gv.getGlyphMetrics(i);
Expand Down Expand Up @@ -1227,6 +1239,22 @@ protected void doExplicitGlyphLayout() {
}
}

// Apply dominant-baseline and alignment-baseline offsets.
// dominant-baseline shifts the element so the specified
// baseline sits at the coordinate position.
// alignment-baseline shifts a child element so its specified
// baseline aligns with the parent's dominant baseline.
float dbOffset = getBaselineOffset(dominantBl, metrics);
float abOffset = getBaselineOffset(alignmentBl, metrics);
float blAdjust = dbOffset - abOffset;
if (blAdjust != 0f) {
if (vertical) {
ox += blAdjust;
} else {
oy -= blAdjust;
}
}

if (vertical) {
// offset due to rotation of first character
oy += verticalFirstOffset;
Expand Down Expand Up @@ -2046,4 +2074,54 @@ public boolean isReversed(){
public void maybeReverse(boolean mirror){
gv.maybeReverse(mirror);
}

/**
* Returns the vertical offset (positive = above the alphabetic baseline)
* for the named SVG baseline value, using the given font metrics.
* Returns 0 for null, "auto", "baseline", or unrecognized values.
*
* @param baselineValue the SVG baseline identifier string
* @param metrics the line metrics for the current font
* @return the offset from the alphabetic baseline (positive = up)
*/
protected static float getBaselineOffset(String baselineValue,
GVTLineMetrics metrics) {
if (baselineValue == null) {
return 0f;
}
float ascent = metrics.getAscent();
float descent = metrics.getDescent();
switch (baselineValue) {
case "alphabetic":
case "auto":
case "baseline":
return 0f;
case "ideographic":
// Bottom of the ideographic em box ≈ descent below alphabetic
return -descent;
case "hanging":
// Hanging baseline — near the top of the em box
return ascent * 0.8f;
case "mathematical":
// Mathematical baseline — approximately at the math axis
return metrics.getStrikethroughOffset()
+ ascent * 0.1f;
case "central":
// Midpoint between ascent and descent
return (ascent - descent) / 2.0f;
case "middle":
// SVG middle ≈ x-height / 2 ≈ strikethrough offset
return metrics.getStrikethroughOffset();
case "text-before-edge": // SVG 1.1 name
case "text-top": // CSS name
case "before-edge":
return ascent;
case "text-after-edge": // SVG 1.1 name
case "text-bottom": // CSS name
case "after-edge":
return -descent;
default:
return 0f;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ public class SVGTextElementBridge extends AbstractGraphicsNodeBridge
AttributedCharacterIterator.Attribute BASELINE_SHIFT
= GVTAttributedCharacterIterator.TextAttribute.BASELINE_SHIFT;

public static final
AttributedCharacterIterator.Attribute DOMINANT_BASELINE
= GVTAttributedCharacterIterator.TextAttribute.DOMINANT_BASELINE;

public static final
AttributedCharacterIterator.Attribute ALIGNMENT_BASELINE
= GVTAttributedCharacterIterator.TextAttribute.ALIGNMENT_BASELINE;

protected AttributedString laidoutText;

// This is used to track the TextPainterInfo for each element
Expand Down Expand Up @@ -709,8 +717,10 @@ public void handleCSSEngineEvent(CSSEngineEvent evt) {
// first try to find CSS properties that change the layout
for (int property : properties) {
switch (property) { // fall-through is intended
case SVGCSSEngine.ALIGNMENT_BASELINE_INDEX:
case SVGCSSEngine.BASELINE_SHIFT_INDEX:
case SVGCSSEngine.DIRECTION_INDEX:
case SVGCSSEngine.DOMINANT_BASELINE_INDEX:
case SVGCSSEngine.DISPLAY_INDEX:
case SVGCSSEngine.FONT_FAMILY_INDEX:
case SVGCSSEngine.FONT_SIZE_INDEX:
Expand Down Expand Up @@ -1604,6 +1614,18 @@ protected Map getAttributeMap(BridgeContext ctx,
result.put(BASELINE_SHIFT, bs);
}

// Dominant baseline
String db = TextUtilities.convertDominantBaseline(element);
if (db != null) {
result.put(DOMINANT_BASELINE, db);
}

// Alignment baseline
String ab = TextUtilities.convertAlignmentBaseline(element);
if (ab != null) {
result.put(ALIGNMENT_BASELINE, ab);
}

// Unicode-bidi mode
Value val = CSSUtilities.getComputedStyle
(element, SVGCSSEngine.UNICODE_BIDI_INDEX);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,42 @@ public static Object convertBaselineShift(Element e) {
}
}

/**
* Converts the dominant-baseline CSS value to a string usable as a
* text attribute, or null if the value is "auto".
* @param e the element
*/
public static String convertDominantBaseline(Element e) {
Value v = CSSUtilities.getComputedStyle
(e, SVGCSSEngine.DOMINANT_BASELINE_INDEX);
if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
String s = v.getStringValue();
if (CSS_AUTO_VALUE.equals(s)) {
return null;
}
return s;
}
return null;
}

/**
* Converts the alignment-baseline CSS value to a string usable as a
* text attribute, or null if the value is "auto" or "baseline".
* @param e the element
*/
public static String convertAlignmentBaseline(Element e) {
Value v = CSSUtilities.getComputedStyle
(e, SVGCSSEngine.ALIGNMENT_BASELINE_INDEX);
if (v.getPrimitiveType() == CSSPrimitiveValue.CSS_IDENT) {
String s = v.getStringValue();
if (CSS_AUTO_VALUE.equals(s) || CSS_BASELINE_VALUE.equals(s)) {
return null;
}
return s;
}
return null;
}

/**
* Converts a kerning CSS value to a value usable as a text
* attribute, or null.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ public TextAttribute(String s) {
public static final TextAttribute BASELINE_SHIFT =
new TextAttribute("BASELINE_SHIFT");

/** Dominant baseline for this character span (String value from CSS).
*/
public static final TextAttribute DOMINANT_BASELINE =
new TextAttribute("DOMINANT_BASELINE");

/** Alignment baseline for this character span (String value from CSS).
*/
public static final TextAttribute ALIGNMENT_BASELINE =
new TextAttribute("ALIGNMENT_BASELINE");

/** Directional writing mode applied to this character span.
*/
public static final TextAttribute WRITING_MODE =
Expand Down