Index: src/java/org/apache/fop/svg/PDFGraphics2D.java
===================================================================
--- src/java/org/apache/fop/svg/PDFGraphics2D.java	(revision 330229)
+++ src/java/org/apache/fop/svg/PDFGraphics2D.java	(working copy)
@@ -45,6 +45,7 @@
 import org.apache.batik.ext.awt.g2d.GraphicContext;
 import org.apache.batik.ext.awt.RadialGradientPaint;
 import org.apache.batik.ext.awt.LinearGradientPaint;
+import org.apache.batik.ext.awt.MultipleGradientPaint;
 import org.apache.batik.ext.awt.RenderingHintsKeyExt;
 import org.apache.batik.gvt.PatternPaint;
 import org.apache.batik.gvt.GraphicsNode;
@@ -61,17 +62,23 @@
 import java.awt.Shape;
 import java.awt.Stroke;
 import java.awt.Paint;
+import java.awt.PaintContext;
 import java.awt.Rectangle;
+import java.awt.Transparency;
 import java.awt.Dimension;
 import java.awt.BasicStroke;
 import java.awt.AlphaComposite;
 import java.awt.geom.AffineTransform;
+import java.awt.color.ColorSpace;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DirectColorModel;
 import java.awt.image.DataBuffer;
 import java.awt.image.DataBufferInt;
 import java.awt.image.ImageObserver;
 import java.awt.image.RenderedImage;
 import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
 import java.awt.image.renderable.RenderableImage;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
@@ -129,7 +136,7 @@
      * The count of JPEG images added to document so they recieve
      * unique keys.
      */
-    protected int jpegCount = 0;
+    protected int jpegCount[] = {0};
 
     /**
      * The current font information.
@@ -376,12 +383,11 @@
     public void addJpegImage(JpegImage jpeg, float x, float y, 
                              float width, float height) {
         preparePainting();
-        String key = "__AddJPEG_" + jpegCount;
-        jpegCount++;
+        String key = "__AddJPEG_" + jpegCount[0];
+        jpegCount[0]++;
         FopPDFImage fopimage = new FopPDFImage(jpeg, key);
         int xObjectNum = this.pdfDoc.addImage(resourceContext, 
                                               fopimage).getXNumber();
-
         AffineTransform at = getTransform();
         double[] matrix = new double[6];
         at.getMatrix(matrix);
@@ -709,7 +715,18 @@
 
         Paint paint = getPaint();
         if (graphicsState.setPaint(paint)) {
-            applyPaint(paint, false);
+            if (!applyPaint(paint, false)) {
+                // Stroke the shape and use it to 'clip'
+                // the paint contents.
+                Shape ss = getStroke().createStrokedShape(s);
+                applyUnknownPaint(paint, ss);
+
+                if (newClip || newTransform) {
+                    currentStream.write("Q\n");
+                    graphicsState.pop();
+                }
+                return;
+            }
         }
         applyStroke(getStroke());
 
@@ -831,19 +848,28 @@
      * @param paint the paint to convert to PDF
      * @param fill true if the paint should be set for filling
      */
-    protected void applyPaint(Paint paint, boolean fill) {
+    protected boolean applyPaint(Paint paint, boolean fill) {
         preparePainting();
 
+        if (paint instanceof Color) {
+            return true;
+        }
         if (paint instanceof LinearGradientPaint) {
             LinearGradientPaint gp = (LinearGradientPaint)paint;
+
+            // This code currently doesn't support 'repeat'.
+            // For linear gradients it is possible to construct
+            // a 'tile' that is repeated with a PDF pattern, but
+            // it would be very tricky as you would have to rotate
+            // the coordinate system so the repeate was axially
+            // aligned.  At this point I'm just going to rasterize it.
+            MultipleGradientPaint.CycleMethodEnum cycle = gp.getCycleMethod();
+            if (cycle != MultipleGradientPaint.NO_CYCLE)
+                return false;
+
             Color[] cols = gp.getColors();
             float[] fractions = gp.getFractions();
 
-            //MultipleGradientPaint.CycleMethodEnum cycenum = gp.getCycleMethod();
-            //boolean cyclic = (cycenum == MultipleGradientPaint.REPEAT);
-            // This code currently doesn't support 'repeat' as PDF has
-            // no way to support this (we need to rasterize).
-
             // Build proper transform from gradient space to page space
             // ('Patterns' don't get userspace transform).
             AffineTransform transform;
@@ -885,6 +911,8 @@
 
             for (int count = 0; count < cols.length; count++) {
                 Color c1 = cols[count];
+                if (c1.getAlpha() != 255) return false;  // PDF can't do alpha
+
                 PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(),
                                                c1.getBlue());
                 someColors.add(color1);
@@ -900,9 +928,22 @@
                     someColors, theBounds, theCoords, theMatrix);
             currentStream.write(myPat.getColorSpaceOut(fill));
 
-        } else if (paint instanceof RadialGradientPaint) {
+            return true;
+        }
+        if (paint instanceof RadialGradientPaint) {
             RadialGradientPaint rgp = (RadialGradientPaint)paint;
 
+            // There is essentially no way to support repeate
+            // in PDF for radial gradients (the one option would
+            // be to 'grow' the outer circle until it fully covered
+            // the bounds and then grow the stops accordingly, the
+            // problem is that this may require an extremely large
+            // number of stops for cases where the focus is near
+            // the edge of the outer circle).  so we rasterize.
+            MultipleGradientPaint.CycleMethodEnum cycle = rgp.getCycleMethod();
+            if (cycle != MultipleGradientPaint.NO_CYCLE)
+                return false;
+
             AffineTransform transform;
             transform = new AffineTransform(graphicsState.getTransform());
             transform.concatenate(getTransform());
@@ -941,6 +982,8 @@
             List someColors = new java.util.ArrayList();
             for (int count = 0; count < cols.length; count++) {
                 Color cc = cols[count];
+                if (cc.getAlpha() != 255) return false;  // PDF can't do alpha
+
                 someColors.add(new PDFColor(cc.getRed(), cc.getGreen(), 
                                             cc.getBlue()));
             }
@@ -960,13 +1003,16 @@
 
             currentStream.write(myPat.getColorSpaceOut(fill));
 
-        } else if (paint instanceof PatternPaint) {
+            return true;
+        } 
+        if (paint instanceof PatternPaint) {
             PatternPaint pp = (PatternPaint)paint;
-            createPattern(pp, fill);
+            return createPattern(pp, fill);
         }
+        return false; // unknown paint
     }
 
-    private void createPattern(PatternPaint pp, boolean fill) {
+    private boolean createPattern(PatternPaint pp, boolean fill) {
         preparePainting();
 
         FontInfo fontInfo = new FontInfo();
@@ -1061,8 +1107,124 @@
                 // ignore exception, will be thrown again later
             }
         }
+        return true;
     }
 
+    protected boolean applyUnknownPaint(Paint paint, Shape shape) {
+        preparePainting();
+
+        Shape clip = getClip();
+        Rectangle2D usrClipBounds, usrBounds;
+        usrBounds = shape.getBounds2D();
+        usrClipBounds  = clip.getBounds2D();
+        if (!usrClipBounds.intersects(usrBounds))
+            return true;
+        Rectangle2D.intersect(usrBounds, usrClipBounds, usrBounds);
+        double usrX = usrBounds.getX();
+        double usrY = usrBounds.getY();
+        double usrW = usrBounds.getWidth();
+        double usrH = usrBounds.getHeight();
+
+        Rectangle devShapeBounds, devClipBounds, devBounds;
+        AffineTransform at = getTransform();
+        devShapeBounds = at.createTransformedShape(shape).getBounds();
+        devClipBounds  = at.createTransformedShape(clip).getBounds();
+        if (!devClipBounds.intersects(devShapeBounds)) 
+            return true;
+        devBounds = devShapeBounds.intersection(devClipBounds);
+        int devX = devBounds.x;
+        int devY = devBounds.y;
+        int devW = devBounds.width;
+        int devH = devBounds.height;
+
+        ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);
+        ColorModel rgbCM = new DirectColorModel
+            (rgbCS, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
+             false, DataBuffer.TYPE_BYTE);
+
+        PaintContext pctx = paint.createContext(rgbCM, devBounds, usrBounds, 
+                                                at, getRenderingHints());
+        PDFXObject imageInfo = pdfDoc.getImage
+            ("TempImage:" + pctx.toString());
+        if (imageInfo != null) {
+            resourceContext.getPDFResources().addXObject(imageInfo);
+        } else {
+            Raster r = pctx.getRaster(devX, devY, devW, devH);
+            WritableRaster wr = (WritableRaster)r;
+            wr = wr.createWritableTranslatedChild(0, 0);
+
+            ColorModel pcm = pctx.getColorModel();
+            BufferedImage bi = new BufferedImage
+                (pcm, wr, pcm.isAlphaPremultiplied(), null);
+            final byte [] rgb  = new byte[devW*devH*3];
+            final int  [] line = new int[devW];
+            final byte [] mask;
+            int x, y, val, rgbIdx=0;
+        
+            if (pcm.hasAlpha()) {
+                mask = new byte[devW*devH];
+                int maskIdx=0;
+                for (y=0; y<devH; y++) {
+                    bi.getRGB(0, y, devW, 1, line, 0, devW);
+                    for (x=0; x< devW; x++) {
+                        val = line[x];
+                        mask[maskIdx++] = (byte)(val>>>24);
+                        rgb [rgbIdx++]  = (byte)((val>>16)&0x0FF);
+                        rgb [rgbIdx++]  = (byte)((val>> 8)&0x0FF);
+                        rgb [rgbIdx++]  = (byte)((val    )&0x0FF);
+                    }
+                }
+            } else {
+                mask = null;
+                for (y=0; y<devH; y++) {
+                    bi.getRGB(0, y, devW, 1, line, 0, devW);
+                    for (x=0; x< devW; x++) {
+                        val = line[x];
+                        rgb [rgbIdx++]  = (byte)((val>>16)&0x0FF);
+                        rgb [rgbIdx++]  = (byte)((val>> 8)&0x0FF);
+                        rgb [rgbIdx++]  = (byte)((val    )&0x0FF);
+                    }
+                }
+            }
+
+            String maskRef = null;
+            if (mask != null) {
+                BitmapImage fopimg = new BitmapImage
+                    ("TempImageMask:"+pctx.toString(), devW, devH, mask, null);
+                fopimg.setColorSpace(new PDFColorSpace(PDFColorSpace.DEVICE_GRAY));
+                PDFXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
+                maskRef = xobj.referencePDF();
+
+                if (outputStream != null) {
+                    try {
+                        this.pdfDoc.output(outputStream);
+                    } catch (IOException ioe) {
+                        // ignore exception, will be thrown again later
+                    }
+                }
+            }
+            BitmapImage fopimg;
+            fopimg = new BitmapImage("TempImage:" + pctx.toString(),
+                                     devW, devH, rgb, maskRef);
+            fopimg.setTransparent(new PDFColor(255, 255, 255));
+            imageInfo = pdfDoc.addImage(resourceContext, fopimg);
+            if (outputStream != null) {
+                try {
+                    this.pdfDoc.output(outputStream);
+                } catch (IOException ioe) {
+                    // ignore exception, will be thrown again later
+                }
+            }
+        }
+
+        currentStream.write("q\n");
+        writeClip(shape);
+        currentStream.write("" + usrW + " 0 0 " + (-usrH) + " " + usrX
+                            + " " + (usrY + usrH) + " cm\n" + "/Im"
+                            + imageInfo.getXNumber() + " Do\nQ\n");
+        return true;
+    }
+
     /**
      * Apply the stroke to the PDF.
      * This takes the java stroke and outputs the appropriate settings
@@ -1512,7 +1674,16 @@
 
         Paint paint = getPaint();
         if (graphicsState.setPaint(paint)) {
-            applyPaint(paint, true);
+            if (!applyPaint(paint, true)) {
+                // Use the shape to 'clip' the paint contents.
+                applyUnknownPaint(paint, s);
+
+                if (newClip || newTransform) {
+                    currentStream.write("Q\n");
+                    graphicsState.pop();
+                }
+                return;
+            }
         }
 
         //PathIterator iter = s.getPathIterator(getTransform());
