//Damit transformationen konsistent sind muss
//jedes tag, da� eine transform attribut hat
//behandelt werden!
//Default
currentLocalTransformMatrix = new Matrix();
//If there is a TRANSFORM attribute parse that and set the
//current transformation matrix to be used with the svg components created after
NamedNodeMap atts = node.getAttributes();
if (atts != null){
for (int i = 0; i < atts.getLength(); i++) {
Node att = atts.item(i);
if (att.getNodeName().equals(SVG_TRANSFORM_ATTRIBUTE)){
CustomTransformHandler transFormHandler = new CustomTransformHandler();
TransformListParser transFormListParser = new TransformListParser();
transFormListParser.setTransformListHandler(transFormHandler);
transFormListParser.parse(att.getNodeValue());
//Overwrite current default matrix if the element has its own
//transform defined, will be used at gfx obj creation
currentLocalTransformMatrix = transFormHandler.getResultMatrix();
}
}
}
// logger.debug("Node: " + node.getNodeName() + " Class: " + node.getClass());
//For opacity inheritance
if (node instanceof SVGGraphicsElement){
SVGGraphicsElement svgGfx = (SVGGraphicsElement)node;
//Handle inherited opacity settings
float opac = queryPrimitiveFloatValue(svgGfx, "opacity", 1f);
opacityStack.push(opac *= opacityStack.peek().floatValue());
}
// if G (GROUP) element, add all children to this element
if ( node instanceof SVGOMGElement
|| node instanceof SVGSVGElement
|| node instanceof SVGOMSVGElement
){
// SVGOMGElement gElem = (SVGOMGElement)node;
SVGElement gElem = (SVGElement)node;
MTComponent group = new MTComponent(pa);
group.setName(gElem.getTagName());
// Element viewPort = gElem.getViewportElement();
// logger.debug("Viewport " + viewPort.getNodeName());
//Set the <g> group to composite, meaning that it will
//be returned at picking, when one of the children gets picked
group.setComposite(true);
group.setLocalMatrix(currentLocalTransformMatrix);
//IF its <svg> element get the transform
//(to honor the viewBox and the width/height attributes
if (node instanceof SVGOMSVGElement ){
SVGOMSVGElement svgGom = ((SVGOMSVGElement)node);
Element viewPort = svgGom.getViewportElement();
if (viewPort != null)
logger.debug("Viewport " + viewPort.getNodeName());
// SVGMatrix mat = svgGom.getScreenCTM();
SVGAnimatedLength widthA = svgGom.getWidth();
SVGAnimatedLength heightA = svgGom.getHeight();
SVGLength w = widthA.getBaseVal();
float width = w.getValue();
SVGLength h = heightA.getBaseVal();
float height = h.getValue();
logger.debug("-> SVG Width: " + width + " Height: " + height);
SVGMatrix mat = svgGom.getCTM();
/*
logger.debug("mat: " + mat.toString());
logger.debug(mat.getA());
logger.debug(mat.getB());
logger.debug(mat.getC());
logger.debug(mat.getD());
logger.debug(mat.getE());
logger.debug(mat.getF());
SVGRect bbox = svgGom.getBBox();
logger.debug("BBOx: X:" + bbox.getX() + " Y:" + bbox.getY() + " Width:" + bbox.getWidth() + " Height:" + bbox.getHeight());
*/
//Hack, because if no width/height is specified default of 1.0
//is assumed by batik -> things may get scaled too small
if ( !(width == 1 && height == 1) ){
currentLocalTransformMatrix = new Matrix(mat.getA(), mat.getC(), 0, mat.getE(),
mat.getB(), mat.getD(), 0, mat.getF(),
0, 0, 1, 0,
0, 0, 0, 1
);
//logger.debug("Matrix: " + currentLocalTransformMatrix);
group.setLocalMatrix(currentLocalTransformMatrix);
}
}
//Make the group pickable and manipulatable
group.setPickable(true);
group.registerInputProcessor(new DragProcessor(pa));
group.setGestureAllowance(DragProcessor.class, true);
group.addGestureListener(DragProcessor.class, (IGestureEventListener)defaultDragAction);
group.registerInputProcessor(new RotateProcessor(pa));
group.addGestureListener(RotateProcessor.class, defaultRotateAction);
group.registerInputProcessor(new ScaleProcessor(pa));
group.addGestureListener(ScaleProcessor.class, defaultScaleAction);
ArrayList<MTComponent> groupChildren = new ArrayList<MTComponent>();
//Traverse the children and add them to a new arraylist
traverseChildren(gElem, groupChildren);
MTComponent[] childComps = (MTComponent[])groupChildren.toArray(new MTComponent[groupChildren.size()]);
//Add the children to the group
group.addChildren(childComps);
//Add the group to the arraylist of the parent
comps.add(group);
}else{//If NOT GROUP
if (node instanceof SVGGraphicsElement){
SVGGraphicsElement svgGfxElem = (SVGGraphicsElement)node;
//IF node isnt a group node just add it to the passed in comps arraylist
try{
//Create a component from the graphicsnode and add it to the parents arraylist
MTComponent liveComponent = handleGraphicsNode(svgGfxElem);
if (liveComponent != null){
comps.add(liveComponent);
}
}catch(Exception e){
logger.error("Error handling svg node: " + svgGfxElem.getTagName());
e.printStackTrace();
}
}
//FIXME IMPLEMENT
if (node instanceof SVGOMTSpanElement){
SVGOMTSpanElement tSpanElement = (SVGOMTSpanElement)node;
}
//FIXME TEST
if (node instanceof SVGOMTextElement){
boolean useVectorFont = false;
SVGOMTextElement textElement = (SVGOMTextElement)node;
//Get <text> position values (can be a list)
List<Float> xValues = getSVGLengthListAsFloat(textElement.getX().getBaseVal());
List<Float> yValues = getSVGLengthListAsFloat(textElement.getY().getBaseVal());
// /*//Not used
String textContent = TextUtilities.getElementContent(textElement);
textContent = textContent.replaceAll("\\n","");
textContent = textContent.trim();
// */
/*
//TODO USE?
textElement.getTextLength();
textElement.getRotate();
*/
if (textElement.getSVGContext() instanceof SVGTextElementBridge){
SVGTextElementBridge b = (SVGTextElementBridge)textElement.getSVGContext();
GraphicsNode gr = b.createGraphicsNode(ctx, textElement);
TextNode tNode = (TextNode)gr;
b.buildGraphicsNode(ctx, textElement, tNode);
List<?> textRuns = tNode.getTextRuns();
logger.debug("Text runs: " + textRuns);
//Get font size
float fontSize = b.getFontSize();
logger.debug("Text:" + " x:" + xValues.get(0) + " y:" + yValues.get(0) + " FontSize: " + fontSize + " Text: '" + textContent + "'");
//Get font FILL
Value fillOpacValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.FILL_OPACITY_INDEX);
float computedfillOpac = PaintServer.convertOpacity(fillOpacValue);
Value fillIndexValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.FILL_INDEX);
Object fill = SVGLoader.getFillOrStroke(textElement, fillIndexValue, computedfillOpac, ctx);
MTColor fillColor = new MTColor(150,150,150,255);
if (fill instanceof java.awt.Color) {
java.awt.Color color = (Color) fill;
fillColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
}
//Get STROKE
// Stroke Opacity \\
Value strokeOpacValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.STROKE_OPACITY_INDEX);
float computedStrokeOpacity = PaintServer.convertOpacity(strokeOpacValue);
// Stroke java.awt.Color \\
Value strokeIndexValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.STROKE_INDEX);
Object stroke = SVGLoader.getFillOrStroke(textElement, strokeIndexValue, computedStrokeOpacity, ctx);
MTColor strokeColor = new MTColor(fillColor.getR(), fillColor.getG(), fillColor.getB(), fillColor.getAlpha());
if (stroke instanceof java.awt.Color) {
java.awt.Color color = (Color) stroke;
strokeColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
}
//Get the font family
Value fontFamilyValue = CSSUtilities.getComputedStyle(textElement, SVGCSSEngine.FONT_FAMILY_INDEX);
String fontFamily = "arial"; //DEFAULT
if (fontFamilyValue instanceof ListValue) {
ListValue listValue = (ListValue) fontFamilyValue;
Value firstValue = listValue.item(0); //Can be a List? -> take only the first one..
if (firstValue != null)
fontFamily = firstValue.getStringValue();
}
logger.debug("Font family: " + fontFamily);
IFont font;
if (useVectorFont)
//Vector font
font = FontManager.getInstance().createFont(pa,
"arial.ttf", Math.round(fontSize), fillColor, strokeColor);
else
//Bitmap font
font = FontManager.getInstance().createFont(pa,
// "Arial", Math.round(fontSize),
fontFamily, Math.round(fontSize), fillColor, strokeColor);
// /*
IFont fontToUse = font;
IFont lastUsedFont = fontToUse;
List<MTTextArea> textAreas = new ArrayList<MTTextArea>();
AttributedCharacterIterator iter = tNode.getAttributedCharacterIterator();
if (font != null && iter != null){ //To avoid not loaded fonts or if text ist empty
for (int i = iter.getBeginIndex(); i < iter.getEndIndex(); i++) {
char currentChar = iter.setIndex(i);
Set<Attribute> keys = iter.getAllAttributeKeys();
Map<Attribute, Object> charAtts = iter.getAttributes();
Object baseLineShift = charAtts.get(SVGTextElementBridge.BASELINE_SHIFT);
Object paintInfo = charAtts.get(SVGTextElementBridge.PAINT_INFO);
Object charX = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.X);
Object charY = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.Y);
Object charDX = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.DX);
Object charDY = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.DY);
Object charRotation = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.ROTATION);
Object gvtFont = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT);
Object gvtFonts = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.GVT_FONTS);
Object gvtFontFamilies = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
Object textCompoundDelimiter = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
Object verticalOrientation = charAtts.get(GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
logger.debug("Character: " + currentChar + " CharX:" + charX + " CharY: " + charY + " CharDX: " + charDX + " CharDY: " + charDY + " Font: " + gvtFont + " Fonts: " + gvtFonts + " FontFamilies: " + gvtFontFamilies);
AWTGVTFont awtGvtFont = (AWTGVTFont)gvtFont;
if (awtGvtFont != null)
logger.debug("CharfontSize: " + awtGvtFont.getSize());
//FIXME REMOVE, Not working always 0,0
SVGPoint startPosOfChar = SVGTextContentSupport.getStartPositionOfChar(textElement, i);
/////////////////////////////////////
//Get the character information - font, colors
String newFamilyName = new String(fontFamily);
float newFontSize = fontSize;
MTColor newFillColor = new MTColor(fillColor);
MTColor newStrokeColor = new MTColor(strokeColor);
boolean charHasColorInfo = false;
boolean charHasFontInfo = false;
//Get chars paint info
if (paintInfo != null && paintInfo instanceof TextPaintInfo){
charHasColorInfo = true;
TextPaintInfo texInfo = (TextPaintInfo)paintInfo;
if (texInfo.fillPaint instanceof java.awt.Color){
java.awt.Color color = (Color)texInfo.fillPaint;
newFillColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
}
if (texInfo.strokePaint instanceof java.awt.Color){
java.awt.Color color = (Color)texInfo.strokePaint;
newStrokeColor.setColor(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
}
}
//Get the chars font family and size
GVTFont aGvtFont = null;
if (gvtFonts!=null){
if (gvtFonts instanceof List) {
List<?> fonts = (List<?>) gvtFonts;
for (Iterator<?> iterator = fonts.iterator(); iterator.hasNext();) {
Object o = (Object) iterator.next();
if (o instanceof GVTFont) {
aGvtFont = (GVTFont) o;
//logger.debug("Char font family: " + aGvtFont.getFamilyName() + " Size:" + aGvtFont.getSize());
}
}
}
}
if (aGvtFont != null){
charHasFontInfo = true;
newFamilyName = aGvtFont.getFamilyName();
newFontSize = aGvtFont.getSize();
}else{
logger.error("Character: " + currentChar + " has no font attached.");
}
if (charHasColorInfo && charHasFontInfo){
logger.debug("Character '" + currentChar + "'-> has font info -> load font!" +
" Family: " + newFamilyName +
" Fontsize: " + Math.round(newFontSize) +
" FillColor: " + newFillColor +
" StrokeColor: " + newStrokeColor);
if (useVectorFont)
fontToUse = FontManager.getInstance().createFont(pa,
"arial.ttf", Math.round(newFontSize), newFillColor, newStrokeColor);
else
fontToUse = FontManager.getInstance().createFont(pa, //uses cached font if available
// "Arial", Math.round(fontSize),
newFamilyName, Math.round(newFontSize), newFillColor, newStrokeColor);
if (fontToUse == null){
fontToUse = font;
}
}else{
fontToUse = font;
}
boolean fontChanged = !FontManager.isFontsAreEqual(fontToUse, lastUsedFont);
lastUsedFont = fontToUse;
// //FIXME REMOVE TEST
// fontChanged = true;
///////////////////////////////////////
boolean textPositionChanged = charX != null || charY != null || charDX != null || charDY != null;
//TODO if we forceAnewTextarea because of font change but ther is NO NEW POSITION, we
//have to set the textareas anchor to the lower left
//TODO problem if we have a tspan centered and a next tspan without new position
//-> the first tspan textarea gets centered on the position
//but we would have to treat them (all in the same line) as 1 textarea when center positioning!
//FIXME there are slight differences because we use a different SPACE character length and no font KERNING!
//FIXME DO WIDHTOUT USERDATA
//FIXME bitmap font has no top border, vector has.. why?
//TODO -> eventuell doch in handleSvgNode machen?
//-> statt graphicsnode /stylable node �bergeben? - SVGOMTextElement is nicht instanceof graphicsnode..
// we have to check font/color etc at every character, not only at new positon because
//pos doesent change at tspans without new posinfo
//check if equal to last used font and if equal original text font
if ( fontChanged || textPositionChanged
){ //Make a new textarea if the text position changed or if the font changed at the current character
MTTextArea previousTextArea = null;
if (!textAreas.isEmpty()){
previousTextArea = textAreas.get(textAreas.size()-1);
}
float newXPos = 0;
float newYPos = 0 ;
//If there is a previous text, get its ending coordinates
//for the DX and DY shift info for the next text area
if (previousTextArea != null){
PositionAnchor oldAnchor = previousTextArea.getAnchor();
// previousTextArea.setAnchor(PositionAnchor.LOWER_RIGHT);
previousTextArea.setAnchor(PositionAnchor.UPPER_LEFT);
//Calculate last/current textposition for DX and DY use
//add up the last textareas start position end position(width)
Vector3D lastPos = previousTextArea.getPosition(TransformSpace.LOCAL);
// lastPos.addLocal(new Vector3D(previousTextArea.getWidthXY(TransformSpace.LOCAL) - 1 * previousTextArea.getInnerPaddingLeft(),0));
lastPos.addLocal(new Vector3D(previousTextArea.getWidthXY(TransformSpace.LOCAL) - 2 * previousTextArea.getInnerPaddingLeft(),0));
// newXPos = lastPos.x - previousTextArea.getInnerPaddingLeft();
newXPos = lastPos.x;
newXPos += (Float)previousTextArea.getUserData("XPos");
newYPos = lastPos.y;
// newYPos -= previousTextArea.getInnerPaddingTop();
// newYPos += fontToUse.getFontMaxDescent(); //FIXME WHY NEVESSARY?
newYPos += (Float)previousTextArea.getUserData("YPos");
previousTextArea.setAnchor(oldAnchor);
}
//IF absolute x or y is present overwrite the position values from the last textarea
if (charX != null)
newXPos = (Float)charX;
if (charY != null)
newYPos = (Float)charY;
if (charDX != null)
newXPos += (Float)charDX;
if (charDY != null)
newYPos += (Float)charDY;
// Create the text area \\
MTTextArea t = new MTTextArea(pa, fontToUse);
t.setNoFill(true);
t.setNoStroke(true);
textAreas.add(t);
try{
t.setLocalMatrix(new Matrix(currentLocalTransformMatrix));
}catch(Exception e){
logger.error(e.getMessage());
}
//FIXME TEST