001 /*
002 * BoundedElement.java
003 *
004 *
005 * The Salamander Project - 2D and 3D graphics libraries in Java
006 * Copyright (C) 2004 Mark McKay
007 *
008 * This library is free software; you can redistribute it and/or
009 * modify it under the terms of the GNU Lesser General Public
010 * License as published by the Free Software Foundation; either
011 * version 2.1 of the License, or (at your option) any later version.
012 *
013 * This library is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016 * Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public
019 * License along with this library; if not, write to the Free Software
020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021 *
022 * Mark McKay can be contacted at mark@kitfox.com. Salamander and other
023 * projects can be found at http://www.kitfox.com
024 *
025 * Created on January 26, 2004, 9:00 AM
026 */
027
028 package com.kitfox.svg;
029
030 import com.kitfox.svg.xml.StyleAttribute;
031 import java.awt.Graphics2D;
032 import java.awt.Shape;
033 import java.awt.geom.AffineTransform;
034 import java.awt.geom.Area;
035 import java.awt.geom.Point2D;
036 import java.awt.geom.Rectangle2D;
037 import java.net.URI;
038 import java.util.List;
039
040
041
042 /**
043 * Maintains bounding box for this element
044 *
045 * @author Mark McKay
046 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
047 */
048 abstract public class RenderableElement extends TransformableElement
049 {
050
051 AffineTransform cachedXform = null;
052 Shape cachedClip = null;
053
054 public static final int VECTOR_EFFECT_NONE = 0;
055 public static final int VECTOR_EFFECT_NON_SCALING_STROKE = 1;
056 int vectorEffect;
057
058 /** Creates a new instance of BoundedElement */
059 public RenderableElement() {
060 }
061
062 public RenderableElement(String id, SVGElement parent)
063 {
064 super(id, parent);
065 }
066
067 protected void build() throws SVGException
068 {
069 super.build();
070
071 StyleAttribute sty = new StyleAttribute();
072
073 if (getPres(sty.setName("vector-effect")))
074 {
075 if ("non-scaling-stroke".equals(sty.getStringValue()))
076 {
077 vectorEffect = VECTOR_EFFECT_NON_SCALING_STROKE;
078 }
079 else
080 {
081 vectorEffect = VECTOR_EFFECT_NONE;
082 }
083 }
084 else
085 {
086 vectorEffect = VECTOR_EFFECT_NONE;
087 }
088 }
089
090 abstract public void render(Graphics2D g) throws SVGException;
091
092 abstract void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException;
093
094 abstract void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException;
095
096 abstract public Rectangle2D getBoundingBox() throws SVGException;
097 /*
098 public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent)
099 {
100 super.loaderStartElement(helper, attrs, parent);
101 }
102 */
103 /**
104 * Pushes transform stack, transforms to local coordinates and sets up
105 * clipping mask.
106 */
107 protected void beginLayer(Graphics2D g) throws SVGException
108 {
109 if (xform != null)
110 {
111 cachedXform = g.getTransform();
112 g.transform(xform);
113 }
114
115 StyleAttribute styleAttrib = new StyleAttribute();
116
117 //Get clipping path
118 // StyleAttribute styleAttrib = getStyle("clip-path", false);
119 Shape clipPath = null;
120 int clipPathUnits = ClipPath.CP_USER_SPACE_ON_USE;
121 if (getStyle(styleAttrib.setName("clip-path")))
122 {
123 URI uri = styleAttrib.getURIValue(getXMLBase());
124 if (uri != null)
125 {
126 ClipPath ele = (ClipPath)diagram.getUniverse().getElement(uri);
127 clipPath = ele.getClipPathShape();
128 clipPathUnits = ele.getClipPathUnits();
129 }
130 }
131
132 //Return if we're out of clipping range
133 if (clipPath != null)
134 {
135 if (clipPathUnits == ClipPath.CP_OBJECT_BOUNDING_BOX && (this instanceof ShapeElement))
136 {
137 Rectangle2D rect = ((ShapeElement)this).getBoundingBox();
138 AffineTransform at = new AffineTransform();
139 at.scale(rect.getWidth(), rect.getHeight());
140 clipPath = at.createTransformedShape(clipPath);
141 }
142
143 cachedClip = g.getClip();
144 if (cachedClip == null)
145 {
146 g.setClip(clipPath);
147 }
148 else
149 {
150 Area newClip = new Area(cachedClip);
151 newClip.intersect(new Area(clipPath));
152 g.setClip(newClip);
153 }
154 }
155 }
156
157 /**
158 * Restores transform and clipping values to the way they were before
159 * this layer was drawn.
160 */
161 protected void finishLayer(Graphics2D g)
162 {
163 if (cachedClip != null)
164 {
165 g.setClip(cachedClip);
166 }
167
168 if (cachedXform != null)
169 {
170 g.setTransform(cachedXform);
171 }
172 }
173
174 }