1) Fixed some surround bugs in the lighting filters

2) Added an optimized path for Int packed data for Src Over composite.
   I'll be filling in optimized paths for the rest of the composite modes
   shortly.

3) AffineRed now forces it's input and output to be premultiplied.
   In certain cases the Affine would fail to properly unpremultiply
   the alpha channel, this solves this issue.

3a) The patternPaintContext now matches it's ColorModel to the destination
    ColorModel much like MultipleGradientPaint does.

    They both now also match the destination's Alpha premult state.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/batik/trunk@199514 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java b/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java
index 1b114c3..b299b6e 100644
--- a/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java
+++ b/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java
@@ -14,6 +14,8 @@
 import java.awt.image.*;
 import java.lang.ref.WeakReference;
 
+import org.apache.batik.ext.awt.image.GraphicsUtil;
+
 /** This is the superclass for all PaintContexts which use a multiple color
  * gradient to fill in their raster. It provides the actual color interpolation
  * functionality.  Subclasses only have to deal with using the gradient to fill
@@ -27,8 +29,13 @@
 abstract class MultipleGradientPaintContext implements PaintContext {
 
     /**
-     * PaintContext's ColorModel ARGB if colors are not all opaque.
-     * RGB otherwise.
+     * The color model data is generated in (always un premult).
+     */
+    protected ColorModel dataModel;
+    /**
+     * PaintContext's output ColorModel ARGB if colors are not all
+     * opaque, RGB otherwise.  Linear and premult are matched to
+     * output ColorModel.
      */
     protected ColorModel model;
 
@@ -61,7 +68,7 @@
     protected static WeakReference cached;
 
     /** Raster is reused whenever possible */
-    protected Raster saved;
+    protected WritableRaster saved;
 
     /** The method to use when painting out of the gradient bounds. */
     protected MultipleGradientPaint.CycleMethodEnum cycleMethod;
@@ -292,12 +299,15 @@
 
         // Setup an example Model, we may refine it later.
         if (cm.getColorSpace() == lrgbmodel_A.getColorSpace())
-            model = lrgbmodel_A;
+            dataModel = lrgbmodel_A;
         else if (cm.getColorSpace() == srgbmodel_A.getColorSpace())
-            model = srgbmodel_A;
+            dataModel = srgbmodel_A;
         else 
             throw new IllegalArgumentException
                 ("Unsupported ColorSpace for interpolation");
+        
+        model = GraphicsUtil.coerceColorModel(dataModel, 
+                                              cm.isAlphaPremultiplied());
     }
 
 
@@ -357,12 +367,13 @@
             calculateSingleArrayGradient(Imin);
         }
 
-        // Use the most 'economical' model.
+        // Use the most 'economical' model (no alpha).
         if((transparencyTest >>> 24) == 0xff) {
-            if (model.getColorSpace() == lrgbmodel_NA.getColorSpace())
-                model = lrgbmodel_NA;
-            else if (model.getColorSpace() == srgbmodel_NA.getColorSpace())
-                model = srgbmodel_NA;
+            if (dataModel.getColorSpace() == lrgbmodel_NA.getColorSpace())
+                dataModel = lrgbmodel_NA;
+            else if (dataModel.getColorSpace() == srgbmodel_NA.getColorSpace())
+                dataModel = srgbmodel_NA;
+            model = dataModel;
         }
     }
 
@@ -435,7 +446,7 @@
         //if interpolation occurred in Linear RGB space, convert the
         //gradients back to SRGB using the lookup table
         if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
-            if (model.getColorSpace() == 
+            if (dataModel.getColorSpace() == 
                 ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
                 for (int i = 0; i < gradient.length; i++) {
                     gradient[i] = 
@@ -443,7 +454,7 @@
                 }
             }
         } else {
-            if (model.getColorSpace() == 
+            if (dataModel.getColorSpace() == 
                 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) {
                 for (int i = 0; i < gradient.length; i++) {
                     gradient[i] = 
@@ -504,7 +515,7 @@
         //if interpolation occurred in Linear RGB space, convert the
         //gradients back to SRGB using the lookup table
         if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
-            if (model.getColorSpace() == 
+            if (dataModel.getColorSpace() == 
                 ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
                 for (int j = 0; j < gradients.length; j++) {
                     for (int i = 0; i < gradients[j].length; i++) {
@@ -514,7 +525,7 @@
                 }
             }
         } else {
-            if (model.getColorSpace() == 
+            if (dataModel.getColorSpace() == 
                 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) {
                 for (int j = 0; j < gradients.length; j++) {
                     for (int i = 0; i < gradients[j].length; i++) {
@@ -747,10 +758,10 @@
         // If working raster is big enough, reuse it. Otherwise,
         // build a large enough new one.
         //
-        Raster raster = saved;
+        WritableRaster raster = saved;
         if (raster == null || raster.getWidth() < w || raster.getHeight() < h)
             {
-                raster = getCachedRaster(model, w, h);
+                raster = getCachedRaster(dataModel, w, h);
                 saved = raster;
             }
         //
@@ -769,6 +780,10 @@
 
         fillRaster(pixels, off, adjust, x, y, w, h); //delegate to subclass.
 
+        GraphicsUtil.coerceData(raster, dataModel, 
+                                model.isAlphaPremultiplied());
+
+
         return raster;
     }
 
@@ -782,10 +797,11 @@
      * large.
      */
     protected final
-    static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) {
+    static synchronized WritableRaster getCachedRaster
+        (ColorModel cm, int w, int h) {
         if (cm == cachedModel) {
             if (cached != null) {
-                Raster ras = (Raster) cached.get();
+                WritableRaster ras = (WritableRaster) cached.get();
                 if (ras != null &&
                     ras.getWidth() >= w &&
                     ras.getHeight() >= h)
@@ -803,9 +819,10 @@
      * large.
      */
     protected final
-    static synchronized void putCachedRaster(ColorModel cm, Raster ras) {
+    static synchronized void putCachedRaster(ColorModel cm, 
+                                             WritableRaster ras) {
         if (cached != null) {
-            Raster cras = (Raster) cached.get();
+            WritableRaster cras = (WritableRaster) cached.get();
             if (cras != null) {
                 int cw = cras.getWidth();
                 int ch = cras.getHeight();
diff --git a/sources/org/apache/batik/ext/awt/image/renderable/BumpMap.java b/sources/org/apache/batik/ext/awt/image/renderable/BumpMap.java
index f33c37e..2bb8c93 100644
--- a/sources/org/apache/batik/ext/awt/image/renderable/BumpMap.java
+++ b/sources/org/apache/batik/ext/awt/image/renderable/BumpMap.java
@@ -129,12 +129,8 @@
         if(h <= 0)
             return N;
 
-        int xEnd = srcRect.x+srcRect.width-1;
-        if (xEnd > x+w) xEnd = x+w;
-
-        int yEnd = srcRect.y+srcRect.height-1;
-        if (yEnd > y+h) yEnd = y+h;
-
+        final int xEnd   = Math.min(srcRect.x+srcRect.width -1, x+w);
+        final int yEnd   = Math.min(srcRect.y+srcRect.height-1, y+h);
         final int offset = 
             (db.getOffset() +
              sppsm.getOffset(srcRect.x -r.getSampleModelTranslateX(), 
@@ -147,7 +143,7 @@
 
         // Top edge extend filters...
         if (yloc == srcRect.y) {
-            double [][] NRow = N[yloc-y];
+            final double [][] NRow = N[yloc-y];
             int p  = offset + scanStride*(yloc-srcRect.y);
             int xloc=x;
             if (xloc < srcRect.x)
@@ -161,7 +157,7 @@
                 crpc = (pixels[p - 1] >>> 24)*pixelScale;
                 nrpc = (pixels[p + scanStrideMM] >>> 24)*pixelScale;
             }
-            else {
+            else if (xloc < xEnd) {
                 // Top left pixel, in src (0, 0);
                 crnc = (pixels[p+1] >>> 24)*pixelScale;
                 nrnc = (pixels[p + scanStridePP] >>> 24)*pixelScale;
@@ -229,7 +225,7 @@
         }
 
         for (; yloc<yEnd; yloc++) {
-            double [][] NRow = N[yloc-y];
+            final double [][] NRow = N[yloc-y];
             int p  = offset + scanStride*(yloc-srcRect.y);
 
             int xloc=x;
@@ -247,7 +243,7 @@
                 crpc = (pixels[p - 1] >>> 24)*pixelScale;
                 nrpc = (pixels[p + scanStrideMM] >>> 24)*pixelScale;
             }
-            else {
+            else if (xloc < xEnd) {
                 // Now, process left column, from (0, 1) to (0, h-1)
                 crnc = (pixels[p+1] >>> 24)*pixelScale;
                 prnc = (pixels[p - scanStrideMM] >>> 24)*pixelScale;
@@ -310,8 +306,8 @@
                 // Now, proces right column, from (w-1, 1) to (w-1, h-1)
                 final double [] n = NRow[xloc-x];
 
-                n[0] = - halfSurfaceScaleX *(( prcc + 2*crcc + nrcc)
-                                             - (prpc + 2*crpc + nrpc));
+                n[0] = - halfSurfaceScaleX *( (prcc + 2*crcc + nrcc)
+                                             -(prpc + 2*crpc + nrpc));
                 n[1] = - thirdSurfaceScaleY *(( nrpc + 2*nrcc)
                                               - ( prpc + 2*prcc));
             
@@ -325,7 +321,7 @@
 
         if ((yloc < y+h) && 
             (yloc == srcRect.y+srcRect.height-1)) {
-            double [][] NRow = N[yloc-y];
+            final double [][] NRow = N[yloc-y];
             int p  = offset + scanStride*(yloc-srcRect.y);
             int xloc=x;
             if (xloc < srcRect.x)
@@ -340,7 +336,7 @@
                 prpc = (pixels[p - scanStridePP] >>> 24)*pixelScale;
                 crpc = (pixels[p - 1] >>> 24)*pixelScale;
             }
-            else {
+            else if (xloc < xEnd) {
                 // Process first pixel of last row
                 crnc = (pixels[p + 1] >>> 24)*pixelScale;
                 prnc = (pixels[p - scanStrideMM] >>> 24)*pixelScale;
@@ -368,6 +364,10 @@
                 crnc = (pixels[p + 1] >>> 24)*pixelScale;
                 prnc = (pixels[p - scanStrideMM] >>> 24)*pixelScale;
 
+                // System.out.println("Vals: " + 
+                //                    prpc + "," + prcc + "," + prnc + "  " +
+                //                    crpc + "," + crcc + "," + crnc );
+                                   
                 final double [] n = NRow[xloc-x];
 
                 n[0] = - thirdSurfaceScaleX *(( 2*crnc + prnc)
diff --git a/sources/org/apache/batik/ext/awt/image/renderable/DiffuseLightingRable8Bit.java b/sources/org/apache/batik/ext/awt/image/renderable/DiffuseLightingRable8Bit.java
index dd4d470..750b3a6 100644
--- a/sources/org/apache/batik/ext/awt/image/renderable/DiffuseLightingRable8Bit.java
+++ b/sources/org/apache/batik/ext/awt/image/renderable/DiffuseLightingRable8Bit.java
@@ -8,21 +8,19 @@
 
 package org.apache.batik.ext.awt.image.renderable;
 
-import java.awt.Color;
-import java.awt.Graphics2D;
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
+import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
 import java.awt.image.RenderedImage;
 import java.awt.image.renderable.RenderContext;
 
-import org.apache.batik.ext.awt.image.rendered.PadRed;
-import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed;
-import org.apache.batik.ext.awt.image.rendered.DiffuseLightingRed;
-import org.apache.batik.ext.awt.image.rendered.CachableRed;
+import org.apache.batik.ext.awt.image.GraphicsUtil;
 import org.apache.batik.ext.awt.image.rendered.AffineRed;
+import org.apache.batik.ext.awt.image.rendered.CachableRed;
+import org.apache.batik.ext.awt.image.rendered.DiffuseLightingRed;
+import org.apache.batik.ext.awt.image.rendered.PadRed;
 
 /**
  * Implementation of the DiffuseLightRable interface.
@@ -145,17 +143,17 @@
     static final boolean SCALE_RESULT=true;
 
     public RenderedImage createRendering(RenderContext rc){
-        Rectangle2D aoi = rc.getAreaOfInterest().getBounds2D();
-        if(aoi == null){
+        Shape aoi = rc.getAreaOfInterest();
+        if (aoi == null)
             aoi = getBounds2D();
-        }
 
-        aoi.intersect(aoi, getBounds2D(), aoi);
+        Rectangle2D aoiR = aoi.getBounds2D();
+        aoiR.intersect(aoiR, getBounds2D(), aoiR);
 
         AffineTransform at = rc.getTransform();
-        Rectangle bounds = at.createTransformedShape(aoi).getBounds();
-
-        if(bounds.width == 0 || bounds.height == 0){
+        Rectangle devRect = at.createTransformedShape(aoiR).getBounds();
+        
+        if(devRect.width == 0 || devRect.height == 0){
             return null;
         }
 
@@ -185,7 +183,7 @@
             // Non invertible transform
             return null;
         }
-        
+
         if (SCALE_RESULT) {
             scaleX = 1;
             scaleY = 1;
@@ -193,30 +191,29 @@
         AffineTransform scale =
             AffineTransform.getScaleInstance(scaleX, scaleY);
 
+        devRect = scale.createTransformedShape(aoiR).getBounds();
+
+        // Grow for surround needs of bump map.
+        aoiR.setRect(aoiR.getX()     -(2/scaleX), 
+                     aoiR.getY()     -(2/scaleY),
+                     aoiR.getWidth() +(4/scaleX), 
+                     aoiR.getHeight()+(4/scaleY));
+
+
         // Build texture from the source
         rc = (RenderContext)rc.clone();
-        rc.setAreaOfInterest(aoi);
+        rc.setAreaOfInterest(aoiR);
         rc.setTransform(scale);
 
         // System.out.println("scaleX / scaleY : " + scaleX + "/" + scaleY);
 
-        RenderingHints rh = rc.getRenderingHints();
-        bounds = scale.createTransformedShape(aoi).getBounds();
+        CachableRed cr;
+        cr = GraphicsUtil.wrap(getSource().createRendering(rc));
 
-        PadRed texture 
-            = new PadRed(RenderedImageCachableRed.wrap(getSource().createRendering(rc)),
-                         bounds,
-                         PadMode.ZERO_PAD,
-                         rh);
+        BumpMap bumpMap = new BumpMap(cr, surfaceScale, scaleX, scaleY);
 
-        BumpMap bumpMap = new BumpMap(texture, surfaceScale, scaleX, scaleY);
-
-        DiffuseLightingRed diffuseRed =
-            new DiffuseLightingRed(kd,
-                                   light,
-                                   bumpMap,
-                                   bounds,
-                                   1/scaleX, 1/scaleY);
+        cr = new DiffuseLightingRed(kd, light, bumpMap,
+                                    devRect, 1/scaleX, 1/scaleY);
 
         // Return sheared/rotated tiled image
         AffineTransform shearAt =
@@ -224,19 +221,17 @@
                                 shx/scaleY, sy/scaleY,
                                 tx, ty);
         
-        if(shearAt.isIdentity()){
-            // System.out.println("Scale only transform");
-            return diffuseRed;
+        if(!shearAt.isIdentity()) {
+            RenderingHints rh = rc.getRenderingHints();
+            Rectangle padRect = new Rectangle(devRect.x-1, devRect.y-1,
+                                              devRect.width+2, 
+                                              devRect.height+2);
+            cr = new PadRed(cr, padRect, PadMode.REPLICATE, rh);
+
+            cr = new AffineRed(cr, shearAt, rh);
         }
        
-        // System.out.println("Transform has translate and/or shear and rotate");
-        CachableRed cr 
-            = new RenderedImageCachableRed(diffuseRed);
-
-        cr = new AffineRed(cr, shearAt, rh);
-
         return cr;
-        
     }
 }
 
diff --git a/sources/org/apache/batik/ext/awt/image/renderable/SVGComposite.java b/sources/org/apache/batik/ext/awt/image/renderable/SVGComposite.java
index 881dc0c..612c1f5 100644
--- a/sources/org/apache/batik/ext/awt/image/renderable/SVGComposite.java
+++ b/sources/org/apache/batik/ext/awt/image/renderable/SVGComposite.java
@@ -19,6 +19,9 @@
 import java.awt.image.WritableRaster;
 import java.awt.image.BufferedImage;
 
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.PackedColorModel;
+import java.awt.image.DataBufferInt;
 
 import org.apache.batik.ext.awt.image.GraphicsUtil;
 
@@ -87,6 +90,25 @@
         return false;
     }
 
+    public boolean is_INT_PACK(ColorModel cm) {
+          // Check ColorModel is of type DirectColorModel
+        if(!(cm instanceof PackedColorModel)) return false;
+
+        PackedColorModel pcm = (PackedColorModel)cm;
+
+        int [] masks = pcm.getMasks();
+
+        // Check transfer type
+        if(masks.length != 4) return false;
+
+        if (masks[0] != 0x00ff0000) return false;
+        if (masks[1] != 0x0000ff00) return false;
+        if (masks[2] != 0x000000ff) return false;
+        if (masks[3] != 0xff000000) return false;
+
+        return true;
+   }
+
     public CompositeContext createContext(ColorModel srcCM,
                                           ColorModel dstCM,
                                           RenderingHints hints) {
@@ -100,9 +122,15 @@
             System.out.println
                 ("sRGB: " + ColorSpace.getInstance(ColorSpace.CS_sRGB));
         }
+
+        boolean use_int_pack = (is_INT_PACK(srcCM) && is_INT_PACK(dstCM));
+
         switch (rule.getRule()) {
         case CompositeRule.RULE_OVER:
-            return new OverCompositeContext(srcCM, dstCM);
+            if (use_int_pack) 
+                return new OverCompositeContext_INT_PACK(srcCM, dstCM);
+            else
+                return new OverCompositeContext(srcCM, dstCM);
 
         case CompositeRule.RULE_IN:
             return new InCompositeContext  (srcCM, dstCM);
@@ -227,16 +255,21 @@
         }
     }
 
-    /*
     public static class OverCompositeContext_INT_PACK 
         extends AlphaPreCompositeContext {
-        OverCompositeContext(ColorModel srcCM, ColorModel dstCM) {
+        OverCompositeContext_INT_PACK(ColorModel srcCM, ColorModel dstCM) {
             super(srcCM, dstCM);
         }
 
         public void precompose(Raster src, Raster dstIn, 
                                WritableRaster dstOut) {
 
+            int x0=dstOut.getMinX();
+            int w =dstOut.getWidth();
+
+            int y0=dstOut.getMinY();
+            int y1=y0 + dstOut.getHeight();
+
             SinglePixelPackedSampleModel srcSPPSM;
             srcSPPSM = (SinglePixelPackedSampleModel)src.getSampleModel();
 
@@ -258,7 +291,7 @@
             final int     dstInBase =
                 (dstInDB.getOffset() +
                  dstInSPPSM.getOffset(x0-dstIn.getSampleModelTranslateX(),
-                                    y0-dstIn.getSampleModelTranslateY()));
+                                      y0-dstIn.getSampleModelTranslateY()));
 
             SinglePixelPackedSampleModel dstOutSPPSM;
             dstOutSPPSM = (SinglePixelPackedSampleModel)dstOut.getSampleModel();
@@ -269,42 +302,45 @@
             final int     dstOutBase =
                 (dstOutDB.getOffset() +
                  dstOutSPPSM.getOffset(x0-dstOut.getSampleModelTranslateX(),
-                                    y0-dstOut.getSampleModelTranslateY()));
-
-            int [] srcPix = null;
-            int [] dstOutPix = null;
-
-            int x=dstOut.getMinX();
-            int w=dstOut.getWidth();
-
-            int y0=dstOut.getMinY();
-            int y1=y0 + dstOut.getHeight();
+                                       y0-dstOut.getSampleModelTranslateY()));
 
             final int norm = (1<<24)/255;
             final int pt5  = (1<<23);
 
-            for (int y = y0; y<y1; y++) {
-                srcPix = src.getPixels  (x, y, w, 1, srcPix);
-                dstPix = dstIn.getPixels(x, y, w, 1, dstPix);
-                int sp  = 0;
-                int end = w*4;
-                while(sp<end) {
-                    final int dstM = (255-srcPix[sp+3])*norm;
-                    dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24);
-                    ++sp;
-                    dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24);
-                    ++sp;
-                    dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24);
-                    ++sp;
-                    dstPix[sp] = srcPix[sp] + ((dstPix[sp]*dstM +pt5)>>>24);
-                    ++sp;
-                }
-                dstOut.setPixels(x, y, w, 1, dstPix);
-            }
+            final int   srcAdjust  =    srcScanStride - w;
+            final int  dstInAdjust =  dstInScanStride - w;
+            final int dstOutAdjust = dstOutScanStride - w;
 
+            int srcSp    = srcBase;
+            int dstInSp  = dstInBase;
+            int dstOutSp = dstOutBase;
+
+            int srcP, dstInP, dstM, a, r, g, b;
+
+            for (int y = y0; y<y1; y++) {
+                final int end = dstOutSp+w;
+                while (dstOutSp<end) {
+                    srcP   = srcPixels  [srcSp++];
+                    dstInP = dstInPixels[dstInSp++];
+                    
+                    dstM = (255-(srcP>>>24))*norm;
+                    a = ((     srcP & 0xFF000000) +
+                         ((((dstInP>>>24)     )*dstM + pt5)     )) &0xFF000000;
+                    r = ((     srcP & 0x00FF0000) +
+                         ((((dstInP>> 16)&0xFF)*dstM + pt5)>>  8)) &0x00FF0000;
+                    g = ((     srcP & 0x0000FF00) +
+                         ((((dstInP>>  8)&0xFF)*dstM + pt5)>> 16)) &0x0000FF00;
+                    b = ((     srcP & 0x000000FF) +
+                         ((((dstInP     )&0xFF)*dstM + pt5)>>>24));
+
+                    dstOutPixels[dstOutSp++] = (a|r|g|b);
+                }
+                srcSp    += srcAdjust;
+                dstInSp  += dstInAdjust;
+                dstOutSp += dstOutAdjust;
+            }
         }
     }
-    /**/
 
     public static class InCompositeContext 
         extends AlphaPreCompositeContext {
diff --git a/sources/org/apache/batik/ext/awt/image/renderable/SpecularLightingRable8Bit.java b/sources/org/apache/batik/ext/awt/image/renderable/SpecularLightingRable8Bit.java
index 9c01525..b5261b9 100644
--- a/sources/org/apache/batik/ext/awt/image/renderable/SpecularLightingRable8Bit.java
+++ b/sources/org/apache/batik/ext/awt/image/renderable/SpecularLightingRable8Bit.java
@@ -8,14 +8,11 @@
 
 package org.apache.batik.ext.awt.image.renderable;
 
-import java.awt.Color;
-import java.awt.Graphics2D;
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
 import java.awt.image.RenderedImage;
 import java.awt.image.renderable.RenderContext;
 
@@ -174,12 +171,9 @@
         Rectangle2D aoiR = aoi.getBounds2D();
         aoiR.intersect(aoiR, getBounds2D(), aoiR);
 
-        aoiR.setRect(aoiR.getX()-1, aoiR.getY()-1,
-                     aoiR.getWidth()+2, aoiR.getHeight()+2);
-
         AffineTransform at = rc.getTransform();
         Rectangle devRect = at.createTransformedShape(aoiR).getBounds();
-
+        
         if(devRect.width == 0 || devRect.height == 0){
             return null;
         }
@@ -218,6 +212,15 @@
         AffineTransform scale =
             AffineTransform.getScaleInstance(scaleX, scaleY);
 
+        devRect = scale.createTransformedShape(aoiR).getBounds();
+
+        // Grow for surround needs.
+        aoiR.setRect(aoiR.getX()     -(2/scaleX), 
+                     aoiR.getY()     -(2/scaleY),
+                     aoiR.getWidth() +(4/scaleX), 
+                     aoiR.getHeight()+(4/scaleY));
+
+
         // Build texture from the source
         rc = (RenderContext)rc.clone();
         rc.setAreaOfInterest(aoiR);
@@ -225,22 +228,13 @@
 
         // System.out.println("scaleX / scaleY : " + scaleX + "/" + scaleY);
 
-        RenderingHints rh = rc.getRenderingHints();
-        devRect = scale.createTransformedShape(aoiR).getBounds();
+        CachableRed cr;
+        cr = GraphicsUtil.wrap(getSource().createRendering(rc));
 
-        CachableRed texture;
-        texture = GraphicsUtil.wrap(getSource().createRendering(rc));
-        texture = new PadRed(texture, devRect, PadMode.ZERO_PAD, rh);
+        BumpMap bumpMap = new BumpMap(cr, surfaceScale, scaleX, scaleY);
 
-        BumpMap bumpMap = new BumpMap(texture, surfaceScale, scaleX, scaleY);
-
-        SpecularLightingRed specularRed =
-            new SpecularLightingRed(ks,
-                                    specularExponent,
-                                    light,
-                                    bumpMap,
-                                    devRect,
-                                    1/scaleX, 1/scaleY);
+        cr = new SpecularLightingRed(ks, specularExponent, light, bumpMap,
+                                    devRect, 1/scaleX, 1/scaleY);
 
         // Return sheared/rotated tiled image
         AffineTransform shearAt =
@@ -248,13 +242,17 @@
                                 shx/scaleY, sy/scaleY,
                                 tx, ty);
 
-        if(shearAt.isIdentity()){
-            // System.out.println("Scale only transform");
-            return specularRed;
+        if(!shearAt.isIdentity()) {
+            RenderingHints rh = rc.getRenderingHints();
+            Rectangle padRect = new Rectangle(devRect.x-1, devRect.y-1,
+                                              devRect.width+2, 
+                                              devRect.height+2);
+            cr = new PadRed(cr, padRect, PadMode.REPLICATE, rh);
+
+            cr = new AffineRed(cr, shearAt, rh);
         }
        
-        // System.out.println("Transform has translate and/or shear and rotate");
-        return new AffineRed(specularRed, shearAt, rh);
+        return cr;
     }
 }
 
diff --git a/sources/org/apache/batik/ext/awt/image/rendered/AffineRed.java b/sources/org/apache/batik/ext/awt/image/rendered/AffineRed.java
index f8a09dc..0a3fd17 100644
--- a/sources/org/apache/batik/ext/awt/image/rendered/AffineRed.java
+++ b/sources/org/apache/batik/ext/awt/image/rendered/AffineRed.java
@@ -71,6 +71,13 @@
         Rectangle myBounds;
         myBounds = src2me.createTransformedShape(src.getBounds()).getBounds();
 
+        // If the output buffer is not premultiplied in certain cases it
+        // fails to properly divide out the Alpha (it always does
+        // the affine on premultiplied data), hence you get ugly
+        // back aliasing effects...
+        ColorModel cm = src.getColorModel();
+        cm = GraphicsUtil.coerceColorModel(cm, true);
+
         // fix my sample model so it makes sense given my size.
         SampleModel sm = fixSampleModel(src, myBounds);
 
@@ -79,7 +86,7 @@
         pt = src2me.transform(pt, null);
         
         // Finish initializing our base class...
-        init(src, myBounds, src.getColorModel(), sm,
+        init(src, myBounds, cm, sm,
              (int)pt.getX(), (int)pt.getY(), null);
     }
 
@@ -161,18 +168,28 @@
 
         BufferedImage srcBI, myBI;
         ColorModel srcCM = src.getColorModel();
-        WritableRaster srcWR = (WritableRaster)srcRas;
-        srcBI = new BufferedImage(srcCM,
-                                  srcWR.createWritableTranslatedChild(0,0),
-                                  srcCM.isAlphaPremultiplied(), null);
-
         ColorModel myCM = getColorModel();
+
+        WritableRaster srcWR = (WritableRaster)srcRas;
+        GraphicsUtil.coerceData(srcWR, srcCM, true);
+        srcBI = new BufferedImage(myCM,
+                                  srcWR.createWritableTranslatedChild(0,0),
+                                  myCM.isAlphaPremultiplied(), null);
+
         myBI = new BufferedImage(myCM,wr.createWritableTranslatedChild(0,0),
                                  myCM.isAlphaPremultiplied(), null);
 
         op.filter(srcBI, myBI);
+
+        // if ((count % 40) == 0) {
+        //     org.apache.batik.ImageDisplay.showImage("Src: " , srcBI);
+        //     org.apache.batik.ImageDisplay.showImage("Dst: " , myBI);
+        // }
+        // count++;
     }
 
+    // int count=0;
+
         /**
          * This function 'fixes' the source's sample model.
          * right now it just ensures that the sample model isn't
diff --git a/sources/org/apache/batik/ext/awt/image/rendered/TileRed.java b/sources/org/apache/batik/ext/awt/image/rendered/TileRed.java
index 8b882f9..d08f524 100644
--- a/sources/org/apache/batik/ext/awt/image/rendered/TileRed.java
+++ b/sources/org/apache/batik/ext/awt/image/rendered/TileRed.java
@@ -118,8 +118,9 @@
         init((CachableRed)null, tiledRegion, cm, sm, 
              tile.getMinX(), tile.getMinY(), null);
 
-        if (raster != null) 
+        if (raster != null) {
             fillRasterFrom(raster, tile);
+        }
         else
             tiles = TileCache.getTileMap(this);
     }
diff --git a/sources/org/apache/batik/gvt/PatternPaintContext.java b/sources/org/apache/batik/gvt/PatternPaintContext.java
index f06b193..ddc5903 100644
--- a/sources/org/apache/batik/gvt/PatternPaintContext.java
+++ b/sources/org/apache/batik/gvt/PatternPaintContext.java
@@ -15,6 +15,7 @@
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
 import java.awt.Shape;
+import java.awt.color.ColorSpace;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.NoninvertibleTransformException;
 import java.awt.geom.Point2D;
@@ -26,9 +27,9 @@
 import java.awt.image.WritableRaster;
 import java.awt.image.renderable.RenderContext;
 
+import org.apache.batik.ext.awt.image.GraphicsUtil;
 import org.apache.batik.ext.awt.image.renderable.Filter;
 import org.apache.batik.ext.awt.image.renderable.TileRable8Bit;
-import org.apache.batik.ext.awt.image.renderable.TileRable;
 
 /**
  * <tt>PaintContext</tt> for the <tt>ConcretePatterPaint</tt>
@@ -70,6 +71,7 @@
                                Rectangle2D     patternRegion,
                                Rectangle2D     userBounds,
                                boolean         overflow) {
+
         if(usr2dev == null){
             throw new IllegalArgumentException();
         }
@@ -86,10 +88,10 @@
         // System.out.println("PatB: " + patternRegion);
         // System.out.println("Tile: " + tile);
 
-        TileRable tileRable = new TileRable8Bit(tile,
-                                                userBounds,
-                                                patternRegion,
-                                                overflow);
+        Filter tileRable = new TileRable8Bit(tile,
+                                             userBounds,
+                                             patternRegion,
+                                             overflow);
 
         RenderContext rc = new RenderContext(usr2dev,  userBounds, hints);
 
@@ -99,14 +101,45 @@
         // org.apache.batik.test.gvt.ImageDisplay.showImage("Tiled: ", tiled);
 
         //System.out.println("Created rendering");
-        if(tiled != null) 
+        if(tiled != null) {
             rasterCM = tiled.getColorModel();
+            ColorSpace destCS = destCM.getColorSpace();
+
+            if (destCS != rasterCM.getColorSpace()) {
+                if (destCS == ColorSpace.getInstance(ColorSpace.CS_sRGB))
+                    tiled = GraphicsUtil.convertTosRGB
+                        (GraphicsUtil.wrap(tiled));
+                else if (destCS == 
+                         ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
+                    tiled = GraphicsUtil.convertToLsRGB
+                        (GraphicsUtil.wrap(tiled));
+            }
+
+            rasterCM = tiled.getColorModel();
+            if (rasterCM.hasAlpha()) {
+                if (destCM.hasAlpha()) {
+                    if (rasterCM.isAlphaPremultiplied() !=
+                        destCM  .isAlphaPremultiplied())
+                        rasterCM = GraphicsUtil.coerceColorModel
+                            (rasterCM, destCM.isAlphaPremultiplied());
+                } else {
+                    rasterCM = GraphicsUtil.coerceColorModel(rasterCM, false);
+                }
+            }
+        }
         else {
             //System.out.println("Tile was null");
             rasterCM = ColorModel.getRGBdefault();
-            WritableRaster wr = rasterCM.createCompatibleWritableRaster(32, 32);
+            WritableRaster wr;
+            wr = rasterCM.createCompatibleWritableRaster(32, 32);
             tiled = new BufferedImage(rasterCM, wr, false, null);
         }
+
+
+        // System.out.println("DestCM  : " + destCM);
+        // System.out.println("RasterCM: " + rasterCM);
+        // Exception e = new Exception("Pattern");
+        // e.printStackTrace();
         
     }
 
@@ -127,9 +160,14 @@
             (raster.getHeight() < height)) {
             raster = rasterCM.createCompatibleWritableRaster(width, height);
         }
+
         WritableRaster wr
             = raster.createWritableChild(0, 0, width, height, x, y, null);
 
-        return tiled.copyData(wr);
+        tiled.copyData(wr);
+        GraphicsUtil.coerceData(wr, tiled.getColorModel(), 
+                                rasterCM.isAlphaPremultiplied());
+
+        return wr;
     }
 }