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 protected void build() throws SVGException 076 { 077 super.build(); 078 079 StyleAttribute sty = new StyleAttribute(); 080 081 if (getPres(sty.setName("vector-effect"))) 082 { 083 if ("non-scaling-stroke".equals(sty.getStringValue())) 084 { 085 vectorEffect = VECTOR_EFFECT_NON_SCALING_STROKE; 086 } else 087 { 088 vectorEffect = VECTOR_EFFECT_NONE; 089 } 090 } else 091 { 092 vectorEffect = VECTOR_EFFECT_NONE; 093 } 094 } 095 096 abstract public void render(Graphics2D g) throws SVGException; 097 098 abstract void pick(Point2D point, boolean boundingBox, List retVec) throws SVGException; 099 100 abstract void pick(Rectangle2D pickArea, AffineTransform ltw, boolean boundingBox, List retVec) throws SVGException; 101 102 abstract public Rectangle2D getBoundingBox() throws SVGException; 103 /* 104 public void loaderStartElement(SVGLoaderHelper helper, Attributes attrs, SVGElement parent) 105 { 106 super.loaderStartElement(helper, attrs, parent); 107 } 108 */ 109 110 /** 111 * Pushes transform stack, transforms to local coordinates and sets up 112 * clipping mask. 113 */ 114 protected void beginLayer(Graphics2D g) throws SVGException 115 { 116 if (xform != null) 117 { 118 cachedXform = g.getTransform(); 119 g.transform(xform); 120 } 121 122 StyleAttribute styleAttrib = new StyleAttribute(); 123 124 //Get clipping path 125// StyleAttribute styleAttrib = getStyle("clip-path", false); 126 Shape clipPath = null; 127 int clipPathUnits = ClipPath.CP_USER_SPACE_ON_USE; 128 if (getStyle(styleAttrib.setName("clip-path"), false) 129 && !"none".equals(styleAttrib.getStringValue())) 130 { 131 URI uri = styleAttrib.getURIValue(getXMLBase()); 132 if (uri != null) 133 { 134 ClipPath ele = (ClipPath) diagram.getUniverse().getElement(uri); 135 clipPath = ele.getClipPathShape(); 136 clipPathUnits = ele.getClipPathUnits(); 137 } 138 } 139 140 //Return if we're out of clipping range 141 if (clipPath != null) 142 { 143 if (clipPathUnits == ClipPath.CP_OBJECT_BOUNDING_BOX && (this instanceof ShapeElement)) 144 { 145 Rectangle2D rect = ((ShapeElement) this).getBoundingBox(); 146 AffineTransform at = new AffineTransform(); 147 at.scale(rect.getWidth(), rect.getHeight()); 148 clipPath = at.createTransformedShape(clipPath); 149 } 150 151 cachedClip = g.getClip(); 152 if (cachedClip == null) 153 { 154 g.setClip(clipPath); 155 } else 156 { 157 Area newClip = new Area(cachedClip); 158 newClip.intersect(new Area(clipPath)); 159 g.setClip(newClip); 160 } 161 } 162 } 163 164 /** 165 * Restores transform and clipping values to the way they were before this 166 * layer was drawn. 167 */ 168 protected void finishLayer(Graphics2D g) 169 { 170 if (cachedClip != null) 171 { 172 g.setClip(cachedClip); 173 } 174 175 if (cachedXform != null) 176 { 177 g.setTransform(cachedXform); 178 } 179 } 180}