fr.itris.glips.svgeditor.display.canvas.SVGCanvas.java Source code

Java tutorial

Introduction

Here is the source code for fr.itris.glips.svgeditor.display.canvas.SVGCanvas.java

Source

/*
 * Created on 23 mars 2004
 * 
 =============================================
 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1
 =============================================
 GLIPS Graffiti Editor, a SVG Editor
 Copyright (C) 2003 Jordi SUC, Philippe Gil, SARL ITRIS
     
 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.
     
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.
     
 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     
 Contact : jordi.suc@itris.fr; philippe.gil@itris.fr
     
 =============================================
 */
package fr.itris.glips.svgeditor.display.canvas;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;

import libraries.URIEncoderDecoder;

import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.DynamicGVTBuilder;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.gvt.CanvasGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.RootGraphicsNode;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.svg.SVGDocument;

import com.nbtoptec.draw.layer.SVGLayer;

import fr.itris.glips.library.FormatStore;
import fr.itris.glips.library.Toolkit;
import fr.itris.glips.library.monitor.Monitor;
import fr.itris.glips.library.util.XMLPrinter;
import fr.itris.glips.svgeditor.Editor;
import fr.itris.glips.svgeditor.EditorToolkit;
import fr.itris.glips.svgeditor.SymbolManager;
import fr.itris.glips.svgeditor.display.canvas.grid.Grid;
import fr.itris.glips.svgeditor.display.canvas.zoom.Zoom;
import fr.itris.glips.svgeditor.display.handle.SVGHandle;
import fr.itris.glips.svgeditor.resources.ResourcesManager;

/**
 * @author ITRIS, Jordi SUC the class of the canvas of a SVG file
 */
public class SVGCanvas extends JPanel {

    /**
     * the constant for the grid layer
     */
    public static final int GRID_LAYER = 0;

    /**
     * the constant for the bottom layer
     */
    public static final int BOTTOM_LAYER = 1;

    /**
     * the constant for the selection layer
     */
    public static final int SELECTION_LAYER = 2;

    /**
     * the constant for the draw layer
     */
    public static final int DRAW_LAYER = 3;

    /**
     * the constant for the top layer
     */
    public static final int TOP_LAYER = 4;

    /**
     * the array of the layers
     */
    protected static int[] layers = { GRID_LAYER, BOTTOM_LAYER, SELECTION_LAYER, DRAW_LAYER, TOP_LAYER };

    /**
     * the color used for drawing the area that is outside the current parent
     * bounds
     */
    protected static final Color parentVeilColor = new Color(255, 255, 255, 150);

    /**
     * the canvas uri
     */
    private String uri = "";

    /**
     * the canvas document
     */
    private Document document;

    /**
     * the builder
     */
    private GVTBuilder builder;

    /**
     * the bridge context
     */
    private BridgeContext ctx;

    /**
     * the root graphics node
     */
    private RootGraphicsNode gvtRoot;

    /**
     * the offscreen image of the canvas
     */
    private BufferedImage canvasOffscreenImage;

    /**
     * the rendered rectangle
     */
    private Rectangle renderedRectangle = new Rectangle(0, 0, 1, 1), tmpRectangle = new Rectangle(0, 0, 0, 0);

    /**
     * the scrollpane that contains the canvas
     */
    private SVGScrollPane scrollpane;

    /**
     * the canvas zoom manager
     */
    private Zoom zoomManager;

    /**
     * the grid manager
     */
    protected Grid gridManager;

    /**
     * the file of the project this canvas is associated with
     */
    private File projectFile;

    private String SvgUri = "http://www.w3.org/2000/svg";
    /**
     * the map associating an id integer to the list of the paint listeners for
     * a layer
     */
    private Map<Integer, Set<CanvasPainter>> paintListeners = new ConcurrentHashMap<Integer, Set<CanvasPainter>>();

    /**
     * the zone that should be repainted with the paint listeners when the
     * rectangle is not null
     */
    private Rectangle2D repaintZone;

    /**
     * the svg handle this canvas is associated to
     */
    private SVGHandle svgHandle;

    /**
     * the repaint manager
     */
    protected RepaintManager repaintManager = RepaintManager.currentManager(this);

    /**
     * the constructor of the class
     * 
     * @param scrollpane
     *            the scrollpane into which the canvas will be inserted
     */
    public SVGCanvas(SVGScrollPane scrollpane) {

        this.scrollpane = scrollpane;
        this.svgHandle = scrollpane.getSVGHandle();
        this.zoomManager = new Zoom(this);
        setDoubleBuffered(true);
        setBackground(Color.white);

        // creating the paint listeners map structure
        paintListeners.put(GRID_LAYER, new CopyOnWriteArraySet<CanvasPainter>());
        paintListeners.put(BOTTOM_LAYER, new CopyOnWriteArraySet<CanvasPainter>());
        paintListeners.put(SELECTION_LAYER, new CopyOnWriteArraySet<CanvasPainter>());
        paintListeners.put(DRAW_LAYER, new CopyOnWriteArraySet<CanvasPainter>());
        paintListeners.put(TOP_LAYER, new CopyOnWriteArraySet<CanvasPainter>());
    }

    /**
     * creates a new svg document
     * 
     * @param width
     *            the width of the new document
     * @param height
     *            the height of the new document
     */
    public void newDocument(String width, String height) {

        DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
        String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
        SVGDocument doc = (SVGDocument) impl.createDocument(svgNS, "svg", null);

        // gets the root element (the svg element)
        Element svgRoot = doc.getDocumentElement();

        // set the width and height attribute on the root svg element
        svgRoot.setAttributeNS(null, "width", width);
        svgRoot.setAttributeNS(null, "height", height);
        svgRoot.setAttribute("viewBox",
                "0 0 " + EditorToolkit.getPixelledNumber(width) + " " + EditorToolkit.getPixelledNumber(height));

        // creating a defs element
        Element defsElement = doc.createElementNS(doc.getNamespaceURI(), "defs");
        svgRoot.appendChild(defsElement);

        //add style element to doc
        doc = (SVGDocument) addStyle(doc); //doc?
        svgRoot = doc.getDocumentElement();

        //add symbol element to doc
        doc = (SVGDocument) addSymbols(doc);

        //initializing the canvas
        //      Toolkit.checkRtdaXmlns(doc);
        this.document = doc;

        // create default layer
        Element g = doc.createElementNS(svgRoot.getNamespaceURI(), "g");
        g.setAttributeNS(null, "layer", "");
        svgRoot.appendChild(g);
        //      this.document = doc;
        SVGLayer layer = new SVGLayer();
        layer.setName("");
        layer.setVisible(true);
        layer.setEdit(true);
        layer.setElement(g);
        svgHandle.getLayerManager().addLayer(layer, 0);
        // initializing the canvas
        initializeCanvas(null);
    }

    /**
     * sets the uri for the canvas (should not be invoked in the AWT thread)
     * 
     * @param uri
     *            the uri of the svg file to be loaded
     * @param monitor
     *            the object monitoring the loading of the svg file
     */
    public void setURI(final String uri, Monitor monitor) {

        synchronized (this) {
            this.uri = uri;
        }

        if (Editor.isRtdaAnimationsVersion) {

            projectFile = Editor.getColorChooser().getProjectFile(uri);
        }

        try {
            if (monitor != null) {

                monitor.start();
                monitor.setProgress(0);
            }

            // creating the svg document corresponding to this uri
            SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory("");
            SVGDocument doc = factory.createSVGDocument(uri);

            if (doc != null) {

                // normalizing the document
                Dimension scaledCanvasSize = getScaledCanvasSize(doc.getDocumentElement());
                svgHandle.getSvgDOMNormalizer().normalize(doc, scaledCanvasSize);
                //Toolkit.checkRtdaXmlns(doc);

                //add style element to doc
                doc = (SVGDocument) addStyle(doc);

                //add symbol element to doc
                doc = (SVGDocument) addSymbols(doc);

                synchronized (this) {
                    this.document = doc;
                }
                // Toolkit.checkRtdaXmlns(doc);

                synchronized (this) {
                    this.document = doc;
                }

                if (monitor != null && monitor.isCancelled()) {

                    monitor.stop();
                    getSVGHandle().dispose();
                    return;
                }
                analyseLayer(doc);
                initializeCanvas(monitor);
            }
        } catch (Exception ex) {

            ex.printStackTrace();
            getSVGHandle().dispose();

            if (monitor != null) {

                String messageLabel = ResourcesManager.bundle.getString("canvasLoadingFailedMessage");
                messageLabel = URIEncoderDecoder.HTMLEntityEncode(messageLabel);

                String returnedErrorMessage = URIEncoderDecoder.HTMLEntityEncode(ex.getMessage());

                messageLabel = "<html><body>" + messageLabel + "<br><i>" + returnedErrorMessage
                        + "</i></body></html>";
                monitor.setErrorMessage(messageLabel);
            }
        }
    }

    //?Document??
    public HashMap<String, String> getNamespace(org.dom4j.Document doc) {
        if (doc != null) {
            try {
                org.dom4j.Element root = doc.getRootElement();
                HashMap<String, String> map = new HashMap<String, String>();

                for (Iterator<?> iter = root.elementIterator(); iter.hasNext();) {
                    org.dom4j.Element e = (org.dom4j.Element) iter.next();
                    map.put("uri", e.getNamespaceURI());
                    //                  System.out.println(e.getNamespaceURI() + "\t" + e.getName());
                }
                return map;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * add  style.svg to doc
     * @param doc
     * @return
     */
    public Document addStyle(Document doc) {
        //converts the svg document into xml strings
        StringBuffer buffer = new StringBuffer("");
        org.dom4j.Document doc4j = null;

        for (Node node = doc.getFirstChild(); node != null; node = node.getNextSibling()) {

            XMLPrinter.writeNode(node, buffer, 0, true, null);

        }

        try {

            doc4j = new SAXReader().read(new ByteArrayInputStream(buffer.toString().getBytes("utf8")));

            if (doc4j != null) {
                XPath x = doc4j.createXPath("/uri:svg/uri:defs");
                x.setNamespaceURIs(getNamespace(doc4j));
                List<org.dom4j.Element> list = x.selectNodes(doc4j);
                for (org.dom4j.Element t : list) {
                    if ("defs".equalsIgnoreCase(t.getName())) {
                        org.dom4j.Element style = t.addElement("style");

                        style.addAttribute("type", "css/text");

                        style.addText(Editor.getEditor().getSymbolManager().getStyle());
                    }
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = SymbolManager.XML2Str(doc4j);
        //        System.out.println(result.substring(result.indexOf("<svg")));

        return SymbolManager.Str2XML(result.substring(result.indexOf("<svg")));
    }

    /**
     * add symbol.svg to doc
     * @author zhangdan 
     * @param doc
     * @return
     */
    public Document addSymbols(Document doc) {
        Document symboldoc = Editor.getEditor().getSymbolManager().getSymbol(); //?symbol.svgdoc

        if (symboldoc != null) {
            try {
                Element orgdef = null;
                for (Node def = doc.getDocumentElement().getFirstChild(); def != null; def = def.getNextSibling()) {
                    if ("defs".equalsIgnoreCase(def.getNodeName())) {
                        orgdef = (Element) def;
                        break;
                    }
                }

                Element root = symboldoc.getDocumentElement();

                for (Node defs = root.getFirstChild(); defs != null; defs = defs.getNextSibling()) {
                    // defs
                    if ("defs".equalsIgnoreCase(defs.getNodeName())) {

                        for (Node symbol = defs.getFirstChild(); symbol != null; symbol = symbol.getNextSibling()) {
                            if ("symbol".equalsIgnoreCase(symbol.getNodeName())) {
                                Element e = (Element) symbol;

                                Element symbole = doc.createElementNS(this.SvgUri, "symbol");

                                symbole.setAttribute("id", e.getAttribute("id"));

                                symbole.setAttribute("viewBox", e.getAttribute("viewBox"));

                                symbole.setAttribute("preserveAspectRatio", "xMidYMid meet");

                                orgdef.appendChild(symbole); //symboldefs

                                for (Node shape = e.getFirstChild(); shape != null; shape = shape
                                        .getNextSibling()) {
                                    if (shape instanceof org.apache.batik.dom.GenericText)
                                        continue;

                                    Element shapeobj = (Element) shape;

                                    NamedNodeMap attrs = shapeobj.getAttributes();

                                    Element de = doc.createElementNS(shapeobj.getNamespaceURI(),
                                            shapeobj.getNodeName());
                                    if (attrs != null) {

                                        for (int i = 0; i < attrs.getLength(); i++) {

                                            Attr attr = (Attr) attrs.item(i);

                                            de.setAttribute(attr.getName(), attr.getValue());
                                        }

                                    }
                                    symbole.appendChild(de);
                                }

                            }
                        }
                    }
                }
                /*
                 * 
                    
                XPathFactory f = XPathFactory.newInstance();
                    
                XPath path = f.newXPath();
                    
                NodeList list = (NodeList) path.evaluate("svg/defs/symbol", symboldoc, XPathConstants.NODESET);
                    
                Element defs = (Element) doc.getDocumentElement().getChildNodes().item(0);   //?defs
                    
                for(int i=0; i< list.getLength(); i++)
                {
                   Element e = (Element)list.item(i);            //?symbolid
                       
                   Element symbol = doc.createElementNS(this.SvgUri, "symbol");
                       
                   symbol.setAttribute("id", e.getAttribute("id"));
                       
                   symbol.setAttribute("viewBox",e.getAttribute("viewBox"));
                       
                   symbol.setAttribute("preserveAspectRatio", "xMidYMid meet");
                       
                   defs.appendChild(symbol);      //symboldefs
                       
                   try {
                          
                      NodeList nl = (NodeList) path.evaluate("circle", e, XPathConstants.NODESET);
                      symbol = addElement(doc,symbol, "circle", nl);
                          
                      nl = (NodeList) path.evaluate("line", e, XPathConstants.NODESET);
                      symbol = addElement(doc,symbol, "line", nl);
                          
                      nl = (NodeList) path.evaluate("rect", e, XPathConstants.NODESET);
                      symbol = addElement(doc, symbol,"rect", nl);
                          
                      nl = (NodeList) path.evaluate("polygon", e, XPathConstants.NODESET);
                      symbol = addElement(doc, symbol,"polygon", nl);
                          
                      nl = (NodeList) path.evaluate("path", e, XPathConstants.NODESET);
                      symbol = addElement(doc,symbol, "path", nl);
                          
                   } catch (Exception ex) {
                      ex.printStackTrace();
                   }
                       
                }
                    
                */} catch (Exception e) {
                e.printStackTrace();
            }
        }
        return doc;
    }

    /** Nodelistroot
    * @param root
    * @param name
    * @param list
    */
    /*public Element addElement(Document root, Element symbol, String name, NodeList list)
    {
       for(int i=0; i<list.getLength(); i++)
       {
     Element e = (Element) list.item(i);
     Element de = root.createElementNS(this.SvgUri, name);
     symbol.appendChild(de);
         
     if(e.getAttribute("cx") != null && !e.getAttribute("cx").isEmpty())         //cx
     {
        de.setAttribute("cx", e.getAttribute("cx"));
     } 
     if(e.getAttribute("cy") != null && !e.getAttribute("cy").isEmpty())   //cy
     {
        de.setAttribute("cy", e.getAttribute("cy"));
     } 
     if(e.getAttribute("r") != null && !e.getAttribute("r").isEmpty())   //y
     {
        de.setAttribute("r", e.getAttribute("r"));
     } 
     if(e.getAttribute("x1") != null && !e.getAttribute("x1").isEmpty())
     {
        de.setAttribute("x1", e.getAttribute("x1"));
     }   
     if(e.getAttribute("x2") != null && !e.getAttribute("x2").isEmpty())
     {
        de.setAttribute("x2", e.getAttribute("x2"));
     }   
     if(e.getAttribute("y1") != null && !e.getAttribute("y1").isEmpty())
     {
        de.setAttribute("y1", e.getAttribute("y1"));
     }   
     if(e.getAttribute("y2") != null && !e.getAttribute("y2").isEmpty())
     {
        de.setAttribute("y2", e.getAttribute("y2"));
     } 
     if(e.getAttribute("x") != null && !e.getAttribute("x").isEmpty())
     {
        de.setAttribute("x", e.getAttribute("x"));
     }  
     if(e.getAttribute("y") != null && !e.getAttribute("y").isEmpty())
     {
        de.setAttribute("y", e.getAttribute("y"));
     }  
     if(e.getAttribute("width") != null && !e.getAttribute("width").isEmpty())
     {
        de.setAttribute("width", e.getAttribute("width"));
     }   
     if(e.getAttribute("height") != null && !e.getAttribute("height").isEmpty())
     {
        de.setAttribute("height", e.getAttribute("height"));
     }  
     if(e.getAttribute("points") != null && !e.getAttribute("points").isEmpty())
     {
        de.setAttribute("points", e.getAttribute("points"));
     }  
     if(e.getAttribute("d") != null && !e.getAttribute("d").isEmpty())
     {
        de.setAttribute("d", e.getAttribute("d"));
     } 
     if(e.getAttribute("stroke-width") != null && !e.getAttribute("stroke-width").isEmpty())      //stroke-width
     {
        de.setAttribute("stroke-width", e.getAttribute("stroke-width"));
     } 
     if(e.getAttribute("fill") != null && !e.getAttribute("fill").isEmpty())         //fill
     {
        de.setAttribute("fill", e.getAttribute("fill"));
     } 
     if(e.getAttribute("stroke") != null && !e.getAttribute("stroke").isEmpty())   //stroke
     {
        de.setAttribute("stroke", e.getAttribute("stroke"));
     }  
     if(e.getAttribute("Plane") != null && !e.getAttribute("Plane").isEmpty())   //Plane
     {
        de.setAttribute("Plane", e.getAttribute("Plane"));
     } 
     if(e.getAttribute("AFMask") != null && !e.getAttribute("AFMask").isEmpty())   //AFMask
     {
        de.setAttribute("AFMask", e.getAttribute("AFMask"));
     }  
     if(e.getAttribute("transform") != null && !e.getAttribute("transform").isEmpty())   //transform
     {
        de.setAttribute("transform", e.getAttribute("transform"));
     } 
       }
           
       return symbol;
    } */

    /**
     * ?svg
     * 
     * @param doc
     */
    private void analyseLayer(SVGDocument doc) {
        NodeList nodelist = doc.getDocumentElement().getChildNodes();
        int len = nodelist.getLength();
        for (int i = 0; i < len; i++) {

            if (nodelist.item(i) instanceof Element) {
                Element node = (Element) nodelist.item(i);
                if (node.getTagName().equals("defs")) {
                    continue;
                }
                String name = node.getAttribute("layer");
                if (name == null || name.trim().isEmpty()) {
                    name = "";
                }
                SVGLayer layer = new SVGLayer();
                layer.setName(name);
                layer.setVisible(true);
                layer.setElement(node);
                if (i == len - 1) {
                    layer.setEdit(true);
                }
                this.svgHandle.getLayerManager().addLayer(layer, 0);
            }
        }
    }

    /**
     * initializes the canvas
     * 
     * @param monitor
     *            the object monitoring the loading of the svg file
     */
    protected void initializeCanvas(final Monitor monitor) {

        // creating the selection handler
        svgHandle.createSelection();

        if (monitor != null) {

            monitor.setProgress(40);
        }

        // creating the graphics node
        try {
            UserAgentAdapter userAgent = new UserAgentAdapter();
            ctx = new BridgeContext(userAgent, null, new DocumentLoader(userAgent));
            builder = new DynamicGVTBuilder();
            ctx.setDynamicState(BridgeContext.DYNAMIC);
            GraphicsNode gvt = builder.build(ctx, document);

            if (gvt != null) {

                gvtRoot = gvt.getRoot();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        if (monitor != null) {

            monitor.setProgress(80);
        }

        if (monitor == null || !monitor.isCancelled()) {

            SwingUtilities.invokeLater(new Runnable() {

                public void run() {

                    // setting the size of the canvas
                    Dimension scaledCanvasSize = getScaledCanvasSize();
                    setCanvasPreferredSize(scaledCanvasSize);
                    svgHandle.getSVGFrame().displayFrame(scaledCanvasSize);

                    // notifies the handle manager that the current handle has
                    // changed
                    Editor.getEditor().getHandlesManager().handleChanged();

                    if (monitor != null) {

                        monitor.stop();
                    }

                    // creating the grid manager
                    gridManager = new Grid(SVGCanvas.this);
                }
            });

        } else {

            monitor.stop();
            getSVGHandle().dispose();
        }
    }

    /**
     * disposes this canvas
     */
    public void dispose() {

        // disposing all the elements of the canvas
        removeAllPaintListeners();
        paintListeners.clear();

        if (ctx != null) {

            ctx.dispose();
        }

        repaintManager.removeInvalidComponent(this);
        removeAll();

        uri = null;
        document = null;
        builder = null;
        ctx = null;
        gvtRoot = null;
        canvasOffscreenImage = null;
        renderedRectangle = null;
        tmpRectangle = null;
        scrollpane = null;
        zoomManager = null;
        gridManager = null;
        projectFile = null;
        paintListeners = null;
        repaintZone = null;
        svgHandle = null;
        repaintManager = null;
    }

    /**
     * sets the new uri for the canvas
     * 
     * @param uri
     *            a uri
     */
    public void setNewURI(String uri) {

        this.uri = uri;

        // getting the uri object
        URI theURI = null;

        try {
            theURI = new URI(uri);
        } catch (Exception ex) {
        }

        if (theURI != null) {

            try {
                ((SVGOMDocument) getDocument()).setURLObject(theURI.toURL());
            } catch (Exception ex) {
            }
        }

        Editor.getEditor().getHandlesManager().handleChanged();
    }

    /**
     * @return the uri of the canvas
     */
    public String getURI() {

        return uri;
    }

    /**
     * @return the viewing transform
     */
    public AffineTransform getViewingTransform() {

        CanvasGraphicsNode canvasGraphicsNode = getCanvasGraphicsNode();

        if (canvasGraphicsNode != null) {

            return canvasGraphicsNode.getViewingTransform();
        }

        return null;
    }

    /**
     * @return the rendering transform
     */
    public AffineTransform getRenderingTransform() {

        double scale = zoomManager.getCurrentScale();
        return AffineTransform.getScaleInstance(scale, scale);
    }

    /**
     * @return the offscreen image
     */
    public BufferedImage getOffscreen() {

        return canvasOffscreenImage;
    }

    /**
     * @return the document of the canvas
     */
    public Document getDocument() {

        return document;
    }

    /**
     * @return the grid manager
     */
    public Grid getGridManager() {
        return gridManager;
    }

    /**
     * @return the zoom manager
     */
    public Zoom getZoomManager() {
        return zoomManager;
    }

    /**
     * setting the preferred size for this canvas
     * 
     * @param size
     *            the preferred size
     */
    public void setCanvasPreferredSize(Dimension size) {

        setPreferredSize(size);
        setSize(size);
    }

    /**
     * @return the bridge context
     */
    public BridgeContext getBridgeContext() {

        return ctx;
    }

    @Override
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        if (canvasOffscreenImage != null) {

            // getting the sub image that should be painted
            Rectangle clip = g.getClipBounds();
            Rectangle rendRect = new Rectangle(renderedRectangle.x, renderedRectangle.y,
                    canvasOffscreenImage.getWidth(), canvasOffscreenImage.getHeight());

            if (clip.width != 0 && clip.height != 0) {

                if (clip.contains(rendRect)) {

                    ((Graphics2D) g).drawRenderedImage(canvasOffscreenImage,
                            AffineTransform.getTranslateInstance(rendRect.x, rendRect.y));

                } else if (clip.intersects(rendRect)) {

                    // getting the sub image to draw
                    Rectangle rZone = clip.intersection(rendRect);

                    if (rZone.width != 0 && rZone.height != 0) {

                        BufferedImage subImage = canvasOffscreenImage.getSubimage(rZone.x - rendRect.x,
                                rZone.y - rendRect.y, rZone.width, rZone.height);

                        ((Graphics2D) g).drawRenderedImage(subImage,
                                AffineTransform.getTranslateInstance(rZone.x, rZone.y));
                    }
                }
            }
        }

        drawPainters((Graphics2D) g);
    }

    /**
     * refreshing the svg canvas content
     * 
     * @param repaintSVGContent
     *            whether the whole svg image should be redrawn
     * @param updateSVGContent
     *            whether one a part of the svg image should be redrawn
     * @param dirtyAreas
     *            the areas to redraw
     */
    protected void refreshCanvasContent(boolean repaintSVGContent, boolean updateSVGContent, Set<Area> dirtyAreas) {

        // drawing the offscreen image and painting it
        if (repaintSVGContent) {

            BufferedImage tempCanvasOffscreenImage = canvasOffscreenImage;

            // getting the gvt root
            GraphicsNode root = gvtRoot;

            if (root != null) {

                Rectangle usedRectangle = null;
                boolean isScrollAction = false;
                int scrollX = 0, scrollY = 0;

                if (tmpRectangle != null) {

                    usedRectangle = new Rectangle(tmpRectangle);
                    scrollX = usedRectangle.x - renderedRectangle.x;
                    scrollY = usedRectangle.y - renderedRectangle.y;
                }

                // checking if the rendered rectangle has been changed owing to
                // a scroll action
                if (usedRectangle != null && usedRectangle.width == renderedRectangle.width
                        && usedRectangle.height == renderedRectangle.height
                        && Math.abs(scrollX) < usedRectangle.width && Math.abs(scrollY) < usedRectangle.height) {

                    renderedRectangle.x = usedRectangle.x;
                    renderedRectangle.y = usedRectangle.y;

                    BufferedImage image = new BufferedImage(renderedRectangle.width, renderedRectangle.height,
                            BufferedImage.TYPE_INT_ARGB);
                    Graphics2D g2 = GraphicsUtil.createGraphics(image);
                    g2.setColor(Color.white);
                    BufferedImage tmpImage = null;

                    if (scrollY > 0) {

                        tmpImage = tempCanvasOffscreenImage.getSubimage(0, scrollY, renderedRectangle.width,
                                renderedRectangle.height - scrollY);
                        g2.drawImage(tmpImage, 0, 0, tmpImage.getWidth(), tmpImage.getHeight(), null);

                    } else if (scrollY < 0) {

                        tmpImage = tempCanvasOffscreenImage.getSubimage(0, 0, renderedRectangle.width,
                                renderedRectangle.height + scrollY);
                        g2.drawImage(tmpImage, 0, -scrollY, tmpImage.getWidth(), tmpImage.getHeight(), null);
                    }

                    if (scrollX > 0) {

                        tmpImage = tempCanvasOffscreenImage.getSubimage(scrollX, 0,
                                renderedRectangle.width - scrollX, renderedRectangle.height);
                        g2.drawImage(tmpImage, 0, 0, tmpImage.getWidth(), tmpImage.getHeight(), null);

                    } else if (scrollX < 0) {

                        tmpImage = tempCanvasOffscreenImage.getSubimage(0, 0, renderedRectangle.width + scrollX,
                                renderedRectangle.height);
                        g2.drawImage(tmpImage, -scrollX, 0, tmpImage.getWidth(), tmpImage.getHeight(), null);
                    }

                    g2.dispose();
                    tempCanvasOffscreenImage = image;
                    isScrollAction = true;

                } else if (!updateSVGContent) {

                    if (usedRectangle != null) {

                        renderedRectangle.x = usedRectangle.x;
                        renderedRectangle.y = usedRectangle.y;
                        renderedRectangle.width = usedRectangle.width;
                        renderedRectangle.height = usedRectangle.height;
                    }

                    // creating the new offscreen image
                    tempCanvasOffscreenImage = new BufferedImage(renderedRectangle.width, renderedRectangle.height,
                            BufferedImage.TYPE_INT_ARGB);
                }

                Graphics2D g2 = null;

                if (isScrollAction) {

                    // getting the canvas scale
                    double scale = zoomManager.getCurrentScale();

                    // computing the transform
                    AffineTransform af = AffineTransform.getScaleInstance(scale, scale);
                    af.preConcatenate(
                            AffineTransform.getTranslateInstance(-renderedRectangle.x, -renderedRectangle.y));

                    // computing the rendered rectangle in the base coordinates
                    Rectangle2D baseRectangle = getSVGHandle().getTransformsManager()
                            .getScaledRectangle(renderedRectangle, true);

                    // computing the image dimensions in the base coordinates
                    Rectangle2D rect = getSVGHandle().getTransformsManager()
                            .getScaledRectangle(new Rectangle2D.Double(0, 0, tempCanvasOffscreenImage.getWidth(),
                                    tempCanvasOffscreenImage.getHeight()), true);
                    Point2D basedImageSize = new Point2D.Double(rect.getWidth(), rect.getHeight());

                    // computing the scrolling values in the base coordinates
                    Point2D baseScrollPoint = getSVGHandle().getTransformsManager()
                            .getScaledPoint(new Point2D.Double(scrollX, scrollY), true);
                    double baseScrollX = baseScrollPoint.getX();
                    double baseScrollY = baseScrollPoint.getY();

                    g2 = GraphicsUtil.createGraphics(tempCanvasOffscreenImage);
                    g2.setTransform(af);

                    // clearing the image
                    g2.setColor(getBackground());

                    Rectangle2D svgRectangle = null;

                    if (baseScrollY > 0) {

                        svgRectangle = new Rectangle2D.Double(baseRectangle.getX(),
                                baseRectangle.getY() + basedImageSize.getY() - baseScrollY, basedImageSize.getX(),
                                baseScrollY);

                    } else if (baseScrollY < 0) {

                        svgRectangle = new Rectangle2D.Double(baseRectangle.getX(), baseRectangle.getY(),
                                basedImageSize.getX(), -baseScrollY);
                    }

                    if (baseScrollX > 0) {

                        svgRectangle = new Rectangle2D.Double(
                                baseRectangle.getX() + basedImageSize.getX() - baseScrollX, baseRectangle.getY(),
                                baseScrollX, basedImageSize.getY());

                    } else if (baseScrollX < 0) {

                        svgRectangle = new Rectangle2D.Double(baseRectangle.getX(), baseRectangle.getY(),
                                -baseScrollX, basedImageSize.getY());
                    }

                    if (svgRectangle != null) {

                        g2.clip(svgRectangle);

                        // painting the background
                        g2.setColor(Color.white);
                        g2.fill(svgRectangle);

                        setRenderingHints(g2);
                    }

                } else {

                    // getting the canvas scale
                    double scale = zoomManager.getCurrentScale();

                    // computing the transform
                    AffineTransform af = AffineTransform.getScaleInstance(scale, scale);
                    af.preConcatenate(
                            AffineTransform.getTranslateInstance(-renderedRectangle.x, -renderedRectangle.y));

                    // root.setTransform(af);
                    g2 = GraphicsUtil.createGraphics(tempCanvasOffscreenImage);
                    g2.setTransform(af);
                    setRenderingHints(g2);

                    if (updateSVGContent) {

                        if (dirtyAreas != null) {

                            // computing the clip rectangle
                            Area clip = null;

                            for (Area area : dirtyAreas) {

                                if (area != null) {

                                    if (clip == null) {

                                        clip = area;

                                    } else {

                                        clip.add(area);
                                    }
                                }
                            }

                            if (clip != null) {

                                g2.clip(clip);

                                // painting the background
                                g2.setColor(Color.white);
                                g2.fill(clip);

                            } else {

                                // clearing the background
                                g2.setColor(Color.white);
                                g2.fillRect(0, 0, tempCanvasOffscreenImage.getWidth(),
                                        tempCanvasOffscreenImage.getHeight());
                            }
                        }
                    }
                }

                // painting the image
                root.paint(g2);

                Rectangle2D clipBounds = g2.getClipBounds();

                if (g2.getClip() != null) {

                    clipBounds = svgHandle.getTransformsManager().getScaledRectangle(clipBounds, false);
                }

                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {

                        if (renderedRectangle != null) {

                            repaintManager.addDirtyRegion(SVGCanvas.this, renderedRectangle.x, renderedRectangle.y,
                                    renderedRectangle.width, renderedRectangle.height);

                        } else {

                            repaintManager.markCompletelyDirty(SVGCanvas.this);
                        }
                    }
                });

                g2.dispose();
            }

            canvasOffscreenImage = tempCanvasOffscreenImage;
            tmpRectangle = null;
        }
    }

    /**
     * sets the rendering hints
     * 
     * @param g
     *            a graphics object
     */
    protected void setRenderingHints(Graphics2D g) {

        // setting the rendering hints
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
                RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
    }

    /**
     * setting the new canvas size
     * 
     * @param newSize
     *            the new size
     */
    public void setCanvasSize(Point2D newSize) {

        CanvasGraphicsNode canvasGraphicsNode = getCanvasGraphicsNode();

        if (canvasGraphicsNode != null && canvasGraphicsNode.getPositionTransform() == null) {

            canvasGraphicsNode.setPositionTransform(new AffineTransform());
        }

        Element root = document.getDocumentElement();
        String width = FormatStore.format(newSize.getX());
        String height = FormatStore.format(newSize.getY());

        root.setAttribute("width", width);
        root.setAttribute("height", height);
        root.setAttribute("viewBox", "0 0 " + width + " " + height);

        setCanvasPreferredSize(getScaledCanvasSize());

        scrollpane.revalidate();
        scrollpane.refreshRulers();
        setRenderedRectangle(new Rectangle(scrollpane.getViewport().getViewRect()), true, true);
    }

    /**
     * @return SVGScrollPane the scrollpane that contains the canvas
     */
    public SVGScrollPane getScrollPane() {
        return scrollpane;
    }

    /**
     * @return the svg handle linked to this canvas
     */
    public SVGHandle getSVGHandle() {
        return svgHandle;
    }

    /**
     * @return the rendering rectangle
     */
    public Rectangle getRenderedRectangle() {
        return renderedRectangle;
    }

    /**
     * sets the new rendered rectangle
     * 
     * @param rect
     *            a rendered rectangle
     * @param reinitialize
     *            whether the stored information about the rendered picture
     *            should be erased or not
     * @param forceReinitialize
     *            whether the stored information about the rendered picture
     *            should be erased or not, forcing it if necessary
     */
    public void setRenderedRectangle(Rectangle rect, boolean reinitialize, boolean forceReinitialize) {

        if (forceReinitialize) {

            renderedRectangle = new Rectangle(0, 0, 1, 1);
            tmpRectangle = rect;
            refreshCanvasContent(true, false, null);

        } else if (reinitialize) {

            if (rect != null && !renderedRectangle.equals(rect) && reinitialize) {

                renderedRectangle = new Rectangle(0, 0, 1, 1);
                tmpRectangle = rect;
                refreshCanvasContent(true, false, null);
            }

        } else if (rect != null && !renderedRectangle.equals(rect) && renderedRectangle.width > 0
                && renderedRectangle.height > 0) {

            tmpRectangle = rect;
            refreshCanvasContent(true, false, null);
        }
    }

    /**
     * requests that the svg content should be repainted
     */
    public void requestRepaintContent() {

        refreshCanvasContent(true, false, null);
    }

    /**
     * requests that the svg content should be updated
     * 
     * @param repaintArea
     *            the area to repaint
     */
    public void requestUpdateContent(Area repaintArea) {

        if (repaintArea != null) {

            Set<Area> dirtyAreas = new HashSet<Area>();
            dirtyAreas.add(repaintArea);

            refreshCanvasContent(true, true, dirtyAreas);
        }
    }

    /**
     * @return the project file linked to the canvas
     */
    public File getProjectFile() {
        return projectFile;
    }

    /**
     * sets the current cursor
     * 
     * @param cursor
     *            the current cursor
     */
    public void setSVGCursor(Cursor cursor) {

        if (cursor != null) {

            setCursor(cursor);
        }
    }

    /**
     * notifies that the parent element has changed
     */
    public void notifyParentElementChanged() {

        repaintManager.markCompletelyDirty(this);
    }

    /**
     * @return the canvas' size
     */
    public Point2D getGeometryCanvasSize() {

        return getGeometryCanvasSize(document);
    }

    /**
     * returns the size of the svg denoted by the provided document
     * 
     * @param aDocument
     *            a svg document
     * @return the size of the svg denoted by the provided document
     */
    public static Point2D getGeometryCanvasSize(Document aDocument) {

        if (aDocument != null) {

            // getting the root element
            Element root = aDocument.getDocumentElement();

            if (root != null) {

                double w = EditorToolkit.getPixelledNumber(root.getAttributeNS(null, "width"));
                double h = EditorToolkit.getPixelledNumber(root.getAttributeNS(null, "height"));

                return new Point2D.Double(w, h);
            }
        }

        return new Point2D.Double(0, 0);
    }

    /**
     * @param root
     *            the root element
     * @return the scaled canvas' size
     */
    public Dimension getScaledCanvasSize(Element root) {

        Dimension scaledSize = new Dimension(0, 0);

        if (root != null) {

            double w = 0, h = 0;

            try {
                // getting the scale factor of the canvas
                double scale = zoomManager.getCurrentScale();

                w = EditorToolkit.getPixelledNumber(root.getAttributeNS(null, "width")) * scale;
                h = EditorToolkit.getPixelledNumber(root.getAttributeNS(null, "height")) * scale;
                if (w == 0 || h == 0) {
                    //if not contain width and height, so analysing viewBox to get width and height
                    String viewBox = root.getAttributeNS(null, "viewBox");
                    String[] box = viewBox.split(",");
                    if (box.length != 4) {
                        box = viewBox.split("\\s");
                    }
                    if (box.length == 4) {
                        w = EditorToolkit.getPixelledNumber(box[2]) * scale;
                        h = EditorToolkit.getPixelledNumber(box[3]) * scale;
                    }
                }
                scaledSize.width = (int) w;
                scaledSize.height = (int) h;

            } catch (Exception ex) {
            }
        }

        return scaledSize;
    }

    /**
     * @return the scaled canvas' size
     */
    public Dimension getScaledCanvasSize() {

        Dimension scaledSize = new Dimension(0, 0);

        // gets the root element
        if (document != null) {

            Element root = document.getDocumentElement();

            if (root != null) {

                double w = 0, h = 0;

                try {
                    // getting the scale factor of the canvas
                    double scale = zoomManager.getCurrentScale();

                    w = EditorToolkit.getPixelledNumber(root.getAttributeNS(null, "width")) * scale;
                    h = EditorToolkit.getPixelledNumber(root.getAttributeNS(null, "height")) * scale;
                    scaledSize.width = (int) w;
                    scaledSize.height = (int) h;
                } catch (Exception ex) {
                }
            }
        }

        return scaledSize;
    }

    /**
     * handles the repaint of the canvas
     * 
     * @param clipZone
     *            the clip zone or null to repaint the whole canvas
     */
    protected void handleRepaint(Rectangle2D clipZone) {

        // getting the repaint zone
        if (clipZone != null) {

            clipZone = new Rectangle2D.Double(clipZone.getX(), clipZone.getY(), clipZone.getWidth(),
                    clipZone.getHeight());
        }

        Rectangle2D clip = null;

        if (repaintZone != null) {

            Rectangle2D rZone = new Rectangle2D.Double(repaintZone.getX(), repaintZone.getY(),
                    repaintZone.getWidth(), repaintZone.getHeight());

            if (clipZone != null) {

                rZone = rZone.createUnion(clipZone);
            }

            rZone = rZone.createIntersection(renderedRectangle);

            double x0 = rZone.getX();
            double y0 = rZone.getY();
            double x1 = rZone.getX() + rZone.getWidth();
            double y1 = rZone.getY() + rZone.getHeight();

            clip = new Rectangle2D.Double(x0 - 2, y0 - 2, x1 - x0 + 5, y1 - y0 + 5);
            repaintZone = null;

        } else if (clipZone != null) {

            clipZone = clipZone.createIntersection(renderedRectangle);

            double x0 = clipZone.getX();
            double y0 = clipZone.getY();
            double x1 = clipZone.getX() + clipZone.getWidth();
            double y1 = clipZone.getY() + clipZone.getHeight();

            clip = new Rectangle2D.Double(x0 - 2, y0 - 2, x1 - x0 + 5, y1 - y0 + 5);
        }

        // repainting
        if (clip == null) {

            // repaint();
            repaintManager.markCompletelyDirty(this);

        } else {

            repaintManager.addDirtyRegion(this, clip.getBounds().x, clip.getBounds().y, clip.getBounds().width,
                    clip.getBounds().height);
            // repaint(clip.getBounds());
        }
    }

    /**
     * adds a grid paint listener
     * 
     * @param type
     *            the integer representing the layer at which the painting
     *            should be done
     * @param l
     *            the grid paint listener to be added
     * @param makeRepaint
     *            whether to make a repaint after the paint listener was added
     *            or not
     */
    public void addLayerPaintListener(int type, CanvasPainter l, boolean makeRepaint) {

        if (l != null) {

            Set<CanvasPainter> set = paintListeners.get(type);

            if (set != null) {

                set.add(l);
            }

            // handle the clips of the painter to compute the new clipping zone
            handleClips(l.getClip(), makeRepaint);
        }
    }

    /**
     * removes a paint listener
     * 
     * @param l
     *            the paint listener to be removed
     * @param makeRepaint
     *            whether to make a repaint after the paint listener was removed
     *            or not
     */
    public void removePaintListener(CanvasPainter l, boolean makeRepaint) {

        try {
            paintListeners.get(GRID_LAYER).remove(l);
            paintListeners.get(BOTTOM_LAYER).remove(l);
            paintListeners.get(SELECTION_LAYER).remove(l);
            paintListeners.get(DRAW_LAYER).remove(l);
            paintListeners.get(TOP_LAYER).remove(l);
        } catch (Exception ex) {
        }

        if (l != null) {

            // handle the clips of the painter to compute the new clipping zone
            handleClips(l.getClip(), makeRepaint);
        }
    }

    /**
     * handles the clipping given the set of clips
     * 
     * @param clips
     *            a set of clip rectangles
     * @param makeRepaint
     *            whether the repaint action should be done
     */
    protected void handleClips(Set<Rectangle2D> clips, boolean makeRepaint) {

        if (clips != null && clips.size() > 0) {

            if (makeRepaint) {

                for (Rectangle2D clip : clips) {

                    handleRepaint(clip);
                }

            } else {

                for (Rectangle2D clip : clips) {

                    if (repaintZone != null) {

                        repaintZone.add(clip);

                    } else {

                        repaintZone = new Rectangle2D.Double();
                        repaintZone.setRect(clip);
                    }
                }
            }

        } else if (makeRepaint) {

            handleRepaint(null);
        }
    }

    /**
     * notifies the paint listeners when a paint action is done
     *
     * @param g2
     *            the graphics
     */
    protected void drawPainters(Graphics2D g2) {

        g2 = (Graphics2D) g2.create();

        //setting the rendering hints
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        g2.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
        g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
        g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
        g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
        g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);

        Set<CanvasPainter> set = null;

        for (int layer : layers) {

            set = paintListeners.get(layer);

            for (CanvasPainter listener : set) {

                listener.paintToBeDone(g2);
            }
        }

        //painting the current parent bounds
        Element parentElement = getSVGHandle().getSelection().getParentElement();

        if (parentElement != null && parentElement.equals(document.getDocumentElement())) { // remove !

            Rectangle2D parentElementBounds = getSVGHandle().getSvgElementsManager().getNodeBounds(parentElement);

            //getting the shape that should be drawn
            Area area = new Area(renderedRectangle);
            area.subtract(new Area(parentElementBounds));

            //painting the area
            g2.setColor(parentVeilColor);
            g2.fill(area);
            g2.setColor(Color.lightGray);
            g2.draw(parentElementBounds);
        }

        g2.dispose();
    }

    /**
     * removes all paint listeners
     */
    public void removeAllPaintListeners() {

        paintListeners.get(GRID_LAYER).clear();
        paintListeners.get(BOTTOM_LAYER).clear();
        paintListeners.get(SELECTION_LAYER).clear();
        paintListeners.get(DRAW_LAYER).clear();
        paintListeners.get(TOP_LAYER).clear();
    }

    /**
     * handles the repaint of the canvas
     * 
     * @param clipZone
     *            the clip zone or null the repaint all the canvas
     */
    public void doRepaint(Rectangle clipZone) {

        handleRepaint(clipZone);
    }

    /**
     * @return the gvt root
     */
    public GraphicsNode getGraphicsNode() {
        return getCanvasGraphicsNode();
    }

    /**
     * @return the canvas graphics node for this canvas
     */
    private CanvasGraphicsNode getCanvasGraphicsNode() {

        java.util.List<?> children = gvtRoot.getChildren();

        if (children.size() == 0) {

            return null;
        }

        GraphicsNode gn = (GraphicsNode) children.get(0);

        if (!(gn instanceof CanvasGraphicsNode)) {

            return null;
        }

        return (CanvasGraphicsNode) gn;
    }

    /**
     * clears the cache
     */
    public void clearCache() {

        if (ctx != null) {

            ctx.getDocumentLoader().dispose();
        }
    }

    public BridgeContext getCtx() {
        return ctx;
    }

    public void setCtx(BridgeContext ctx) {
        this.ctx = ctx;
    }
}