You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2007/09/23 04:50:22 UTC

svn commit: r578549 - in /xmlgraphics/batik/trunk/sources/org/apache/batik/bridge: SVGFilterElementBridge.java SVGUtilities.java

Author: cam
Date: Sat Sep 22 19:50:21 2007
New Revision: 578549

URL: http://svn.apache.org/viewvc?rev=578549&view=rev
Log:
Make empty <filter> elements result in no rendering for the filtered element.
Fixes bug 26815.

Modified:
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGFilterElementBridge.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGUtilities.java

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGFilterElementBridge.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGFilterElementBridge.java?rev=578549&r1=578548&r2=578549&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGFilterElementBridge.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGFilterElementBridge.java Sat Sep 22 19:50:21 2007
@@ -18,6 +18,7 @@
  */
 package org.apache.batik.bridge;
 
+import java.awt.Color;
 import java.awt.geom.Rectangle2D;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -33,6 +34,7 @@
 import org.apache.batik.ext.awt.image.renderable.Filter;
 import org.apache.batik.ext.awt.image.renderable.FilterChainRable;
 import org.apache.batik.ext.awt.image.renderable.FilterChainRable8Bit;
+import org.apache.batik.ext.awt.image.renderable.FloodRable8Bit;
 import org.apache.batik.ext.awt.image.renderable.PadRable8Bit;
 import org.apache.batik.gvt.GraphicsNode;
 import org.w3c.dom.Element;
@@ -48,6 +50,11 @@
         implements FilterBridge, ErrorConstants {
 
     /**
+     * Transparent black color.
+     */
+    protected static final Color TRANSPARENT_BLACK = new Color(0, true);
+
+    /**
      * Constructs a new bridge for the &lt;filter> element.
      */
     public SVGFilterElementBridge() {}
@@ -107,12 +114,37 @@
                                           sourceGraphic,
                                           filterNodeMap,
                                           ctx);
-        if ((in == null) || (in == sourceGraphic)) {
-            return null; // no filter primitives found, disable the filter.
-        } else {
-            filterChain.setSource(in);
-            return filterChain;
+        if (in == null) {
+            // error in one of the primitives, disable the filter
+            return null;
+        } else if (in == sourceGraphic) {
+            // no filter primitive found, so output transparent black
+            in = createEmptyFilter(filterElement, filterRegion, filteredElement,
+                                   filteredNode, ctx);
         }
+        filterChain.setSource(in);
+        return filterChain;
+    }
+
+    /**
+     * Creates a new returns a new filter that fills its output with
+     * transparent black.  This is used when a &lt;filter&gt; element
+     * has no filter primitive children.
+     */
+    protected static Filter createEmptyFilter(Element filterElement,
+                                              Rectangle2D filterRegion,
+                                              Element filteredElement,
+                                              GraphicsNode filteredNode,
+                                              BridgeContext ctx) {
+        Rectangle2D primitiveRegion
+            = SVGUtilities.convertFilterPrimitiveRegion(null,
+                                                        filterElement,
+                                                        filteredElement,
+                                                        filteredNode,
+                                                        filterRegion,
+                                                        filterRegion,
+                                                        ctx);
+        return new FloodRable8Bit(primitiveRegion, TRANSPARENT_BLACK);
     }
 
     /**

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGUtilities.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGUtilities.java?rev=578549&r1=578548&r2=578549&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGUtilities.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGUtilities.java Sat Sep 22 19:50:21 2007
@@ -814,6 +814,7 @@
      * element as the top one in the filter chain.
      *
      * @param filterPrimitiveElement the filter primitive element
+     * @param filterElement the filter element
      * @param filteredElement the element referencing the filter
      * @param filteredNode the graphics node to use (objectBoundingBox)
      * @param defaultRegion the default region to filter
@@ -822,6 +823,7 @@
      */
     public static Rectangle2D
         convertFilterPrimitiveRegion(Element filterPrimitiveElement,
+                                     Element filterElement,
                                      Element filteredElement,
                                      GraphicsNode filteredNode,
                                      Rectangle2D defaultRegion,
@@ -829,12 +831,9 @@
                                      BridgeContext ctx) {
 
         // 'primitiveUnits' - default is userSpaceOnUse
-        Node parentNode = filterPrimitiveElement.getParentNode();
         String units = "";
-        if ((parentNode != null) &&
-            (parentNode.getNodeType() == Node.ELEMENT_NODE)) {
-            Element parent = (Element)parentNode;
-            units = getChainableAttributeNS(parent,
+        if (filterElement != null) {
+            units = getChainableAttributeNS(filterElement,
                                             null,
                                             SVG_PRIMITIVE_UNITS_ATTRIBUTE,
                                             ctx);
@@ -844,25 +843,28 @@
             unitsType = USER_SPACE_ON_USE;
         } else {
             unitsType = parseCoordinateSystem
-                (filterPrimitiveElement, SVG_FILTER_UNITS_ATTRIBUTE, units,
-                 ctx);
+                (filterElement, SVG_FILTER_UNITS_ATTRIBUTE, units, ctx);
         }
 
-        // 'x' attribute - default is defaultRegion.getX()
-        String xStr =
-            filterPrimitiveElement.getAttributeNS(null, SVG_X_ATTRIBUTE);
-
-        // 'y' attribute - default is defaultRegion.getY()
-        String yStr =
-            filterPrimitiveElement.getAttributeNS(null, SVG_Y_ATTRIBUTE);
-
-        // 'width' attribute - default is defaultRegion.getWidth()
-        String wStr =
-            filterPrimitiveElement.getAttributeNS(null, SVG_WIDTH_ATTRIBUTE);
-
-        // 'height' attribute - default is defaultRegion.getHeight()
-        String hStr =
-            filterPrimitiveElement.getAttributeNS(null, SVG_HEIGHT_ATTRIBUTE);
+        String xStr = "", yStr = "", wStr = "", hStr = "";
+
+        if (filterPrimitiveElement != null) {
+            // 'x' attribute - default is defaultRegion.getX()
+            xStr = filterPrimitiveElement.getAttributeNS(null,
+                                                         SVG_X_ATTRIBUTE);
+
+            // 'y' attribute - default is defaultRegion.getY()
+            yStr = filterPrimitiveElement.getAttributeNS(null,
+                                                         SVG_Y_ATTRIBUTE);
+
+            // 'width' attribute - default is defaultRegion.getWidth()
+            wStr = filterPrimitiveElement.getAttributeNS(null,
+                                                         SVG_WIDTH_ATTRIBUTE);
+
+            // 'height' attribute - default is defaultRegion.getHeight()
+            hStr = filterPrimitiveElement.getAttributeNS(null,
+                                                         SVG_HEIGHT_ATTRIBUTE);
+        }
 
         double x = defaultRegion.getX();
         double y = defaultRegion.getY();
@@ -918,7 +920,7 @@
             }
             break;
         default:
-            throw new Error("invalid unitsType:" + unitsType ); // can't be reached
+            throw new Error("invalid unitsType:" + unitsType); // can't be reached
         }
 
         Rectangle2D region = new Rectangle2D.Double(x, y, w, h);
@@ -928,11 +930,9 @@
         // *always* in userSpaceOnUse space.
 
         units = "";
-        if ((parentNode != null) &&
-            (parentNode.getNodeType() == Node.ELEMENT_NODE)) {
-            Element parent = (Element)parentNode;
+        if (filterElement != null) {
             units = getChainableAttributeNS
-                (parent, null,
+                (filterElement, null,
                  SVG12Constants.SVG_FILTER_PRIMITIVE_MARGINS_UNITS_ATTRIBUTE,
                  ctx);
         }
@@ -941,35 +941,39 @@
             unitsType = USER_SPACE_ON_USE;
         } else {
             unitsType = parseCoordinateSystem
-                (filterPrimitiveElement,
+                (filterElement,
                  SVG12Constants.SVG_FILTER_PRIMITIVE_MARGINS_UNITS_ATTRIBUTE,
                  units, ctx);
         }
 
-        // 'batik:dx' attribute - default is 0
-        String dxStr = filterPrimitiveElement.getAttributeNS
-            (null, SVG12Constants.SVG_MX_ATRIBUTE);
+        String dxStr = "", dyStr = "", dwStr = "", dhStr = "";
+
+        if (filterPrimitiveElement != null) {
+            // 'batik:dx' attribute - default is 0
+            dxStr = filterPrimitiveElement.getAttributeNS
+                (null, SVG12Constants.SVG_MX_ATRIBUTE);
+
+            // 'batik:dy' attribute - default is 0
+            dyStr = filterPrimitiveElement.getAttributeNS
+                (null, SVG12Constants.SVG_MY_ATRIBUTE);
+
+            // 'batik:dw' attribute - default is 0
+            dwStr = filterPrimitiveElement.getAttributeNS
+                (null, SVG12Constants.SVG_MW_ATRIBUTE);
+
+            // 'batik:dh' attribute - default is 0
+            dhStr = filterPrimitiveElement.getAttributeNS
+                (null, SVG12Constants.SVG_MH_ATRIBUTE);
+        }
         if (dxStr.length() == 0) {
             dxStr = SVG12Constants.SVG_FILTER_MX_DEFAULT_VALUE;
         }
-
-        // 'batik:dy' attribute - default is 0
-        String dyStr = filterPrimitiveElement.getAttributeNS
-            (null, SVG12Constants.SVG_MY_ATRIBUTE);
         if (dyStr.length() == 0) {
             dyStr = SVG12Constants.SVG_FILTER_MY_DEFAULT_VALUE;
         }
-
-        // 'batik:dw' attribute - default is 0
-        String dwStr = filterPrimitiveElement.getAttributeNS
-            (null, SVG12Constants.SVG_MW_ATRIBUTE);
         if (dwStr.length() == 0) {
             dwStr = SVG12Constants.SVG_FILTER_MW_DEFAULT_VALUE;
         }
-
-        // 'batik:dh' attribute - default is 0
-        String dhStr = filterPrimitiveElement.getAttributeNS
-            (null, SVG12Constants.SVG_MH_ATRIBUTE);
         if (dhStr.length() == 0) {
             dhStr = SVG12Constants.SVG_FILTER_MH_DEFAULT_VALUE;
         }
@@ -986,6 +990,41 @@
         Rectangle2D.intersect(region, filterRegion, region);
 
         return region;
+    }
+
+    /**
+     * Returns the filter primitive region according to the x, y,
+     * width, height, and filterUnits attributes. Processing the
+     * element as the top one in the filter chain.
+     *
+     * @param filterPrimitiveElement the filter primitive element
+     * @param filteredElement the element referencing the filter
+     * @param filteredNode the graphics node to use (objectBoundingBox)
+     * @param defaultRegion the default region to filter
+     * @param filterRegion the filter chain region
+     * @param ctx the bridge context
+     */
+    public static Rectangle2D
+        convertFilterPrimitiveRegion(Element filterPrimitiveElement,
+                                     Element filteredElement,
+                                     GraphicsNode filteredNode,
+                                     Rectangle2D defaultRegion,
+                                     Rectangle2D filterRegion,
+                                     BridgeContext ctx) {
+
+        Node parentNode = filterPrimitiveElement.getParentNode();
+        Element filterElement = null;
+        if (parentNode != null &&
+                parentNode.getNodeType() == Node.ELEMENT_NODE) {
+            filterElement = (Element) parentNode;
+        }
+        return convertFilterPrimitiveRegion(filterPrimitiveElement,
+                                            filterElement,
+                                            filteredElement,
+                                            filteredNode,
+                                            defaultRegion,
+                                            filterRegion,
+                                            ctx);
     }
 
     /////////////////////////////////////////////////////////////////////////