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}