001/*
002 * SVG Salamander
003 * Copyright (c) 2004, Mark McKay
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or 
007 * without modification, are permitted provided that the following
008 * conditions are met:
009 *
010 *   - Redistributions of source code must retain the above 
011 *     copyright notice, this list of conditions and the following
012 *     disclaimer.
013 *   - Redistributions in binary form must reproduce the above
014 *     copyright notice, this list of conditions and the following
015 *     disclaimer in the documentation and/or other materials 
016 *     provided with the distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
021 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
022 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
029 * OF THE POSSIBILITY OF SUCH DAMAGE. 
030 * 
031 * Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
032 * projects can be found at http://www.kitfox.com
033 *
034 * Created on January 26, 2004, 9:00 AM
035 */
036package com.kitfox.svg;
037
038import com.kitfox.svg.xml.StyleAttribute;
039import java.awt.Graphics2D;
040import java.awt.Shape;
041import java.awt.geom.AffineTransform;
042import java.awt.geom.Area;
043import java.awt.geom.Point2D;
044import java.awt.geom.Rectangle2D;
045import java.net.URI;
046import java.util.List;
047
048/**
049 * Maintains bounding box for this element
050 *
051 * @author Mark McKay
052 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
053 */
054abstract public class RenderableElement extends TransformableElement
055{
056    AffineTransform cachedXform = null;
057    
058    Shape cachedClip = null;
059    public static final int VECTOR_EFFECT_NONE = 0;
060    public static final int VECTOR_EFFECT_NON_SCALING_STROKE = 1;
061    int vectorEffect;
062
063    /**
064     * Creates a new instance of BoundedElement
065     */
066    public RenderableElement()
067    {
068    }
069
070    public RenderableElement(String id, SVGElement parent)
071    {
072        super(id, parent);
073    }
074
075    @Override
076    protected void build() throws SVGException
077    {
078        super.build();
079
080        StyleAttribute sty = new StyleAttribute();
081
082        if (getPres(sty.setName("vector-effect")))
083        {
084            if ("non-scaling-stroke".equals(sty.getStringValue()))
085            {
086                vectorEffect = VECTOR_EFFECT_NON_SCALING_STROKE;
087            } else
088            {
089                vectorEffect = VECTOR_EFFECT_NONE;
090            }
091        } else
092        {
093            vectorEffect = VECTOR_EFFECT_NONE;
094        }
095    }
096
097    abstract public void render(Graphics2D g) throws SVGException;
098
099    abstract void pick(Point2D point, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException;
100
101    abstract void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List<List<SVGElement>> retVec) throws SVGException;
102
103    abstract public Rectangle2D getBoundingBox() throws SVGException;
104    /*
105     public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
106     {
107     super.loaderStartElement(helper, attrs, parent);
108     }
109     */
110
111    /**
112     * Pushes transform stack, transforms to local coordinates and sets up
113     * clipping mask.
114     * 
115     * @param g Graphics context
116     * @throws com.kitfox.svg.SVGException
117     */
118    protected void beginLayer(Graphics2D g) throws SVGException
119    {
120        if (xform != null)
121        {
122            cachedXform = g.getTransform();
123            g.transform(xform);
124        }
125
126        StyleAttribute styleAttrib = new StyleAttribute();
127
128        //Get clipping path
129//        StyleAttribute styleAttrib = getStyle("clip-path", false);
130        Shape clipPath = null;
131        int clipPathUnits = ClipPath.CP_USER_SPACE_ON_USE;
132        if (getStyle(styleAttrib.setName("clip-path"), false)
133             && !"none".equals(styleAttrib.getStringValue()))
134        {
135            URI uri = styleAttrib.getURIValue(getXMLBase());
136            if (uri != null)
137            {
138                ClipPath ele = (ClipPath) diagram.getUniverse().getElement(uri);
139                clipPath = ele.getClipPathShape();
140                clipPathUnits = ele.getClipPathUnits();
141            }
142        }
143
144        //Return if we're out of clipping range
145        if (clipPath != null)
146        {
147            if (clipPathUnits == ClipPath.CP_OBJECT_BOUNDING_BOX && (this instanceof ShapeElement))
148            {
149                Rectangle2D rect = ((ShapeElement) this).getBoundingBox();
150                AffineTransform at = new AffineTransform();
151                at.scale(rect.getWidth(), rect.getHeight());
152                clipPath = at.createTransformedShape(clipPath);
153            }
154
155            cachedClip = g.getClip();
156            if (cachedClip == null)
157            {
158                g.setClip(clipPath);
159            } else
160            {
161                Area newClip = new Area(cachedClip);
162                newClip.intersect(new Area(clipPath));
163                g.setClip(newClip);
164            }
165        }
166    }
167
168    /**
169     * Restores transform and clipping values to the way they were before this
170     * layer was drawn.
171     * @param g
172     */
173    protected void finishLayer(Graphics2D g)
174    {
175        if (cachedClip != null)
176        {
177            g.setClip(cachedClip);
178        }
179
180        if (cachedXform != null)
181        {
182            g.setTransform(cachedXform);
183        }
184    }
185}