Element markerElement,
Element paintedElement) {
GVTBuilder builder = ctx.getGVTBuilder();
CompositeGraphicsNode markerContentNode
= new CompositeGraphicsNode();
// build the GVT tree that represents the marker
boolean hasChildren = false;
for(Node n = markerElement.getFirstChild();
n != null;
n = n.getNextSibling()) {
// check if the node is a valid Element
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element child = (Element)n;
GraphicsNode markerNode = builder.build(ctx, child) ;
// check if a GVT node has been created
if (markerNode == null) {
continue; // skip element as <marker> can contain <defs>...
}
hasChildren = true;
markerContentNode.getChildren().add(markerNode);
}
if (!hasChildren) {
return null; // no marker content defined
}
String s;
UnitProcessor.Context uctx
= UnitProcessor.createContext(ctx, paintedElement);
// 'markerWidth' attribute - default is 3
float markerWidth = 3;
s = markerElement.getAttributeNS(null, SVG_MARKER_WIDTH_ATTRIBUTE);
if (s.length() != 0) {
markerWidth = UnitProcessor.svgHorizontalLengthToUserSpace
(s, SVG_MARKER_WIDTH_ATTRIBUTE, uctx);
}
if (markerWidth == 0) {
// A value of zero disables rendering of the element.
return null;
}
// 'markerHeight' attribute - default is 3
float markerHeight = 3;
s = markerElement.getAttributeNS(null, SVG_MARKER_HEIGHT_ATTRIBUTE);
if (s.length() != 0) {
markerHeight = UnitProcessor.svgVerticalLengthToUserSpace
(s, SVG_MARKER_HEIGHT_ATTRIBUTE, uctx);
}
if (markerHeight == 0) {
// A value of zero disables rendering of the element.
return null;
}
// 'orient' attribute - default is '0'
double orient;
s = markerElement.getAttributeNS(null, SVG_ORIENT_ATTRIBUTE);
if (s.length() == 0) {
orient = 0;
} else if (SVG_AUTO_VALUE.equals(s)) {
orient = Double.NaN;
} else {
try {
orient = SVGUtilities.convertSVGNumber(s);
} catch (NumberFormatException ex) {
throw new BridgeException
(markerElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object [] {SVG_ORIENT_ATTRIBUTE, s});
}
}
// 'stroke-width' property
Value val = CSSUtilities.getComputedStyle
(paintedElement, SVGCSSEngine.STROKE_WIDTH_INDEX);
float strokeWidth = val.getFloatValue();
// 'markerUnits' attribute - default is 'strokeWidth'
short unitsType;
s = markerElement.getAttributeNS(null, SVG_MARKER_UNITS_ATTRIBUTE);
if (s.length() == 0) {
unitsType = SVGUtilities.STROKE_WIDTH;
} else {
unitsType = SVGUtilities.parseMarkerCoordinateSystem
(markerElement, SVG_MARKER_UNITS_ATTRIBUTE, s);
}
//
//
//
// compute an additional transform for 'strokeWidth' coordinate system
AffineTransform markerTxf;
if (unitsType == SVGUtilities.STROKE_WIDTH) {
markerTxf = new AffineTransform();
markerTxf.scale(strokeWidth, strokeWidth);
} else {
markerTxf = new AffineTransform();
}
// 'viewBox' and 'preserveAspectRatio' attributes
// viewBox -> viewport(0, 0, markerWidth, markerHeight)
AffineTransform preserveAspectRatioTransform
= ViewBox.getPreserveAspectRatioTransform(markerElement,
markerWidth,
markerHeight);
if (preserveAspectRatioTransform == null) {
// disable the rendering of the element
return null;
} else {
markerTxf.concatenate(preserveAspectRatioTransform);
}
// now we can set the transform to the 'markerContentNode'
markerContentNode.setTransform(markerTxf);
// 'overflow' property
if (CSSUtilities.convertOverflow(markerElement)) { // overflow:hidden
Rectangle2D markerClip;
float [] offsets = CSSUtilities.convertClip(markerElement);
if (offsets == null) { // clip:auto
markerClip
= new Rectangle2D.Float(0,
0,
strokeWidth * markerWidth,
strokeWidth * markerHeight);
} else { // clip:rect(<x>, <y>, <w>, <h>)
// offsets[0] = top
// offsets[1] = right
// offsets[2] = bottom
// offsets[3] = left
markerClip = new Rectangle2D.Float
(offsets[3],
offsets[0],
strokeWidth * markerWidth - offsets[1] - offsets[3],
strokeWidth * markerHeight - offsets[2] - offsets[0]);
}
CompositeGraphicsNode comp = new CompositeGraphicsNode();
comp.getChildren().add(markerContentNode);
Filter clipSrc = comp.getGraphicsNodeRable(true);
comp.setClip(new ClipRable8Bit(clipSrc, markerClip));
markerContentNode = comp;
}
// 'refX' attribute - default is 0
float refX = 0;