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 de...@apache.org on 2006/04/21 13:00:09 UTC

svn commit: r395847 - in /xmlgraphics/batik/branches/svg11: samples/ sources/org/apache/batik/apps/rasterizer/ sources/org/apache/batik/ext/awt/image/rendered/ sources/org/apache/batik/gvt/event/ sources/org/apache/batik/swing/gvt/ sources/org/apache/b...

Author: deweese
Date: Fri Apr 21 04:00:05 2006
New Revision: 395847

URL: http://svn.apache.org/viewcvs?rev=395847&view=rev
Log:
1) Applied patch from 35683 (Thanks Dieter)
2) Applied patch from 39297 (modified for SVG11 branch) - (Thanks Dieter)
3) Applied suggestion from 39058 (Thanks Chris)
4) Fixed problem with ZoomAndPan handling overriding user disabling of
   Interactors.
5) More sensible handling of source 'URLs' in svgrasterizer.


Modified:
    xmlgraphics/batik/branches/svg11/samples/batikLogo.svg
    xmlgraphics/batik/branches/svg11/sources/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java
    xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/image/rendered/IndexImage.java
    xmlgraphics/batik/branches/svg11/sources/org/apache/batik/gvt/event/AWTEventDispatcher.java
    xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/gvt/TextSelectionManager.java
    xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/svg/JSVGComponent.java
    xmlgraphics/batik/branches/svg11/sources/org/apache/batik/transcoder/print/PrintTranscoder.java

Modified: xmlgraphics/batik/branches/svg11/samples/batikLogo.svg
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/samples/batikLogo.svg?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/samples/batikLogo.svg (original)
+++ xmlgraphics/batik/branches/svg11/samples/batikLogo.svg Fri Apr 21 04:00:05 2006
@@ -28,9 +28,18 @@
 <!-- @version $Id$    -->
 <!-- ====================================================================== -->
 
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500"
+    onload="load()">
     <title>Batik Logo</title>
     <g id="content">
+    <script type="text/ecmascript"><![CDATA[
+        function load() {
+            var e = document.getElementById("Batik_Logo_Underline2");
+            System.err.println("Elem: " + e);
+            e.setAttributeNS(null, "style", 
+                             "fill:url(file:///C:/de.svg#MyGradient)");
+        }
+    ]]></script>
         <defs>
             <symbol id="Batik_Squiggle" stroke="none" viewBox="0 0 540 570">
                 <path id="Batik_Squiggle_Blue" fill="#6666FF"
@@ -137,7 +146,7 @@
                <hkern g1="ti" g2="k"  k="6"/>
           </font>
 
-          <g id="Batik_Logo_Underline" transform="scale(.75,.75)" >
+          <g id="Batik_Logo_Underline" transform="scale(.75,.75)">
              <path d="M37.886,60c-0.018,0.1-0.377,1.375-0.439,1.492c-0.15,0.285-1.382,2.046-1.598,2.291c0.206-0.233,0.428-0.452,0.65-0.67c-6.851,6.751-0.262,0.713,0.893-0.499c1.893-1.986-2.124,1.712,0.112-0.08
                               c0.604-0.484,1.242-0.925,1.886-1.355c-2.574,1.719,0.458-0.228,1.417-0.868c-2.634,1.761-1.231,0.788-0.605,0.423c1.799-1.049,3.686-1.946,5.591-2.783c0.978-0.43,1.97-0.828,2.964-1.217c1.844-0.723-1.918,0.683-0.003,0.012
                               c0.706-0.264,1.412-0.528,2.117-0.792c-1.224,0.456-1.388,0.521-0.491,0.195c2.531-0.908,5.102-1.708,7.683-2.461c5.73-1.672,11.556-3.013,17.401-4.216c30.689-6.315,61.555-8.765,92.723-10.467c35.225-1.924,70.559-2.313,105.819-1.278
@@ -176,6 +185,19 @@
         </defs>
 
         <use x="65" y="233" xlink:href="#Batik_Logo_Shadow" />
+
+
+          <g id="Batik_Logo_Underline2" transform="scale(.75,.75)">
+             <path d="M37.886,60c-0.018,0.1-0.377,1.375-0.439,1.492c-0.15,0.285-1.382,2.046-1.598,2.291c0.206-0.233,0.428-0.452,0.65-0.67c-6.851,6.751-0.262,0.713,0.893-0.499c1.893-1.986-2.124,1.712,0.112-0.08
+                              c0.604-0.484,1.242-0.925,1.886-1.355c-2.574,1.719,0.458-0.228,1.417-0.868c-2.634,1.761-1.231,0.788-0.605,0.423c1.799-1.049,3.686-1.946,5.591-2.783c0.978-0.43,1.97-0.828,2.964-1.217c1.844-0.723-1.918,0.683-0.003,0.012
+                              c0.706-0.264,1.412-0.528,2.117-0.792c-1.224,0.456-1.388,0.521-0.491,0.195c2.531-0.908,5.102-1.708,7.683-2.461c5.73-1.672,11.556-3.013,17.401-4.216c30.689-6.315,61.555-8.765,92.723-10.467c35.225-1.924,70.559-2.313,105.819-1.278
+                              c27.375,0.803,55.137,2.029,82.154,6.813c1.854,0.328,3.702,0.69,5.545,1.079c-2.182-0.459,0.632,0.149,1.102,0.26c0.785,0.185,1.566,0.383,2.347,0.585c2.714,0.705,5.407,1.537,7.987,2.642c0.676-4.98,1.351-9.959,2.026-14.939
+                              c-29.001,20.428-70.184,18.783-104.484,20.881c-37.85,2.314-78.422,7.341-105.371,37.024c-3.142,3.46-5.693,10.35-0.21,12.998c8.018,3.873,16.683,5.137,25.266,7.166c7.149,1.69,13.362,4.381,16.934,11.121c4.934,9.311,2.75,18.519-0.175,28.003
+                              c-3.217,10.428-5.508,20.886-0.692,31.219c4.219,9.05,19.441-3.641,15.823-11.611c-4.234-9.326,1.407-19.828,3.653-28.997c2.667-10.888,1.908-22.401-3.872-32.224c-9.76-16.588-31.066-13.848-46.449-21.271c-0.07,4.333-0.14,8.666-0.21,12.998
+                              c10.537-11.719,25.017-18.668,40.974-22.714c18.159-4.604,37.034-5.719,55.666-6.747c37.146-2.049,77.822-2.405,109.506-24.634c4.136-2.902,8.771-12.048,2.026-14.939c-7.868-3.373-16.687-4.781-25.083-6.132c-12.447-2.004-25.032-3.156-37.6-4.075
+                              c-33.215-2.427-66.599-2.839-99.887-2.247c-34.872,0.621-69.791,2.496-104.432,6.637c-24.317,2.907-50.972,6.112-73.187,17.171c-4.951,2.465-9.505,5.587-13.309,9.623c-1.027,1.089-2.19,2.464-2.986,3.643c0.137-0.203-3.419,6.639-1.518,3.165
+                              c-0.205,0.374-0.38,0.762-0.549,1.151c-1.126,2.59-2.056,5.322-2.196,8.168c-0.222,4.484,4.48,3.091,6.917,1.551c3.856-2.437,7.345-6.516,8.167-11.093z"/>
+          </g> <!-- End Batik_Logo_Underline -->
     </g>
 
     <!-- ============================================================= -->

Modified: xmlgraphics/batik/branches/svg11/sources/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/sources/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java (original)
+++ xmlgraphics/batik/branches/svg11/sources/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java Fri Apr 21 04:00:05 2006
@@ -52,29 +52,40 @@
 
         // Get the path portion
         String path = this.purl.getPath();
-        if (path == null || 
-            !(path.toLowerCase().endsWith(SVG_EXTENSION) ||
-              path.toLowerCase().endsWith(SVGZ_EXTENSION))){
-            throw new SVGConverterException(ERROR_INVALID_URL,
-                                            new Object[]{url});
-        }
-
-        int n = path.lastIndexOf("/");
+        int n = path.lastIndexOf('/');
+        String file = path;
         if (n != -1){
             // The following is safe because we know there is at least ".svg"
             // after the slash.
-            path = path.substring(n+1);
+            file = path.substring(n+1);
+        }
+        if (file.length() == 0) {
+            int idx = path.lastIndexOf('/', n-1);
+            file = path.substring(idx+1, n);
+        }
+        if (file.length() == 0) {
+            throw new SVGConverterException(ERROR_INVALID_URL,
+                                            new Object[]{url});
+        }
+        n = file.indexOf('?');
+        String args = "";
+        if (n != -1) {
+            args = file.substring(n+1);
+            file = file.substring(0, n);
         }
-            
-        name = path;
+
+        name = file;
 
         //
         // The following will force creation of different output file names
         // for urls with references (e.g., anne.svg#svgView(viewBox(0,0,4,5)))
         //
         String ref = this.purl.getRef();
-        if (ref != null && (ref.length()!=0)) {
-            name += "" + ref.hashCode();
+        if ((ref != null) && (ref.length()!=0)) {
+            name += "_" + ref.hashCode();
+        }
+        if ((args != null) && (args.length()!=0)) {
+            name += "_" + args.hashCode();
         }
     }
 

Modified: xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/image/rendered/IndexImage.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/image/rendered/IndexImage.java?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/image/rendered/IndexImage.java (original)
+++ xmlgraphics/batik/branches/svg11/sources/org/apache/batik/ext/awt/image/rendered/IndexImage.java Fri Apr 21 04:00:05 2006
@@ -1,6 +1,6 @@
 /*
 
-   Copyright 2002-2003  The Apache Software Foundation 
+   Copyright 2002-2003,2006  The Apache Software Foundation
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -29,49 +29,94 @@
 import java.awt.image.SampleModel;
 import java.awt.image.WritableRaster;
 import java.util.Iterator;
-import java.util.Vector;
+import java.util.List;
+import java.util.ArrayList;
 
 import org.apache.batik.ext.awt.image.GraphicsUtil;
 
 /**
- * This implements an adaptive pallete generator to reduce images to a
+ * This class implements an adaptive palette generator to reduce images to a
  * specified number of colors.
  *
  * Ideally this would also support a better dither option than just 
  * the JDK's pattern dither.
  *
+ * The algorithm used is the 'Median Cut Algorithm' published by
+ * Paul Heckbert in early '80s.
+ *
  * @author <a href="mailto:deweese@apache.org">Thomas DeWeese</a>
  * @author <a href="mailto:jun@oop-reserch.com">Jun Inamori</a>
- * @version $Id$ */
+ * @version $Id$ 
+ */
+
 public class IndexImage{
 
     /**
      * Used to track a color and the number of pixels of that colors
      */
     private static class Counter {
-        public int val;
-        public int count=1;
-        public Counter(int val) {  this.val = val; }
-        public boolean add(int val) {
+
+        /**
+         * contains the 'packed' rgb-color for this point.
+         * Must not change after construction!
+         */
+        final int val;
+
+        /**
+         * the number of image-pixels with this color.
+         */
+        int count=1;
+
+        Counter(int val) {  this.val = val; }
+
+        boolean add(int val) {
             // See if the value matches us...
             if (this.val != val)
                 return false;
             count++;
             return true;
         }
-    }
+
+        /**
+         * convert the color-point of this counter to an rgb-array.
+         * To avoid creating lots of arrays, the caller passes the
+         * array to store the result.
+         *
+         * @param rgb an int[ 3 ] to store the result.
+         * @return an int-array with rgb-color-values (same as rgb-parameter)
+         */
+        int[] getRgb( int[] rgb ){
+            rgb[ Cube.RED ] = (val&0xFF0000)>>16;
+            rgb[ Cube.GRN ] = (val&0x00FF00)>>8;
+            rgb[ Cube.BLU ] = (val&0x0000FF);
+            return rgb;
+        }
+   }
 
     /**
      * Used to define a cube of the colorspace.  The cube can be split
-     * approximagely in half to generate two cubes.  
+     * approximagely in half to generate two cubes.
      */
     private static class Cube {
-        int []min={0, 0, 0}, max={255,255,255};
+        static final byte[] RGB_BLACK= new byte[]{ 0, 0, 0 };
+
+        int[] min = {0, 0, 0}, max={255,255,255};
 
         boolean done = false;
         
-        Vector []colors = null;
+
+        /**
+         * the colors-array is not modified - in fact, all cubes use
+         * the same colors-array.  The Counter contains the
+         * rgb-color-code and the count of pixels with this color.
+         */
+        final Counter[][] colors;
+
+        /**
+         * the number of color-points in this cube.
+         */
         int count=0;
+
         static final int RED = 0;
         static final int GRN = 1;
         static final int BLU = 2;
@@ -81,7 +126,7 @@
          * @param colors contains the 3D color histogram to be subdivided
          * @param count the total number of pixels in the 3D histogram.
          */
-        public Cube(Vector []colors, int count) {
+        Cube( Counter[][] colors, int count) {
             this.colors = colors;
             this.count = count;
         }
@@ -91,122 +136,193 @@
          * further
          */
         public boolean isDone() { return done; }
+
+        /**
+         * check, if the color defined by val[] is inside this cube.
+         *
+         * @param val int[ 3 ] containing r,g,b-values
+         * @return true when color is inside this cube
+         */
+        private boolean contains( int[] val ){
+
+            int vRed = val[ RED ]; // just save some array-accesses
+            int vGrn = val[ GRN ];
+            int vBlu = val[ BLU ];
+
+            return (
+                ( ( min[ RED ] <= vRed ) && ( vRed <= max[ RED ]))&&
+                ( ( min[ GRN ] <= vGrn ) && ( vGrn <= max[ GRN ]))&&
+                ( ( min[ BLU ] <= vBlu ) && ( vBlu <= max[ BLU ])));
+        }
+
         /**
          * Splits the cube into two parts.  This cube is
          * changed to be one half and the returned cube is the other half.
          * This tries to pick the right channel to split on.
          */
-        public Cube split() {
-            int dr = max[0]-min[0]+1;
-            int dg = max[1]-min[1]+1;
-            int db = max[2]-min[2]+1;
+        Cube split() {
+            int dr = max[ RED ]-min[ RED ]+1;
+            int dg = max[ GRN ]-min[ GRN ]+1;
+            int db = max[ BLU ]-min[ BLU ]+1;
             int c0, c1, splitChannel;
 
             // Figure out which axis is the longest and split along
             // that axis (this tries to keep cubes square-ish).
             if (dr >= dg) {
-                c0 = GRN;
-                if (dr >= db) { splitChannel = RED; c1=BLU; }
-                else          { splitChannel = BLU; c1=RED; }
+                if (dr >= db) { splitChannel = RED; c0=GRN; c1=BLU; }
+                else          { splitChannel = BLU; c0=RED; c1=GRN; }
             } else if (dg >= db) {
                 splitChannel = GRN;
                 c0=RED;
                 c1=BLU;
             } else {
                 splitChannel = BLU;
-                c0=RED;
-                c1=GRN;
+                c0=GRN;
+                c1=RED;
             }
 
+//            System.out.println("Red:" + dr
+//                    + " Grn:" + dg
+//                    + " Blu:" + db
+//                    + " Split:" + splitChannel
+//                    + " c0:" + c0
+//                    + " c1:" + c1 );
+
             Cube ret;
+
+            // try to split the longest axis
             ret = splitChannel(splitChannel, c0, c1);
             if (ret != null ) return ret;
 
+            // try to split along the 2nd longest axis
             ret = splitChannel(c0, splitChannel, c1);
             if (ret != null ) return ret;
 
+            // only one left
             ret = splitChannel(c1, splitChannel, c0);
             if (ret != null) return ret;
-            
+
+            // so far, no split was possible trying all 3 colors: this
+            // cube can't be split further
             done = true;
             return null;
         }
 
         /**
+         * Adjust (normalize) min/max of this cube so that they span
+         * the actual content.  This method is called on the two cubes
+         * resulting from a split.  <br> We search the counts[] from
+         * min to max for the leftmost non-null entry.  That is the
+         * new min.  Then we search counts[] from max to min for the
+         * rightmost non-null entry.  That is the new max.  <br>This
+         * requires, that {@link #computeCounts } really computes
+         * <i>all</i> counts-values (and does not stop after the
+         * necessary number of points for a split is found, as it was
+         * done in the previous version of this class).
+         *
+         * @param splitChannel the color used for the last split
+         * @param counts contains the number of points along the splitChannel
+         *        - only counts[ min .. max ] is valid.
+         */
+        private void normalize( int splitChannel, int[] counts ){
+
+            if ( count == 0 ){
+                // empty cube: nothing to normalize
+                return;
+            }
+
+            int iMin = min[ splitChannel ];
+            int iMax = max[ splitChannel ];
+            int loBound = -1;
+            int hiBound = -1;
+
+            // we search from left to right for the first non-null
+            // entry in counts[]
+            for( int i = iMin; i <= iMax; i++ ){
+                if ( counts[ i ] == 0 ){
+                    // this entry is 0: search more
+                    continue;
+                }
+
+                // we reached a non-null entry: stop looking further
+                loBound = i;
+                break;
+            }
+
+            // we search from right to left for the first non-null
+            // entry in counts[]
+            for( int i= iMax; i >= iMin; i-- ){
+                if ( counts[ i ] == 0 ){
+                    // this entry is 0: search more
+                    continue;
+                }
+                // we reached a non-null entry: stop looking further
+                hiBound = i;
+                break;
+            }
+
+            boolean flagChangedLo = (loBound != -1 ) && ( iMin != loBound );
+            boolean flagChangedHi = (hiBound != -1 ) && ( iMax != hiBound );
+//            if ( flagChangedLo || flagChangedHi ){
+//                System.out.println("old min:" + min[ splitChannel ] + "/max:" + max[ splitChannel ]
+//                + " new: " + loBound + "/" + hiBound );
+//                StringBuffer buff = new StringBuffer( 100 );
+//                for( int i= min[ splitChannel ]; i <= max[ splitChannel]; i++ ){
+//                    buff.append( counts[ i ] );
+//                    buff.append( ',' );
+//                }
+//                System.out.println("Counts:" + buff );
+//            }
+
+            if ( flagChangedLo ){
+                min[ splitChannel ]= loBound;
+            }
+            if ( flagChangedHi ){
+                max[ splitChannel ]= hiBound;
+            }
+        }
+
+
+        /**
          * Splits the image according to the parameters.  It tries
          * to find a location where half the pixels are on one side
          * and half the pixels are on the other.
          */
-        public Cube splitChannel(int splitChannel, int c0, int c1) {
-            if (min[splitChannel] == max[splitChannel]) return null;
-            
-            int splitSh4 = (2-splitChannel)*4;
-            int c0Sh4    = (2-c0)*4;
-            int c1Sh4    = (2-c1)*4;
+        Cube splitChannel(int splitChannel, int c0, int c1) {
+
+            if (min[splitChannel] == max[splitChannel]) {
+                // thickness along the splitChannel is only one point: cannot split
+                return null;
+            }
+
+            if ( count == 0 ){
+                // this Cube has no points: cannot split
+                return null;
+            }
+
+            // System.out.println( toString() );
 
             int half = count/2;
             // Each entry is the number of pixels that have that value
             // in the split channel within the cube (so pixels
             // that have that value in the split channel aren't counted
             // if they are outside the cube in the other color channels.
-            int counts [] = new int[256];
-            int tcount = 0;
-
-            // System.out.println("Cube: [" + 
-            //                    min[0] + "-" + max[0] + "] [" +
-            //                    min[1] + "-" + max[1] + "] [" +
-            //                    min[2] + "-" + max[2] + "]");
+            int[] counts = computeCounts( splitChannel, c0, c1 );
 
-            int [] minIdx = {min[0]>>4, min[1]>>4, min[2]>>4};
-            int [] maxIdx = {max[0]>>4, max[1]>>4, max[2]>>4};
-            int minR=min[0], minG=min[1], minB=min[2];
-            int maxR=max[0], maxG=max[1], maxB=max[2];
-            int val = 0;
-            int [] vals = {0, 0, 0};
-            for (int i=minIdx[splitChannel]; i<=maxIdx[splitChannel]; i++) {
-                int idx1 = i<<splitSh4;
-                for (int j=minIdx[c0]; j<=maxIdx[c0]; j++) {
-                    int idx2 = idx1 | (j<<c0Sh4);
-                    for (int k=minIdx[c1]; k<=maxIdx[c1]; k++) {
-                        int idx = idx2 | (k<<c1Sh4);
-                        Vector v = colors[idx];
-                        if (v==null) continue;
-                        Iterator itr = v.iterator();
-                        Counter c;
-                        while (itr.hasNext()) {
-                            c = (Counter)itr.next();
-                            val = c.val;
-                            vals[0] = (val&0xFF0000)>>16;
-                            vals[1] = (val&0xFF00)>>8;
-                            vals[2] = (val&0xFF);
-                            if (((vals[0] >= minR) && (vals[0] <= maxR))&&
-                                ((vals[1] >= minG) && (vals[1] <= maxG))&&
-                                ((vals[2] >= minB) && (vals[2] <= maxB))) {
-                                // The val lies within this cube so count it.
-                                counts[vals[splitChannel]] += c.count;
-                                tcount += c.count;
-                            }
-                        }
-                    }
-                }
-                // We've found the half way point.  Note that the
-                // rest of counts is not filled out.
-                if (tcount >= half) break;
-            }
-
-            tcount=0;
+            int tcount=0;
             int lastAdd=-1;
             // These indicate what the top value for the low cube and
             // the low value of the high cube should be in the split channel
             // (they may not be one off if there are 'dead' spots in the
             // counts array.
-            int splitLo=min[splitChannel], splitHi=max[splitChannel];
+            int splitLo=min[splitChannel];
+            int splitHi=max[splitChannel];
             for (int i=min[splitChannel]; i<=max[splitChannel]; i++) {
                 int c = counts[i];
                 if (c == 0) {
                     // No counts below this so move up bottom of cube.
                     if ((tcount == 0) && (i < max[splitChannel]))
-                        this.min[splitChannel] = i+1;
+                        min[splitChannel] = i+1;
                     continue;
                 }
 
@@ -219,24 +335,25 @@
                     // Then lastAdd is a better top idx for this then i.
                     if (lastAdd == -1) {
                         // No lower place to break.
-                        if (c == this.count) {
+                        if (c == count) {
                             // All pixels are at this value so make min/max
                             // reflect that.
-                            this.max[splitChannel] = i;
+                            max[splitChannel] = i;
                             return null; // no split to make.
                         } else {
                             // There are values about this one so
                             // split above.
                             splitLo = i;
                             splitHi = i+1;
+                            tcount += c;    // fix 35683
                             break;
                         }
                     }
                     splitLo = lastAdd;
                     splitHi = i;
                 } else {
-                    if (i == this.max[splitChannel]) {
-                        if ( c == this.count) {
+                    if (i == max[splitChannel]) {
+                        if ( c == count) {
                             // would move min up but that should
                             // have happened already.
                             return null; // no split to make.
@@ -256,104 +373,263 @@
                 break;
             }
 
-            // System.out.println("Split: " + splitChannel + "@" 
-            //                    + splitLo + "-"+splitHi + 
+            // System.out.println("Split: " + splitChannel + "@"
+            //                    + splitLo + "-"+splitHi +
             //                    " Count: " + tcount  + " of " + count +
             //                    " LA: " + lastAdd);
 
-            // Create the new cube and update everone's bounds & counts.
+            // Create the new cube and update everyone's bounds & counts.
             Cube ret = new Cube(colors, tcount);
-            this.count = this.count-tcount;
-            ret.min[splitChannel] = this.min[splitChannel];
+            count = count-tcount;
+            ret.min[splitChannel] = min[splitChannel];
             ret.max[splitChannel] = splitLo;
-            this.min[splitChannel] = splitHi;
-            ret.min[c0] = this.min[c0];
-            ret.max[c0] = this.max[c0];
-            ret.min[c1] = this.min[c1];
-            ret.max[c1] = this.max[c1];
+            min[splitChannel] = splitHi;
+
+            // the cube was split along splitChannel, the other
+            // dimensions dont change
+            ret.min[c0] = min[c0];
+            ret.max[c0] = max[c0];
+            ret.min[c1] = min[c1];
+            ret.max[c1] = max[c1];
+
+//            if ( count <= 0 ){
+//                System.out.println("This cube has no points after split:" + toString() );
+//            }
+//            if ( ret.count <= 0 ){
+//                System.out.println("That cube has no points after split:" + ret.toString() + "    this:" + toString() );
+//                System.out.println("SplitLo:"  + splitLo + "  SplitHi:" + splitHi );
+//            }
+
+            // after a split we 'normalize' both cubes, so that their
+            // min/max reflect the actual bounds of the cube.  comment
+            // the next two lines when you want to see the impact of
+            // using non-normalized cubes
+            normalize( splitChannel, counts );
+            ret.normalize( splitChannel, counts );
+
             return ret;
         }
 
         /**
-         * Returns the average color for this cube
+         * create an array, which contains the number of pixels for
+         * each point along the splitChannel (between min and max of
+         * this cube).
+         *
+         * @param splitChannel one of RED | GRN | BLU
+         * @param c0 one of the other channels
+         * @param c1 the third channel
+         * @return an int[ 255 ] where only int[ min .. max ] contain
+         *         valid counts.
+         */
+        private int[] computeCounts( int splitChannel, int c0, int c1) {
+
+            int splitSh4 = (2-splitChannel)*4;
+            int c0Sh4    = (2-c0)*4;
+            int c1Sh4    = (2-c1)*4;
+
+            // after split, each half should have half of the cube's points
+            int half = count/2;
+
+            // Each entry is the number of pixels that have that value
+            // in the split channel within the cube (so pixels
+            // that have that value in the split channel aren't counted
+            // if they are outside the cube in the other color channels.
+            int[] counts = new int[256];
+            int tcount = 0;
+
+            int minR=min[0], minG=min[1], minB=min[2];
+            int maxR=max[0], maxG=max[1], maxB=max[2];
+
+            int[] minIdx = { minR >> 4, minG >> 4, minB >> 4 };
+            int[] maxIdx = { maxR >> 4, maxG >> 4, maxB >> 4 };
+
+            int [] vals = {0, 0, 0};
+            for (int i=minIdx[splitChannel]; i<=maxIdx[splitChannel]; i++) {
+                int idx1 = i<<splitSh4;
+                for (int j=minIdx[c0]; j <=maxIdx[c0]; j++) {
+                    int idx2 = idx1 | (j<<c0Sh4);
+                    for (int k=minIdx[c1]; k<=maxIdx[c1]; k++) {
+                        int idx = idx2 | (k<<c1Sh4);
+                        Counter[] v = colors[idx];
+                        for( int iColor = 0; iColor < v.length; iColor++ ){
+                            Counter c = v[ iColor ];
+                            vals = c.getRgb( vals );
+                            if ( contains( vals )){
+                                // The vals[] lies completly within
+                                // this cube so count it.
+                                counts[ vals[splitChannel] ] += c.count;
+                                tcount += c.count;
+                            }
+                        }
+                    }
+                }
+                // the next statement-line stops the loop after we
+                // found the split-point.  however, we continue to
+                // fill the counts[] because that is needed for
+                // normalization
+//                // We've found the half way point.  Note that the
+//                // rest of counts is not filled out.
+//                if (( tcount > 0 ) && (tcount >= half)) break;  // fix 35683
+            }
+
+            // the result so far is the filled counts[]
+            return counts;
+        }
+
+
+        /**
+         * convert the cube-content to String-representation for logging.
+         * @return the min/max-boundarys of the rgb-channels and
+         *         pixel-count of this Cube.
+         */
+        public String toString() {
+            return "Cube: [" +
+                    min[ RED ] + '-' + max[ RED ] + "] [" +
+                    min[ GRN ] + '-' + max[ GRN ] + "] [" +
+                    min[ BLU ] + '-' + max[ BLU ] + "] n:" + count;
+        }
+
+
+        /**
+         * Returns the average color for this cube (no alpha).
          */
         public int averageColor() {
-            if (this.count == 0) return 0;
+            if (count == 0) {
+                // cube is empty: return black
+                return 0;
+            }
+
+            byte[] rgb = averageColorRGB( null );
+
+            return (( rgb[ RED ] << 16 ) & 0x00FF0000)
+                 | (( rgb[ GRN ] <<  8 ) & 0x0000FF00)
+                 | (( rgb[ BLU ]       ) & 0x000000FF);
+        }
+
+        /**
+         * Returns the average color for this cube
+         */
+        public byte[] averageColorRGB( byte[] rgb ) {
+
+            if (count == 0) return RGB_BLACK;
 
             float red=0, grn=0, blu=0;
 
+            // the boundarys of this cube
             int minR=min[0], minG=min[1], minB=min[2];
             int maxR=max[0], maxG=max[1], maxB=max[2];
             int [] minIdx = {minR>>4, minG>>4, minB>>4};
             int [] maxIdx = {maxR>>4, maxG>>4, maxB>>4};
-            int val, ired, igrn, iblu;
-            float weight;
+            int[] vals = new int[3];
+
             for (int i=minIdx[0]; i<=maxIdx[0]; i++) {
                 int idx1 = i<<8;
                 for (int j=minIdx[1]; j<=maxIdx[1]; j++) {
                     int idx2 = idx1 | (j<<4);
                     for (int k=minIdx[2]; k<=maxIdx[2]; k++) {
                         int idx = idx2 | k;
-                        Vector v = colors[idx];
-                        if (v==null) continue;
-                        Iterator itr = v.iterator();
-                        Counter c;
-                        while (itr.hasNext()) {
-                            c = (Counter)itr.next();
-                            val = c.val;
-                            ired = (val&0xFF0000)>>16;
-                            igrn = (val&0x00FF00)>>8;
-                            iblu = (val&0x0000FF);
-                            if (((ired >= minR) && (ired <= maxR))&&
-                                ((igrn >= minG) && (igrn <= maxG))&&
-                                ((iblu >= minB) && (iblu <= maxB))) {
-                                weight = (c.count/(float)this.count);
-                                red += (ired*weight);
-                                grn += (igrn*weight);
-                                blu += (iblu*weight);
+                        Counter[] v = colors[idx];
+                        for( int iColor = 0; iColor < v.length; iColor++ ){
+                            Counter c = v[ iColor ];
+                            vals = c.getRgb( vals );
+                            if ( contains( vals ) ) {
+                                float weight = (c.count/(float)count);
+                                red += (vals[0]*weight);
+                                grn += (vals[1]*weight);
+                                blu += (vals[2]*weight);
                             }
                         }
                     }
                 }
             }
-            // System.out.println("RGB: [" + red + ", " + 
-            //                    grn + ", " + blu + "]");
-            return (((int)(red+0.5))<<16 |
-                    ((int)(grn+0.5))<<8  | 
-                    ((int)(blu+0.5)));
+            byte[] result = (rgb == null) ? new byte[3] : rgb;
+            result[ RED ] = (byte)(red + 0.5f);
+            result[ GRN ] = (byte)(grn + 0.5f);
+            result[ BLU ] = (byte)(blu + 0.5f);
+
+            return result;
         }
+
     }
 
     /**
-     * Converts the input image (must be TYPE_INT_RGB or
-     * TYPE_INT_ARGB) to an indexed image.  Generating an adaptive
-     * palette with number of colors specified.
-     * @param bi the image to be processed.
-     * @param nColors number of colors in the palette
+     * create an array of rgb-colors from the cubes-array.
+     * The color of each cube is computed as the sum of all colors in the cube,
+     * where each pixel is weighted according to it's count.
+     *
+     * @param nCubes number of entries to use in cubes
+     * @param cubes contains the Cubes resulting from running the split-algorithm.
+     * @return a byte[][] which is arranged as [ r|g|b ][ 0..nCubes-1 ]
      */
-    static public BufferedImage getIndexedImage
-        (BufferedImage bi, int nColors) {
-        int w=bi.getWidth();
-        int h=bi.getHeight();
+    static byte[][] computeRGB( int nCubes, Cube[] cubes ){
+
+        byte[] r = new byte[nCubes];
+        byte[] g = new byte[nCubes];
+        byte[] b = new byte[nCubes];
+
+        byte[] rgb = new byte[3];
+        for (int i=0; i<nCubes; i++) {
+            rgb = cubes[i].averageColorRGB( rgb );
+            r[i] = rgb[ Cube.RED ];
+            g[i] = rgb[ Cube.GRN ];
+            b[i] = rgb[ Cube.BLU ];
+        }
+
+        byte[][] result = new byte[3][];
+        result[ Cube.RED ] = r;
+        result[ Cube.GRN ] = g;
+        result[ Cube.BLU ] = b;
+
+//        logRGB( r, g, b );
+
+        return result;
+    }
+
+    /**
+     * helper-method to print the complete rgb-arrays.
+     * @param r
+     * @param g
+     * @param b
+     */
+    static void logRGB( byte[] r, byte[] g, byte[] b ){
+
+        StringBuffer buff = new StringBuffer( 100 );
+        int nColors = r.length;
+        for( int i= 0; i < nColors; i++ ) {
+            String rgbStr= "(" + (r[i]+128) + ',' + (g[i] +128 ) + ',' + (b[i] + 128) + ")," ;
+            buff.append( rgbStr );
+        }
+        System.out.println("RGB:" + nColors + buff );
+    }
+
+
+    /**
+     * step 1: fill a data-structure with the count of each color in the image.
+     * @param bi input-image
+     * @return a List[] where each slot is a List of Counters (or null)
+     */
+    static List[] createColorList( BufferedImage bi ){
+
+        int w= bi.getWidth();
+        int h= bi.getHeight();
 
         // Using 4 bits from RG & B.
-        Vector [] colors = new Vector[1<<12]; 
+        List[] colors = new ArrayList[1<<12];
 
-        int rgb=0;
         for(int i_w=0; i_w<w; i_w++){
             for(int i_h=0; i_h<h; i_h++){
-                rgb=(bi.getRGB(i_w,i_h) & 0xFFFFFF);
+                int rgb=(bi.getRGB(i_w,i_h) & 0x00FFFFFF);  // mask away alpha
                 // Get index from high four bits of each component.
                 int idx = (((rgb&0xF00000)>>> 12) |
                            ((rgb&0x00F000)>>>  8) |
                            ((rgb&0x0000F0)>>>  4));
 
-                    // Get the 'hash vector' for that key.
-                Vector v = colors[idx];
+                // Get the 'hash vector' for that key.
+                List v = colors[idx];
                 if (v == null) {
-                    // No colors in this bin yet so create vector and
+                    // No colors in this bin yet so create list and
                     // add color.
-                    v = new Vector();
+                    v = new ArrayList();
                     v.add(new Counter(rgb));
                     colors[idx] = v;
                 } else {
@@ -372,27 +648,92 @@
             }
         }
 
+        return colors;
+    }
+
+
+    /**
+     * step 2: convert the result of step 1 to an Cube[][] which is
+     * more efficient in the following iterations. All slots in the
+     * result are filled with at least an empty array - thus we avoid
+     * tests for null.  <br>Note: the converted slots in colors are no
+     * longer needed and removed.
+     *
+     * @param colors the data-structure to convert. Note that it is
+     * empty after conversion!
+     * @return same data as in colors, but Lists are converted to arrays.
+     */
+    static Counter[][] convertColorList( List[] colors ){
+
+        // used to fill empty slots
+        final Counter[] EMPTY_COUNTER = new Counter[0];
+
+        Counter[][] colorTbl= new Counter[ 1<< 12 ][];
+        for( int i= 0; i < colors.length; i++ ){
+            List cl = colors[ i ];
+            if ( cl == null ){
+                colorTbl[ i ] = EMPTY_COUNTER;
+                continue;
+            }
+            int nSlots = cl.size();
+            colorTbl[i] = (Counter[])cl.toArray( new Counter[ nSlots ] );
+
+            // the colors[ i ] - data is no longer needed: discard
+            colors[ i ] = null;
+        }
+
+        return colorTbl;
+    }
+
+    /**
+     * Converts the input image (must be TYPE_INT_RGB or
+     * TYPE_INT_ARGB) to an indexed image.  Generating an adaptive
+     * palette with number of colors specified.
+     * @param bi the image to be processed.
+     * @param nColors number of colors in the palette
+     */
+    public static BufferedImage getIndexedImage( BufferedImage bi, int nColors) {
+        int w=bi.getWidth();
+        int h=bi.getHeight();
+
+        // Using 4 bits from RG & B.
+        List[] colors = createColorList( bi );
+
+        // now we have initialized the colors[] with lists of Counters.
+        // from now on, this data-structure is just read, not modified.
+        // convert it to Counter[][] for faster iteration
+        Counter[][] colorTbl = convertColorList( colors );
+
+        // this is no longer needed: discard
+        colors = null;
+
         int nCubes=1;
         int fCube=0;
         Cube [] cubes = new Cube[nColors];
-        cubes[0] = new Cube(colors, w*h);
-        
+        cubes[0] = new Cube(colorTbl, w*h);
+
         while (nCubes < nColors) {
             while (cubes[fCube].isDone()) {
                 fCube++;
                 if (fCube == nCubes) break;
             }
-            if (fCube == nCubes) break;
+            if (fCube == nCubes) {
+                // System.out.println("fCube == nCubes" + fCube );
+                break;
+            }
             Cube c = cubes[fCube];
             Cube nc = c.split();
             if (nc != null) {
+                // store the cube with less points towards the end of
+                // the array, so that fat cubes get more splits
                 if (nc.count > c.count) {
+                    // new cube has more points: swap
                     Cube tmp = c; c= nc; nc = tmp;
                 }
                 int j = fCube;
                 int cnt = c.count;
                 for (int i=fCube+1; i<nCubes; i++) {
-                    if (cubes[i].count < cnt) 
+                    if (cubes[i].count < cnt)
                         break;
                     cubes[j++] = cubes[i];
                 }
@@ -400,7 +741,7 @@
 
                 cnt = nc.count;
                 while (j<nCubes) {
-                    if (cubes[j].count < cnt) 
+                    if (cubes[j].count < cnt)
                         break;
                     j++;
                 }
@@ -411,28 +752,16 @@
             }
         }
 
-        byte [] r = new byte[nCubes];
-        byte [] g = new byte[nCubes]; 
-        byte [] b = new byte[nCubes]; 
-        for (int i=0; i<nCubes; i++) {
-            int val = cubes[i].averageColor();
-            r[i] = (byte)((val>>16)&0xFF);
-            g[i] = (byte)((val>> 8)&0xFF);
-            b[i] = (byte)((val    )&0xFF);
-
-            // System.out.println("Color [" + i + "]: #" + 
-            //                    (((val>>16)<16)?"0":"") +
-            //                    Integer.toHexString(val));
-        }
-        BufferedImage indexed;
-
+        // convert the remaining cubes to the colors they represent
+        byte[][] rgbTbl = computeRGB( nCubes, cubes );
 
         // The JDK doesn't seem to dither the image correctly if I go
-        // below 8bits per pixel.  So I dither to an 8bit pallete
+        // below 8bits per pixel.  So I dither to an 8bit palette
         // image that only has nCubes colors.  Then I copy the data to
         // a lower bit depth image that I return.
-        IndexColorModel icm=new IndexColorModel(8,nCubes,r,g,b);
-        indexed =new BufferedImage
+        IndexColorModel icm= new IndexColorModel( 8, nCubes, rgbTbl[0], rgbTbl[1], rgbTbl[2] );
+
+        BufferedImage indexed =new BufferedImage
             (w, h, BufferedImage.TYPE_BYTE_INDEXED, icm);
         Graphics2D g2d=indexed.createGraphics();
         g2d.setRenderingHint
@@ -446,24 +775,24 @@
         for (bits=1; bits <=8; bits++) {
             if ((1<<bits) >= nCubes) break;
         }
-        // System.out.println("Bits: " + bits + " Cubes: " + nCubes);
+//        System.out.println("Bits: " + bits + " Cubes: " + nCubes);
 
-        if (bits > 4)
+        if (bits > 4) {
             // 8 bit image we are done...
             return indexed;
+        }
 
         // Create our low bit depth image...
         if (bits ==3) bits = 4;
-        ColorModel cm=new IndexColorModel(bits,nCubes,r,g,b);
-        SampleModel sm = new MultiPixelPackedSampleModel
-            (DataBuffer.TYPE_BYTE, w, h, bits);
-        WritableRaster ras = Raster.createWritableRaster
-            (sm, new Point(0,0));
+        ColorModel cm = new IndexColorModel(bits,nCubes, 
+                                            rgbTbl[0], rgbTbl[1], rgbTbl[2] );
+        SampleModel sm;
+        sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, bits);
+        WritableRaster ras = Raster.createWritableRaster( sm, new Point(0,0));
 
         // Copy the data to the low bitdepth image.
         bi = indexed;
-        indexed = new BufferedImage(cm, ras, 
-                                    bi.isAlphaPremultiplied(), null);
+        indexed = new BufferedImage(cm, ras, bi.isAlphaPremultiplied(), null);
         GraphicsUtil.copyData(bi, indexed);
         return indexed;
     }

Modified: xmlgraphics/batik/branches/svg11/sources/org/apache/batik/gvt/event/AWTEventDispatcher.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/gvt/event/AWTEventDispatcher.java?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/sources/org/apache/batik/gvt/event/AWTEventDispatcher.java (original)
+++ xmlgraphics/batik/branches/svg11/sources/org/apache/batik/gvt/event/AWTEventDispatcher.java Fri Apr 21 04:00:05 2006
@@ -1,6 +1,6 @@
 /*
 
-   Copyright 2001-2003  The Apache Software Foundation 
+   Copyright 2001-2003  The Apache Software Foundation
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -135,7 +135,7 @@
             ((baseTransform == null) || (!baseTransform.equals(t))))
             // new Display transform so events are not where user
             // thinks they were.
-            eventQueue.clear(); 
+            eventQueue.clear();
         baseTransform = t;
     }
 
@@ -297,6 +297,10 @@
      * @param listenerType the type of the listeners to return
      */
     public EventListener [] getListeners(Class listenerType) {
+
+        // TODO the listeners should be cached per class in a map.
+        // this list is build again and again in mouse-event-handling...
+        // note: the cache must be flushed when the gListeners is modified
         Object array =
             Array.newInstance(listenerType,
                               glisteners.getListenerCount(listenerType));
@@ -327,6 +331,7 @@
     public void setEventQueueMaxSize(int n) {
         eventQueueMaxSize = n;
         if (n == 0) eventQueue.clear();
+        // the current size is larger than the new size: shrink
         while(eventQueue.size() > eventQueueMaxSize)
             eventQueue.remove(0);
     }
@@ -344,7 +349,7 @@
                 while (eventQueue.size() > eventQueueMaxSize)
                     // Limit how many events we queue - don't want
                     // user waiting forever for them to clear.
-                    eventQueue.remove(0); 
+                    eventQueue.remove(0);
             }
             return;
         }
@@ -392,7 +397,7 @@
         }
 
         GraphicsNode node = root.nodeHitAt(gnp);
-        
+
         // If the receiving node has changed, send a notification
         // check if we enter a new node
         Point screenPos;
@@ -429,8 +434,7 @@
                                                     MouseEvent.
                                                     MOUSE_ENTERED,
                                                     evt.getWhen(),
-                                                    evt.
-                                                    getModifiers(),
+                                                    evt.getModifiers(),
                                                     (float)gnp.getX(),
                                                     (float)gnp.getY(),
                                                     (int)Math.floor(p.getX()),
@@ -528,7 +532,8 @@
                 }
                 break;
             default:
-                throw new Error("Unknown Mouse Event type: "+evt.getID());
+                throw new IllegalArgumentException
+                    ("Unknown Mouse Event type: "+evt.getID());
             }
         }
     }
@@ -562,7 +567,8 @@
                 }
                 break;
             default:
-                throw new Error("Unknown Key Event type: "+evt.getID());
+                throw new IllegalArgumentException
+                    ("Unknown Key Event type: "+evt.getID());
             }
         }
         evt.consume();
@@ -571,12 +577,12 @@
 
     private void incrementKeyTarget() {
         // <!> FIXME TODO: Not implemented.
-        throw new Error("Increment not implemented.");
+        throw new UnsupportedOperationException("Increment not implemented.");
     }
 
     private void decrementKeyTarget() {
         // <!> FIXME TODO: Not implemented.
-        throw new Error("Decrement not implemented.");
+        throw new UnsupportedOperationException("Decrement not implemented.");
     }
 
     /**
@@ -611,11 +617,32 @@
      * @param e the input event
      */
     protected boolean isNodeIncrementEvent(InputEvent e) {
-        // TODO: Improve code readability!
-        return ((e.getID() == nodeIncrementEventID) &&
-                ((e instanceof KeyEvent) ?
-                     (((KeyEvent) e).getKeyCode() == nodeIncrementEventCode) : true) &&
-                ((e.getModifiers() & nodeIncrementEventModifiers) != 0));
+        // DONE: Improve code readability!
+        //        return ((e.getID() == nodeIncrementEventID) &&
+        //                ((e instanceof KeyEvent) ?
+        //                     (((KeyEvent) e).getKeyCode() == nodeIncrementEventCode) : true) &&
+        //                ((e.getModifiers() & nodeIncrementEventModifiers) != 0));
+
+        if ( e.getID() != nodeIncrementEventID ){
+            // not an incrementEvent: false
+            return false;
+        }
+
+        if (( e instanceof KeyEvent ) ){
+            if (( (KeyEvent) e).getKeyCode() != nodeIncrementEventCode ){
+                // it was a KeyEvent, but not a nodeIncrementEventCode : false
+                return false;
+            }
+        }
+        // here: it was not a KeyEvent at all OR a KeyEvent with
+        // nodeIncrementEventCode
+        if (( e.getModifiers() & nodeIncrementEventModifiers ) == 0 ) {
+            // no nodeIncrementEventModifiers were set: false
+            return false;
+        }
+
+        // this is the only path to success...
+        return true;
     }
 
     /**
@@ -623,11 +650,31 @@
      * false otherwise.
      */
     protected boolean isNodeDecrementEvent(InputEvent e) {
-        // TODO: Improve code readability!
-        return ((e.getID() == nodeDecrementEventID) &&
-                ((e instanceof KeyEvent) ?
-                     ( ((KeyEvent) e).getKeyCode() == nodeDecrementEventCode) : true) &&
-                ((e.getModifiers() & nodeDecrementEventModifiers) != 0  ));
+        // DONE: Improve code readability!   YES !!
+        //        return ((e.getID() == nodeDecrementEventID) &&
+        //                ((e instanceof KeyEvent) ?
+        //                     ( ((KeyEvent) e).getKeyCode() == nodeDecrementEventCode) : true) &&
+        //                ((e.getModifiers() & nodeDecrementEventModifiers) != 0  ));
+
+        if ( e.getID() != nodeDecrementEventID ){
+            // not an nodeDecrementEvent: false
+            return false;
+        }
+
+        if (( e instanceof KeyEvent ) ){
+            if (( (KeyEvent) e).getKeyCode() != nodeDecrementEventCode ){
+                // it was a KeyEvent, but not a nodeDecrementEventCode : false
+                return false;
+            }
+        }
+        // here: it was not a KeyEvent at all OR a KeyEvent with
+        // nodeIncrementEventCode
+        if (( e.getModifiers() & nodeDecrementEventModifiers ) == 0 ) {
+            // no nodeDecrementEventModifiers were set: false
+            return false;
+        }
 
+        // this is the only path to success...
+        return true;
     }
 }

Modified: xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/gvt/TextSelectionManager.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/gvt/TextSelectionManager.java?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/gvt/TextSelectionManager.java (original)
+++ xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/gvt/TextSelectionManager.java Fri Apr 21 04:00:05 2006
@@ -1,18 +1,18 @@
 /*
 
-   Copyright 1999-2003  The Apache Software Foundation 
+Copyright 1999-2003  The Apache Software Foundation 
 
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
 
 */
 
@@ -142,14 +142,14 @@
      * @param color the new color of the selection overlay
      */
     public void setSelectionOverlayColor(Color color) {
-	this.selectionOverlayColor = color;
+        this.selectionOverlayColor = color;
     }
 
     /**
      * Returns the color of the selection overlay.
      */
     public Color getSelectionOverlayColor() {
-	return selectionOverlayColor;
+        return selectionOverlayColor;
     }
 
     /**
@@ -159,14 +159,14 @@
      * @param color the new color of the outline of the selection overlay 
      */
     public void setSelectionOverlayStrokeColor(Color color) {
-	this.selectionOverlayStrokeColor = color;
+        this.selectionOverlayStrokeColor = color;
     }
 
     /**
      * Returns the color of the outline of the selection overlay.
      */
     public Color getSelectionOverlayStrokeColor() {
-	return selectionOverlayStrokeColor;
+        return selectionOverlayStrokeColor;
     }
 
     /**
@@ -176,7 +176,7 @@
      * @param state true implies the selection overlay will be in XOR mode 
      */
     public void setSelectionOverlayXORMode(boolean state) {
-	this.xorMode = state;
+        this.xorMode = state;
     }
 
     /**
@@ -184,7 +184,7 @@
      * otherwise.
      */
     public boolean isSelectionOverlayXORMode() {
-	return xorMode;
+        return xorMode;
     }
 
     /**
@@ -212,7 +212,7 @@
      * Clears the selection.
      */
     public void clearSelection() {
-	textSelector.clearSelection();
+        textSelector.clearSelection();
     }
 
     /**
@@ -338,19 +338,19 @@
                 Shape s = at.createTransformedShape(selectionHighlight);
 
                 Graphics2D g2d = (Graphics2D)g;
-		if (xorMode) {
-		    g2d.setColor(Color.black);
-		    g2d.setXORMode(Color.white);
-		    g2d.fill(s);
-		} else {
-		    g2d.setColor(selectionOverlayColor);
-		    g2d.fill(s);
-		    if (selectionOverlayStrokeColor != null) {
-			g2d.setStroke(new java.awt.BasicStroke(1.0f));
-			g2d.setColor(selectionOverlayStrokeColor);
-			g2d.draw(s);
-		    }
-		}
+                if (xorMode) {
+                    g2d.setColor(Color.black);
+                    g2d.setXORMode(Color.white);
+                    g2d.fill(s);
+                } else {
+                    g2d.setColor(selectionOverlayColor);
+                    g2d.fill(s);
+                    if (selectionOverlayStrokeColor != null) {
+                        g2d.setStroke(new java.awt.BasicStroke(1.0f));
+                        g2d.setColor(selectionOverlayStrokeColor);
+                        g2d.draw(s);
+                    }
+                }
             }
         }
     }

Modified: xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/svg/JSVGComponent.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/svg/JSVGComponent.java?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/svg/JSVGComponent.java (original)
+++ xmlgraphics/batik/branches/svg11/sources/org/apache/batik/swing/svg/JSVGComponent.java Fri Apr 21 04:00:05 2006
@@ -358,6 +358,17 @@
     protected boolean isInteractiveDocument;
 
     /**
+     * Set to true before component calls setDisableInteractors
+     * so it knows that the users isn't the one calling it.
+     */
+    protected boolean selfCallingDisableInteractions = false;
+
+    /**
+     * Set to true if the user ever calls setDisableInteractions
+     */
+    protected boolean userSetDisableInteractions = false;
+
+    /**
      * The document state.
      */
     protected int documentState;
@@ -405,6 +416,42 @@
         setSVGDocument(null);
     }
 
+    public void setDisableInteractions(boolean b) {
+        super.setDisableInteractions(b);
+        if (!selfCallingDisableInteractions)
+            userSetDisableInteractions = true;
+    }
+
+    /**
+     * Clears the boolean that indicates the 'user'
+     * has set disable interactions so that the canvas
+     * uses the value from documents.
+     */
+    public void clearUserSetDisableInteractions() {
+        userSetDisableInteractions = false;
+        updateZoomAndPanEnable(svgDocument);
+    }
+
+    /**
+     * Enables/Disables Zoom And Pan based on the zoom and
+     * pan attribute of the currently installed document,
+     * Unless the user has set the Interactions State.
+     */
+    public void updateZoomAndPanEnable(Document doc) {
+        if (userSetDisableInteractions) return;
+        if (doc == null) return;
+        try {
+            Element root = doc.getDocumentElement();
+            String znp = root.getAttributeNS
+                (null, SVGConstants.SVG_ZOOM_AND_PAN_ATTRIBUTE);
+            boolean enable = SVGConstants.SVG_MAGNIFY_VALUE.equals(znp);
+            selfCallingDisableInteractions = true;
+            setDisableInteractions(!enable);
+        } finally {
+            selfCallingDisableInteractions = false;
+        }
+    }
+
     /**
      * Indicates if the canvas should recenter the content after
      * the canvas is resized.  If true it will try and keep the
@@ -706,11 +753,7 @@
                 bridgeContext.setDynamicState(BridgeContext.INTERACTIVE);
         }
 
-        Element root = doc.getDocumentElement();
-        String znp = root.getAttributeNS
-            (null, SVGConstants.SVG_ZOOM_AND_PAN_ATTRIBUTE);
-
-        setDisableInteractions(!znp.equals(SVGConstants.SVG_MAGNIFY_VALUE));
+        updateZoomAndPanEnable(doc);
 
         nextGVTTreeBuilder = new GVTTreeBuilder(doc, bridgeContext);
         nextGVTTreeBuilder.setPriority(Thread.MIN_PRIORITY);

Modified: xmlgraphics/batik/branches/svg11/sources/org/apache/batik/transcoder/print/PrintTranscoder.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/svg11/sources/org/apache/batik/transcoder/print/PrintTranscoder.java?rev=395847&r1=395846&r2=395847&view=diff
==============================================================================
--- xmlgraphics/batik/branches/svg11/sources/org/apache/batik/transcoder/print/PrintTranscoder.java (original)
+++ xmlgraphics/batik/branches/svg11/sources/org/apache/batik/transcoder/print/PrintTranscoder.java Fri Apr 21 04:00:05 2006
@@ -244,6 +244,10 @@
             pageFormat = tmpPageFormat;
         }
 
+        // Set printable before showing printer dialog so
+        // it can update the pageFormat if it wishes...
+        printerJob.setPrintable(this, pageFormat);
+
         //
         // If required, pop up a dialog to select the printer
         //
@@ -258,7 +262,6 @@
         }
 
         // Print now
-        printerJob.setPrintable(this, pageFormat);
         printerJob.print();
 
     }