java2d backports

Dr Andrew John Hughes ahughes at redhat.com
Wed Feb 23 05:53:39 PST 2011


On 19:08 Tue 22 Feb     , Denis Lila wrote:
> Hi.
> 
> I would like to backport these changesets to head:
> http://hg.openjdk.java.net/jdk7/2d-gate/jdk/rev/4d6f9aaa2600
> http://hg.openjdk.java.net/jdk7/2d-gate/jdk/rev/4d6f9aaa2600
> 

I think you need another URL there ;-)

> They will give us huge performance improvements to the drawing
> of simple shapes (and I'll finally be able to decisively close
> RH540575 ;-) 
> 
> I've had to make some manual modifications to the output of
> hg export (like removing CRLF line endings and removing hunks
> that change generated files) but they apply mostly cleanly
> and everything builds and works properly.
> 
> Ok to push?
> 
> Thank you,
> Denis.

Fine by me.  We spoke about these a while back IIRC.

> diff -r e1a5ab4cf428 ChangeLog
> --- a/ChangeLog	Tue Feb 22 23:07:58 2011 +0000
> +++ b/ChangeLog	Tue Feb 22 19:04:38 2011 -0500
> @@ -1,3 +1,10 @@
> +2011-02-22  Denis Lila  <dlila at redhat.com>
> +
> +	* Makefile.am: Added 2 patches.
> +	* NEWS: Updated.
> +	* patches/openjdk/6775317-non-AA-simple-shape-performance.patch
> +	* patches/openjdk/6766342-AA-simple-shape-performance.patch
> +
>  2011-02-22  Andrew John Hughes  <ahughes at redhat.com>
>  
>  	* patches/sunsrc.patch: Removed.
> diff -r e1a5ab4cf428 Makefile.am
> --- a/Makefile.am	Tue Feb 22 23:07:58 2011 +0000
> +++ b/Makefile.am	Tue Feb 22 19:04:38 2011 -0500
> @@ -325,7 +325,9 @@
>  	patches/openjdk/6749060-bad-lcd-aa-non-opaque-dest.patch \
>  	patches/openjdk/6896068-sg2d.patch \
>  	patches/pr633-no_javaws_man_page.patch \
> -	patches/pr586-include_all_srcs.patch
> +	patches/pr586-include_all_srcs.patch \
> +	patches/openjdk/6775317-non-AA-simple-shape-performance.patch \
> +	patches/openjdk/6766342-AA-simple-shape-performance.patch
>  
>  if !WITH_ALT_HSBUILD
>  ICEDTEA_PATCHES += \
> diff -r e1a5ab4cf428 NEWS
> --- a/NEWS	Tue Feb 22 23:07:58 2011 +0000
> +++ b/NEWS	Tue Feb 22 19:04:38 2011 -0500
> @@ -425,6 +425,8 @@
>    - S6779717: A Window does not show applet security warning icon on X platforms
>    - S6785058: Parent don't get the focus after dialog is closed if security warning is applied
>    - S6444769: java/awt/Insets/WindowWithWarningTest/WindowWithWarningTest.html fails
> +  - S6775317: Improve performance of non-AA transformed rectangles and single wide lines in software pipelines
> +  - S6766342: Improve performance of Ductus rasterizer
>  * Bug fixes
>    - RH661505: JPEGs with sRGB IEC61966-2.1 color profiles have wrong colors
>    - PR600: HS19 upgrade broke CACAO build on ARM
> diff -r e1a5ab4cf428 patches/openjdk/6766342-AA-simple-shape-performance.patch
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/patches/openjdk/6766342-AA-simple-shape-performance.patch	Tue Feb 22 19:04:38 2011 -0500
> @@ -0,0 +1,3819 @@
> +# HG changeset patch
> +# User flar
> +# Date 1292361929 28800
> +# Node ID 4d6f9aaa2600eec36725ab7cd47cb4b652755723
> +# Parent  0eeac8ca33e329aab7a9ad0fcfb3a321cd1abd06
> +6766342: Improve performance of Ductus rasterizer
> +Reviewed-by: jgodinez, prr
> +
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 make/sun/awt/mapfile-vers
> +--- openjdk.orig/jdk/make/sun/awt/mapfile-vers	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/mapfile-vers	Tue Dec 14 13:25:29 2010 -0800
> +@@ -118,6 +118,8 @@
> + 		Java_sun_java2d_loops_GraphicsPrimitiveMgr_registerNativeLoops;
> + 		Java_sun_java2d_loops_MaskBlit_MaskBlit;
> + 		Java_sun_java2d_loops_MaskFill_MaskFill;
> ++		Java_sun_java2d_loops_MaskFill_FillAAPgram;
> ++		Java_sun_java2d_loops_MaskFill_DrawAAPgram;
> + 		Java_sun_java2d_loops_TransformHelper_Transform;
> + 		Java_sun_java2d_pipe_Region_initIDs;
> + 		Java_sun_java2d_pipe_SpanClipRenderer_initIDs;
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 make/sun/awt/mapfile-vers-linux
> +--- openjdk.orig/jdk/make/sun/awt/mapfile-vers-linux	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/mapfile-vers-linux	Tue Dec 14 13:25:29 2010 -0800
> +@@ -115,6 +115,8 @@
> + 		Java_sun_java2d_loops_GraphicsPrimitiveMgr_registerNativeLoops;
> + 		Java_sun_java2d_loops_MaskBlit_MaskBlit;
> + 		Java_sun_java2d_loops_MaskFill_MaskFill;
> ++		Java_sun_java2d_loops_MaskFill_FillAAPgram;
> ++		Java_sun_java2d_loops_MaskFill_DrawAAPgram;
> +                 Java_sun_java2d_pipe_BufferedRenderPipe_fillSpans;
> + 		Java_sun_java2d_pipe_SpanClipRenderer_initIDs;
> + 		sun_awt_image_GifImageDecoder_initIDs;
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/dc/DuctusRenderingEngine.java
> +--- openjdk.orig/jdk/src/share/classes/sun/dc/DuctusRenderingEngine.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/dc/DuctusRenderingEngine.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -635,6 +635,88 @@
> +         return r;
> +     }
> + 
> ++    /**
> ++     * {@inheritDoc}
> ++     */
> ++    @Override
> ++    public AATileGenerator getAATileGenerator(double x, double y,
> ++                                              double dx1, double dy1,
> ++                                              double dx2, double dy2,
> ++                                              double lw1, double lw2,
> ++                                              Region clip,
> ++                                              int bbox[])
> ++    {
> ++        // REMIND: Deal with large coordinates!
> ++        double ldx1, ldy1, ldx2, ldy2;
> ++        boolean innerpgram = (lw1 > 0 && lw2 > 0);
> ++
> ++        if (innerpgram) {
> ++            ldx1 = dx1 * lw1;
> ++            ldy1 = dy1 * lw1;
> ++            ldx2 = dx2 * lw2;
> ++            ldy2 = dy2 * lw2;
> ++            x -= (ldx1 + ldx2) / 2.0;
> ++            y -= (ldy1 + ldy2) / 2.0;
> ++            dx1 += ldx1;
> ++            dy1 += ldy1;
> ++            dx2 += ldx2;
> ++            dy2 += ldy2;
> ++            if (lw1 > 1 && lw2 > 1) {
> ++                // Inner parallelogram was entirely consumed by stroke...
> ++                innerpgram = false;
> ++            }
> ++        } else {
> ++            ldx1 = ldy1 = ldx2 = ldy2 = 0;
> ++        }
> ++
> ++        Rasterizer r = getRasterizer();
> ++
> ++        r.setUsage(Rasterizer.EOFILL);
> ++
> ++        r.beginPath();
> ++        r.beginSubpath((float) x, (float) y);
> ++        r.appendLine((float) (x+dx1), (float) (y+dy1));
> ++        r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2));
> ++        r.appendLine((float) (x+dx2), (float) (y+dy2));
> ++        r.closedSubpath();
> ++        if (innerpgram) {
> ++            x += ldx1 + ldx2;
> ++            y += ldy1 + ldy2;
> ++            dx1 -= 2.0 * ldx1;
> ++            dy1 -= 2.0 * ldy1;
> ++            dx2 -= 2.0 * ldx2;
> ++            dy2 -= 2.0 * ldy2;
> ++            r.beginSubpath((float) x, (float) y);
> ++            r.appendLine((float) (x+dx1), (float) (y+dy1));
> ++            r.appendLine((float) (x+dx1+dx2), (float) (y+dy1+dy2));
> ++            r.appendLine((float) (x+dx2), (float) (y+dy2));
> ++            r.closedSubpath();
> ++        }
> ++
> ++        try {
> ++            r.endPath();
> ++            r.getAlphaBox(bbox);
> ++            clip.clipBoxToBounds(bbox);
> ++            if (bbox[0] >= bbox[2] || bbox[1] >= bbox[3]) {
> ++                dropRasterizer(r);
> ++                return null;
> ++            }
> ++            r.setOutputArea(bbox[0], bbox[1],
> ++                            bbox[2] - bbox[0],
> ++                            bbox[3] - bbox[1]);
> ++        } catch (PRException e) {
> ++            /*
> ++             * This exeption is thrown from the native part of the Ductus
> ++             * (only in case of a debug build) to indicate that some
> ++             * segments of the path have very large coordinates.
> ++             * See 4485298 for more info.
> ++             */
> ++            System.err.println("DuctusRenderingEngine.getAATileGenerator: "+e);
> ++        }
> ++
> ++        return r;
> ++    }
> ++
> +     private void feedConsumer(PathConsumer consumer, PathIterator pi) {
> +         try {
> +             consumer.beginPath();
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/SurfaceData.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/SurfaceData.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/SurfaceData.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -367,16 +367,17 @@
> +     public static final TextPipe aaTextRenderer;
> +     public static final TextPipe lcdTextRenderer;
> + 
> +-    protected static final CompositePipe colorPipe;
> ++    protected static final AlphaColorPipe colorPipe;
> +     protected static final PixelToShapeConverter colorViaShape;
> +     protected static final PixelToParallelogramConverter colorViaPgram;
> +     protected static final TextPipe colorText;
> +     protected static final CompositePipe clipColorPipe;
> +     protected static final TextPipe clipColorText;
> +     protected static final AAShapePipe AAColorShape;
> +-    protected static final PixelToShapeConverter AAColorViaShape;
> ++    protected static final PixelToParallelogramConverter AAColorViaShape;
> ++    protected static final PixelToParallelogramConverter AAColorViaPgram;
> +     protected static final AAShapePipe AAClipColorShape;
> +-    protected static final PixelToShapeConverter AAClipColorViaShape;
> ++    protected static final PixelToParallelogramConverter AAClipColorViaShape;
> + 
> +     protected static final CompositePipe paintPipe;
> +     protected static final SpanShapeRenderer paintShape;
> +@@ -385,9 +386,9 @@
> +     protected static final CompositePipe clipPaintPipe;
> +     protected static final TextPipe clipPaintText;
> +     protected static final AAShapePipe AAPaintShape;
> +-    protected static final PixelToShapeConverter AAPaintViaShape;
> ++    protected static final PixelToParallelogramConverter AAPaintViaShape;
> +     protected static final AAShapePipe AAClipPaintShape;
> +-    protected static final PixelToShapeConverter AAClipPaintViaShape;
> ++    protected static final PixelToParallelogramConverter AAClipPaintViaShape;
> + 
> +     protected static final CompositePipe compPipe;
> +     protected static final SpanShapeRenderer compShape;
> +@@ -396,9 +397,9 @@
> +     protected static final CompositePipe clipCompPipe;
> +     protected static final TextPipe clipCompText;
> +     protected static final AAShapePipe AACompShape;
> +-    protected static final PixelToShapeConverter AACompViaShape;
> ++    protected static final PixelToParallelogramConverter AACompViaShape;
> +     protected static final AAShapePipe AAClipCompShape;
> +-    protected static final PixelToShapeConverter AAClipCompViaShape;
> ++    protected static final PixelToParallelogramConverter AAClipCompViaShape;
> + 
> +     protected static final DrawImagePipe imagepipe;
> + 
> +@@ -427,6 +428,22 @@
> +         }
> +     }
> + 
> ++    private static PixelToParallelogramConverter
> ++        makeConverter(AAShapePipe renderer,
> ++                      ParallelogramPipe pgrampipe)
> ++    {
> ++        return new PixelToParallelogramConverter(renderer,
> ++                                                 pgrampipe,
> ++                                                 1.0/8.0, 0.499,
> ++                                                 false);
> ++    }
> ++
> ++    private static PixelToParallelogramConverter
> ++        makeConverter(AAShapePipe renderer)
> ++    {
> ++        return makeConverter(renderer, renderer);
> ++    }
> ++
> +     static {
> +         colorPrimitives = new LoopPipe();
> + 
> +@@ -445,9 +462,10 @@
> +         clipColorPipe = new SpanClipRenderer(colorPipe);
> +         clipColorText = new TextRenderer(clipColorPipe);
> +         AAColorShape = new AAShapePipe(colorPipe);
> +-        AAColorViaShape = new PixelToShapeConverter(AAColorShape);
> ++        AAColorViaShape = makeConverter(AAColorShape);
> ++        AAColorViaPgram = makeConverter(AAColorShape, colorPipe);
> +         AAClipColorShape = new AAShapePipe(clipColorPipe);
> +-        AAClipColorViaShape = new PixelToShapeConverter(AAClipColorShape);
> ++        AAClipColorViaShape = makeConverter(AAClipColorShape);
> + 
> +         paintPipe = new AlphaPaintPipe();
> +         paintShape = new SpanShapeRenderer.Composite(paintPipe);
> +@@ -456,9 +474,9 @@
> +         clipPaintPipe = new SpanClipRenderer(paintPipe);
> +         clipPaintText = new TextRenderer(clipPaintPipe);
> +         AAPaintShape = new AAShapePipe(paintPipe);
> +-        AAPaintViaShape = new PixelToShapeConverter(AAPaintShape);
> ++        AAPaintViaShape = makeConverter(AAPaintShape);
> +         AAClipPaintShape = new AAShapePipe(clipPaintPipe);
> +-        AAClipPaintViaShape = new PixelToShapeConverter(AAClipPaintShape);
> ++        AAClipPaintViaShape = makeConverter(AAClipPaintShape);
> + 
> +         compPipe = new GeneralCompositePipe();
> +         compShape = new SpanShapeRenderer.Composite(compPipe);
> +@@ -467,9 +485,9 @@
> +         clipCompPipe = new SpanClipRenderer(compPipe);
> +         clipCompText = new TextRenderer(clipCompPipe);
> +         AACompShape = new AAShapePipe(compPipe);
> +-        AACompViaShape = new PixelToShapeConverter(AACompShape);
> ++        AACompViaShape = makeConverter(AACompShape);
> +         AAClipCompShape = new AAShapePipe(clipCompPipe);
> +-        AAClipCompViaShape = new PixelToShapeConverter(AAClipCompShape);
> ++        AAClipCompViaShape = makeConverter(AAClipCompShape);
> + 
> +         imagepipe = new DrawImage();
> +     }
> +@@ -591,12 +609,12 @@
> +                 if (sg2d.clipState == sg2d.CLIP_SHAPE) {
> +                     sg2d.drawpipe = AAClipCompViaShape;
> +                     sg2d.fillpipe = AAClipCompViaShape;
> +-                    sg2d.shapepipe = AAClipCompShape;
> ++                    sg2d.shapepipe = AAClipCompViaShape;
> +                     sg2d.textpipe = clipCompText;
> +                 } else {
> +                     sg2d.drawpipe = AACompViaShape;
> +                     sg2d.fillpipe = AACompViaShape;
> +-                    sg2d.shapepipe = AACompShape;
> ++                    sg2d.shapepipe = AACompViaShape;
> +                     sg2d.textpipe = compText;
> +                 }
> +             } else {
> +@@ -616,12 +634,16 @@
> +                 if (sg2d.clipState == sg2d.CLIP_SHAPE) {
> +                     sg2d.drawpipe = AAClipColorViaShape;
> +                     sg2d.fillpipe = AAClipColorViaShape;
> +-                    sg2d.shapepipe = AAClipColorShape;
> ++                    sg2d.shapepipe = AAClipColorViaShape;
> +                     sg2d.textpipe = clipColorText;
> +                 } else {
> +-                    sg2d.drawpipe = AAColorViaShape;
> +-                    sg2d.fillpipe = AAColorViaShape;
> +-                    sg2d.shapepipe = AAColorShape;
> ++                    PixelToParallelogramConverter converter =
> ++                        (sg2d.alphafill.canDoParallelograms()
> ++                         ? AAColorViaPgram
> ++                         : AAColorViaShape);
> ++                    sg2d.drawpipe = converter;
> ++                    sg2d.fillpipe = converter;
> ++                    sg2d.shapepipe = converter;
> +                     if (sg2d.paintState > sg2d.PAINT_OPAQUECOLOR ||
> +                         sg2d.compositeState > sg2d.COMP_ISCOPY)
> +                     {
> +@@ -634,12 +656,12 @@
> +                 if (sg2d.clipState == sg2d.CLIP_SHAPE) {
> +                     sg2d.drawpipe = AAClipPaintViaShape;
> +                     sg2d.fillpipe = AAClipPaintViaShape;
> +-                    sg2d.shapepipe = AAClipPaintShape;
> ++                    sg2d.shapepipe = AAClipPaintViaShape;
> +                     sg2d.textpipe = clipPaintText;
> +                 } else {
> +                     sg2d.drawpipe = AAPaintViaShape;
> +                     sg2d.fillpipe = AAPaintViaShape;
> +-                    sg2d.shapepipe = AAPaintShape;
> ++                    sg2d.shapepipe = AAPaintViaShape;
> +                     sg2d.textpipe = paintText;
> +                 }
> +             }
> +@@ -793,6 +815,18 @@
> +         }
> +     }
> + 
> ++    private static CompositeType getFillCompositeType(SunGraphics2D sg2d) {
> ++        CompositeType compType = sg2d.imageComp;
> ++        if (sg2d.compositeState == sg2d.COMP_ISCOPY) {
> ++            if (compType == CompositeType.SrcOverNoEa) {
> ++                compType = CompositeType.OpaqueSrcOverNoEa;
> ++            } else {
> ++                compType = CompositeType.SrcNoEa;
> ++            }
> ++        }
> ++        return compType;
> ++    }
> ++
> +     /**
> +      * Returns a MaskFill object that can be used on this destination
> +      * with the source (paint) and composite types determined by the given
> +@@ -802,9 +836,10 @@
> +      * surface) before returning a specific MaskFill object.
> +      */
> +     protected MaskFill getMaskFill(SunGraphics2D sg2d) {
> +-        return MaskFill.getFromCache(getPaintSurfaceType(sg2d),
> +-                                     sg2d.imageComp,
> +-                                     getSurfaceType());
> ++        SurfaceType src = getPaintSurfaceType(sg2d);
> ++        CompositeType comp = getFillCompositeType(sg2d);
> ++        SurfaceType dst = getSurfaceType();
> ++        return MaskFill.getFromCache(src, comp, dst);
> +     }
> + 
> +     private static RenderCache loopcache = new RenderCache(30);
> +@@ -816,9 +851,7 @@
> +      */
> +     public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
> +         SurfaceType src = getPaintSurfaceType(sg2d);
> +-        CompositeType comp = (sg2d.compositeState == sg2d.COMP_ISCOPY
> +-                              ? CompositeType.SrcNoEa
> +-                              : sg2d.imageComp);
> ++        CompositeType comp = getFillCompositeType(sg2d);
> +         SurfaceType dst = sg2d.getSurfaceData().getSurfaceType();
> + 
> +         Object o = loopcache.get(src, comp, dst);
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/loops/CompositeType.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/loops/CompositeType.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/loops/CompositeType.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -27,6 +27,7 @@
> + 
> + import java.awt.image.BufferedImage;
> + import java.awt.AlphaComposite;
> ++import java.util.HashMap;
> + 
> + /**
> +  * A CompositeType object provides a chained description of a type of
> +@@ -51,6 +52,11 @@
> +  * the indicated algorithm if all of the more specific searches fail.
> +  */
> + public final class CompositeType {
> ++
> ++    private static int unusedUID = 1;
> ++    private static final HashMap<String,Integer> compositeUIDMap =
> ++        new HashMap<String,Integer>(100);
> ++
> +     /*
> +      * CONSTANTS USED BY ALL PRIMITIVES TO DESCRIBE THE COMPOSITING
> +      * ALGORITHMS THEY CAN PERFORM
> +@@ -153,6 +159,22 @@
> +         SrcOverNoEa   = SrcOver.deriveSubType(DESC_SRC_OVER_NO_EA);
> + 
> +     /*
> ++     * A special CompositeType for the case where we are filling in
> ++     * SrcOverNoEa mode with an opaque color.  In that case then the
> ++     * best loop for us to use would be a SrcNoEa loop, but what if
> ++     * there is no such loop?  In that case then we would end up
> ++     * backing off to a Src loop (which should still be fine) or an
> ++     * AnyAlpha loop which would be slower than a SrcOver loop in
> ++     * most cases.
> ++     * The fix is to use the following chain which looks for loops
> ++     * in the following order:
> ++     *    SrcNoEa, Src, SrcOverNoEa, SrcOver, AnyAlpha
> ++     */
> ++    public static final CompositeType
> ++        OpaqueSrcOverNoEa = SrcOverNoEa.deriveSubType(DESC_SRC)
> ++                                       .deriveSubType(DESC_SRC_NO_EA);
> ++
> ++    /*
> +      * END OF CompositeType OBJECTS FOR THE VARIOUS CONSTANTS
> +      */
> + 
> +@@ -210,7 +232,6 @@
> +         }
> +     }
> + 
> +-    private static int unusedUID = 1;
> +     private int uniqueID;
> +     private String desc;
> +     private CompositeType next;
> +@@ -218,14 +239,20 @@
> +     private CompositeType(CompositeType parent, String desc) {
> +         next = parent;
> +         this.desc = desc;
> +-        this.uniqueID = makeUniqueID();
> ++        this.uniqueID = makeUniqueID(desc);
> +     }
> + 
> +-    private synchronized static final int makeUniqueID() {
> +-        if (unusedUID > 255) {
> +-            throw new InternalError("composite type id overflow");
> ++    public synchronized static final int makeUniqueID(String desc) {
> ++        Integer i = compositeUIDMap.get(desc);
> ++
> ++        if (i == null) {
> ++            if (unusedUID > 255) {
> ++                throw new InternalError("composite type id overflow");
> ++            }
> ++            i = unusedUID++;
> ++            compositeUIDMap.put(desc, i);
> +         }
> +-        return unusedUID++;
> ++        return i;
> +     }
> + 
> +     public int getUniqueID() {
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/loops/MaskFill.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/loops/MaskFill.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/loops/MaskFill.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -50,6 +50,10 @@
> + public class MaskFill extends GraphicsPrimitive
> + {
> +     public static final String methodSignature = "MaskFill(...)".toString();
> ++    public static final String fillPgramSignature =
> ++        "FillAAPgram(...)".toString();
> ++    public static final String drawPgramSignature =
> ++        "DrawAAPgram(...)".toString();
> + 
> +     public static final int primTypeID = makePrimTypeID();
> + 
> +@@ -92,6 +96,14 @@
> +         return fill;
> +     }
> + 
> ++    protected MaskFill(String alternateSignature,
> ++                       SurfaceType srctype,
> ++                       CompositeType comptype,
> ++                       SurfaceType dsttype)
> ++    {
> ++        super(alternateSignature, primTypeID, srctype, comptype, dsttype);
> ++    }
> ++
> +     protected MaskFill(SurfaceType srctype,
> +                        CompositeType comptype,
> +                        SurfaceType dsttype)
> +@@ -115,6 +127,23 @@
> +                                 int x, int y, int w, int h,
> +                                 byte[] mask, int maskoff, int maskscan);
> + 
> ++    public native void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData,
> ++                                   Composite comp,
> ++                                   double x, double y,
> ++                                   double dx1, double dy1,
> ++                                   double dx2, double dy2);
> ++
> ++    public native void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData,
> ++                                   Composite comp,
> ++                                   double x, double y,
> ++                                   double dx1, double dy1,
> ++                                   double dx2, double dy2,
> ++                                   double lw1, double lw2);
> ++
> ++    public boolean canDoParallelograms() {
> ++        return (getNativePrim() != 0);
> ++    }
> ++
> +     static {
> +         GraphicsPrimitiveMgr.registerGeneral(new MaskFill(null, null, null));
> +     }
> +@@ -182,12 +211,22 @@
> + 
> +     private static class TraceMaskFill extends MaskFill {
> +         MaskFill target;
> ++        MaskFill fillPgramTarget;
> ++        MaskFill drawPgramTarget;
> + 
> +         public TraceMaskFill(MaskFill target) {
> +             super(target.getSourceType(),
> +                   target.getCompositeType(),
> +                   target.getDestType());
> +             this.target = target;
> ++            this.fillPgramTarget = new MaskFill(fillPgramSignature,
> ++                                                target.getSourceType(),
> ++                                                target.getCompositeType(),
> ++                                                target.getDestType());
> ++            this.drawPgramTarget = new MaskFill(drawPgramSignature,
> ++                                                target.getSourceType(),
> ++                                                target.getCompositeType(),
> ++                                                target.getDestType());
> +         }
> + 
> +         public GraphicsPrimitive traceWrap() {
> +@@ -203,5 +242,32 @@
> +             target.MaskFill(sg2d, sData, comp, x, y, w, h,
> +                             mask, maskoff, maskscan);
> +         }
> ++
> ++        public void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData,
> ++                                Composite comp,
> ++                                double x, double y,
> ++                                double dx1, double dy1,
> ++                                double dx2, double dy2)
> ++        {
> ++            tracePrimitive(fillPgramTarget);
> ++            target.FillAAPgram(sg2d, sData, comp,
> ++                               x, y, dx1, dy1, dx2, dy2);
> ++        }
> ++
> ++        public void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData,
> ++                                Composite comp,
> ++                                double x, double y,
> ++                                double dx1, double dy1,
> ++                                double dx2, double dy2,
> ++                                double lw1, double lw2)
> ++        {
> ++            tracePrimitive(drawPgramTarget);
> ++            target.DrawAAPgram(sg2d, sData, comp,
> ++                               x, y, dx1, dy1, dx2, dy2, lw1, lw2);
> ++        }
> ++
> ++        public boolean canDoParallelograms() {
> ++            return target.canDoParallelograms();
> ++        }
> +     }
> + }
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/pipe/AAShapePipe.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/pipe/AAShapePipe.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/pipe/AAShapePipe.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -28,6 +28,7 @@
> + import java.awt.BasicStroke;
> + import java.awt.Rectangle;
> + import java.awt.Shape;
> ++import java.awt.geom.Rectangle2D;
> + import java.awt.geom.PathIterator;
> + import sun.awt.SunHints;
> + import sun.java2d.SunGraphics2D;
> +@@ -39,7 +40,9 @@
> +  * This class sets up the Generator and computes the alpha tiles
> +  * and then passes them on to a CompositePipe object for painting.
> +  */
> +-public class AAShapePipe implements ShapeDrawPipe {
> ++public class AAShapePipe
> ++    implements ShapeDrawPipe, ParallelogramPipe
> ++{
> +     static RenderingEngine renderengine = RenderingEngine.getInstance();
> + 
> +     CompositePipe outpipe;
> +@@ -65,6 +68,59 @@
> +         renderPath(sg, s, null);
> +     }
> + 
> ++    private static Rectangle2D computeBBox(double x, double y,
> ++                                           double dx1, double dy1,
> ++                                           double dx2, double dy2)
> ++    {
> ++        double lox, loy, hix, hiy;
> ++        lox = hix = x;
> ++        loy = hiy = y;
> ++        if (dx1 < 0) { lox += dx1; } else { hix += dx1; }
> ++        if (dy1 < 0) { loy += dy1; } else { hiy += dy1; }
> ++        if (dx2 < 0) { lox += dx2; } else { hix += dx2; }
> ++        if (dy2 < 0) { loy += dy2; } else { hiy += dy2; }
> ++        return new Rectangle2D.Double(lox, loy, hix-lox, hiy-loy);
> ++    }
> ++
> ++    public void fillParallelogram(SunGraphics2D sg,
> ++                                  double x, double y,
> ++                                  double dx1, double dy1,
> ++                                  double dx2, double dy2)
> ++    {
> ++        Region clip = sg.getCompClip();
> ++        int abox[] = new int[4];
> ++        AATileGenerator aatg =
> ++            renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
> ++                                            clip, abox);
> ++        if (aatg == null) {
> ++            // Nothing to render
> ++            return;
> ++        }
> ++
> ++        renderTiles(sg, computeBBox(x, y, dx1, dy1, dx2, dy2), aatg, abox);
> ++    }
> ++
> ++    public void drawParallelogram(SunGraphics2D sg,
> ++                                  double x, double y,
> ++                                  double dx1, double dy1,
> ++                                  double dx2, double dy2,
> ++                                  double lw1, double lw2)
> ++    {
> ++        Region clip = sg.getCompClip();
> ++        int abox[] = new int[4];
> ++        AATileGenerator aatg =
> ++            renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
> ++                                            clip, abox);
> ++        if (aatg == null) {
> ++            // Nothing to render
> ++            return;
> ++        }
> ++
> ++        // Note that bbox is of the original shape, not the wide path.
> ++        // This is appropriate for handing to Paint methods...
> ++        renderTiles(sg, computeBBox(x, y, dx1, dy1, dx2, dy2), aatg, abox);
> ++    }
> ++
> +     private static byte[] theTile;
> + 
> +     public synchronized static byte[] getAlphaTile(int len) {
> +@@ -85,8 +141,6 @@
> +         boolean adjust = (bs != null &&
> +                           sg.strokeHint != SunHints.INTVAL_STROKE_PURE);
> +         boolean thin = (sg.strokeState <= sg.STROKE_THINDASHED);
> +-        Object context = null;
> +-        byte alpha[] = null;
> + 
> +         Region clip = sg.getCompClip();
> +         int abox[] = new int[4];
> +@@ -98,6 +152,14 @@
> +             return;
> +         }
> + 
> ++        renderTiles(sg, s, aatg, abox);
> ++    }
> ++
> ++    public void renderTiles(SunGraphics2D sg, Shape s,
> ++                            AATileGenerator aatg, int abox[])
> ++    {
> ++        Object context = null;
> ++        byte alpha[] = null;
> +         try {
> +             context = outpipe.startSequence(sg, s,
> +                                             new Rectangle(abox[0], abox[1],
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/pipe/AlphaColorPipe.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/pipe/AlphaColorPipe.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/pipe/AlphaColorPipe.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -34,7 +34,7 @@
> +  * into a destination that supports direct alpha compositing of a solid
> +  * color, according to one of the rules in the AlphaComposite class.
> +  */
> +-public class AlphaColorPipe implements CompositePipe {
> ++public class AlphaColorPipe implements CompositePipe, ParallelogramPipe {
> +     public AlphaColorPipe() {
> +     }
> + 
> +@@ -64,4 +64,23 @@
> +     public void endSequence(Object context) {
> +         return;
> +     }
> ++
> ++    public void fillParallelogram(SunGraphics2D sg,
> ++                                  double x, double y,
> ++                                  double dx1, double dy1,
> ++                                  double dx2, double dy2)
> ++    {
> ++        sg.alphafill.FillAAPgram(sg, sg.getSurfaceData(), sg.composite,
> ++                                 x, y, dx1, dy1, dx2, dy2);
> ++    }
> ++
> ++    public void drawParallelogram(SunGraphics2D sg,
> ++                                  double x, double y,
> ++                                  double dx1, double dy1,
> ++                                  double dx2, double dy2,
> ++                                  double lw1, double lw2)
> ++    {
> ++        sg.alphafill.DrawAAPgram(sg, sg.getSurfaceData(), sg.composite,
> ++                                 x, y, dx1, dy1, dx2, dy2, lw1, lw2);
> ++    }
> + }
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/pipe/RenderingEngine.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/pipe/RenderingEngine.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/pipe/RenderingEngine.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -281,6 +281,72 @@
> +                                                        int bbox[]);
> + 
> +     /**
> ++     * Construct an antialiased tile generator for the given parallelogram
> ++     * store the bounds of the tile iteration in the bbox parameter.
> ++     * The parallelogram is specified as a starting point and 2 delta
> ++     * vectors that indicate the slopes of the 2 pairs of sides of the
> ++     * parallelogram.
> ++     * The 4 corners of the parallelogram are defined by the 4 points:
> ++     * <ul>
> ++     * <li> {@code x}, {@code y}
> ++     * <li> {@code x+dx1}, {@code y+dy1}
> ++     * <li> {@code x+dx1+dx2}, {@code y+dy1+dy2}
> ++     * <li> {@code x+dx2}, {@code y+dy2}
> ++     * </ul>
> ++     * The {@code lw1} and {@code lw2} parameters provide a specification
> ++     * for an optionally stroked parallelogram if they are positive numbers.
> ++     * The {@code lw1} parameter is the ratio of the length of the {@code dx1},
> ++     * {@code dx2} delta vector to half of the line width in that same
> ++     * direction.
> ++     * The {@code lw2} parameter provides the same ratio for the other delta
> ++     * vector.
> ++     * If {@code lw1} and {@code lw2} are both greater than zero, then
> ++     * the parallelogram figure is doubled by both expanding and contracting
> ++     * each delta vector by its corresponding {@code lw} value.
> ++     * If either (@code lw1) or {@code lw2} are also greater than 1, then
> ++     * the inner (contracted) parallelogram disappears and the figure is
> ++     * simply a single expanded parallelogram.
> ++     * The {@code clip} parameter specifies the current clip in effect
> ++     * in device coordinates and can be used to prune the data for the
> ++     * operation, but the renderer is not required to perform any
> ++     * clipping.
> ++     * <p>
> ++     * Upon returning, this method will fill the {@code bbox} parameter
> ++     * with 4 values indicating the bounds of the iteration of the
> ++     * tile generator.
> ++     * The iteration order of the tiles will be as specified by the
> ++     * pseudo-code:
> ++     * <pre>
> ++     *     for (y = bbox[1]; y < bbox[3]; y += tileheight) {
> ++     *         for (x = bbox[0]; x < bbox[2]; x += tilewidth) {
> ++     *         }
> ++     *     }
> ++     * </pre>
> ++     * If there is no output to be rendered, this method may return
> ++     * null.
> ++     *
> ++     * @param x the X coordinate of the first corner of the parallelogram
> ++     * @param y the Y coordinate of the first corner of the parallelogram
> ++     * @param dx1 the X coordinate delta of the first leg of the parallelogram
> ++     * @param dy1 the Y coordinate delta of the first leg of the parallelogram
> ++     * @param dx2 the X coordinate delta of the second leg of the parallelogram
> ++     * @param dy2 the Y coordinate delta of the second leg of the parallelogram
> ++     * @param lw1 the line width ratio for the first leg of the parallelogram
> ++     * @param lw2 the line width ratio for the second leg of the parallelogram
> ++     * @param clip the current clip in effect in device coordinates
> ++     * @param bbox returns the bounds of the iteration
> ++     * @return the {@code AATileGenerator} instance to be consulted
> ++     *         for tile coverages, or null if there is no output to render
> ++     * @since 1.7
> ++     */
> ++    public abstract AATileGenerator getAATileGenerator(double x, double y,
> ++                                                       double dx1, double dy1,
> ++                                                       double dx2, double dy2,
> ++                                                       double lw1, double lw2,
> ++                                                       Region clip,
> ++                                                       int bbox[]);
> ++
> ++    /**
> +      * Returns the minimum pen width that the antialiasing rasterizer
> +      * can represent without dropouts occuring.
> +      * @since 1.7
> +@@ -393,5 +459,24 @@
> +                                              bs, thin, normalize,
> +                                              bbox);
> +         }
> ++        public AATileGenerator getAATileGenerator(double x, double y,
> ++                                                  double dx1, double dy1,
> ++                                                  double dx2, double dy2,
> ++                                                  double lw1, double lw2,
> ++                                                  Region clip,
> ++                                                  int bbox[])
> ++        {
> ++            System.out.println(name+".getAATileGenerator("+
> ++                               x+", "+y+", "+
> ++                               dx1+", "+dy1+", "+
> ++                               dx2+", "+dy2+", "+
> ++                               lw1+", "+lw2+", "+
> ++                               clip+")");
> ++            return target.getAATileGenerator(x, y,
> ++                                             dx1, dy1,
> ++                                             dx2, dy2,
> ++                                             lw1, lw2,
> ++                                             clip, bbox);
> ++        }
> +     }
> + }
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -557,6 +557,69 @@
> +         return ptg;
> +     }
> + 
> ++    public AATileGenerator getAATileGenerator(double x, double y,
> ++                                              double dx1, double dy1,
> ++                                              double dx2, double dy2,
> ++                                              double lw1, double lw2,
> ++                                              Region clip,
> ++                                              int bbox[])
> ++    {
> ++        // REMIND: Deal with large coordinates!
> ++        double ldx1, ldy1, ldx2, ldy2;
> ++        boolean innerpgram = (lw1 > 0 && lw2 > 0);
> ++
> ++        if (innerpgram) {
> ++            ldx1 = dx1 * lw1;
> ++            ldy1 = dy1 * lw1;
> ++            ldx2 = dx2 * lw2;
> ++            ldy2 = dy2 * lw2;
> ++            x -= (ldx1 + ldx2) / 2.0;
> ++            y -= (ldy1 + ldy2) / 2.0;
> ++            dx1 += ldx1;
> ++            dy1 += ldy1;
> ++            dx2 += ldx2;
> ++            dy2 += ldy2;
> ++            if (lw1 > 1 && lw2 > 1) {
> ++                // Inner parallelogram was entirely consumed by stroke...
> ++                innerpgram = false;
> ++            }
> ++        } else {
> ++            ldx1 = ldy1 = ldx2 = ldy2 = 0;
> ++        }
> ++
> ++        Renderer r = new Renderer(3, 3,
> ++                                  clip.getLoX(), clip.getLoY(),
> ++                                  clip.getWidth(), clip.getHeight(),
> ++                                  PathIterator.WIND_EVEN_ODD);
> ++
> ++        r.moveTo((float) x, (float) y);
> ++        r.lineTo((float) (x+dx1), (float) (y+dy1));
> ++        r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
> ++        r.lineTo((float) (x+dx2), (float) (y+dy2));
> ++        r.closePath();
> ++
> ++        if (innerpgram) {
> ++            x += ldx1 + ldx2;
> ++            y += ldy1 + ldy2;
> ++            dx1 -= 2.0 * ldx1;
> ++            dy1 -= 2.0 * ldy1;
> ++            dx2 -= 2.0 * ldx2;
> ++            dy2 -= 2.0 * ldy2;
> ++            r.moveTo((float) x, (float) y);
> ++            r.lineTo((float) (x+dx1), (float) (y+dy1));
> ++            r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
> ++            r.lineTo((float) (x+dx2), (float) (y+dy2));
> ++            r.closePath();
> ++        }
> ++
> ++        r.pathDone();
> ++
> ++        r.endRendering();
> ++        PiscesTileGenerator ptg = new PiscesTileGenerator(r, r.MAX_AA_ALPHA);
> ++        ptg.getBbox(bbox);
> ++        return ptg;
> ++    }
> ++
> +     /**
> +      * Returns the minimum pen width that the antialiasing rasterizer
> +      * can represent without dropouts occuring.
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/native/sun/java2d/loops/DrawParallelogram.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/DrawParallelogram.c	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/DrawParallelogram.c	Tue Dec 14 13:25:29 2010 -0800
> +@@ -26,14 +26,11 @@
> + #include "math.h"
> + #include "GraphicsPrimitiveMgr.h"
> + #include "LineUtils.h"
> +-#include "LoopMacros.h"
> + #include "Trace.h"
> ++#include "ParallelogramUtils.h"
> + 
> +-#include "sun_java2d_loops_FillParallelogram.h"
> + #include "sun_java2d_loops_DrawParallelogram.h"
> + 
> +-DECLARE_SOLID_DRAWLINE(AnyInt);
> +-
> + #define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \
> +                           pRasInfo, pixel, pPrim, pFunc, pCompInfo) \
> +     do { \
> +@@ -46,28 +43,6 @@
> +                                ix1, iy1, ix2, iy2, JNI_TRUE); \
> +     } while (0)
> + 
> +-#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \
> +-    do { \
> +-        double vmin, vmax; \
> +-        if (dv1 < 0) { \
> +-            vmin = v0+dv1; \
> +-            vmax = v0; \
> +-        } else { \
> +-            vmin = v0; \
> +-            vmax = v0+dv1; \
> +-        } \
> +-        if (dv2 < 0) { \
> +-            vmin -= dv2; \
> +-        } else { \
> +-            vmax += dv2; \
> +-        } \
> +-        bmin = (jint) floor(vmin + 0.5); \
> +-        bmax = (jint) floor(vmax + 0.5); \
> +-    } while(0)
> +-
> +-#define PGRAM_INIT_X(starty, x, y, slope) \
> +-    (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1)
> +-
> + typedef struct {
> +     jdouble x0;
> +     jdouble y0;
> +@@ -136,20 +111,8 @@
> +      * Sort parallelogram by y values, ensure that each delta vector
> +      * has a non-negative y delta.
> +      */
> +-    if (dy1 < 0) {
> +-        x0 += dx1;  y0 += dy1;
> +-        dx1 = -dx1; dy1 = -dy1;
> +-    }
> +-    if (dy2 < 0) {
> +-        x0 += dx2;  y0 += dy2;
> +-        dx2 = -dx2; dy2 = -dy2;
> +-    }
> +-    /* Sort delta vectors so dxy1 is left of dxy2. */
> +-    if (dx1 * dy2 > dx2 * dy1) {
> +-        double v = dx1; dx1 = dx2; dx2 = v;
> +-               v = dy1; dy1 = dy2; dy2 = v;
> +-               v = lw1; lw1 = lw2; lw2 = v;
> +-    }
> ++    SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2,
> ++               v = lw1; lw1 = lw2; lw2 = v;);
> + 
> +     // dx,dy for line width in the "1" and "2" directions.
> +     ldx1 = dx1 * lw1;
> +@@ -161,7 +124,7 @@
> +     ox0 = x0 - (ldx1 + ldx2) / 2.0;
> +     oy0 = y0 - (ldy1 + ldy2) / 2.0;
> + 
> +-    PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2);
> ++    PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_FALSE);
> +     iy1 = (jint) floor(oy0 + 0.5);
> +     iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5);
> + 
> +@@ -212,7 +175,7 @@
> +             // Only need to generate 4 quads if the interior still
> +             // has a hole in it (i.e. if the line width ratios were
> +             // both less than 1.0)
> +-            if (lw1 < 1.0f && lw2 < 1.0f) {
> ++            if (lw1 < 1.0 && lw2 < 1.0) {
> +                 // If the line widths are both less than a pixel wide
> +                 // then we can use a drawline function instead for even
> +                 // more performance.
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/native/sun/java2d/loops/FillParallelogram.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/FillParallelogram.c	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/FillParallelogram.c	Tue Dec 14 13:25:29 2010 -0800
> +@@ -25,31 +25,10 @@
> + 
> + #include "math.h"
> + #include "GraphicsPrimitiveMgr.h"
> ++#include "ParallelogramUtils.h"
> + 
> + #include "sun_java2d_loops_FillParallelogram.h"
> + 
> +-#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \
> +-    do { \
> +-        double vmin, vmax; \
> +-        if (dv1 < 0) { \
> +-            vmin = v0+dv1; \
> +-            vmax = v0; \
> +-        } else { \
> +-            vmin = v0; \
> +-            vmax = v0+dv1; \
> +-        } \
> +-        if (dv2 < 0) { \
> +-            vmin -= dv2; \
> +-        } else { \
> +-            vmax += dv2; \
> +-        } \
> +-        bmin = (jint) floor(vmin + 0.5); \
> +-        bmax = (jint) floor(vmax + 0.5); \
> +-    } while(0)
> +-
> +-#define PGRAM_INIT_X(starty, x, y, slope) \
> +-    (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1)
> +-
> + /*
> +  * Class:     sun_java2d_loops_FillParallelogram
> +  * Method:    FillParallelogram
> +@@ -76,22 +55,11 @@
> + 
> +     /*
> +      * Sort parallelogram by y values, ensure that each delta vector
> +-     * has a non-negative y delta, and eliminate degenerate parallelograms.
> ++     * has a non-negative y delta.
> +      */
> +-    if (dy1 < 0) {
> +-        x0 += dx1;  y0 += dy1;
> +-        dx1 = -dx1; dy1 = -dy1;
> +-    }
> +-    if (dy2 < 0) {
> +-        x0 += dx2;  y0 += dy2;
> +-        dx2 = -dx2; dy2 = -dy2;
> +-    }
> +-    /* Sort delta vectors so dxy1 is left of dxy2. */
> +-    if (dx1 * dy2 > dx2 * dy1) {
> +-        double v = dx1; dx1 = dx2; dx2 = v;
> +-               v = dy1; dy1 = dy2; dy2 = v;
> +-    }
> +-    PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2);
> ++    SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, );
> ++
> ++    PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2, JNI_FALSE);
> +     iy1 = (jint) floor(y0 + 0.5);
> +     iy2 = (jint) floor(y0 + dy1 + dy2 + 0.5);
> + 
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/native/sun/java2d/loops/MaskFill.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/MaskFill.c	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/MaskFill.c	Tue Dec 14 13:25:29 2010 -0800
> +@@ -23,7 +23,11 @@
> +  * questions.
> +  */
> + 
> ++#include <math.h>
> ++#include <stdlib.h>
> ++#include <string.h>
> + #include "GraphicsPrimitiveMgr.h"
> ++#include "ParallelogramUtils.h"
> + 
> + #include "sun_java2d_loops_MaskFill.h"
> + 
> +@@ -93,6 +97,967 @@
> +             }
> +         }
> +         SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
> ++   }
> ++   SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
> ++}
> ++
> ++#define MASK_BUF_LEN 1024
> ++
> ++#define DblToMask(v) ((unsigned char) ((v)*255.9999))
> ++
> ++/* Fills an aligned rectangle with potentially translucent edges. */
> ++static void
> ++fillAARect(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
> ++           CompositeInfo *pCompInfo, jint color, unsigned char *pMask,
> ++           void *pDst,
> ++           jdouble x1, jdouble y1, jdouble x2, jdouble y2)
> ++{
> ++    jint cx1 = pRasInfo->bounds.x1;
> ++    jint cy1 = pRasInfo->bounds.y1;
> ++    jint cx2 = pRasInfo->bounds.x2;
> ++    jint cy2 = pRasInfo->bounds.y2;
> ++    jint rx1 = (jint) ceil(x1);
> ++    jint ry1 = (jint) ceil(y1);
> ++    jint rx2 = (jint) floor(x2);
> ++    jint ry2 = (jint) floor(y2);
> ++    jint width = cx2 - cx1;
> ++    jint scan = pRasInfo->scanStride;
> ++    /* Convert xy12 into the edge coverage fractions for those edges. */
> ++    x1 = rx1-x1;
> ++    y1 = ry1-y1;
> ++    x2 = x2-rx2;
> ++    y2 = y2-ry2;
> ++    if (ry2 < ry1) {
> ++        /* Accumulate bottom coverage into top coverage. */
> ++        y1 = y1 + y2 - 1.0;
> ++        /* prevent processing of "bottom fractional row" */
> ++        ry2 = cy2;
> ++    }
> ++    if (rx2 < rx1) {
> ++        /* Accumulate right coverage into left coverage. */
> ++        x1 = x1 + x2 - 1.0;
> ++        /* prevent processing of "right fractional column" */
> ++        rx2 = cx2;
> ++    }
> ++    /* Check for a visible "top fractional row" and process it */
> ++    if (cy1 < ry1) {
> ++        unsigned char midcov = DblToMask(y1);
> ++        jint x;
> ++        for (x = 0; x < width; x++) {
> ++            pMask[x] = midcov;
> ++        }
> ++        if (cx1 < rx1) {
> ++            pMask[0] = DblToMask(y1 * x1);
> ++        }
> ++        if (cx2 > rx2) {
> ++            pMask[width-1] = DblToMask(y1 * x2);
> ++        }
> ++        (*pPrim->funcs.maskfill)(pDst,
> ++                                 pMask, 0, 0,
> ++                                 width, 1,
> ++                                 color, pRasInfo,
> ++                                 pPrim, pCompInfo);
> ++        pDst = PtrAddBytes(pDst, scan);
> ++        cy1++;
> ++    }
> ++    /* Check for a visible "left fract, solid middle, right fract" section. */
> ++    if (cy1 < ry2 && cy1 < cy2) {
> ++        jint midh = ((ry2 < cy2) ? ry2 : cy2) - cy1;
> ++        jint midx = cx1;
> ++        void *pMid = pDst;
> ++        /* First process the left "fractional column" if it is visible. */
> ++        if (midx < rx1) {
> ++            pMask[0] = DblToMask(x1);
> ++            /* Note: maskscan == 0 means we reuse this value for every row. */
> ++            (*pPrim->funcs.maskfill)(pMid,
> ++                                     pMask, 0, 0,
> ++                                     1, midh,
> ++                                     color, pRasInfo,
> ++                                     pPrim, pCompInfo);
> ++            pMid = PtrAddBytes(pMid, pRasInfo->pixelStride);
> ++            midx++;
> ++        }
> ++        /* Process the central solid section if it is visible. */
> ++        if (midx < rx2 && midx < cx2) {
> ++            jint midw = ((rx2 < cx2) ? rx2 : cx2) - midx;
> ++            /* A NULL mask buffer means "all coverages are 0xff" */
> ++            (*pPrim->funcs.maskfill)(pMid,
> ++                                     NULL, 0, 0,
> ++                                     midw, midh,
> ++                                     color, pRasInfo,
> ++                                     pPrim, pCompInfo);
> ++            pMid = PtrCoord(pMid, midw, pRasInfo->pixelStride, 0, 0);
> ++            midx += midw;
> ++        }
> ++        /* Finally process the right "fractional column" if it is visible. */
> ++        if (midx < cx2) {
> ++            pMask[0] = DblToMask(x2);
> ++            /* Note: maskscan == 0 means we reuse this value for every row. */
> ++            (*pPrim->funcs.maskfill)(pMid,
> ++                                     pMask, 0, 0,
> ++                                     1, midh,
> ++                                     color, pRasInfo,
> ++                                     pPrim, pCompInfo);
> ++        }
> ++        cy1 += midh;
> ++        pDst = PtrCoord(pDst, 0, 0, midh, scan);
> ++    }
> ++    /* Check for a visible "bottom fractional row" and process it */
> ++    if (cy1 < cy2) {
> ++        unsigned char midcov = DblToMask(y2);
> ++        jint x;
> ++        for (x = 0; x < width; x++) {
> ++            pMask[x] = midcov;
> ++        }
> ++        if (cx1 < rx1) {
> ++            pMask[0] = DblToMask(y2 * x1);
> ++        }
> ++        if (cx2 > rx2) {
> ++            pMask[width-1] = DblToMask(y2 * x2);
> ++        }
> ++        (*pPrim->funcs.maskfill)(pDst,
> ++                                 pMask, 0, 0,
> ++                                 width, 1,
> ++                                 color, pRasInfo,
> ++                                 pPrim, pCompInfo);
> ++    }
> ++}
> ++
> ++/*
> ++ * Support code for arbitrary tracing and MaskFill filling of
> ++ * non-rectilinear (diagonal) parallelograms.
> ++ *
> ++ * This code is based upon the following model of AA coverage.
> ++ *
> ++ * Each edge of a parallelogram (for fillPgram) or a double
> ++ * parallelogram (inner and outer parallelograms for drawPgram)
> ++ * can be rasterized independently because the geometry is well
> ++ * defined in such a way that none of the sides will ever cross
> ++ * each other and they have a fixed ordering that is fairly
> ++ * well predetermined.
> ++ *
> ++ * So, for each edge we will look at the diagonal line that
> ++ * the edge makes as it passes through a row of pixels.  Some
> ++ * such diagonal lines may pass entirely through the row of
> ++ * pixels in a single pixel column.  Some may cut across the
> ++ * row and pass through several pixel columns before they pass
> ++ * on to the next row.
> ++ *
> ++ * As the edge passes through the row of pixels it will affect
> ++ * the coverage of the pixels it passes through as well as all
> ++ * of the pixels to the right of the edge.  The coverage will
> ++ * either be increased (by a left edge of a parallelogram) or
> ++ * decreased (by a right edge) for all pixels to the right, until
> ++ * another edge passing the opposite direction is encountered.
> ++ *
> ++ * The coverage added or subtracted by an edge as it crosses a
> ++ * given pixel is calculated using a trapezoid formula in the
> ++ * following manner:
> ++ *
> ++ *                /
> ++ *     +-----+---/-+-----+
> ++ *     |     |  /  |     |
> ++ *     |     | /   |     |
> ++ *     +-----+/----+-----+
> ++ *           /
> ++ *
> ++ * The area to the right of that edge for the pixel where it
> ++ * crosses is given as:
> ++ *
> ++ *     trapheight * (topedge + bottomedge)/2
> ++ *
> ++ * Another thing to note is that the above formula gives the
> ++ * contribution of that edge to the given pixel where it crossed,
> ++ * but in so crossing the pixel row, it also created 100% coverage
> ++ * for all of the pixels to the right.
> ++ *
> ++ * This example was simplified in that the edge depicted crossed
> ++ * the complete pixel row and it did so entirely within the bounds
> ++ * of a single pixel column.  In practice, many edges may start or
> ++ * end in a given row and thus provide only partial row coverage
> ++ * (i.e. the total "trapheight" in the formula never reaches 1.0).
> ++ * And in other cases, edges may travel sideways through several
> ++ * pixel columns on a given pixel row from where they enter it to
> ++ * where the leave it (which also mans that the trapheight for a
> ++ * given pixel will be less than 1.0, but by the time the edge
> ++ * completes its journey through the pixel row the "coverage shadow"
> ++ * that it casts on all pixels to the right eventually reaches 100%).
> ++ *
> ++ * In order to simplify the calculations so that we don't have to
> ++ * keep propagating coverages we calculate for one edge "until we
> ++ * reach another edge" we will process one edge at a time and
> ++ * simply record in a buffer the amount that an edge added to
> ++ * or subtracted from the coverage for a given pixel and its
> ++ * following right-side neighbors.  Thus, the true total coverage
> ++ * of a given pixel is only determined by summing the deltas for
> ++ * that pixel and all of the pixels to its left.  Since we already
> ++ * have to scan the buffer to change floating point coverages into
> ++ * mask values for a MaskFill loop, it is simple enough to sum the
> ++ * values as we perform that scan from left to right.
> ++ *
> ++ * In the above example, note that 2 deltas need to be recorded even
> ++ * though the edge only intersected a single pixel.  The delta recorded
> ++ * for the pixel where the edge crossed will be approximately 55%
> ++ * (guesstimating by examining the poor ascii art) which is fine for
> ++ * determining how to render that pixel, but the rest of the pixels
> ++ * to its right should have their coverage modified by a full 100%
> ++ * and the 55% delta value we recorded for the pixel that the edge
> ++ * crossed will not get them there.  We adjust for this by adding
> ++ * the "remainder" of the coverage implied by the shadow to the
> ++ * pixel immediately to the right of where we record a trapezoidal
> ++ * contribution.  In this case a delta of 45% will be recorded in
> ++ * the pixel immediately to the right to raise the total to 100%.
> ++ *
> ++ * As we sum these delta values as we process the line from left
> ++ * to right, these delta values will typically drive the sum from
> ++ * 0% up to 100% and back down to 0% over the course of a single
> ++ * pixel row.  In the case of a drawn (double) parallelogram the
> ++ * sum will go to 100% and back to 0% twice on most scanlines.
> ++ *
> ++ * The fillAAPgram and drawAAPgram functions drive the main flow
> ++ * of the algorithm with help from the following structures,
> ++ * macros, and functions.  It is probably best to start with
> ++ * those 2 functions to gain an understanding of the algorithm.
> ++ */
> ++typedef struct {
> ++    jdouble x;
> ++    jdouble y;
> ++    jdouble xbot;
> ++    jdouble ybot;
> ++    jdouble xnexty;
> ++    jdouble ynextx;
> ++    jdouble xnextx;
> ++    jdouble linedx;
> ++    jdouble celldx;
> ++    jdouble celldy;
> ++    jboolean isTrailing;
> ++} EdgeInfo;
> ++
> ++#define MIN_DELTA  (1.0/256.0)
> ++
> ++/*
> ++ * Calculates slopes and deltas for an edge and stores results in an EdgeInfo.
> ++ * Returns true if the edge was valid (i.e. not ignored for some reason).
> ++ */
> ++static jboolean
> ++storeEdge(EdgeInfo *pEdge,
> ++          jdouble x, jdouble y, jdouble dx, jdouble dy,
> ++          jint cx1, jint cy1, jint cx2, jint cy2,
> ++          jboolean isTrailing)
> ++{
> ++    jdouble xbot = x + dx;
> ++    jdouble ybot = y + dy;
> ++    jboolean ret;
> ++
> ++    pEdge->x = x;
> ++    pEdge->y = y;
> ++    pEdge->xbot = xbot;
> ++    pEdge->ybot = ybot;
> ++
> ++    /* Note that parallelograms are sorted so dy is always non-negative */
> ++    if (dy > MIN_DELTA &&        /* NaN and horizontal protection */
> ++        ybot > cy1 &&            /* NaN and "OUT_ABOVE" protection */
> ++        y < cy2 &&               /* NaN and "OUT_BELOW" protection */
> ++        xbot == xbot &&          /* NaN protection */
> ++        (x < cx2 || xbot < cx2)) /* "OUT_RIGHT" protection */
> ++        /* Note: "OUT_LEFT" segments may still contribute coverage... */
> ++    {
> ++        /* no NaNs, dy is not horizontal, and segment contributes to clip */
> ++        if (dx < -MIN_DELTA || dx > MIN_DELTA) {
> ++            /* dx is not vertical */
> ++            jdouble linedx;
> ++            jdouble celldy;
> ++            jdouble nextx;
> ++
> ++            linedx = dx / dy;
> ++            celldy = dy / dx;
> ++            if (y < cy1) {
> ++                pEdge->x = x = x + (cy1 - y) * linedx;
> ++                pEdge->y = y = cy1;
> ++            }
> ++            pEdge->linedx = linedx;
> ++            if (dx < 0) {
> ++                pEdge->celldx = -1.0;
> ++                pEdge->celldy = -celldy;
> ++                pEdge->xnextx = nextx = ceil(x) - 1.0;
> ++            } else {
> ++                pEdge->celldx = +1.0;
> ++                pEdge->celldy = celldy;
> ++                pEdge->xnextx = nextx = floor(x) + 1.0;
> ++            }
> ++            pEdge->ynextx = y + (nextx - x) * celldy;
> ++            pEdge->xnexty = x + ((floor(y) + 1) - y) * linedx;
> ++        } else {
> ++            /* dx is essentially vertical */
> ++            if (y < cy1) {
> ++                pEdge->y = y = cy1;
> ++            }
> ++            pEdge->xbot = x;
> ++            pEdge->linedx = 0.0;
> ++            pEdge->celldx = 0.0;
> ++            pEdge->celldy = 1.0;
> ++            pEdge->xnextx = x;
> ++            pEdge->xnexty = x;
> ++            pEdge->ynextx = ybot;
> ++        }
> ++        ret = JNI_TRUE;
> ++    } else {
> ++        /* There is some reason to ignore this segment, "celldy=0" omits it */
> ++        pEdge->ybot = y;
> ++        pEdge->linedx = dx;
> ++        pEdge->celldx = dx;
> ++        pEdge->celldy = 0.0;
> ++        pEdge->xnextx = xbot;
> ++        pEdge->xnexty = xbot;
> ++        pEdge->ynextx = y;
> ++        ret = JNI_FALSE;
> ++    }
> ++    pEdge->isTrailing = isTrailing;
> ++    return ret;
> ++}
> ++
> ++/*
> ++ * Calculates and stores slopes and deltas for all edges of a parallelogram.
> ++ * Returns true if at least 1 edge was valid (i.e. not ignored for some reason).
> ++ *
> ++ * The inverted flag is true for an outer parallelogram (left and right
> ++ * edges are leading and trailing) and false for an inner parallelogram
> ++ * (where the left edge is trailing and the right edge is leading).
> ++ */
> ++static jboolean
> ++storePgram(EdgeInfo *pLeftEdge, EdgeInfo *pRightEdge,
> ++           jdouble x, jdouble y,
> ++           jdouble dx1, jdouble dy1,
> ++           jdouble dx2, jdouble dy2,
> ++           jint cx1, jint cy1, jint cx2, jint cy2,
> ++           jboolean inverted)
> ++{
> ++    jboolean ret = JNI_FALSE;
> ++    ret = (storeEdge(pLeftEdge  + 0,
> ++                     x    , y    , dx1, dy1,
> ++                     cx1, cy1, cx2, cy2, inverted) || ret);
> ++    ret = (storeEdge(pLeftEdge  + 1,
> ++                     x+dx1, y+dy1, dx2, dy2,
> ++                     cx1, cy1, cx2, cy2, inverted) || ret);
> ++    ret = (storeEdge(pRightEdge + 0,
> ++                     x    , y    , dx2, dy2,
> ++                     cx1, cy1, cx2, cy2, !inverted) || ret);
> ++    ret = (storeEdge(pRightEdge + 1,
> ++                     x+dx2, y+dy2, dx1, dy1,
> ++                     cx1, cy1, cx2, cy2, !inverted) || ret);
> ++    return ret;
> ++}
> ++
> ++/*
> ++ * The X0,Y0,X1,Y1 values represent a trapezoidal fragment whose
> ++ * coverage must be accounted for in the accum buffer.
> ++ *
> ++ * All four values are assumed to fall within (or on the edge of)
> ++ * a single pixel.
> ++ *
> ++ * The trapezoid area is accumulated into the proper element of
> ++ * the accum buffer and the remainder of the "slice height" is
> ++ * accumulated into the element to its right.
> ++ */
> ++#define INSERT_ACCUM(pACCUM, IMIN, IMAX, X0, Y0, X1, Y1, CX1, CX2, MULT) \
> ++    do { \
> ++        jdouble xmid = ((X0) + (X1)) * 0.5; \
> ++        if (xmid <= (CX2)) { \
> ++            jdouble sliceh = ((Y1) - (Y0)); \
> ++            jdouble slicearea; \
> ++            jint i; \
> ++            if (xmid < (CX1)) { \
> ++                /* Accumulate the entire slice height into accum[0]. */ \
> ++                i = 0; \
> ++                slicearea = sliceh; \
> ++            } else { \
> ++                jdouble xpos = floor(xmid); \
> ++                i = ((jint) xpos) - (CX1); \
> ++                slicearea = (xpos+1-xmid) * sliceh; \
> ++            } \
> ++            if (IMIN > i) { \
> ++                IMIN = i; \
> ++            } \
> ++            (pACCUM)[i++] += (jfloat) ((MULT) * slicearea); \
> ++            (pACCUM)[i++] += (jfloat) ((MULT) * (sliceh - slicearea)); \
> ++            if (IMAX < i) { \
> ++                IMAX = i; \
> ++            } \
> ++        } \
> ++    } while (0)
> ++
> ++/*
> ++ * Accumulate the contributions for a given edge crossing a given
> ++ * scan line into the corresponding entries of the accum buffer.
> ++ * CY1 is the Y coordinate of the top edge of the scanline and CY2
> ++ * is equal to (CY1 + 1) and is the Y coordinate of the bottom edge
> ++ * of the scanline.  CX1 and CX2 are the left and right edges of the
> ++ * clip (or area of interest) being rendered.
> ++ *
> ++ * The edge is processed from the top edge to the bottom edge and
> ++ * a single pixel column at a time.
> ++ */
> ++#define ACCUM_EDGE(pEDGE, pACCUM, IMIN, IMAX, CX1, CY1, CX2, CY2) \
> ++    do { \
> ++        jdouble x, y, xnext, ynext, xlast, ylast, dx, dy, mult; \
> ++        y = (pEDGE)->y; \
> ++        dy = (pEDGE)->celldy; \
> ++        ylast = (pEDGE)->ybot; \
> ++        if (ylast <= (CY1) || y >= (CY2) || dy == 0.0) { \
> ++            break; \
> ++        } \
> ++        x = (pEDGE)->x; \
> ++        dx = (pEDGE)->celldx; \
> ++        if (ylast > (CY2)) { \
> ++            ylast = (CY2); \
> ++            xlast = (pEDGE)->xnexty; \
> ++        } else { \
> ++            xlast = (pEDGE)->xbot; \
> ++        } \
> ++        xnext = (pEDGE)->xnextx; \
> ++        ynext = (pEDGE)->ynextx; \
> ++        mult = ((pEDGE)->isTrailing) ? -1.0 : 1.0; \
> ++        while (ynext <= ylast) { \
> ++            INSERT_ACCUM(pACCUM, IMIN, IMAX, \
> ++                         x, y, xnext, ynext, \
> ++                         CX1, CX2, mult); \
> ++            x = xnext; \
> ++            y = ynext; \
> ++            xnext += dx; \
> ++            ynext += dy; \
> ++        } \
> ++        (pEDGE)->ynextx = ynext; \
> ++        (pEDGE)->xnextx = xnext; \
> ++        INSERT_ACCUM(pACCUM, IMIN, IMAX, \
> ++                     x, y, xlast, ylast, \
> ++                     CX1, CX2, mult); \
> ++        (pEDGE)->x = xlast; \
> ++        (pEDGE)->y = ylast; \
> ++        (pEDGE)->xnexty = xlast + (pEDGE)->linedx; \
> ++    } while(0)
> ++
> ++/* Main function to fill a single Parallelogram */
> ++static void
> ++fillAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
> ++            CompositeInfo *pCompInfo, jint color, unsigned char *pMask,
> ++            void *pDst,
> ++            jdouble x1, jdouble y1,
> ++            jdouble dx1, jdouble dy1,
> ++            jdouble dx2, jdouble dy2)
> ++{
> ++    jint cx1 = pRasInfo->bounds.x1;
> ++    jint cy1 = pRasInfo->bounds.y1;
> ++    jint cx2 = pRasInfo->bounds.x2;
> ++    jint cy2 = pRasInfo->bounds.y2;
> ++    jint width = cx2 - cx1;
> ++    EdgeInfo edges[4];
> ++    jfloat localaccum[MASK_BUF_LEN + 1];
> ++    jfloat *pAccum;
> ++
> ++    if (!storePgram(edges + 0, edges + 2,
> ++                    x1, y1, dx1, dy1, dx2, dy2,
> ++                    cx1, cy1, cx2, cy2,
> ++                    JNI_FALSE))
> ++    {
> ++        return;
> ++    }
> ++
> ++    pAccum = ((width > MASK_BUF_LEN)
> ++              ? malloc((width + 1) * sizeof(jfloat))
> ++              : localaccum);
> ++    if (pAccum == NULL) {
> ++        return;
> ++    }
> ++    memset(pAccum, 0, (width+1) * sizeof(jfloat));
> ++
> ++    while (cy1 < cy2) {
> ++        jint lmin, lmax, rmin, rmax;
> ++        jint moff, x;
> ++        jdouble accum;
> ++        unsigned char lastcov;
> ++
> ++        lmin = rmin = width + 2;
> ++        lmax = rmax = 0;
> ++        ACCUM_EDGE(&edges[0], pAccum, lmin, lmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[1], pAccum, lmin, lmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[2], pAccum, rmin, rmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[3], pAccum, rmin, rmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        if (lmax > width) {
> ++            lmax = width; /* Extra col has data we do not need. */
> ++        }
> ++        if (rmax > width) {
> ++            rmax = width; /* Extra col has data we do not need. */
> ++        }
> ++        /* If ranges overlap, handle both in the first pass. */
> ++        if (rmin <= lmax) {
> ++            lmax = rmax;
> ++        }
> ++
> ++        x = lmin;
> ++        accum = 0.0;
> ++        moff = 0;
> ++        lastcov = 0;
> ++        while (x < lmax) {
> ++            accum += pAccum[x];
> ++            pAccum[x] = 0.0f;
> ++            pMask[moff++] = lastcov = DblToMask(accum);
> ++            x++;
> ++        }
> ++        /* Check for a solid center section. */
> ++        if (lastcov == 0xFF) {
> ++            jint endx;
> ++            void *pRow;
> ++
> ++            /* First process the existing partial coverage data. */
> ++            if (moff > 0) {
> ++                pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
> ++                (*pPrim->funcs.maskfill)(pRow,
> ++                                         pMask, 0, 0,
> ++                                         moff, 1,
> ++                                         color, pRasInfo,
> ++                                         pPrim, pCompInfo);
> ++                moff = 0;
> ++            }
> ++
> ++            /* Where does the center section end? */
> ++            /* If there is no right AA edge in the accum buffer, then */
> ++            /* the right edge was beyond the clip, so fill out to width */
> ++            endx = (rmin < rmax) ? rmin : width;
> ++            if (x < endx) {
> ++                pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0);
> ++                (*pPrim->funcs.maskfill)(pRow,
> ++                                         NULL, 0, 0,
> ++                                         endx - x, 1,
> ++                                         color, pRasInfo,
> ++                                         pPrim, pCompInfo);
> ++                x = endx;
> ++            }
> ++        } else if (lastcov > 0 && rmin >= rmax) {
> ++            /* We are not at 0 coverage, but there is no right edge, */
> ++            /* force a right edge so we process pixels out to width. */
> ++            rmax = width;
> ++        }
> ++        /* The following loop will process the right AA edge and/or any */
> ++        /* partial coverage center section not processed above. */
> ++        while (x < rmax) {
> ++            accum += pAccum[x];
> ++            pAccum[x] = 0.0f;
> ++            pMask[moff++] = DblToMask(accum);
> ++            x++;
> ++        }
> ++        if (moff > 0) {
> ++            void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
> ++            (*pPrim->funcs.maskfill)(pRow,
> ++                                     pMask, 0, 0,
> ++                                     moff, 1,
> ++                                     color, pRasInfo,
> ++                                     pPrim, pCompInfo);
> ++        }
> ++        pDst = PtrAddBytes(pDst, pRasInfo->scanStride);
> ++        cy1++;
> ++    }
> ++    if (pAccum != localaccum) {
> ++        free(pAccum);
> ++    }
> ++}
> ++
> ++/*
> ++ * Class:     sun_java2d_loops_MaskFill
> ++ * Method:    FillAAPgram
> ++ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDD)V
> ++ */
> ++JNIEXPORT void JNICALL
> ++Java_sun_java2d_loops_MaskFill_FillAAPgram
> ++    (JNIEnv *env, jobject self,
> ++     jobject sg2d, jobject sData, jobject comp,
> ++     jdouble x0, jdouble y0,
> ++     jdouble dx1, jdouble dy1,
> ++     jdouble dx2, jdouble dy2)
> ++{
> ++    SurfaceDataOps *sdOps;
> ++    SurfaceDataRasInfo rasInfo;
> ++    NativePrimitive *pPrim;
> ++    CompositeInfo compInfo;
> ++    jint ix1, iy1, ix2, iy2;
> ++
> ++    if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
> ++        return;
> ++    }
> ++
> ++    /*
> ++     * Sort parallelogram by y values, ensure that each delta vector
> ++     * has a non-negative y delta.
> ++     */
> ++    SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, );
> ++
> ++    PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2, JNI_TRUE);
> ++    iy1 = (jint) floor(y0);
> ++    iy2 = (jint) ceil(y0 + dy1 + dy2);
> ++
> ++    pPrim = GetNativePrim(env, self);
> ++    if (pPrim == NULL) {
> ++        return;
> ++    }
> ++    if (pPrim->pCompType->getCompInfo != NULL) {
> ++        (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp);
> ++    }
> ++
> ++    sdOps = SurfaceData_GetOps(env, sData);
> ++    if (sdOps == 0) {
> ++        return;
> ++    }
> ++
> ++    GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
> ++    SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
> ++    if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
> ++        rasInfo.bounds.x2 <= rasInfo.bounds.x1)
> ++    {
> ++        return;
> ++    }
> ++
> ++    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
> ++        return;
> ++    }
> ++
> ++    ix1 = rasInfo.bounds.x1;
> ++    iy1 = rasInfo.bounds.y1;
> ++    ix2 = rasInfo.bounds.x2;
> ++    iy2 = rasInfo.bounds.y2;
> ++    if (ix2 > ix1 && iy2 > iy1) {
> ++        jint width = ix2 - ix1;
> ++        jint color = GrPrim_Sg2dGetEaRGB(env, sg2d);
> ++        unsigned char localmask[MASK_BUF_LEN];
> ++        unsigned char *pMask = ((width > MASK_BUF_LEN)
> ++                                ? malloc(width)
> ++                                : localmask);
> ++
> ++        sdOps->GetRasInfo(env, sdOps, &rasInfo);
> ++        if (rasInfo.rasBase != NULL && pMask != NULL) {
> ++            void *pDst = PtrCoord(rasInfo.rasBase,
> ++                                  ix1, rasInfo.pixelStride,
> ++                                  iy1, rasInfo.scanStride);
> ++            if (dy1 == 0 && dx2 == 0) {
> ++                if (dx1 < 0) {
> ++                    // We sorted by Y above, but not by X
> ++                    x0 += dx1;
> ++                    dx1 = -dx1;
> ++                }
> ++                fillAARect(pPrim, &rasInfo, &compInfo,
> ++                           color, pMask, pDst,
> ++                           x0, y0, x0+dx1, y0+dy2);
> ++            } else if (dx1 == 0 && dy2 == 0) {
> ++                if (dx2 < 0) {
> ++                    // We sorted by Y above, but not by X
> ++                    x0 += dx2;
> ++                    dx2 = -dx2;
> ++                }
> ++                fillAARect(pPrim, &rasInfo, &compInfo,
> ++                           color, pMask, pDst,
> ++                           x0, y0, x0+dx2, y0+dy1);
> ++            } else {
> ++                fillAAPgram(pPrim, &rasInfo, &compInfo,
> ++                            color, pMask, pDst,
> ++                            x0, y0, dx1, dy1, dx2, dy2);
> ++            }
> ++        }
> ++        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
> ++        if (pMask != NULL && pMask != localmask) {
> ++            free(pMask);
> ++        }
> +     }
> +     SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
> + }
> ++
> ++/* Main function to fill a double pair of (inner and outer) parallelograms */
> ++static void
> ++drawAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo,
> ++            CompositeInfo *pCompInfo, jint color, unsigned char *pMask,
> ++            void *pDst,
> ++            jdouble ox0, jdouble oy0,
> ++            jdouble dx1, jdouble dy1,
> ++            jdouble dx2, jdouble dy2,
> ++            jdouble ldx1, jdouble ldy1,
> ++            jdouble ldx2, jdouble ldy2)
> ++{
> ++    jint cx1 = pRasInfo->bounds.x1;
> ++    jint cy1 = pRasInfo->bounds.y1;
> ++    jint cx2 = pRasInfo->bounds.x2;
> ++    jint cy2 = pRasInfo->bounds.y2;
> ++    jint width = cx2 - cx1;
> ++    EdgeInfo edges[8];
> ++    jfloat localaccum[MASK_BUF_LEN + 1];
> ++    jfloat *pAccum;
> ++
> ++    if (!storePgram(edges + 0, edges + 6,
> ++                    ox0, oy0,
> ++                    dx1 + ldx1, dy1 + ldy1,
> ++                    dx2 + ldx2, dy2 + ldy2,
> ++                    cx1, cy1, cx2, cy2,
> ++                    JNI_FALSE))
> ++    {
> ++        /* If outer pgram does not contribute, then inner cannot either. */
> ++        return;
> ++    }
> ++    storePgram(edges + 2, edges + 4,
> ++               ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2,
> ++               dx1 - ldx1, dy1 - ldy1,
> ++               dx2 - ldx2, dy2 - ldy2,
> ++               cx1, cy1, cx2, cy2,
> ++               JNI_TRUE);
> ++
> ++    pAccum = ((width > MASK_BUF_LEN)
> ++              ? malloc((width + 1) * sizeof(jfloat))
> ++              : localaccum);
> ++    if (pAccum == NULL) {
> ++        return;
> ++    }
> ++    memset(pAccum, 0, (width+1) * sizeof(jfloat));
> ++
> ++    while (cy1 < cy2) {
> ++        jint lmin, lmax, rmin, rmax;
> ++        jint moff, x;
> ++        jdouble accum;
> ++        unsigned char lastcov;
> ++
> ++        lmin = rmin = width + 2;
> ++        lmax = rmax = 0;
> ++        ACCUM_EDGE(&edges[0], pAccum, lmin, lmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[1], pAccum, lmin, lmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[2], pAccum, lmin, lmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[3], pAccum, lmin, lmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[4], pAccum, rmin, rmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[5], pAccum, rmin, rmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[6], pAccum, rmin, rmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        ACCUM_EDGE(&edges[7], pAccum, rmin, rmax,
> ++                   cx1, cy1, cx2, cy1+1);
> ++        if (lmax > width) {
> ++            lmax = width; /* Extra col has data we do not need. */
> ++        }
> ++        if (rmax > width) {
> ++            rmax = width; /* Extra col has data we do not need. */
> ++        }
> ++        /* If ranges overlap, handle both in the first pass. */
> ++        if (rmin <= lmax) {
> ++            lmax = rmax;
> ++        }
> ++
> ++        x = lmin;
> ++        accum = 0.0;
> ++        moff = 0;
> ++        lastcov = 0;
> ++        while (x < lmax) {
> ++            accum += pAccum[x];
> ++            pAccum[x] = 0.0f;
> ++            pMask[moff++] = lastcov = DblToMask(accum);
> ++            x++;
> ++        }
> ++        /* Check for an empty or solidcenter section. */
> ++        if (lastcov == 0 || lastcov == 0xFF) {
> ++            jint endx;
> ++            void *pRow;
> ++
> ++            /* First process the existing partial coverage data. */
> ++            if (moff > 0) {
> ++                pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
> ++                (*pPrim->funcs.maskfill)(pRow,
> ++                                         pMask, 0, 0,
> ++                                         moff, 1,
> ++                                         color, pRasInfo,
> ++                                         pPrim, pCompInfo);
> ++                moff = 0;
> ++            }
> ++
> ++            /* Where does the center section end? */
> ++            /* If there is no right AA edge in the accum buffer, then */
> ++            /* the right edge was beyond the clip, so fill out to width */
> ++            endx = (rmin < rmax) ? rmin : width;
> ++            if (x < endx) {
> ++                if (lastcov == 0xFF) {
> ++                    pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0);
> ++                    (*pPrim->funcs.maskfill)(pRow,
> ++                                             NULL, 0, 0,
> ++                                             endx - x, 1,
> ++                                             color, pRasInfo,
> ++                                             pPrim, pCompInfo);
> ++                }
> ++                x = endx;
> ++            }
> ++        } else if (rmin >= rmax) {
> ++            /* We are not at 0 coverage, but there is no right edge, */
> ++            /* force a right edge so we process pixels out to width. */
> ++            rmax = width;
> ++        }
> ++        /* The following loop will process the right AA edge and/or any */
> ++        /* partial coverage center section not processed above. */
> ++        while (x < rmax) {
> ++            accum += pAccum[x];
> ++            pAccum[x] = 0.0f;
> ++            pMask[moff++] = lastcov = DblToMask(accum);
> ++            x++;
> ++        }
> ++        if (moff > 0) {
> ++            void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0);
> ++            (*pPrim->funcs.maskfill)(pRow,
> ++                                     pMask, 0, 0,
> ++                                     moff, 1,
> ++                                     color, pRasInfo,
> ++                                     pPrim, pCompInfo);
> ++        }
> ++        if (lastcov == 0xFF && x < width) {
> ++            void *pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0);
> ++            (*pPrim->funcs.maskfill)(pRow,
> ++                                     NULL, 0, 0,
> ++                                     width - x, 1,
> ++                                     color, pRasInfo,
> ++                                     pPrim, pCompInfo);
> ++        }
> ++        pDst = PtrAddBytes(pDst, pRasInfo->scanStride);
> ++        cy1++;
> ++    }
> ++    if (pAccum != localaccum) {
> ++        free(pAccum);
> ++    }
> ++}
> ++
> ++/*
> ++ * Class:     sun_java2d_loops_MaskFill
> ++ * Method:    DrawAAPgram
> ++ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDDDD)V
> ++ */
> ++JNIEXPORT void JNICALL
> ++Java_sun_java2d_loops_MaskFill_DrawAAPgram
> ++    (JNIEnv *env, jobject self,
> ++     jobject sg2d, jobject sData, jobject comp,
> ++     jdouble x0, jdouble y0,
> ++     jdouble dx1, jdouble dy1,
> ++     jdouble dx2, jdouble dy2,
> ++     jdouble lw1, jdouble lw2)
> ++{
> ++    SurfaceDataOps *sdOps;
> ++    SurfaceDataRasInfo rasInfo;
> ++    NativePrimitive *pPrim;
> ++    CompositeInfo compInfo;
> ++    jint ix1, iy1, ix2, iy2;
> ++    jdouble ldx1, ldy1, ldx2, ldy2;
> ++    jdouble ox0, oy0;
> ++
> ++    if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
> ++        return;
> ++    }
> ++
> ++    /*
> ++     * Sort parallelogram by y values, ensure that each delta vector
> ++     * has a non-negative y delta.
> ++     */
> ++    SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2,
> ++               v = lw1; lw1 = lw2; lw2 = v;);
> ++
> ++    // dx,dy for line width in the "1" and "2" directions.
> ++    ldx1 = dx1 * lw1;
> ++    ldy1 = dy1 * lw1;
> ++    ldx2 = dx2 * lw2;
> ++    ldy2 = dy2 * lw2;
> ++
> ++    // calculate origin of the outer parallelogram
> ++    ox0 = x0 - (ldx1 + ldx2) / 2.0;
> ++    oy0 = y0 - (ldy1 + ldy2) / 2.0;
> ++
> ++    if (lw1 >= 1.0 || lw2 >= 1.0) {
> ++        /* Only need to fill an outer pgram if the interior no longer
> ++         * has a hole in it (i.e. if either of the line width ratios
> ++         * were greater than or equal to 1.0).
> ++         */
> ++        Java_sun_java2d_loops_MaskFill_FillAAPgram(env, self,
> ++                                                   sg2d, sData, comp,
> ++                                                   ox0, oy0,
> ++                                                   dx1 + ldx1, dy1 + ldy1,
> ++                                                   dx2 + ldx2, dy2 + ldy2);
> ++        return;
> ++    }
> ++
> ++    PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_TRUE);
> ++    iy1 = (jint) floor(oy0);
> ++    iy2 = (jint) ceil(oy0 + dy1 + ldy1 + dy2 + ldy2);
> ++
> ++    pPrim = GetNativePrim(env, self);
> ++    if (pPrim == NULL) {
> ++        return;
> ++    }
> ++    if (pPrim->pCompType->getCompInfo != NULL) {
> ++        (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp);
> ++    }
> ++
> ++    sdOps = SurfaceData_GetOps(env, sData);
> ++    if (sdOps == 0) {
> ++        return;
> ++    }
> ++
> ++    GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
> ++    SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
> ++    if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
> ++        rasInfo.bounds.x2 <= rasInfo.bounds.x1)
> ++    {
> ++        return;
> ++    }
> ++
> ++    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
> ++        return;
> ++    }
> ++
> ++    ix1 = rasInfo.bounds.x1;
> ++    iy1 = rasInfo.bounds.y1;
> ++    ix2 = rasInfo.bounds.x2;
> ++    iy2 = rasInfo.bounds.y2;
> ++    if (ix2 > ix1 && iy2 > iy1) {
> ++        jint width = ix2 - ix1;
> ++        jint color = GrPrim_Sg2dGetEaRGB(env, sg2d);
> ++        unsigned char localmask[MASK_BUF_LEN];
> ++        unsigned char *pMask = ((width > MASK_BUF_LEN)
> ++                                ? malloc(width)
> ++                                : localmask);
> ++
> ++        sdOps->GetRasInfo(env, sdOps, &rasInfo);
> ++        if (rasInfo.rasBase != NULL && pMask != NULL) {
> ++            void *pDst = PtrCoord(rasInfo.rasBase,
> ++                                  ix1, rasInfo.pixelStride,
> ++                                  iy1, rasInfo.scanStride);
> ++            /*
> ++             * NOTE: aligned rects could probably be drawn
> ++             * even faster with a little work here.
> ++             * if (dy1 == 0 && dx2 == 0) {
> ++             *     drawAARect(pPrim, &rasInfo, &compInfo,
> ++             *                color, pMask, pDst,
> ++             *                ox0, oy0, ox0+dx1+ldx1, oy0+dy2+ldy2, ldx1, ldy2);
> ++             * } else if (dx1 == 0 && dy2 == 0) {
> ++             *     drawAARect(pPrim, &rasInfo, &compInfo,
> ++             *                color, pMask, pDst,
> ++             *                ox0, oy0, ox0+dx2+ldx2, oy0+dy1+ldy1, ldx2, ldy1);
> ++             * } else {
> ++             */
> ++            drawAAPgram(pPrim, &rasInfo, &compInfo,
> ++                        color, pMask, pDst,
> ++                        ox0, oy0,
> ++                        dx1, dy1, dx2, dy2,
> ++                        ldx1, ldy1, ldx2, ldy2);
> ++            /*
> ++             * }
> ++             */
> ++        }
> ++        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
> ++        if (pMask != NULL && pMask != localmask) {
> ++            free(pMask);
> ++        }
> ++    }
> ++    SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
> ++}
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/share/native/sun/java2d/loops/ParallelogramUtils.h
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/ParallelogramUtils.h	Tue Dec 14 13:25:29 2010 -0800
> +@@ -0,0 +1,83 @@
> ++/*
> ++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
> ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> ++ *
> ++ * This code is free software; you can redistribute it and/or modify it
> ++ * under the terms of the GNU General Public License version 2 only, as
> ++ * published by the Free Software Foundation.  Oracle designates this
> ++ * particular file as subject to the "Classpath" exception as provided
> ++ * by Oracle in the LICENSE file that accompanied this code.
> ++ *
> ++ * This code is distributed in the hope that it will be useful, but WITHOUT
> ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> ++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> ++ * version 2 for more details (a copy is included in the LICENSE file that
> ++ * accompanied this code).
> ++ *
> ++ * You should have received a copy of the GNU General Public License version
> ++ * 2 along with this work; if not, write to the Free Software Foundation,
> ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> ++ *
> ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> ++ * or visit www.oracle.com if you need additional information or have any
> ++ * questions.
> ++ */
> ++
> ++#ifndef ParallelogramUtils_h_Included
> ++#define ParallelogramUtils_h_Included
> ++
> ++#ifdef __cplusplus
> ++extern "C" {
> ++#endif
> ++
> ++#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2, AA) \
> ++    do { \
> ++        double vmin, vmax; \
> ++        if (dv1 < 0) { \
> ++            vmin = v0+dv1; \
> ++            vmax = v0; \
> ++        } else { \
> ++            vmin = v0; \
> ++            vmax = v0+dv1; \
> ++        } \
> ++        if (dv2 < 0) { \
> ++            vmin += dv2; \
> ++        } else { \
> ++            vmax += dv2; \
> ++        } \
> ++        if (AA) { \
> ++            bmin = (jint) floor(vmin); \
> ++            bmax = (jint) ceil(vmax); \
> ++        } else { \
> ++            bmin = (jint) floor(vmin + 0.5); \
> ++            bmax = (jint) floor(vmax + 0.5); \
> ++        } \
> ++    } while(0)
> ++
> ++#define PGRAM_INIT_X(starty, x, y, slope) \
> ++    (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1)
> ++
> ++/*
> ++ * Sort parallelogram by y values, ensure that each delta vector
> ++ * has a non-negative y delta.
> ++ */
> ++#define SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, OTHER_SWAP_CODE) \
> ++    do { \
> ++        if (dy1 < 0) { \
> ++            x0 += dx1;  y0 += dy1; \
> ++            dx1 = -dx1; dy1 = -dy1; \
> ++        } \
> ++        if (dy2 < 0) { \
> ++            x0 += dx2;  y0 += dy2; \
> ++            dx2 = -dx2; dy2 = -dy2; \
> ++        } \
> ++        /* Sort delta vectors so dxy1 is left of dxy2. */ \
> ++        if (dx1 * dy2 > dx2 * dy1) { \
> ++            double v; \
> ++            v = dx1; dx1 = dx2; dx2 = v; \
> ++            v = dy1; dy1 = dy2; dy2 = v; \
> ++            OTHER_SWAP_CODE \
> ++        } \
> ++    } while(0)
> ++
> ++#endif /* ParallelogramUtils_h_Included */
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c
> +--- openjdk.orig/jdk/src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c	Tue Dec 14 13:25:29 2010 -0800
> +@@ -517,13 +517,15 @@
> +         ADD_SUFF(AnyIntSetRect)(pRasInfo, 0, 0, width, height,
> +                                 fgColor, pPrim, pCompInfo);
> + #else
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         if (cnstA != 0xff) {
> +             fgColor = (cnstA << 24) | (cnstR << 16) | (cnstG << 8) | cnstB;
> +         }
> +         ADD_SUFF(AnyIntSetRect)(pRasInfo,
> +-                                pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                0, 0, width, height,
> +                                 fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> + #endif
> +         return;
> +     }
> +@@ -582,11 +584,13 @@
> +     }
> + 
> +     if (pMask == NULL) {
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         fgColor = (cnstR << 24) | (cnstG << 16) | (cnstB << 8) | cnstA;
> +         ADD_SUFF(Any4ByteSetRect)(pRasInfo,
> +-                                  pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                  pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                  0, 0, width, height,
> +                                   fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> +         return;
> +     }
> + 
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c
> +--- openjdk.orig/jdk/src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c	Fri Dec 10 16:14:04 2010 -0800
> ++++ openjdk/jdk/src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c	Tue Dec 14 13:25:29 2010 -0800
> +@@ -150,10 +150,12 @@
> +     }
> + 
> +     if (pMask == NULL) {
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         ADD_SUFF(AnyIntSetRect)(pRasInfo,
> +-                                pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                0, 0, width, height,
> +                                 fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> +         return;
> +     }
> + 
> +@@ -214,15 +216,17 @@
> +     cnstB = (fgColor      ) & 0xff;
> + 
> +     if (pMask == NULL) {
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         if (cnstA == 0) {
> +             fgColor = 0;
> +         } else {
> +             fgColor = (fgColor << 8) | cnstA;
> +         }
> +         ADD_SUFF(Any4ByteSetRect)(pRasInfo,
> +-                                  pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                  pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                  0, 0, width, height,
> +                                   fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> +         return;
> +     }
> + 
> +@@ -390,10 +394,12 @@
> +     if (cnstA == 0) fgColor = 0;
> + 
> +     if (pMask == NULL) {
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         ADD_SUFF(AnyIntSetRect)(pRasInfo,
> +-                                pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                0, 0, width, height,
> +                                 fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> +         return;
> +     }
> + 
> +@@ -458,10 +464,12 @@
> +     }
> + 
> +     if (pMask == NULL) {
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         ADD_SUFF(AnyIntSetRect)(pRasInfo,
> +-                                pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                0, 0, width, height,
> +                                 fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> +         return;
> +     }
> + 
> +@@ -526,10 +534,12 @@
> +     }
> + 
> +     if (pMask == NULL) {
> ++        void *pBase = pRasInfo->rasBase;
> ++        pRasInfo->rasBase = rasBase;
> +         ADD_SUFF(Any3ByteSetRect)(pRasInfo,
> +-                                  pRasInfo->bounds.x1, pRasInfo->bounds.y1,
> +-                                  pRasInfo->bounds.x2, pRasInfo->bounds.y2,
> ++                                  0, 0, width, height,
> +                                   fgColor, pPrim, pCompInfo);
> ++        pRasInfo->rasBase = pBase;
> +         return;
> +     }
> + 
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 test/java/awt/Graphics2D/RenderClipTest/6766342.tests
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/test/java/awt/Graphics2D/RenderClipTest/6766342.tests	Tue Dec 14 13:25:29 2010 -0800
> +@@ -0,0 +1,3 @@
> ++Filled AA Pure Rect(5, 29.4, 10, 10)
> ++Stroked AA Pure Rect(5, 4.4, 10, 10)
> ++Stroked AA Line(20, 20, -10, 20)
> +diff -r 0eeac8ca33e3 -r 4d6f9aaa2600 test/java/awt/Graphics2D/RenderClipTest/RenderClipTest.java
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/test/java/awt/Graphics2D/RenderClipTest/RenderClipTest.java	Tue Dec 14 13:25:29 2010 -0800
> +@@ -0,0 +1,1634 @@
> ++/*
> ++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
> ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> ++ *
> ++ * This code is free software; you can redistribute it and/or modify it
> ++ * under the terms of the GNU General Public License version 2 only, as
> ++ * published by the Free Software Foundation.
> ++ *
> ++ * This code is distributed in the hope that it will be useful, but WITHOUT
> ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> ++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> ++ * version 2 for more details (a copy is included in the LICENSE file that
> ++ * accompanied this code).
> ++ *
> ++ * You should have received a copy of the GNU General Public License version
> ++ * 2 along with this work; if not, write to the Free Software Foundation,
> ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> ++ *
> ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> ++ * or visit www.oracle.com if you need additional information or have any
> ++ * questions.
> ++ */
> ++
> ++/*
> ++ * @test
> ++ * @bug 6766342
> ++ * @summary Tests clipping invariance for AA rectangle and line primitives
> ++ * @run main RenderClipTest -strict -readfile 6766342.tests
> ++ * @run main RenderClipTest -rectsuite -count 10
> ++ */
> ++
> ++import java.awt.*;
> ++import java.awt.geom.*;
> ++import java.awt.image.*;
> ++import java.awt.event.*;
> ++import java.util.Vector;
> ++import java.io.*;
> ++
> ++public class RenderClipTest {
> ++    public static double randDblCoord() {
> ++        return Math.random()*60 - 10;
> ++    }
> ++
> ++    public static float randFltCoord() {
> ++        return (float) randDblCoord();
> ++    }
> ++
> ++    public static int randIntCoord() {
> ++        return (int) Math.round(randDblCoord());
> ++    }
> ++
> ++    public static int randInt(int n) {
> ++        return ((int) (Math.random() * (n*4))) >> 2;
> ++    }
> ++
> ++    static int numtests;
> ++    static int numerrors;
> ++    static int numfillfailures;
> ++    static int numstrokefailures;
> ++    static int maxerr;
> ++
> ++    static boolean useAA;
> ++    static boolean strokePure;
> ++    static boolean testFill;
> ++    static boolean testDraw;
> ++    static boolean silent;
> ++    static boolean verbose;
> ++    static boolean strict;
> ++    static boolean showErrors;
> ++    static float lw;
> ++    static double rot;
> ++
> ++    static BufferedImage imgref;
> ++    static BufferedImage imgtst;
> ++
> ++    static Graphics2D grefclear;
> ++    static Graphics2D gtstclear;
> ++    static Graphics2D grefrender;
> ++    static Graphics2D gtstrender;
> ++
> ++    public static abstract class AnnotatedRenderOp {
> ++        public static AnnotatedRenderOp parse(String str) {
> ++            AnnotatedRenderOp ar;
> ++            if (((ar = Cubic.tryparse(str)) != null) ||
> ++                ((ar = Quad.tryparse(str)) != null) ||
> ++                ((ar = Poly.tryparse(str)) != null) ||
> ++                ((ar = Path.tryparse(str)) != null) ||
> ++                ((ar = Rect.tryparse(str)) != null) ||
> ++                ((ar = Line.tryparse(str)) != null) ||
> ++                ((ar = RectMethod.tryparse(str)) != null) ||
> ++                ((ar = LineMethod.tryparse(str)) != null))
> ++            {
> ++                return ar;
> ++            }
> ++            System.err.println("Unable to parse shape: "+str);
> ++            return null;
> ++        }
> ++
> ++        public abstract void randomize();
> ++
> ++        public abstract void fill(Graphics2D g2d);
> ++
> ++        public abstract void draw(Graphics2D g2d);
> ++    }
> ++
> ++    public static abstract class AnnotatedShapeOp extends AnnotatedRenderOp {
> ++        public abstract Shape getShape();
> ++
> ++        public void fill(Graphics2D g2d) {
> ++            g2d.fill(getShape());
> ++        }
> ++
> ++        public void draw(Graphics2D g2d) {
> ++            g2d.draw(getShape());
> ++        }
> ++    }
> ++
> ++    public static void usage(String err) {
> ++        if (err != null) {
> ++            System.err.println(err);
> ++        }
> ++        System.err.println("usage: java RenderClipTest "+
> ++                           "[-read[file F]] [-rectsuite] [-fill] [-draw]");
> ++        System.err.println("                           "+
> ++                           "[-aa] [-pure] [-lw N] [-rot N]");
> ++        System.err.println("                           "+
> ++                           "[-rectmethod] [-linemethod] [-rect] [-line]");
> ++        System.err.println("                           "+
> ++                           "[-cubic] [-quad] [-poly] [-path]");
> ++        System.err.println("                           "+
> ++                           "[-silent] [-verbose] [-showerr] [-count N]");
> ++        System.err.println("                           "+
> ++                           "[-strict] [-usage]");
> ++        System.err.println("    -read         Read test data from stdin");
> ++        System.err.println("    -readfile F   Read test data from file F");
> ++        System.err.println("    -rectsuite    Run a suite of rect/line tests");
> ++        System.err.println("    -fill         Test g.fill*(...)");
> ++        System.err.println("    -draw         Test g.draw*(...)");
> ++        System.err.println("    -aa           Use antialiased rendering");
> ++        System.err.println("    -pure         Use STROKE_PURE hint");
> ++        System.err.println("    -lw N         Test line widths of N "+
> ++                           "(default 1.0)");
> ++        System.err.println("    -rot N        Test rotation by N degrees "+
> ++                           "(default 0.0)");
> ++        System.err.println("    -rectmethod   Test fillRect/drawRect methods");
> ++        System.err.println("    -linemethod   Test drawLine method");
> ++        System.err.println("    -rect         Test Rectangle2D shapes");
> ++        System.err.println("    -line         Test Line2D shapes");
> ++        System.err.println("    -cubic        Test CubicCurve2D shapes");
> ++        System.err.println("    -quad         Test QuadCurve2D shapes");
> ++        System.err.println("    -poly         Test Polygon shapes");
> ++        System.err.println("    -path         Test GeneralPath shapes");
> ++        System.err.println("    -silent       Do not print out error curves");
> ++        System.err.println("    -verbose      Print out progress info");
> ++        System.err.println("    -showerr      Display errors on screen");
> ++        System.err.println("    -count N      N tests per shape, then exit "+
> ++                           "(default 1000)");
> ++        System.err.println("    -strict       All failures are important");
> ++        System.err.println("    -usage        Print this help, then exit");
> ++        System.exit((err != null) ? -1 : 0);
> ++    }
> ++
> ++    public static void main(String argv[]) {
> ++        boolean readTests = false;
> ++        String readFile = null;
> ++        boolean rectsuite = false;
> ++        int count = 1000;
> ++        lw = 1.0f;
> ++        rot = 0.0;
> ++        Vector<AnnotatedRenderOp> testOps = new Vector<AnnotatedRenderOp>();
> ++        for (int i = 0; i < argv.length; i++) {
> ++            String arg = argv[i].toLowerCase();
> ++            if (arg.equals("-aa")) {
> ++                useAA = true;
> ++            } else if (arg.equals("-pure")) {
> ++                strokePure = true;
> ++            } else if (arg.equals("-fill")) {
> ++                testFill = true;
> ++            } else if (arg.equals("-draw")) {
> ++                testDraw = true;
> ++            } else if (arg.equals("-lw")) {
> ++                if (i+1 >= argv.length) {
> ++                    usage("Missing argument: "+argv[i]);
> ++                }
> ++                lw = Float.parseFloat(argv[++i]);
> ++            } else if (arg.equals("-rot")) {
> ++                if (i+1 >= argv.length) {
> ++                    usage("Missing argument: "+argv[i]);
> ++                }
> ++                rot = Double.parseDouble(argv[++i]);
> ++            } else if (arg.equals("-cubic")) {
> ++                testOps.add(new Cubic());
> ++            } else if (arg.equals("-quad")) {
> ++                testOps.add(new Quad());
> ++            } else if (arg.equals("-poly")) {
> ++                testOps.add(new Poly());
> ++            } else if (arg.equals("-path")) {
> ++                testOps.add(new Path());
> ++            } else if (arg.equals("-rect")) {
> ++                testOps.add(new Rect());
> ++            } else if (arg.equals("-line")) {
> ++                testOps.add(new Line());
> ++            } else if (arg.equals("-rectmethod")) {
> ++                testOps.add(new RectMethod());
> ++            } else if (arg.equals("-linemethod")) {
> ++                testOps.add(new LineMethod());
> ++            } else if (arg.equals("-verbose")) {
> ++                verbose = true;
> ++            } else if (arg.equals("-strict")) {
> ++                strict = true;
> ++            } else if (arg.equals("-silent")) {
> ++                silent = true;
> ++            } else if (arg.equals("-showerr")) {
> ++                showErrors = true;
> ++            } else if (arg.equals("-readfile")) {
> ++                if (i+1 >= argv.length) {
> ++                    usage("Missing argument: "+argv[i]);
> ++                }
> ++                readTests = true;
> ++                readFile = argv[++i];
> ++            } else if (arg.equals("-read")) {
> ++                readTests = true;
> ++                readFile = null;
> ++            } else if (arg.equals("-rectsuite")) {
> ++                rectsuite = true;
> ++            } else if (arg.equals("-count")) {
> ++                if (i+1 >= argv.length) {
> ++                    usage("Missing argument: "+argv[i]);
> ++                }
> ++                count = Integer.parseInt(argv[++i]);
> ++            } else if (arg.equals("-usage")) {
> ++                usage(null);
> ++            } else {
> ++                usage("Unknown argument: "+argv[i]);
> ++            }
> ++        }
> ++        if (readTests) {
> ++            if (rectsuite || testDraw || testFill ||
> ++                useAA || strokePure ||
> ++                lw != 1.0f || rot != 0.0 ||
> ++                testOps.size() > 0)
> ++            {
> ++                usage("Should not specify test types with -read options");
> ++            }
> ++        } else if (rectsuite) {
> ++            if (testDraw || testFill ||
> ++                useAA || strokePure ||
> ++                lw != 1.0f || rot != 0.0 ||
> ++                testOps.size() > 0)
> ++            {
> ++                usage("Should not specify test types with -rectsuite option");
> ++            }
> ++        } else {
> ++            if (!testDraw && !testFill) {
> ++                usage("No work: Must specify one or both of "+
> ++                      "-fill or -draw");
> ++            }
> ++            if (testOps.size() == 0) {
> ++                usage("No work: Must specify one or more of "+
> ++                      "-rect[method], -line[method], "+
> ++                      "-cubic, -quad, -poly, or -path");
> ++            }
> ++        }
> ++        initImages();
> ++        if (readTests) {
> ++            try {
> ++                InputStream is;
> ++                if (readFile == null) {
> ++                    is = System.in;
> ++                } else {
> ++                    File f =
> ++                        new File(System.getProperty("test.src", "."),
> ++                                 readFile);
> ++                    is = new FileInputStream(f);
> ++                }
> ++                parseAndRun(is);
> ++            } catch (IOException e) {
> ++                throw new RuntimeException(e);
> ++            }
> ++        } else if (rectsuite) {
> ++            runRectSuite(count);
> ++        } else {
> ++            initGCs();
> ++            for (int k = 0; k < testOps.size(); k++) {
> ++                AnnotatedRenderOp ar = testOps.get(k);
> ++                runRandomTests(ar, count);
> ++            }
> ++            disposeGCs();
> ++        }
> ++        grefclear.dispose();
> ++        gtstclear.dispose();
> ++        grefclear = gtstclear = null;
> ++        reportStatistics();
> ++    }
> ++
> ++    public static int reportStatistics() {
> ++        String connector = "";
> ++        if (numfillfailures > 0) {
> ++            System.out.print(numfillfailures+" fills ");
> ++            connector = "and ";
> ++        }
> ++        if (numstrokefailures > 0) {
> ++            System.out.print(connector+numstrokefailures+" strokes ");
> ++        }
> ++        int totalfailures = numfillfailures + numstrokefailures;
> ++        if (totalfailures == 0) {
> ++            System.out.print("0 ");
> ++        }
> ++        System.out.println("out of "+numtests+" tests failed...");
> ++        int critical = numerrors;
> ++        if (strict) {
> ++            critical += totalfailures;
> ++        }
> ++        if (critical > 0) {
> ++            throw new RuntimeException(critical+" tests had critical errors");
> ++        }
> ++        System.out.println("No tests had critical errors");
> ++        return (numerrors+totalfailures);
> ++    }
> ++
> ++    public static void runRectSuite(int count) {
> ++        AnnotatedRenderOp ops[] = {
> ++            new Rect(),
> ++            new RectMethod(),
> ++            new Line(),
> ++            new LineMethod(),
> ++        };
> ++        // Sometimes different fill algorithms are chosen for
> ++        // thin and wide line modes, make sure we test both...
> ++        float filllinewidths[] = { 0.0f, 2.0f };
> ++        float drawlinewidths[] = { 0.0f, 0.5f, 1.0f,
> ++                                   2.0f, 2.5f,
> ++                                   5.0f, 5.3f };
> ++        double rotations[] = { 0.0, 15.0, 90.0,
> ++                               135.0, 180.0,
> ++                               200.0, 270.0,
> ++                               300.0};
> ++        for (AnnotatedRenderOp ar: ops) {
> ++            for (double r: rotations) {
> ++                rot = r;
> ++                for (int i = 0; i < 8; i++) {
> ++                    float linewidths[];
> ++                    if ((i & 1) == 0) {
> ++                        if ((ar instanceof Line) ||
> ++                            (ar instanceof LineMethod))
> ++                        {
> ++                            continue;
> ++                        }
> ++                        testFill = true;
> ++                        testDraw = false;
> ++                        linewidths = filllinewidths;
> ++                    } else {
> ++                        testFill = false;
> ++                        testDraw = true;
> ++                        linewidths = drawlinewidths;
> ++                    }
> ++                    useAA = ((i & 2) != 0);
> ++                    strokePure = ((i & 4) != 0);
> ++                    for (float w : linewidths) {
> ++                        lw = w;
> ++                        runSuiteTests(ar, count);
> ++                    }
> ++                }
> ++            }
> ++        }
> ++    }
> ++
> ++    public static void runSuiteTests(AnnotatedRenderOp ar, int count) {
> ++        if (verbose) {
> ++            System.out.print("Running ");
> ++            System.out.print(testFill ? "Fill " : "Draw ");
> ++            System.out.print(BaseName(ar));
> ++            if (useAA) {
> ++                System.out.print(" AA");
> ++            }
> ++            if (strokePure) {
> ++                System.out.print(" Pure");
> ++            }
> ++            if (lw != 1.0f) {
> ++                System.out.print(" lw="+lw);
> ++            }
> ++            if (rot != 0.0f) {
> ++                System.out.print(" rot="+rot);
> ++            }
> ++            System.out.println();
> ++        }
> ++        initGCs();
> ++        runRandomTests(ar, count);
> ++        disposeGCs();
> ++    }
> ++
> ++    public static String BaseName(AnnotatedRenderOp ar) {
> ++        String s = ar.toString();
> ++        int leftparen = s.indexOf('(');
> ++        if (leftparen >= 0) {
> ++            s = s.substring(0, leftparen);
> ++        }
> ++        return s;
> ++    }
> ++
> ++    public static void runRandomTests(AnnotatedRenderOp ar, int count) {
> ++        for (int i = 0; i < count; i++) {
> ++            ar.randomize();
> ++            if (testDraw) {
> ++                test(ar, false);
> ++            }
> ++            if (testFill) {
> ++                test(ar, true);
> ++            }
> ++        }
> ++    }
> ++
> ++    public static void initImages() {
> ++        imgref = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB);
> ++        imgtst = new BufferedImage(40, 40, BufferedImage.TYPE_INT_RGB);
> ++        grefclear = imgref.createGraphics();
> ++        gtstclear = imgtst.createGraphics();
> ++        grefclear.setColor(Color.white);
> ++        gtstclear.setColor(Color.white);
> ++    }
> ++
> ++    public static void initGCs() {
> ++        grefrender = imgref.createGraphics();
> ++        gtstrender = imgtst.createGraphics();
> ++        gtstrender.clipRect(10, 10, 20, 20);
> ++        grefrender.setColor(Color.blue);
> ++        gtstrender.setColor(Color.blue);
> ++        if (lw != 1.0f) {
> ++            BasicStroke bs = new BasicStroke(lw);
> ++            grefrender.setStroke(bs);
> ++            gtstrender.setStroke(bs);
> ++        }
> ++        if (rot != 0.0) {
> ++            double rotrad = Math.toRadians(rot);
> ++            grefrender.rotate(rotrad, 20, 20);
> ++            gtstrender.rotate(rotrad, 20, 20);
> ++        }
> ++        if (strokePure) {
> ++            grefrender.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
> ++                                        RenderingHints.VALUE_STROKE_PURE);
> ++            gtstrender.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
> ++                                        RenderingHints.VALUE_STROKE_PURE);
> ++        }
> ++        if (useAA) {
> ++            grefrender.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> ++                                        RenderingHints.VALUE_ANTIALIAS_ON);
> ++            gtstrender.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> ++                                        RenderingHints.VALUE_ANTIALIAS_ON);
> ++            maxerr = 1;
> ++        }
> ++    }
> ++
> ++    public static void disposeGCs() {
> ++        grefrender.dispose();
> ++        gtstrender.dispose();
> ++        grefrender = gtstrender = null;
> ++    }
> ++
> ++    public static void parseAndRun(InputStream in) throws IOException {
> ++        BufferedReader br = new BufferedReader(new InputStreamReader(in));
> ++        String str;
> ++        while ((str = br.readLine()) != null) {
> ++            if (str.startsWith("Stroked ") || str.startsWith("Filled ")) {
> ++                parseTest(str);
> ++                continue;
> ++            }
> ++            if (str.startsWith("Running ")) {
> ++                continue;
> ++            }
> ++            if (str.startsWith("Failed: ")) {
> ++                continue;
> ++            }
> ++            if (str.indexOf(" out of ") > 0 &&
> ++                str.indexOf(" tests failed...") > 0)
> ++            {
> ++                continue;
> ++            }
> ++            if (str.indexOf(" tests had critical errors") > 0) {
> ++                continue;
> ++            }
> ++            System.err.println("Unparseable line: "+str);
> ++        }
> ++    }
> ++
> ++    public static void parseTest(String origstr) {
> ++        String str = origstr;
> ++        boolean isfill = false;
> ++        useAA = strokePure = false;
> ++        lw = 1.0f;
> ++        rot = 0.0;
> ++        if (str.startsWith("Stroked ")) {
> ++            str = str.substring(8);
> ++            isfill = false;
> ++        } else if (str.startsWith("Filled ")) {
> ++            str = str.substring(7);
> ++            isfill = true;
> ++        } else {
> ++            System.err.println("Unparseable test line: "+origstr);
> ++        }
> ++        if (str.startsWith("AA ")) {
> ++            str = str.substring(3);
> ++            useAA = true;
> ++        }
> ++        if (str.startsWith("Pure ")) {
> ++            str = str.substring(5);
> ++            strokePure = true;
> ++        }
> ++        if (str.startsWith("Lw=")) {
> ++            int index = str.indexOf(' ', 3);
> ++            if (index > 0) {
> ++                lw = Float.parseFloat(str.substring(3, index));
> ++                str = str.substring(index+1);
> ++            }
> ++        }
> ++        if (str.startsWith("Rot=")) {
> ++            int index = str.indexOf(' ', 4);
> ++            if (index > 0) {
> ++                rot = Double.parseDouble(str.substring(4, index));
> ++                str = str.substring(index+1);
> ++            }
> ++        }
> ++        AnnotatedRenderOp ar = AnnotatedRenderOp.parse(str);
> ++        if (ar != null) {
> ++            initGCs();
> ++            test(ar, isfill);
> ++            disposeGCs();
> ++        } else {
> ++            System.err.println("Unparseable test line: "+origstr);
> ++        }
> ++    }
> ++
> ++    public static void test(AnnotatedRenderOp ar, boolean isfill) {
> ++        grefclear.fillRect(0, 0, 40, 40);
> ++        gtstclear.fillRect(0, 0, 40, 40);
> ++        if (isfill) {
> ++            ar.fill(grefrender);
> ++            ar.fill(gtstrender);
> ++        } else {
> ++            ar.draw(grefrender);
> ++            ar.draw(gtstrender);
> ++        }
> ++        check(imgref, imgtst, ar, isfill);
> ++    }
> ++
> ++    public static int[] getData(BufferedImage img) {
> ++        Raster r = img.getRaster();
> ++        DataBufferInt dbi = (DataBufferInt) r.getDataBuffer();
> ++        return dbi.getData();
> ++    }
> ++
> ++    public static int getScan(BufferedImage img) {
> ++        Raster r = img.getRaster();
> ++        SinglePixelPackedSampleModel sppsm =
> ++            (SinglePixelPackedSampleModel) r.getSampleModel();
> ++        return sppsm.getScanlineStride();
> ++    }
> ++
> ++    public static int getOffset(BufferedImage img) {
> ++        Raster r = img.getRaster();
> ++        SinglePixelPackedSampleModel sppsm =
> ++            (SinglePixelPackedSampleModel) r.getSampleModel();
> ++        return sppsm.getOffset(-r.getSampleModelTranslateX(),
> ++                               -r.getSampleModelTranslateY());
> ++    }
> ++
> ++    final static int opaque = 0xff000000;
> ++    final static int whitergb = Color.white.getRGB();
> ++
> ++    public static final int maxdiff(int rgb1, int rgb2) {
> ++        int maxd = 0;
> ++        for (int i = 0; i < 32; i += 8) {
> ++            int c1 = (rgb1 >> i) & 0xff;
> ++            int c2 = (rgb2 >> i) & 0xff;
> ++            int d = Math.abs(c1-c2);
> ++            if (maxd < d) {
> ++                maxd = d;
> ++            }
> ++        }
> ++        return maxd;
> ++    }
> ++
> ++    public static void check(BufferedImage imgref, BufferedImage imgtst,
> ++                             AnnotatedRenderOp ar, boolean wasfill)
> ++    {
> ++        numtests++;
> ++        int dataref[] = getData(imgref);
> ++        int datatst[] = getData(imgtst);
> ++        int scanref = getScan(imgref);
> ++        int scantst = getScan(imgtst);
> ++        int offref = getOffset(imgref);
> ++        int offtst = getOffset(imgtst);
> ++
> ++        // We want to check for errors outside the clip at a higher
> ++        // priority than errors involving different pixels touched
> ++        // inside the clip.
> ++
> ++        // Check above clip
> ++        if (check(ar, wasfill,
> ++                  null, 0, 0,
> ++                  datatst, scantst, offtst,
> ++                  0, 0, 40, 10))
> ++        {
> ++            return;
> ++        }
> ++        // Check below clip
> ++        if (check(ar, wasfill,
> ++                  null, 0, 0,
> ++                  datatst, scantst, offtst,
> ++                  0, 30, 40, 40))
> ++        {
> ++            return;
> ++        }
> ++        // Check left of clip
> ++        if (check(ar, wasfill,
> ++                  null, 0, 0,
> ++                  datatst, scantst, offtst,
> ++                  0, 10, 10, 30))
> ++        {
> ++            return;
> ++        }
> ++        // Check right of clip
> ++        if (check(ar, wasfill,
> ++                  null, 0, 0,
> ++                  datatst, scantst, offtst,
> ++                  30, 10, 40, 30))
> ++        {
> ++            return;
> ++        }
> ++        // Check inside clip
> ++        check(ar, wasfill,
> ++              dataref, scanref, offref,
> ++              datatst, scantst, offtst,
> ++              10, 10, 30, 30);
> ++    }
> ++
> ++    public static boolean check(AnnotatedRenderOp ar, boolean wasfill,
> ++                                int dataref[], int scanref, int offref,
> ++                                int datatst[], int scantst, int offtst,
> ++                                int x0, int y0, int x1, int y1)
> ++    {
> ++        offref += scanref * y0;
> ++        offtst += scantst * y0;
> ++        for (int y = y0; y < y1; y++) {
> ++            for (int x = x0; x < x1; x++) {
> ++                boolean failed;
> ++                String reason;
> ++                int rgbref;
> ++                int rgbtst;
> ++
> ++                rgbtst = datatst[offtst+x] | opaque;
> ++                if (dataref == null) {
> ++                    /* Outside of clip, must be white, no error tolerance */
> ++                    rgbref = whitergb;
> ++                    failed = (rgbtst != rgbref);
> ++                    reason = "stray pixel rendered outside of clip";
> ++                } else {
> ++                    /* Inside of clip, check for maxerr delta in components */
> ++                    rgbref = dataref[offref+x] | opaque;
> ++                    failed = (rgbref != rgbtst &&
> ++                              maxdiff(rgbref, rgbtst) > maxerr);
> ++                    reason = "different pixel rendered inside clip";
> ++                }
> ++                if (failed) {
> ++                    if (dataref == null) {
> ++                        numerrors++;
> ++                    }
> ++                    if (wasfill) {
> ++                        numfillfailures++;
> ++                    } else {
> ++                        numstrokefailures++;
> ++                    }
> ++                    if (!silent) {
> ++                        System.out.println("Failed: "+reason+" at "+x+", "+y+
> ++                                           " ["+Integer.toHexString(rgbref)+
> ++                                           " != "+Integer.toHexString(rgbtst)+
> ++                                           "]");
> ++                        System.out.print(wasfill ? "Filled " : "Stroked ");
> ++                        if (useAA) System.out.print("AA ");
> ++                        if (strokePure) System.out.print("Pure ");
> ++                        if (lw != 1) System.out.print("Lw="+lw+" ");
> ++                        if (rot != 0) System.out.print("Rot="+rot+" ");
> ++                        System.out.println(ar);
> ++                    }
> ++                    if (showErrors) {
> ++                        show(imgref, imgtst);
> ++                    }
> ++                    return true;
> ++                }
> ++            }
> ++            offref += scanref;
> ++            offtst += scantst;
> ++        }
> ++        return false;
> ++    }
> ++
> ++    static ErrorWindow errw;
> ++
> ++    public static void show(BufferedImage imgref, BufferedImage imgtst) {
> ++        ErrorWindow errw = new ErrorWindow();
> ++        errw.setImages(imgref, imgtst);
> ++        errw.setVisible(true);
> ++        errw.waitForHide();
> ++        errw.dispose();
> ++    }
> ++
> ++    public static class Cubic extends AnnotatedShapeOp {
> ++        public static Cubic tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("Cubic(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(6);
> ++            double coords[] = new double[8];
> ++            boolean foundparen = false;
> ++            for (int i = 0; i < coords.length; i++) {
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    if (i < coords.length-1) {
> ++                        return null;
> ++                    }
> ++                    index = str.indexOf(")");
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    foundparen = true;
> ++                }
> ++                String num = str.substring(0, index);
> ++                try {
> ++                    coords[i] = Double.parseDouble(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++            }
> ++            if (!foundparen || str.length() > 0) {
> ++                return null;
> ++            }
> ++            Cubic c = new Cubic();
> ++            c.cubic.setCurve(coords[0], coords[1],
> ++                             coords[2], coords[3],
> ++                             coords[4], coords[5],
> ++                             coords[6], coords[7]);
> ++            return c;
> ++        }
> ++
> ++        private CubicCurve2D cubic = new CubicCurve2D.Double();
> ++
> ++        public void randomize() {
> ++            cubic.setCurve(randDblCoord(), randDblCoord(),
> ++                           randDblCoord(), randDblCoord(),
> ++                           randDblCoord(), randDblCoord(),
> ++                           randDblCoord(), randDblCoord());
> ++        }
> ++
> ++        public Shape getShape() {
> ++            return cubic;
> ++        }
> ++
> ++        public String toString() {
> ++            return ("Cubic("+
> ++                    cubic.getX1()+", "+
> ++                    cubic.getY1()+", "+
> ++                    cubic.getCtrlX1()+", "+
> ++                    cubic.getCtrlY1()+", "+
> ++                    cubic.getCtrlX2()+", "+
> ++                    cubic.getCtrlY2()+", "+
> ++                    cubic.getX2()+", "+
> ++                    cubic.getY2()
> ++                    +")");
> ++        }
> ++    }
> ++
> ++    public static class Quad extends AnnotatedShapeOp {
> ++        public static Quad tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("Quad(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(5);
> ++            double coords[] = new double[6];
> ++            boolean foundparen = false;
> ++            for (int i = 0; i < coords.length; i++) {
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    if (i < coords.length-1) {
> ++                        return null;
> ++                    }
> ++                    index = str.indexOf(")");
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    foundparen = true;
> ++                }
> ++                String num = str.substring(0, index);
> ++                try {
> ++                    coords[i] = Double.parseDouble(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++            }
> ++            if (!foundparen || str.length() > 0) {
> ++                return null;
> ++            }
> ++            Quad c = new Quad();
> ++            c.quad.setCurve(coords[0], coords[1],
> ++                            coords[2], coords[3],
> ++                            coords[4], coords[5]);
> ++            return c;
> ++        }
> ++
> ++        private QuadCurve2D quad = new QuadCurve2D.Double();
> ++
> ++        public void randomize() {
> ++            quad.setCurve(randDblCoord(), randDblCoord(),
> ++                          randDblCoord(), randDblCoord(),
> ++                          randDblCoord(), randDblCoord());
> ++        }
> ++
> ++        public Shape getShape() {
> ++            return quad;
> ++        }
> ++
> ++        public String toString() {
> ++            return ("Quad("+
> ++                    quad.getX1()+", "+
> ++                    quad.getY1()+", "+
> ++                    quad.getCtrlX()+", "+
> ++                    quad.getCtrlY()+", "+
> ++                    quad.getX2()+", "+
> ++                    quad.getY2()
> ++                    +")");
> ++        }
> ++    }
> ++
> ++    public static class Poly extends AnnotatedShapeOp {
> ++        public static Poly tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("Poly(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(5);
> ++            Polygon p = new Polygon();
> ++            while (true) {
> ++                int x, y;
> ++                str = str.trim();
> ++                if (str.startsWith(")")) {
> ++                    str = str.substring(1);
> ++                    break;
> ++                }
> ++                if (p.npoints > 0) {
> ++                    if (str.startsWith(",")) {
> ++                        str = str.substring(2).trim();
> ++                    } else {
> ++                        return null;
> ++                    }
> ++                }
> ++                if (str.startsWith("[")) {
> ++                    str = str.substring(1);
> ++                } else {
> ++                    return null;
> ++                }
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    return null;
> ++                }
> ++                String num = str.substring(0, index);
> ++                try {
> ++                    x = Integer.parseInt(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++                index = str.indexOf("]");
> ++                if (index < 0) {
> ++                    return null;
> ++                }
> ++                num = str.substring(0, index).trim();
> ++                try {
> ++                    y = Integer.parseInt(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++                p.addPoint(x, y);
> ++            }
> ++            if (str.length() > 0) {
> ++                return null;
> ++            }
> ++            if (p.npoints < 3) {
> ++                return null;
> ++            }
> ++            return new Poly(p);
> ++        }
> ++
> ++        private Polygon poly;
> ++
> ++        public Poly() {
> ++            this.poly = new Polygon();
> ++        }
> ++
> ++        private Poly(Polygon p) {
> ++            this.poly = p;
> ++        }
> ++
> ++        public void randomize() {
> ++            poly.reset();
> ++            poly.addPoint(randIntCoord(), randIntCoord());
> ++            poly.addPoint(randIntCoord(), randIntCoord());
> ++            poly.addPoint(randIntCoord(), randIntCoord());
> ++            poly.addPoint(randIntCoord(), randIntCoord());
> ++            poly.addPoint(randIntCoord(), randIntCoord());
> ++        }
> ++
> ++        public Shape getShape() {
> ++            return poly;
> ++        }
> ++
> ++        public String toString() {
> ++            StringBuffer sb = new StringBuffer(100);
> ++            sb.append("Poly(");
> ++            for (int i = 0; i < poly.npoints; i++) {
> ++                if (i != 0) {
> ++                    sb.append(", ");
> ++                }
> ++                sb.append("[");
> ++                sb.append(poly.xpoints[i]);
> ++                sb.append(", ");
> ++                sb.append(poly.ypoints[i]);
> ++                sb.append("]");
> ++            }
> ++            sb.append(")");
> ++            return sb.toString();
> ++        }
> ++    }
> ++
> ++    public static class Path extends AnnotatedShapeOp {
> ++        public static Path tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("Path(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(5);
> ++            GeneralPath gp = new GeneralPath();
> ++            float coords[] = new float[6];
> ++            int numsegs = 0;
> ++            while (true) {
> ++                int type;
> ++                int n;
> ++                str = str.trim();
> ++                if (str.startsWith(")")) {
> ++                    str = str.substring(1);
> ++                    break;
> ++                }
> ++                if (str.startsWith("M[")) {
> ++                    type = PathIterator.SEG_MOVETO;
> ++                    n = 2;
> ++                } else if (str.startsWith("L[")) {
> ++                    type = PathIterator.SEG_LINETO;
> ++                    n = 2;
> ++                } else if (str.startsWith("Q[")) {
> ++                    type = PathIterator.SEG_QUADTO;
> ++                    n = 4;
> ++                } else if (str.startsWith("C[")) {
> ++                    type = PathIterator.SEG_CUBICTO;
> ++                    n = 6;
> ++                } else if (str.startsWith("E[")) {
> ++                    type = PathIterator.SEG_CLOSE;
> ++                    n = 0;
> ++                } else {
> ++                    return null;
> ++                }
> ++                str = str.substring(2);
> ++                if (n == 0) {
> ++                    if (str.startsWith("]")) {
> ++                        str = str.substring(1);
> ++                    } else {
> ++                        return null;
> ++                    }
> ++                }
> ++                for (int i = 0; i < n; i++) {
> ++                    int index;
> ++                    if (i < n-1) {
> ++                        index = str.indexOf(",");
> ++                    } else {
> ++                        index = str.indexOf("]");
> ++                    }
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    String num = str.substring(0, index);
> ++                    try {
> ++                        coords[i] = Float.parseFloat(num);
> ++                    } catch (NumberFormatException nfe) {
> ++                        return null;
> ++                    }
> ++                    str = str.substring(index+1).trim();
> ++                }
> ++                switch (type) {
> ++                case PathIterator.SEG_MOVETO:
> ++                    gp.moveTo(coords[0], coords[1]);
> ++                    break;
> ++                case PathIterator.SEG_LINETO:
> ++                    gp.lineTo(coords[0], coords[1]);
> ++                    break;
> ++                case PathIterator.SEG_QUADTO:
> ++                    gp.quadTo(coords[0], coords[1],
> ++                              coords[2], coords[3]);
> ++                    break;
> ++                case PathIterator.SEG_CUBICTO:
> ++                    gp.curveTo(coords[0], coords[1],
> ++                               coords[2], coords[3],
> ++                               coords[4], coords[5]);
> ++                    break;
> ++                case PathIterator.SEG_CLOSE:
> ++                    gp.closePath();
> ++                    break;
> ++                }
> ++                numsegs++;
> ++            }
> ++            if (str.length() > 0) {
> ++                return null;
> ++            }
> ++            if (numsegs < 2) {
> ++                return null;
> ++            }
> ++            return new Path(gp);
> ++        }
> ++
> ++        private GeneralPath path;
> ++
> ++        public Path() {
> ++            this.path = new GeneralPath();
> ++        }
> ++
> ++        private Path(GeneralPath gp) {
> ++            this.path = gp;
> ++        }
> ++
> ++        public void randomize() {
> ++            path.reset();
> ++            path.moveTo(randFltCoord(), randFltCoord());
> ++            for (int i = randInt(5)+3; i > 0; --i) {
> ++                switch(randInt(5)) {
> ++                case 0:
> ++                    path.moveTo(randFltCoord(), randFltCoord());
> ++                    break;
> ++                case 1:
> ++                    path.lineTo(randFltCoord(), randFltCoord());
> ++                    break;
> ++                case 2:
> ++                    path.quadTo(randFltCoord(), randFltCoord(),
> ++                                randFltCoord(), randFltCoord());
> ++                    break;
> ++                case 3:
> ++                    path.curveTo(randFltCoord(), randFltCoord(),
> ++                                 randFltCoord(), randFltCoord(),
> ++                                 randFltCoord(), randFltCoord());
> ++                    break;
> ++                case 4:
> ++                    path.closePath();
> ++                    break;
> ++                }
> ++            }
> ++        }
> ++
> ++        public Shape getShape() {
> ++            return path;
> ++        }
> ++
> ++        public String toString() {
> ++            StringBuffer sb = new StringBuffer(100);
> ++            sb.append("Path(");
> ++            PathIterator pi = path.getPathIterator(null);
> ++            float coords[] = new float[6];
> ++            boolean first = true;
> ++            while (!pi.isDone()) {
> ++                int n;
> ++                char c;
> ++                switch(pi.currentSegment(coords)) {
> ++                case PathIterator.SEG_MOVETO:
> ++                    c = 'M';
> ++                    n = 2;
> ++                    break;
> ++                case PathIterator.SEG_LINETO:
> ++                    c = 'L';
> ++                    n = 2;
> ++                    break;
> ++                case PathIterator.SEG_QUADTO:
> ++                    c = 'Q';
> ++                    n = 4;
> ++                    break;
> ++                case PathIterator.SEG_CUBICTO:
> ++                    c = 'C';
> ++                    n = 6;
> ++                    break;
> ++                case PathIterator.SEG_CLOSE:
> ++                    c = 'E';
> ++                    n = 0;
> ++                    break;
> ++                default:
> ++                    throw new InternalError("Unknown segment!");
> ++                }
> ++                sb.append(c);
> ++                sb.append("[");
> ++                for (int i = 0; i < n; i++) {
> ++                    if (i != 0) {
> ++                        sb.append(",");
> ++                    }
> ++                    sb.append(coords[i]);
> ++                }
> ++                sb.append("]");
> ++                pi.next();
> ++            }
> ++            sb.append(")");
> ++            return sb.toString();
> ++        }
> ++    }
> ++
> ++    public static class Rect extends AnnotatedShapeOp {
> ++        public static Rect tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("Rect(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(5);
> ++            double coords[] = new double[4];
> ++            boolean foundparen = false;
> ++            for (int i = 0; i < coords.length; i++) {
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    if (i < coords.length-1) {
> ++                        return null;
> ++                    }
> ++                    index = str.indexOf(")");
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    foundparen = true;
> ++                }
> ++                String num = str.substring(0, index);
> ++                try {
> ++                    coords[i] = Double.parseDouble(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++            }
> ++            if (!foundparen || str.length() > 0) {
> ++                return null;
> ++            }
> ++            Rect r = new Rect();
> ++            r.rect.setRect(coords[0], coords[1],
> ++                           coords[2], coords[3]);
> ++            return r;
> ++        }
> ++
> ++        private Rectangle2D rect = new Rectangle2D.Double();
> ++
> ++        public void randomize() {
> ++            rect.setRect(randDblCoord(), randDblCoord(),
> ++                         randDblCoord(), randDblCoord());
> ++        }
> ++
> ++        public Shape getShape() {
> ++            return rect;
> ++        }
> ++
> ++        public String toString() {
> ++            return ("Rect("+
> ++                    rect.getX()+", "+
> ++                    rect.getY()+", "+
> ++                    rect.getWidth()+", "+
> ++                    rect.getHeight()
> ++                    +")");
> ++        }
> ++    }
> ++
> ++    public static class Line extends AnnotatedShapeOp {
> ++        public static Line tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("Line(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(5);
> ++            double coords[] = new double[4];
> ++            boolean foundparen = false;
> ++            for (int i = 0; i < coords.length; i++) {
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    if (i < coords.length-1) {
> ++                        return null;
> ++                    }
> ++                    index = str.indexOf(")");
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    foundparen = true;
> ++                }
> ++                String num = str.substring(0, index);
> ++                try {
> ++                    coords[i] = Double.parseDouble(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++            }
> ++            if (!foundparen || str.length() > 0) {
> ++                return null;
> ++            }
> ++            Line l = new Line();
> ++            l.line.setLine(coords[0], coords[1],
> ++                           coords[2], coords[3]);
> ++            return l;
> ++        }
> ++
> ++        private Line2D line = new Line2D.Double();
> ++
> ++        public void randomize() {
> ++            line.setLine(randDblCoord(), randDblCoord(),
> ++                         randDblCoord(), randDblCoord());
> ++        }
> ++
> ++        public Shape getShape() {
> ++            return line;
> ++        }
> ++
> ++        public String toString() {
> ++            return ("Line("+
> ++                    line.getX1()+", "+
> ++                    line.getY1()+", "+
> ++                    line.getX2()+", "+
> ++                    line.getY2()
> ++                    +")");
> ++        }
> ++    }
> ++
> ++    public static class RectMethod extends AnnotatedRenderOp {
> ++        public static RectMethod tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("RectMethod(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(11);
> ++            int coords[] = new int[4];
> ++            boolean foundparen = false;
> ++            for (int i = 0; i < coords.length; i++) {
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    if (i < coords.length-1) {
> ++                        return null;
> ++                    }
> ++                    index = str.indexOf(")");
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    foundparen = true;
> ++                }
> ++                String num = str.substring(0, index).trim();
> ++                try {
> ++                    coords[i] = Integer.parseInt(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++            }
> ++            if (!foundparen || str.length() > 0) {
> ++                return null;
> ++            }
> ++            RectMethod rm = new RectMethod();
> ++            rm.rect.setBounds(coords[0], coords[1],
> ++                              coords[2], coords[3]);
> ++            return rm;
> ++        }
> ++
> ++        private Rectangle rect = new Rectangle();
> ++
> ++        public void randomize() {
> ++            rect.setBounds(randIntCoord(), randIntCoord(),
> ++                           randIntCoord(), randIntCoord());
> ++        }
> ++
> ++        public void fill(Graphics2D g2d) {
> ++            g2d.fillRect(rect.x, rect.y, rect.width, rect.height);
> ++        }
> ++
> ++        public void draw(Graphics2D g2d) {
> ++            g2d.drawRect(rect.x, rect.y, rect.width, rect.height);
> ++        }
> ++
> ++        public String toString() {
> ++            return ("RectMethod("+
> ++                    rect.x+", "+
> ++                    rect.y+", "+
> ++                    rect.width+", "+
> ++                    rect.height
> ++                    +")");
> ++        }
> ++    }
> ++
> ++    public static class LineMethod extends AnnotatedRenderOp {
> ++        public static LineMethod tryparse(String str) {
> ++            str = str.trim();
> ++            if (!str.startsWith("LineMethod(")) {
> ++                return null;
> ++            }
> ++            str = str.substring(11);
> ++            int coords[] = new int[4];
> ++            boolean foundparen = false;
> ++            for (int i = 0; i < coords.length; i++) {
> ++                int index = str.indexOf(",");
> ++                if (index < 0) {
> ++                    if (i < coords.length-1) {
> ++                        return null;
> ++                    }
> ++                    index = str.indexOf(")");
> ++                    if (index < 0) {
> ++                        return null;
> ++                    }
> ++                    foundparen = true;
> ++                }
> ++                String num = str.substring(0, index).trim();
> ++                try {
> ++                    coords[i] = Integer.parseInt(num);
> ++                } catch (NumberFormatException nfe) {
> ++                    return null;
> ++                }
> ++                str = str.substring(index+1);
> ++            }
> ++            if (!foundparen || str.length() > 0) {
> ++                return null;
> ++            }
> ++            LineMethod lm = new LineMethod();
> ++            lm.line = coords;
> ++            return lm;
> ++        }
> ++
> ++        private int line[] = new int[4];
> ++
> ++        public void randomize() {
> ++            line[0] = randIntCoord();
> ++            line[1] = randIntCoord();
> ++            line[2] = randIntCoord();
> ++            line[3] = randIntCoord();
> ++        }
> ++
> ++        public void fill(Graphics2D g2d) {
> ++        }
> ++
> ++        public void draw(Graphics2D g2d) {
> ++            g2d.drawLine(line[0], line[1], line[2], line[3]);
> ++        }
> ++
> ++        public String toString() {
> ++            return ("LineMethod("+
> ++                    line[0]+", "+
> ++                    line[1]+", "+
> ++                    line[2]+", "+
> ++                    line[3]
> ++                    +")");
> ++        }
> ++    }
> ++
> ++    public static class ErrorWindow extends Frame {
> ++        ImageCanvas unclipped;
> ++        ImageCanvas reference;
> ++        ImageCanvas actual;
> ++        ImageCanvas diff;
> ++
> ++        public ErrorWindow() {
> ++            super("Error Comparison Window");
> ++
> ++            unclipped = new ImageCanvas();
> ++            reference = new ImageCanvas();
> ++            actual = new ImageCanvas();
> ++            diff = new ImageCanvas();
> ++
> ++            setLayout(new SmartGridLayout(0, 2, 5, 5));
> ++            addImagePanel(unclipped, "Unclipped rendering");
> ++            addImagePanel(reference, "Clipped reference");
> ++            addImagePanel(actual, "Actual clipped");
> ++            addImagePanel(diff, "Difference");
> ++
> ++            addWindowListener(new WindowAdapter() {
> ++                public void windowClosing(WindowEvent e) {
> ++                    setVisible(false);
> ++                }
> ++            });
> ++        }
> ++
> ++        public void addImagePanel(ImageCanvas ic, String label) {
> ++            add(ic);
> ++            add(new Label(label));
> ++        }
> ++
> ++        public void setImages(BufferedImage imgref, BufferedImage imgtst) {
> ++            unclipped.setImage(imgref);
> ++            reference.setReference(imgref);
> ++            actual.setImage(imgtst);
> ++            diff.setDiff(reference.getImage(), imgtst);
> ++            invalidate();
> ++            pack();
> ++            repaint();
> ++        }
> ++
> ++        public void setVisible(boolean vis) {
> ++            super.setVisible(vis);
> ++            synchronized (this) {
> ++                notifyAll();
> ++            }
> ++        }
> ++
> ++        public synchronized void waitForHide() {
> ++            while (isShowing()) {
> ++                try {
> ++                    wait();
> ++                } catch (InterruptedException e) {
> ++                    System.exit(2);
> ++                }
> ++            }
> ++        }
> ++    }
> ++
> ++    public static class SmartGridLayout implements LayoutManager {
> ++        int rows;
> ++        int cols;
> ++        int hgap;
> ++        int vgap;
> ++
> ++        public SmartGridLayout(int r, int c, int h, int v) {
> ++            this.rows = r;
> ++            this.cols = c;
> ++            this.hgap = h;
> ++            this.vgap = v;
> ++        }
> ++
> ++        public void addLayoutComponent(String name, Component comp) {
> ++        }
> ++
> ++        public void removeLayoutComponent(Component comp) {
> ++        }
> ++
> ++        public int[][] getGridSizes(Container parent, boolean min) {
> ++            int ncomponents = parent.getComponentCount();
> ++            int nrows = rows;
> ++            int ncols = cols;
> ++
> ++            if (nrows > 0) {
> ++                ncols = (ncomponents + nrows - 1) / nrows;
> ++            } else {
> ++                nrows = (ncomponents + ncols - 1) / ncols;
> ++            }
> ++            int widths[] = new int[ncols+1];
> ++            int heights[] = new int[nrows+1];
> ++            int x = 0;
> ++            int y = 0;
> ++            for (int i = 0 ; i < ncomponents ; i++) {
> ++                Component comp = parent.getComponent(i);
> ++                Dimension d = (min
> ++                               ? comp.getMinimumSize()
> ++                               : comp.getPreferredSize());
> ++                if (widths[x] < d.width) {
> ++                    widths[x] = d.width;
> ++                }
> ++                if (heights[y] < d.height) {
> ++                    heights[y] = d.height;
> ++                }
> ++                x++;
> ++                if (x >= ncols) {
> ++                    x = 0;
> ++                    y++;
> ++                }
> ++            }
> ++            for (int i = 0; i < ncols; i++) {
> ++                widths[ncols] += widths[i];
> ++            }
> ++            for (int i = 0; i < nrows; i++) {
> ++                heights[nrows] += heights[i];
> ++            }
> ++            return new int[][] { widths, heights };
> ++        }
> ++
> ++        public Dimension getSize(Container parent, boolean min) {
> ++            int sizes[][] = getGridSizes(parent, min);
> ++            int widths[] = sizes[0];
> ++            int heights[] = sizes[1];
> ++            int nrows = heights.length-1;
> ++            int ncols = widths.length-1;
> ++            int w = widths[ncols];
> ++            int h = heights[nrows];
> ++            Insets insets = parent.getInsets();
> ++            return new Dimension(insets.left+insets.right + w+(ncols+1)*hgap,
> ++                                 insets.top+insets.bottom + h+(nrows+1)*vgap);
> ++        }
> ++
> ++        public Dimension preferredLayoutSize(Container parent) {
> ++            return getSize(parent, false);
> ++        }
> ++
> ++        public Dimension minimumLayoutSize(Container parent) {
> ++            return getSize(parent, true);
> ++        }
> ++
> ++        public void layoutContainer(Container parent) {
> ++            int pref[][] = getGridSizes(parent, false);
> ++            int min[][] = getGridSizes(parent, true);
> ++            int minwidths[] = min[0];
> ++            int minheights[] = min[1];
> ++            int prefwidths[] = pref[0];
> ++            int prefheights[] = pref[1];
> ++            int nrows = minheights.length - 1;
> ++            int ncols = minwidths.length - 1;
> ++            Insets insets = parent.getInsets();
> ++            int w = parent.getWidth() - insets.left - insets.right;
> ++            int h = parent.getHeight() - insets.top - insets.bottom;
> ++            w = w - (ncols+1)*hgap;
> ++            h = h - (nrows+1)*vgap;
> ++            int widths[] = calculateSizes(w, ncols, minwidths, prefwidths);
> ++            int heights[] = calculateSizes(h, nrows, minheights, prefheights);
> ++            int ncomponents = parent.getComponentCount();
> ++            int x = insets.left + hgap;
> ++            int y = insets.top + vgap;
> ++            int r = 0;
> ++            int c = 0;
> ++            for (int i = 0; i < ncomponents; i++) {
> ++                parent.getComponent(i).setBounds(x, y, widths[c], heights[r]);
> ++                x += widths[c++] + hgap;
> ++                if (c >= ncols) {
> ++                    c = 0;
> ++                    x = insets.left + hgap;
> ++                    y += heights[r++] + vgap;
> ++                    if (r >= nrows) {
> ++                        // just in case
> ++                        break;
> ++                    }
> ++                }
> ++            }
> ++        }
> ++
> ++        public static int[] calculateSizes(int total, int num,
> ++                                           int minsizes[], int prefsizes[])
> ++        {
> ++            if (total <= minsizes[num]) {
> ++                return minsizes;
> ++            }
> ++            if (total >= prefsizes[num]) {
> ++                return prefsizes;
> ++            }
> ++            int sizes[] = new int[total];
> ++            int prevhappy = 0;
> ++            int nhappy = 0;
> ++            int happysize = 0;
> ++            do {
> ++                int addsize = (total - happysize) / (num - nhappy);
> ++                happysize = 0;
> ++                for (int i = 0; i < num; i++) {
> ++                    if (sizes[i] >= prefsizes[i] ||
> ++                        minsizes[i] + addsize > prefsizes[i])
> ++                    {
> ++                        happysize += (sizes[i] = prefsizes[i]);
> ++                        nhappy++;
> ++                    } else {
> ++                        sizes[i] = minsizes[i] + addsize;
> ++                    }
> ++                }
> ++            } while (nhappy < num && nhappy > prevhappy);
> ++            return sizes;
> ++        }
> ++    }
> ++
> ++    public static class ImageCanvas extends Canvas {
> ++        BufferedImage image;
> ++
> ++        public void setImage(BufferedImage img) {
> ++            this.image = img;
> ++        }
> ++
> ++        public BufferedImage getImage() {
> ++            return image;
> ++        }
> ++
> ++        public void checkImage(int w, int h) {
> ++            if (image == null ||
> ++                image.getWidth() < w ||
> ++                image.getHeight() < h)
> ++            {
> ++                image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
> ++            }
> ++        }
> ++
> ++        public void setReference(BufferedImage img) {
> ++            checkImage(img.getWidth(), img.getHeight());
> ++            Graphics g = image.createGraphics();
> ++            g.drawImage(img, 0, 0, null);
> ++            g.setColor(Color.white);
> ++            g.fillRect(0, 0, 30, 10);
> ++            g.fillRect(30, 0, 10, 30);
> ++            g.fillRect(10, 30, 30, 10);
> ++            g.fillRect(0, 10, 10, 30);
> ++            g.dispose();
> ++        }
> ++
> ++        public void setDiff(BufferedImage imgref, BufferedImage imgtst) {
> ++            int w = Math.max(imgref.getWidth(), imgtst.getWidth());
> ++            int h = Math.max(imgref.getHeight(), imgtst.getHeight());
> ++            checkImage(w, h);
> ++            Graphics g = image.createGraphics();
> ++            g.drawImage(imgref, 0, 0, null);
> ++            g.setXORMode(Color.white);
> ++            g.drawImage(imgtst, 0, 0, null);
> ++            g.setPaintMode();
> ++            g.setColor(new Color(1f, 1f, 0f, 0.25f));
> ++            g.fillRect(10, 10, 20, 20);
> ++            g.setColor(new Color(1f, 0f, 0f, 0.25f));
> ++            g.fillRect(0, 0, 30, 10);
> ++            g.fillRect(30, 0, 10, 30);
> ++            g.fillRect(10, 30, 30, 10);
> ++            g.fillRect(0, 10, 10, 30);
> ++            g.dispose();
> ++        }
> ++
> ++        public Dimension getPreferredSize() {
> ++            if (image == null) {
> ++                return new Dimension();
> ++            } else {
> ++                return new Dimension(image.getWidth(), image.getHeight());
> ++            }
> ++        }
> ++
> ++        public void paint(Graphics g) {
> ++            g.drawImage(image, 0, 0, null);
> ++        }
> ++    }
> ++}
> diff -r e1a5ab4cf428 patches/openjdk/6775317-non-AA-simple-shape-performance.patch
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/patches/openjdk/6775317-non-AA-simple-shape-performance.patch	Tue Feb 22 19:04:38 2011 -0500
> @@ -0,0 +1,1697 @@
> +# HG changeset patch
> +# User flar
> +# Date 1291700748 28800
> +# Node ID 47cd69eff64122a14e1e1557bc0f6e00f66e9980
> +# Parent  1d4340015b85857a7f001fff4776307f576dc274
> +6775317: Improve performance of non-AA transformed rectangles and single wide lines in software pipelines
> +Reviewed-by: jgodinez, prr
> +
> +diff -r 1d4340015b85 -r 47cd69eff641 make/sun/awt/Depend.mak
> +--- openjdk.orig/jdk/make/sun/awt/Depend.mak	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/Depend.mak	Mon Dec 06 21:45:48 2010 -0800
> +@@ -18,11 +18,15 @@
> + J2D_SRC  = $(SUN_SRC)/java2d
> + J2D_FONT_SRC = $(SUN_SRC)/font
> + J2D_WINDOWS_SRC = $(WINDOWS_SRC)/native/sun/java2d
> ++AWT_WINDOWS_SRC = $(WINDOWS_SRC)/native/sun/awt
> + LOOP_SRC = $(SUN_SRC)/java2d/loops
> + PIPE_SRC = $(SUN_SRC)/java2d/pipe
> + WINDOWS_SRC = $(TOPDIR)/src/windows
> + SRC = $(WINDOWS_SRC)/native/sun/windows
> + 
> ++# ensure consistent sort order
> ++LC_ALL:= C
> ++
> + SRCDIRS = \
> + 	$(COMP_SRC) \
> + 	$(DEBUG_SRC) \
> +@@ -61,6 +65,7 @@
> + 	   -I$(J2D_WINDOWS_SRC)/windows \
> + 	   -I$(J2D_WINDOWS_SRC)/d3d \
> + 	   -I$(J2D_WINDOWS_SRC)/opengl \
> ++	   -I$(AWT_WINDOWS_SRC) \
> + 	   -I$(LOOP_SRC) \
> + 	   -I$(PIPE_SRC) \
> + 	   -I$(SRC)
> +@@ -68,22 +73,29 @@
> + STUBFILES = \
> + 	$(STUBDIR)/ddraw.h \
> + 	$(STUBDIR)/d3d.h \
> ++	$(STUBDIR)/d3d9.h \
> + 	$(STUBDIR)/Ole2.h \
> + 	$(STUBDIR)/Zmouse.h \
> + 	$(STUBDIR)/cderr.h \
> ++	$(STUBDIR)/comdef.h \
> + 	$(STUBDIR)/commctrl.h \
> + 	$(STUBDIR)/commdlg.h \
> ++	$(STUBDIR)/comutil.h \
> + 	$(STUBDIR)/direct.h \
> + 	$(STUBDIR)/d3dcom.h \
> + 	$(STUBDIR)/imm.h \
> + 	$(STUBDIR)/ime.h \
> + 	$(STUBDIR)/io.h \
> ++	$(STUBDIR)/map \
> + 	$(STUBDIR)/mmsystem.h \
> + 	$(STUBDIR)/new.h \
> ++	$(STUBDIR)/new \
> + 	$(STUBDIR)/ole2.h \
> ++	$(STUBDIR)/process.h \
> + 	$(STUBDIR)/richole.h \
> + 	$(STUBDIR)/richedit.h \
> + 	$(STUBDIR)/shellapi.h \
> ++	$(STUBDIR)/shlwapi.h \
> + 	$(STUBDIR)/shlobj.h \
> + 	$(STUBDIR)/tchar.h \
> + 	$(STUBDIR)/winbase.h \
> +@@ -135,6 +147,9 @@
> + include FILES_export_windows.gmk
> + 
> + EXTRAFILES_java = \
> ++        sun/java2d/opengl/OGLContext/OGLContextCaps.java \
> ++        sun/java2d/d3d/D3DPaints/MultiGradient.java \
> ++        sun/java2d/d3d/D3DContext/D3DContextCaps.java \
> + 	java/lang/Integer.java
> + 
> + FILES_java = $(FILES_export) $(FILES_export2) $(FILES_export3) \
> +diff -r 1d4340015b85 -r 47cd69eff641 make/sun/awt/FILES_c_unix.gmk
> +--- openjdk.orig/jdk/make/sun/awt/FILES_c_unix.gmk	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/FILES_c_unix.gmk	Mon Dec 06 21:45:48 2010 -0800
> +@@ -85,6 +85,8 @@
> + 	ScaledBlit.c \
> + 	FillRect.c \
> + 	FillSpans.c \
> ++	FillParallelogram.c \
> ++	DrawParallelogram.c \
> + 	DrawLine.c \
> + 	DrawRect.c \
> + 	DrawPolygons.c \
> +diff -r 1d4340015b85 -r 47cd69eff641 make/sun/awt/FILES_c_windows.gmk
> +--- openjdk.orig/jdk/make/sun/awt/FILES_c_windows.gmk	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/FILES_c_windows.gmk	Mon Dec 06 21:45:48 2010 -0800
> +@@ -30,6 +30,8 @@
> + 	ScaledBlit.c \
> + 	FillRect.c \
> + 	FillSpans.c \
> ++	FillParallelogram.c \
> ++	DrawParallelogram.c \
> + 	DrawLine.c \
> + 	DrawRect.c \
> + 	DrawPolygons.c \
> +diff -r 1d4340015b85 -r 47cd69eff641 make/sun/awt/FILES_export_unix.gmk
> +--- openjdk.orig/jdk/make/sun/awt/FILES_export_unix.gmk	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/FILES_export_unix.gmk	Mon Dec 06 21:45:48 2010 -0800
> +@@ -36,6 +36,8 @@
> + 	sun/java2d/loops/TransformBlit.java \
> + 	sun/java2d/loops/FillRect.java \
> + 	sun/java2d/loops/FillSpans.java \
> ++	sun/java2d/loops/FillParallelogram.java \
> ++	sun/java2d/loops/DrawParallelogram.java \
> +         sun/java2d/loops/DrawGlyphList.java \
> +         sun/java2d/loops/DrawGlyphListAA.java \
> +         sun/java2d/loops/DrawGlyphListLCD.java \
> +diff -r 1d4340015b85 -r 47cd69eff641 make/sun/awt/FILES_export_windows.gmk
> +--- openjdk.orig/jdk/make/sun/awt/FILES_export_windows.gmk	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/FILES_export_windows.gmk	Mon Dec 06 21:45:48 2010 -0800
> +@@ -135,6 +135,8 @@
> + 	sun/java2d/loops/ScaledBlit.java \
> + 	sun/java2d/loops/FillRect.java \
> + 	sun/java2d/loops/FillSpans.java \
> ++	sun/java2d/loops/FillParallelogram.java \
> ++	sun/java2d/loops/DrawParallelogram.java \
> +         sun/java2d/loops/DrawGlyphList.java \
> +         sun/java2d/loops/DrawGlyphListAA.java \
> +         sun/java2d/loops/DrawGlyphListLCD.java \
> +diff -r 1d4340015b85 -r 47cd69eff641 make/sun/awt/mapfile-vers
> +--- openjdk.orig/jdk/make/sun/awt/mapfile-vers	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/make/sun/awt/mapfile-vers	Mon Dec 06 21:45:48 2010 -0800
> +@@ -112,6 +112,8 @@
> + 		Java_sun_java2d_loops_DrawRect_DrawRect;
> + 		Java_sun_java2d_loops_FillRect_FillRect;
> + 		Java_sun_java2d_loops_FillSpans_FillSpans;
> ++		Java_sun_java2d_loops_FillParallelogram_FillParallelogram;
> ++		Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram;
> + 		Java_sun_java2d_loops_GraphicsPrimitiveMgr_initIDs;
> + 		Java_sun_java2d_loops_GraphicsPrimitiveMgr_registerNativeLoops;
> + 		Java_sun_java2d_loops_MaskBlit_MaskBlit;
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/classes/sun/java2d/SurfaceData.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/SurfaceData.java	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/SurfaceData.java	Mon Dec 06 21:45:48 2010 -0800
> +@@ -46,11 +46,15 @@
> + import sun.java2d.loops.DrawPath;
> + import sun.java2d.loops.FillPath;
> + import sun.java2d.loops.FillSpans;
> ++import sun.java2d.loops.FillParallelogram;
> ++import sun.java2d.loops.DrawParallelogram;
> + import sun.java2d.loops.FontInfo;
> + import sun.java2d.loops.DrawGlyphList;
> + import sun.java2d.loops.DrawGlyphListAA;
> + import sun.java2d.loops.DrawGlyphListLCD;
> + import sun.java2d.pipe.LoopPipe;
> ++import sun.java2d.pipe.ShapeDrawPipe;
> ++import sun.java2d.pipe.ParallelogramPipe;
> + import sun.java2d.pipe.CompositePipe;
> + import sun.java2d.pipe.GeneralCompositePipe;
> + import sun.java2d.pipe.SpanClipRenderer;
> +@@ -59,6 +63,7 @@
> + import sun.java2d.pipe.AlphaPaintPipe;
> + import sun.java2d.pipe.AlphaColorPipe;
> + import sun.java2d.pipe.PixelToShapeConverter;
> ++import sun.java2d.pipe.PixelToParallelogramConverter;
> + import sun.java2d.pipe.TextPipe;
> + import sun.java2d.pipe.TextRenderer;
> + import sun.java2d.pipe.AATextRenderer;
> +@@ -364,6 +369,7 @@
> + 
> +     protected static final CompositePipe colorPipe;
> +     protected static final PixelToShapeConverter colorViaShape;
> ++    protected static final PixelToParallelogramConverter colorViaPgram;
> +     protected static final TextPipe colorText;
> +     protected static final CompositePipe clipColorPipe;
> +     protected static final TextPipe clipColorText;
> +@@ -396,6 +402,31 @@
> + 
> +     protected static final DrawImagePipe imagepipe;
> + 
> ++    // Utility subclass to add the LoopBasedPipe tagging interface
> ++    static class PixelToShapeLoopConverter
> ++        extends PixelToShapeConverter
> ++        implements LoopBasedPipe
> ++    {
> ++        public PixelToShapeLoopConverter(ShapeDrawPipe pipe) {
> ++            super(pipe);
> ++        }
> ++    }
> ++
> ++    // Utility subclass to add the LoopBasedPipe tagging interface
> ++    static class PixelToPgramLoopConverter
> ++        extends PixelToParallelogramConverter
> ++        implements LoopBasedPipe
> ++    {
> ++        public PixelToPgramLoopConverter(ShapeDrawPipe shapepipe,
> ++                                         ParallelogramPipe pgrampipe,
> ++                                         double minPenSize,
> ++                                         double normPosition,
> ++                                         boolean adjustfill)
> ++        {
> ++            super(shapepipe, pgrampipe, minPenSize, normPosition, adjustfill);
> ++        }
> ++    }
> ++
> +     static {
> +         colorPrimitives = new LoopPipe();
> + 
> +@@ -406,7 +437,10 @@
> + 
> +         colorPipe = new AlphaColorPipe();
> +         // colorShape = colorPrimitives;
> +-        colorViaShape = new PixelToShapeConverter(colorPrimitives);
> ++        colorViaShape = new PixelToShapeLoopConverter(colorPrimitives);
> ++        colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives,
> ++                                                      colorPrimitives,
> ++                                                      1.0, 0.25, true);
> +         colorText = new TextRenderer(colorPipe);
> +         clipColorPipe = new SpanClipRenderer(colorPipe);
> +         clipColorText = new TextRenderer(clipColorPipe);
> +@@ -441,10 +475,12 @@
> +     }
> + 
> +     /* Not all surfaces and rendering mode combinations support LCD text. */
> +-    static final int LCDLOOP_UNKNOWN = 0;
> +-    static final int LCDLOOP_FOUND = 1;
> +-    static final int LCDLOOP_NOTFOUND = 2;
> ++    static final int LOOP_UNKNOWN = 0;
> ++    static final int LOOP_FOUND = 1;
> ++    static final int LOOP_NOTFOUND = 2;
> +     int haveLCDLoop;
> ++    int havePgramXORLoop;
> ++    int havePgramSolidLoop;
> + 
> +     public boolean canRenderLCDText(SunGraphics2D sg2d) {
> +         // For now the answer can only be true in the following cases:
> +@@ -453,18 +489,48 @@
> +             sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR &&
> +             sg2d.surfaceData.getTransparency() == Transparency.OPAQUE)
> +         {
> +-            if (haveLCDLoop == LCDLOOP_UNKNOWN) {
> ++            if (haveLCDLoop == LOOP_UNKNOWN) {
> +                 DrawGlyphListLCD loop =
> +                     DrawGlyphListLCD.locate(SurfaceType.AnyColor,
> +                                             CompositeType.SrcNoEa,
> +                                             getSurfaceType());
> +-                haveLCDLoop = (loop!= null) ? LCDLOOP_FOUND : LCDLOOP_NOTFOUND;
> ++                haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;
> +             }
> +-            return haveLCDLoop == LCDLOOP_FOUND;
> ++            return haveLCDLoop == LOOP_FOUND;
> +         }
> +         return false; /* for now - in the future we may want to search */
> +     }
> + 
> ++    public boolean canRenderParallelograms(SunGraphics2D sg2d) {
> ++        if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR) {
> ++            if (sg2d.compositeState == sg2d.COMP_XOR) {
> ++                if (havePgramXORLoop == LOOP_UNKNOWN) {
> ++                    FillParallelogram loop =
> ++                        FillParallelogram.locate(SurfaceType.AnyColor,
> ++                                                 CompositeType.Xor,
> ++                                                 getSurfaceType());
> ++                    havePgramXORLoop =
> ++                        (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;
> ++                }
> ++                return havePgramXORLoop == LOOP_FOUND;
> ++            } else if (sg2d.compositeState <= sg2d.COMP_ISCOPY &&
> ++                       sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
> ++                       sg2d.clipState != sg2d.CLIP_SHAPE)
> ++            {
> ++                if (havePgramSolidLoop == LOOP_UNKNOWN) {
> ++                    FillParallelogram loop =
> ++                        FillParallelogram.locate(SurfaceType.AnyColor,
> ++                                                 CompositeType.SrcNoEa,
> ++                                                 getSurfaceType());
> ++                    havePgramSolidLoop =
> ++                        (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;
> ++                }
> ++                return havePgramSolidLoop == LOOP_FOUND;
> ++            }
> ++        }
> ++        return false;
> ++    }
> ++
> +     public void validatePipe(SunGraphics2D sg2d) {
> +         sg2d.imagepipe = imagepipe;
> +         if (sg2d.compositeState == sg2d.COMP_XOR) {
> +@@ -480,9 +546,21 @@
> +                 // text drawn in XOR mode with a Paint object.
> +                 sg2d.textpipe = outlineTextRenderer;
> +             } else {
> ++                PixelToShapeConverter converter;
> ++                if (canRenderParallelograms(sg2d)) {
> ++                    converter = colorViaPgram;
> ++                    // Note that we use the transforming pipe here because it
> ++                    // will examine the shape and possibly perform an optimized
> ++                    // operation if it can be simplified.  The simplifications
> ++                    // will be valid for all STROKE and TRANSFORM types.
> ++                    sg2d.shapepipe = colorViaPgram;
> ++                } else {
> ++                    converter = colorViaShape;
> ++                    sg2d.shapepipe = colorPrimitives;
> ++                }
> +                 if (sg2d.clipState == sg2d.CLIP_SHAPE) {
> +-                    sg2d.drawpipe = colorViaShape;
> +-                    sg2d.fillpipe = colorViaShape;
> ++                    sg2d.drawpipe = converter;
> ++                    sg2d.fillpipe = converter;
> +                     // REMIND: We should not be changing text strategies
> +                     // between outline and glyph rendering based upon the
> +                     // presence of a complex clip as that could cause a
> +@@ -494,11 +572,11 @@
> +                     sg2d.textpipe = outlineTextRenderer;
> +                 } else {
> +                     if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
> +-                        sg2d.drawpipe = colorViaShape;
> +-                        sg2d.fillpipe = colorViaShape;
> ++                        sg2d.drawpipe = converter;
> ++                        sg2d.fillpipe = converter;
> +                     } else {
> +                         if (sg2d.strokeState != sg2d.STROKE_THIN) {
> +-                            sg2d.drawpipe = colorViaShape;
> ++                            sg2d.drawpipe = converter;
> +                         } else {
> +                             sg2d.drawpipe = colorPrimitives;
> +                         }
> +@@ -506,7 +584,6 @@
> +                     }
> +                     sg2d.textpipe = solidTextRenderer;
> +                 }
> +-                sg2d.shapepipe = colorPrimitives;
> +                 // assert(sg2d.surfaceData == this);
> +             }
> +         } else if (sg2d.compositeState == sg2d.COMP_CUSTOM) {
> +@@ -589,12 +666,24 @@
> +                 }
> +             }
> +         } else {
> ++            PixelToShapeConverter converter;
> ++            if (canRenderParallelograms(sg2d)) {
> ++                converter = colorViaPgram;
> ++                // Note that we use the transforming pipe here because it
> ++                // will examine the shape and possibly perform an optimized
> ++                // operation if it can be simplified.  The simplifications
> ++                // will be valid for all STROKE and TRANSFORM types.
> ++                sg2d.shapepipe = colorViaPgram;
> ++            } else {
> ++                converter = colorViaShape;
> ++                sg2d.shapepipe = colorPrimitives;
> ++            }
> +             if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
> +-                sg2d.drawpipe = colorViaShape;
> +-                sg2d.fillpipe = colorViaShape;
> ++                sg2d.drawpipe = converter;
> ++                sg2d.fillpipe = converter;
> +             } else {
> +                 if (sg2d.strokeState != sg2d.STROKE_THIN) {
> +-                    sg2d.drawpipe = colorViaShape;
> ++                    sg2d.drawpipe = converter;
> +                 } else {
> +                     sg2d.drawpipe = colorPrimitives;
> +                 }
> +@@ -602,7 +691,6 @@
> +             }
> + 
> +             sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */);
> +-            sg2d.shapepipe = colorPrimitives;
> +             // assert(sg2d.surfaceData == this);
> +         }
> + 
> +@@ -761,6 +849,8 @@
> +         loops.drawPathLoop = DrawPath.locate(src, comp, dst);
> +         loops.fillPathLoop = FillPath.locate(src, comp, dst);
> +         loops.fillSpansLoop = FillSpans.locate(src, comp, dst);
> ++        loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst);
> ++        loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst);
> +         loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst);
> +         loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst);
> +         loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst);
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/classes/sun/java2d/loops/DrawParallelogram.java
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/src/share/classes/sun/java2d/loops/DrawParallelogram.java	Mon Dec 06 21:45:48 2010 -0800
> +@@ -0,0 +1,123 @@
> ++/*
> ++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
> ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> ++ *
> ++ * This code is free software; you can redistribute it and/or modify it
> ++ * under the terms of the GNU General Public License version 2 only, as
> ++ * published by the Free Software Foundation.  Oracle designates this
> ++ * particular file as subject to the "Classpath" exception as provided
> ++ * by Oracle in the LICENSE file that accompanied this code.
> ++ *
> ++ * This code is distributed in the hope that it will be useful, but WITHOUT
> ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> ++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> ++ * version 2 for more details (a copy is included in the LICENSE file that
> ++ * accompanied this code).
> ++ *
> ++ * You should have received a copy of the GNU General Public License version
> ++ * 2 along with this work; if not, write to the Free Software Foundation,
> ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> ++ *
> ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> ++ * or visit www.oracle.com if you need additional information or have any
> ++ * questions.
> ++ */
> ++
> ++/*
> ++ * @author Jim Graham
> ++ */
> ++
> ++package sun.java2d.loops;
> ++
> ++import sun.java2d.loops.GraphicsPrimitive;
> ++import sun.java2d.SunGraphics2D;
> ++import sun.java2d.SurfaceData;
> ++
> ++/**
> ++ * DrawParallelogram
> ++ * 1) fill the area between the 4 edges of an outer parallelogram
> ++ *    (as specified by an origin and 2 delta vectors)
> ++ *    but also outside the 4 edges of an inner parallelogram
> ++ *    (as specified by proportional amounts of the outer delta vectors)
> ++ */
> ++public class DrawParallelogram extends GraphicsPrimitive
> ++{
> ++    public final static String methodSignature =
> ++        "DrawParallelogram(...)".toString();
> ++
> ++    public final static int primTypeID = makePrimTypeID();
> ++
> ++    public static DrawParallelogram locate(SurfaceType srctype,
> ++                                           CompositeType comptype,
> ++                                           SurfaceType dsttype)
> ++    {
> ++        return (DrawParallelogram)
> ++            GraphicsPrimitiveMgr.locate(primTypeID,
> ++                                        srctype, comptype, dsttype);
> ++    }
> ++
> ++    protected DrawParallelogram(SurfaceType srctype,
> ++                                CompositeType comptype,
> ++                                SurfaceType dsttype)
> ++    {
> ++        super(methodSignature, primTypeID,
> ++              srctype, comptype, dsttype);
> ++    }
> ++
> ++    public DrawParallelogram(long pNativePrim,
> ++                             SurfaceType srctype,
> ++                             CompositeType comptype,
> ++                             SurfaceType dsttype)
> ++    {
> ++        super(pNativePrim, methodSignature, primTypeID,
> ++              srctype, comptype, dsttype);
> ++    }
> ++
> ++    /**
> ++     * All DrawParallelogram implementors must have this invoker method
> ++     */
> ++    public native void DrawParallelogram(SunGraphics2D sg, SurfaceData dest,
> ++                                         double x, double y,
> ++                                         double dx1, double dy1,
> ++                                         double dx2, double dy2,
> ++                                         double lw1, double lw2);
> ++
> ++    public GraphicsPrimitive makePrimitive(SurfaceType srctype,
> ++                                           CompositeType comptype,
> ++                                           SurfaceType dsttype)
> ++    {
> ++        // REMIND: iterate with a FillRect primitive?
> ++        throw new InternalError("DrawParallelogram not implemented for "+
> ++                                srctype+" with "+comptype);
> ++    }
> ++
> ++    public GraphicsPrimitive traceWrap() {
> ++        return new TraceDrawParallelogram(this);
> ++    }
> ++
> ++    private static class TraceDrawParallelogram extends DrawParallelogram {
> ++        DrawParallelogram target;
> ++
> ++        public TraceDrawParallelogram(DrawParallelogram target) {
> ++            super(target.getSourceType(),
> ++                  target.getCompositeType(),
> ++                  target.getDestType());
> ++            this.target = target;
> ++        }
> ++
> ++        public GraphicsPrimitive traceWrap() {
> ++            return this;
> ++        }
> ++
> ++        public void DrawParallelogram(SunGraphics2D sg2d, SurfaceData dest,
> ++                                      double x, double y,
> ++                                      double dx1, double dy1,
> ++                                      double dx2, double dy2,
> ++                                      double lw1, double lw2)
> ++        {
> ++            tracePrimitive(target);
> ++            target.DrawParallelogram(sg2d, dest,
> ++                                     x, y, dx1, dy1, dx2, dy2, lw1, lw2);
> ++        }
> ++    }
> ++}
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/classes/sun/java2d/loops/FillParallelogram.java
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/src/share/classes/sun/java2d/loops/FillParallelogram.java	Mon Dec 06 21:45:48 2010 -0800
> +@@ -0,0 +1,118 @@
> ++/*
> ++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
> ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> ++ *
> ++ * This code is free software; you can redistribute it and/or modify it
> ++ * under the terms of the GNU General Public License version 2 only, as
> ++ * published by the Free Software Foundation.  Oracle designates this
> ++ * particular file as subject to the "Classpath" exception as provided
> ++ * by Oracle in the LICENSE file that accompanied this code.
> ++ *
> ++ * This code is distributed in the hope that it will be useful, but WITHOUT
> ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> ++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> ++ * version 2 for more details (a copy is included in the LICENSE file that
> ++ * accompanied this code).
> ++ *
> ++ * You should have received a copy of the GNU General Public License version
> ++ * 2 along with this work; if not, write to the Free Software Foundation,
> ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> ++ *
> ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> ++ * or visit www.oracle.com if you need additional information or have any
> ++ * questions.
> ++ */
> ++
> ++/*
> ++ * @author Jim Graham
> ++ */
> ++
> ++package sun.java2d.loops;
> ++
> ++import sun.java2d.loops.GraphicsPrimitive;
> ++import sun.java2d.SunGraphics2D;
> ++import sun.java2d.SurfaceData;
> ++
> ++/**
> ++ * FillParallelogram
> ++ * 1) fill the area between the 4 edges of a parallelogram
> ++ *    (as specified by an origin and 2 delta vectors)
> ++ */
> ++public class FillParallelogram extends GraphicsPrimitive
> ++{
> ++    public final static String methodSignature =
> ++        "FillParallelogram(...)".toString();
> ++
> ++    public final static int primTypeID = makePrimTypeID();
> ++
> ++    public static FillParallelogram locate(SurfaceType srctype,
> ++                                           CompositeType comptype,
> ++                                           SurfaceType dsttype)
> ++    {
> ++        return (FillParallelogram)
> ++            GraphicsPrimitiveMgr.locate(primTypeID,
> ++                                        srctype, comptype, dsttype);
> ++    }
> ++
> ++    protected FillParallelogram(SurfaceType srctype,
> ++                                CompositeType comptype,
> ++                                SurfaceType dsttype)
> ++    {
> ++        super(methodSignature, primTypeID,
> ++              srctype, comptype, dsttype);
> ++    }
> ++
> ++    public FillParallelogram(long pNativePrim,
> ++                             SurfaceType srctype,
> ++                             CompositeType comptype,
> ++                             SurfaceType dsttype)
> ++    {
> ++        super(pNativePrim, methodSignature, primTypeID,
> ++              srctype, comptype, dsttype);
> ++    }
> ++
> ++    /**
> ++     * All FillParallelogram implementors must have this invoker method
> ++     */
> ++    public native void FillParallelogram(SunGraphics2D sg2d, SurfaceData dest,
> ++                                         double x0, double y0,
> ++                                         double dx1, double dy1,
> ++                                         double dx2, double dy2);
> ++
> ++    public GraphicsPrimitive makePrimitive(SurfaceType srctype,
> ++                                           CompositeType comptype,
> ++                                           SurfaceType dsttype)
> ++    {
> ++        // REMIND: iterate with a FillRect primitive?
> ++        throw new InternalError("FillParallelogram not implemented for "+
> ++                                srctype+" with "+comptype);
> ++    }
> ++
> ++    public GraphicsPrimitive traceWrap() {
> ++        return new TraceFillParallelogram(this);
> ++    }
> ++
> ++    private static class TraceFillParallelogram extends FillParallelogram {
> ++        FillParallelogram target;
> ++
> ++        public TraceFillParallelogram(FillParallelogram target) {
> ++            super(target.getSourceType(),
> ++                  target.getCompositeType(),
> ++                  target.getDestType());
> ++            this.target = target;
> ++        }
> ++
> ++        public GraphicsPrimitive traceWrap() {
> ++            return this;
> ++        }
> ++
> ++        public void FillParallelogram(SunGraphics2D sg2d, SurfaceData dest,
> ++                                      double x0, double y0,
> ++                                      double dx1, double dy1,
> ++                                      double dx2, double dy2)
> ++        {
> ++            tracePrimitive(target);
> ++            target.FillParallelogram(sg2d, dest, x0, y0, dx1, dy1, dx2, dy2);
> ++        }
> ++    }
> ++}
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/classes/sun/java2d/loops/RenderLoops.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/loops/RenderLoops.java	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/loops/RenderLoops.java	Mon Dec 06 21:45:48 2010 -0800
> +@@ -47,6 +47,8 @@
> +     public DrawPath             drawPathLoop;
> +     public FillPath             fillPathLoop;
> +     public FillSpans            fillSpansLoop;
> ++    public FillParallelogram    fillParallelogramLoop;
> ++    public DrawParallelogram    drawParallelogramLoop;
> +     public DrawGlyphList        drawGlyphListLoop;
> +     public DrawGlyphListAA      drawGlyphListAALoop;
> +     public DrawGlyphListLCD     drawGlyphListLCDLoop;
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/classes/sun/java2d/pipe/LoopPipe.java
> +--- openjdk.orig/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java	Mon Dec 06 21:45:48 2010 -0800
> +@@ -41,11 +41,14 @@
> + import sun.java2d.SurfaceData;
> + import sun.java2d.loops.FontInfo;
> + import sun.java2d.loops.DrawPolygons;
> ++import sun.java2d.loops.FillParallelogram;
> ++import sun.java2d.loops.DrawParallelogram;
> + import sun.awt.SunHints;
> + 
> + public class LoopPipe
> +     implements PixelDrawPipe,
> +                PixelFillPipe,
> ++               ParallelogramPipe,
> +                ShapeDrawPipe,
> +                LoopBasedPipe
> + {
> +@@ -347,4 +350,25 @@
> +             sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h);
> +         }
> +     }
> ++
> ++    public void fillParallelogram(SunGraphics2D sg2d,
> ++                                  double x, double y,
> ++                                  double dx1, double dy1,
> ++                                  double dx2, double dy2)
> ++    {
> ++        FillParallelogram fp = sg2d.loops.fillParallelogramLoop;
> ++        fp.FillParallelogram(sg2d, sg2d.getSurfaceData(),
> ++                             x, y, dx1, dy1, dx2, dy2);
> ++    }
> ++
> ++    public void drawParallelogram(SunGraphics2D sg2d,
> ++                                  double x, double y,
> ++                                  double dx1, double dy1,
> ++                                  double dx2, double dy2,
> ++                                  double lw1, double lw2)
> ++    {
> ++        DrawParallelogram dp = sg2d.loops.drawParallelogramLoop;
> ++        dp.DrawParallelogram(sg2d, sg2d.getSurfaceData(),
> ++                             x, y, dx1, dy1, dx2, dy2, lw1, lw2);
> ++    }
> + }
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/Any3Byte.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/Any3Byte.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/Any3Byte.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -38,6 +38,7 @@
> + 
> + DECLARE_SOLID_FILLRECT(Any3Byte);
> + DECLARE_SOLID_FILLSPANS(Any3Byte);
> ++DECLARE_SOLID_PARALLELOGRAM(Any3Byte);
> + DECLARE_SOLID_DRAWLINE(Any3Byte);
> + DECLARE_XOR_FILLRECT(Any3Byte);
> + DECLARE_XOR_FILLSPANS(Any3Byte);
> +@@ -48,6 +49,7 @@
> + NativePrimitive Any3BytePrimitives[] = {
> +     REGISTER_SOLID_FILLRECT(Any3Byte),
> +     REGISTER_SOLID_FILLSPANS(Any3Byte),
> ++    REGISTER_SOLID_PARALLELOGRAM(Any3Byte),
> +     REGISTER_SOLID_LINE_PRIMITIVES(Any3Byte),
> +     REGISTER_XOR_FILLRECT(Any3Byte),
> +     REGISTER_XOR_FILLSPANS(Any3Byte),
> +@@ -72,6 +74,8 @@
> + 
> + DEFINE_SOLID_FILLSPANS(Any3Byte)
> + 
> ++DEFINE_SOLID_PARALLELOGRAM(Any3Byte)
> ++
> + DEFINE_SOLID_DRAWLINE(Any3Byte)
> + 
> + DEFINE_XOR_FILLRECT(Any3Byte)
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/Any4Byte.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/Any4Byte.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/Any4Byte.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -41,6 +41,7 @@
> + 
> + DECLARE_SOLID_FILLRECT(Any4Byte);
> + DECLARE_SOLID_FILLSPANS(Any4Byte);
> ++DECLARE_SOLID_PARALLELOGRAM(Any4Byte);
> + DECLARE_SOLID_DRAWLINE(Any4Byte);
> + DECLARE_XOR_FILLRECT(Any4Byte);
> + DECLARE_XOR_FILLSPANS(Any4Byte);
> +@@ -51,6 +52,7 @@
> + NativePrimitive Any4BytePrimitives[] = {
> +     REGISTER_SOLID_FILLRECT(Any4Byte),
> +     REGISTER_SOLID_FILLSPANS(Any4Byte),
> ++    REGISTER_SOLID_PARALLELOGRAM(Any4Byte),
> +     REGISTER_SOLID_LINE_PRIMITIVES(Any4Byte),
> +     REGISTER_XOR_FILLRECT(Any4Byte),
> +     REGISTER_XOR_FILLSPANS(Any4Byte),
> +@@ -75,6 +77,8 @@
> + 
> + DEFINE_SOLID_FILLSPANS(Any4Byte)
> + 
> ++DEFINE_SOLID_PARALLELOGRAM(Any4Byte)
> ++
> + DEFINE_SOLID_DRAWLINE(Any4Byte)
> + 
> + DEFINE_XOR_FILLRECT(Any4Byte)
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/AnyByte.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/AnyByte.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/AnyByte.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -38,6 +38,7 @@
> + 
> + DECLARE_SOLID_FILLRECT(AnyByte);
> + DECLARE_SOLID_FILLSPANS(AnyByte);
> ++DECLARE_SOLID_PARALLELOGRAM(AnyByte);
> + DECLARE_SOLID_DRAWLINE(AnyByte);
> + DECLARE_XOR_FILLRECT(AnyByte);
> + DECLARE_XOR_FILLSPANS(AnyByte);
> +@@ -48,6 +49,7 @@
> + NativePrimitive AnyBytePrimitives[] = {
> +     REGISTER_SOLID_FILLRECT(AnyByte),
> +     REGISTER_SOLID_FILLSPANS(AnyByte),
> ++    REGISTER_SOLID_PARALLELOGRAM(AnyByte),
> +     REGISTER_SOLID_LINE_PRIMITIVES(AnyByte),
> +     REGISTER_XOR_FILLRECT(AnyByte),
> +     REGISTER_XOR_FILLSPANS(AnyByte),
> +@@ -72,6 +74,8 @@
> + 
> + DEFINE_SOLID_FILLSPANS(AnyByte)
> + 
> ++DEFINE_SOLID_PARALLELOGRAM(AnyByte)
> ++
> + DEFINE_SOLID_DRAWLINE(AnyByte)
> + 
> + DEFINE_XOR_FILLRECT(AnyByte)
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/AnyInt.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/AnyInt.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/AnyInt.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -38,6 +38,7 @@
> + 
> + DECLARE_SOLID_FILLRECT(AnyInt);
> + DECLARE_SOLID_FILLSPANS(AnyInt);
> ++DECLARE_SOLID_PARALLELOGRAM(AnyInt);
> + DECLARE_SOLID_DRAWLINE(AnyInt);
> + DECLARE_XOR_FILLRECT(AnyInt);
> + DECLARE_XOR_FILLSPANS(AnyInt);
> +@@ -48,6 +49,7 @@
> + NativePrimitive AnyIntPrimitives[] = {
> +     REGISTER_SOLID_FILLRECT(AnyInt),
> +     REGISTER_SOLID_FILLSPANS(AnyInt),
> ++    REGISTER_SOLID_PARALLELOGRAM(AnyInt),
> +     REGISTER_SOLID_LINE_PRIMITIVES(AnyInt),
> +     REGISTER_XOR_FILLRECT(AnyInt),
> +     REGISTER_XOR_FILLSPANS(AnyInt),
> +@@ -72,6 +74,8 @@
> + 
> + DEFINE_SOLID_FILLSPANS(AnyInt)
> + 
> ++DEFINE_SOLID_PARALLELOGRAM(AnyInt)
> ++
> + DEFINE_SOLID_DRAWLINE(AnyInt)
> + 
> + DEFINE_XOR_FILLRECT(AnyInt)
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/AnyShort.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/AnyShort.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/AnyShort.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -38,6 +38,7 @@
> + 
> + DECLARE_SOLID_FILLRECT(AnyShort);
> + DECLARE_SOLID_FILLSPANS(AnyShort);
> ++DECLARE_SOLID_PARALLELOGRAM(AnyShort);
> + DECLARE_SOLID_DRAWLINE(AnyShort);
> + DECLARE_XOR_FILLRECT(AnyShort);
> + DECLARE_XOR_FILLSPANS(AnyShort);
> +@@ -48,6 +49,7 @@
> + NativePrimitive AnyShortPrimitives[] = {
> +     REGISTER_SOLID_FILLRECT(AnyShort),
> +     REGISTER_SOLID_FILLSPANS(AnyShort),
> ++    REGISTER_SOLID_PARALLELOGRAM(AnyShort),
> +     REGISTER_SOLID_LINE_PRIMITIVES(AnyShort),
> +     REGISTER_XOR_FILLRECT(AnyShort),
> +     REGISTER_XOR_FILLSPANS(AnyShort),
> +@@ -72,6 +74,8 @@
> + 
> + DEFINE_SOLID_FILLSPANS(AnyShort)
> + 
> ++DEFINE_SOLID_PARALLELOGRAM(AnyShort)
> ++
> + DEFINE_SOLID_DRAWLINE(AnyShort)
> + 
> + DEFINE_XOR_FILLRECT(AnyShort)
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/DrawParallelogram.c
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/DrawParallelogram.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -0,0 +1,341 @@
> ++/*
> ++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
> ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> ++ *
> ++ * This code is free software; you can redistribute it and/or modify it
> ++ * under the terms of the GNU General Public License version 2 only, as
> ++ * published by the Free Software Foundation.  Oracle designates this
> ++ * particular file as subject to the "Classpath" exception as provided
> ++ * by Oracle in the LICENSE file that accompanied this code.
> ++ *
> ++ * This code is distributed in the hope that it will be useful, but WITHOUT
> ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> ++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> ++ * version 2 for more details (a copy is included in the LICENSE file that
> ++ * accompanied this code).
> ++ *
> ++ * You should have received a copy of the GNU General Public License version
> ++ * 2 along with this work; if not, write to the Free Software Foundation,
> ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> ++ *
> ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> ++ * or visit www.oracle.com if you need additional information or have any
> ++ * questions.
> ++ */
> ++
> ++#include "math.h"
> ++#include "GraphicsPrimitiveMgr.h"
> ++#include "LineUtils.h"
> ++#include "LoopMacros.h"
> ++#include "Trace.h"
> ++
> ++#include "sun_java2d_loops_FillParallelogram.h"
> ++#include "sun_java2d_loops_DrawParallelogram.h"
> ++
> ++DECLARE_SOLID_DRAWLINE(AnyInt);
> ++
> ++#define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \
> ++                          pRasInfo, pixel, pPrim, pFunc, pCompInfo) \
> ++    do { \
> ++         jint ix1 = (jint) floor(X1); \
> ++         jint ix2 = (jint) floor(X2); \
> ++         jint iy1 = (jint) floor(Y1); \
> ++         jint iy2 = (jint) floor(Y2); \
> ++         LineUtils_ProcessLine(pRasInfo, pixel, \
> ++                               pFunc, pPrim, pCompInfo, \
> ++                               ix1, iy1, ix2, iy2, JNI_TRUE); \
> ++    } while (0)
> ++
> ++#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \
> ++    do { \
> ++        double vmin, vmax; \
> ++        if (dv1 < 0) { \
> ++            vmin = v0+dv1; \
> ++            vmax = v0; \
> ++        } else { \
> ++            vmin = v0; \
> ++            vmax = v0+dv1; \
> ++        } \
> ++        if (dv2 < 0) { \
> ++            vmin -= dv2; \
> ++        } else { \
> ++            vmax += dv2; \
> ++        } \
> ++        bmin = (jint) floor(vmin + 0.5); \
> ++        bmax = (jint) floor(vmax + 0.5); \
> ++    } while(0)
> ++
> ++#define PGRAM_INIT_X(starty, x, y, slope) \
> ++    (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1)
> ++
> ++typedef struct {
> ++    jdouble x0;
> ++    jdouble y0;
> ++    jdouble y1;
> ++    jdouble slope;
> ++    jlong dx;
> ++    jint ystart;
> ++    jint yend;
> ++} EdgeInfo;
> ++
> ++#define STORE_EDGE(pEDGE, X0, Y0, Y1, SLOPE, DELTAX) \
> ++    do { \
> ++        (pEDGE)->x0 = (X0); \
> ++        (pEDGE)->y0 = (Y0); \
> ++        (pEDGE)->y1 = (Y1); \
> ++        (pEDGE)->slope = (SLOPE); \
> ++        (pEDGE)->dx = (DELTAX); \
> ++        (pEDGE)->ystart = (jint) floor((Y0) + 0.5); \
> ++        (pEDGE)->yend   = (jint) floor((Y1) + 0.5); \
> ++    } while (0)
> ++
> ++#define STORE_PGRAM(pLTEDGE, pRTEDGE, \
> ++                    X0, Y0, dX1, dY1, dX2, dY2, \
> ++                    SLOPE1, SLOPE2, DELTAX1, DELTAX2) \
> ++    do { \
> ++        STORE_EDGE((pLTEDGE)+0, \
> ++                   (X0), (Y0), (Y0) + (dY1), \
> ++                   (SLOPE1), (DELTAX1)); \
> ++        STORE_EDGE((pRTEDGE)+0, \
> ++                   (X0), (Y0), (Y0) + (dY2), \
> ++                   (SLOPE2), (DELTAX2)); \
> ++        STORE_EDGE((pLTEDGE)+1, \
> ++                   (X0) + (dX1), (Y0) + (dY1), (Y0) + (dY1) + (dY2), \
> ++                   (SLOPE2), (DELTAX2)); \
> ++        STORE_EDGE((pRTEDGE)+1, \
> ++                   (X0) + (dX2), (Y0) + (dY2), (Y0) + (dY1) + (dY2), \
> ++                   (SLOPE1), (DELTAX1)); \
> ++    } while (0)
> ++
> ++/*
> ++ * Class:     sun_java2d_loops_DrawParallelogram
> ++ * Method:    DrawParallelogram
> ++ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDDDD)V
> ++ */
> ++JNIEXPORT void JNICALL
> ++Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram
> ++    (JNIEnv *env, jobject self,
> ++     jobject sg2d, jobject sData,
> ++     jdouble x0, jdouble y0,
> ++     jdouble dx1, jdouble dy1,
> ++     jdouble dx2, jdouble dy2,
> ++     jdouble lw1, jdouble lw2)
> ++{
> ++    SurfaceDataOps *sdOps;
> ++    SurfaceDataRasInfo rasInfo;
> ++    NativePrimitive *pPrim;
> ++    CompositeInfo compInfo;
> ++    jint pixel;
> ++    EdgeInfo edges[8];
> ++    EdgeInfo *active[4];
> ++    jint ix1, iy1, ix2, iy2;
> ++    jdouble ldx1, ldy1, ldx2, ldy2;
> ++    jdouble ox0, oy0;
> ++
> ++    /*
> ++     * Sort parallelogram by y values, ensure that each delta vector
> ++     * has a non-negative y delta.
> ++     */
> ++    if (dy1 < 0) {
> ++        x0 += dx1;  y0 += dy1;
> ++        dx1 = -dx1; dy1 = -dy1;
> ++    }
> ++    if (dy2 < 0) {
> ++        x0 += dx2;  y0 += dy2;
> ++        dx2 = -dx2; dy2 = -dy2;
> ++    }
> ++    /* Sort delta vectors so dxy1 is left of dxy2. */
> ++    if (dx1 * dy2 > dx2 * dy1) {
> ++        double v = dx1; dx1 = dx2; dx2 = v;
> ++               v = dy1; dy1 = dy2; dy2 = v;
> ++               v = lw1; lw1 = lw2; lw2 = v;
> ++    }
> ++
> ++    // dx,dy for line width in the "1" and "2" directions.
> ++    ldx1 = dx1 * lw1;
> ++    ldy1 = dy1 * lw1;
> ++    ldx2 = dx2 * lw2;
> ++    ldy2 = dy2 * lw2;
> ++
> ++    // calculate origin of the outer parallelogram
> ++    ox0 = x0 - (ldx1 + ldx2) / 2.0;
> ++    oy0 = y0 - (ldy1 + ldy2) / 2.0;
> ++
> ++    PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2);
> ++    iy1 = (jint) floor(oy0 + 0.5);
> ++    iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5);
> ++
> ++    pPrim = GetNativePrim(env, self);
> ++    if (pPrim == NULL) {
> ++        return;
> ++    }
> ++    pixel = GrPrim_Sg2dGetPixel(env, sg2d);
> ++    if (pPrim->pCompType->getCompInfo != NULL) {
> ++        GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);
> ++    }
> ++
> ++    sdOps = SurfaceData_GetOps(env, sData);
> ++    if (sdOps == NULL) {
> ++        return;
> ++    }
> ++
> ++    GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
> ++    SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
> ++    if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
> ++        rasInfo.bounds.x2 <= rasInfo.bounds.x1)
> ++    {
> ++        return;
> ++    }
> ++
> ++    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
> ++        return;
> ++    }
> ++
> ++    ix1 = rasInfo.bounds.x1;
> ++    iy1 = rasInfo.bounds.y1;
> ++    ix2 = rasInfo.bounds.x2;
> ++    iy2 = rasInfo.bounds.y2;
> ++    if (ix2 > ix1 && iy2 > iy1) {
> ++        sdOps->GetRasInfo(env, sdOps, &rasInfo);
> ++        if (rasInfo.rasBase) {
> ++            jdouble lslope, rslope;
> ++            jlong ldx, rdx;
> ++            jint loy, hiy, numedges;
> ++            FillParallelogramFunc *pFill =
> ++                pPrim->funcs.drawparallelogram->fillpgram;
> ++
> ++            lslope = (dy1 == 0) ? 0 : dx1 / dy1;
> ++            rslope = (dy2 == 0) ? 0 : dx2 / dy2;
> ++            ldx = DblToLong(lslope);
> ++            rdx = DblToLong(rslope);
> ++
> ++            // Only need to generate 4 quads if the interior still
> ++            // has a hole in it (i.e. if the line width ratios were
> ++            // both less than 1.0)
> ++            if (lw1 < 1.0f && lw2 < 1.0f) {
> ++                // If the line widths are both less than a pixel wide
> ++                // then we can use a drawline function instead for even
> ++                // more performance.
> ++                lw1 = sqrt(ldx1*ldx1 + ldy1*ldy1);
> ++                lw2 = sqrt(ldx2*ldx2 + ldy2*ldy2);
> ++                if (lw1 <= 1.0001 && lw2 <= 1.0001) {
> ++                    jdouble x3, y3;
> ++                    DrawLineFunc *pLine =
> ++                        pPrim->funcs.drawparallelogram->drawline;
> ++
> ++                    x3 = (dx1 += x0);
> ++                    y3 = (dy1 += y0);
> ++                    x3 += dx2;
> ++                    y3 += dy2;
> ++                    dx2 += x0;
> ++                    dy2 += y0;
> ++
> ++                    HANDLE_PGRAM_EDGE( x0,  y0, dx1, dy1,
> ++                                      &rasInfo, pixel, pPrim, pLine, &compInfo);
> ++                    HANDLE_PGRAM_EDGE(dx1, dy1,  x3,  y3,
> ++                                      &rasInfo, pixel, pPrim, pLine, &compInfo);
> ++                    HANDLE_PGRAM_EDGE( x3,  y3, dx2, dy2,
> ++                                      &rasInfo, pixel, pPrim, pLine, &compInfo);
> ++                    HANDLE_PGRAM_EDGE(dx2, dy2,  x0,  y0,
> ++                                      &rasInfo, pixel, pPrim, pLine, &compInfo);
> ++                    SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
> ++                    SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
> ++                    return;
> ++                }
> ++
> ++                // To simplify the edge management below we presort the
> ++                // inner and outer edges so that they are globally sorted
> ++                // from left to right.  If you scan across the array of
> ++                // edges for a given Y range then the edges you encounter
> ++                // will be sorted in X as well.
> ++                // If AB are left top and bottom edges of outer parallelogram,
> ++                // and CD are the right pair of edges, and abcd are the
> ++                // corresponding inner parallelogram edges then we want them
> ++                // sorted as ABabcdCD to ensure this horizontal ordering.
> ++                // Conceptually it is like 2 pairs of nested parentheses.
> ++                STORE_PGRAM(edges + 2, edges + 4,
> ++                            ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2,
> ++                            dx1 - ldx1, dy1 - ldy1,
> ++                            dx2 - ldx2, dy2 - ldy2,
> ++                            lslope, rslope, ldx, rdx);
> ++                numedges = 8;
> ++            } else {
> ++                // The line width ratios were large enough to consume
> ++                // the entire hole in the middle of the parallelogram
> ++                // so we can just issue one large quad for the outer
> ++                // parallelogram.
> ++                numedges = 4;
> ++            }
> ++
> ++            // The outer parallelogram always goes in the first two
> ++            // and last two entries in the array so we either have
> ++            // ABabcdCD ordering for 8 edges or ABCD ordering for 4
> ++            // edges.  See comment above where we store the inner
> ++            // parallelogram for a more complete description.
> ++            STORE_PGRAM(edges + 0, edges + numedges-2,
> ++                        ox0, oy0,
> ++                        dx1 + ldx1, dy1 + ldy1,
> ++                        dx2 + ldx2, dy2 + ldy2,
> ++                        lslope, rslope, ldx, rdx);
> ++
> ++            loy = edges[0].ystart;
> ++            if (loy < iy1) loy = iy1;
> ++            while (loy < iy2) {
> ++                jint numactive = 0;
> ++                jint cur;
> ++
> ++                hiy = iy2;
> ++                // Maintaining a sorted edge list is probably overkill for
> ++                // 4 or 8 edges.  The indices chosen above for storing the
> ++                // inner and outer left and right edges already guarantee
> ++                // left to right ordering so we just need to scan for edges
> ++                // that overlap the current Y range (and also determine the
> ++                // maximum Y value for which the range is valid).
> ++                for (cur = 0; cur < numedges; cur++) {
> ++                    EdgeInfo *pEdge = &edges[cur];
> ++                    jint yend = pEdge->yend;
> ++                    if (loy < yend) {
> ++                        // This edge is still in play, have we reached it yet?
> ++                        jint ystart = pEdge->ystart;
> ++                        if (loy < ystart) {
> ++                            // This edge is not active (yet)
> ++                            // Stop before we get to the top of it
> ++                            if (hiy > ystart) hiy = ystart;
> ++                        } else {
> ++                            // This edge is active, store it
> ++                            active[numactive++] = pEdge;
> ++                            // And stop when we get to the bottom of it
> ++                            if (hiy > yend) hiy = yend;
> ++                        }
> ++                    }
> ++                }
> ++#ifdef DEBUG
> ++                if ((numactive & 1) != 0) {
> ++                    J2dTraceLn1(J2D_TRACE_ERROR,
> ++                                "DrawParallelogram: "
> ++                                "ODD NUMBER OF PGRAM EDGES (%d)!!",
> ++                                numactive);
> ++                }
> ++#endif
> ++                for (cur = 0; cur < numactive; cur += 2) {
> ++                    EdgeInfo *pLeft  = active[cur+0];
> ++                    EdgeInfo *pRight = active[cur+1];
> ++                    jlong lx = PGRAM_INIT_X(loy,
> ++                                            pLeft->x0, pLeft->y0,
> ++                                            pLeft->slope);
> ++                    jlong rx = PGRAM_INIT_X(loy,
> ++                                            pRight->x0, pRight->y0,
> ++                                            pRight->slope);
> ++                    (*pFill)(&rasInfo,
> ++                             ix1, loy, ix2, hiy,
> ++                             lx, pLeft->dx,
> ++                             rx, pRight->dx,
> ++                             pixel, pPrim, &compInfo);
> ++                }
> ++                loy = hiy;
> ++            }
> ++        }
> ++        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
> ++    }
> ++    SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
> ++}
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/FillParallelogram.c
> +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/FillParallelogram.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -0,0 +1,209 @@
> ++/*
> ++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
> ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> ++ *
> ++ * This code is free software; you can redistribute it and/or modify it
> ++ * under the terms of the GNU General Public License version 2 only, as
> ++ * published by the Free Software Foundation.  Oracle designates this
> ++ * particular file as subject to the "Classpath" exception as provided
> ++ * by Oracle in the LICENSE file that accompanied this code.
> ++ *
> ++ * This code is distributed in the hope that it will be useful, but WITHOUT
> ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> ++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> ++ * version 2 for more details (a copy is included in the LICENSE file that
> ++ * accompanied this code).
> ++ *
> ++ * You should have received a copy of the GNU General Public License version
> ++ * 2 along with this work; if not, write to the Free Software Foundation,
> ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
> ++ *
> ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
> ++ * or visit www.oracle.com if you need additional information or have any
> ++ * questions.
> ++ */
> ++
> ++#include "math.h"
> ++#include "GraphicsPrimitiveMgr.h"
> ++
> ++#include "sun_java2d_loops_FillParallelogram.h"
> ++
> ++#define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \
> ++    do { \
> ++        double vmin, vmax; \
> ++        if (dv1 < 0) { \
> ++            vmin = v0+dv1; \
> ++            vmax = v0; \
> ++        } else { \
> ++            vmin = v0; \
> ++            vmax = v0+dv1; \
> ++        } \
> ++        if (dv2 < 0) { \
> ++            vmin -= dv2; \
> ++        } else { \
> ++            vmax += dv2; \
> ++        } \
> ++        bmin = (jint) floor(vmin + 0.5); \
> ++        bmax = (jint) floor(vmax + 0.5); \
> ++    } while(0)
> ++
> ++#define PGRAM_INIT_X(starty, x, y, slope) \
> ++    (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1)
> ++
> ++/*
> ++ * Class:     sun_java2d_loops_FillParallelogram
> ++ * Method:    FillParallelogram
> ++ * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDD)V
> ++ */
> ++JNIEXPORT void JNICALL
> ++Java_sun_java2d_loops_FillParallelogram_FillParallelogram
> ++    (JNIEnv *env, jobject self,
> ++     jobject sg2d, jobject sData,
> ++     jdouble x0, jdouble y0,
> ++     jdouble dx1, jdouble dy1,
> ++     jdouble dx2, jdouble dy2)
> ++{
> ++    SurfaceDataOps *sdOps;
> ++    SurfaceDataRasInfo rasInfo;
> ++    NativePrimitive *pPrim;
> ++    CompositeInfo compInfo;
> ++    jint pixel;
> ++    jint ix1, iy1, ix2, iy2;
> ++
> ++    if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
> ++        return;
> ++    }
> ++
> ++    /*
> ++     * Sort parallelogram by y values, ensure that each delta vector
> ++     * has a non-negative y delta, and eliminate degenerate parallelograms.
> ++     */
> ++    if (dy1 < 0) {
> ++        x0 += dx1;  y0 += dy1;
> ++        dx1 = -dx1; dy1 = -dy1;
> ++    }
> ++    if (dy2 < 0) {
> ++        x0 += dx2;  y0 += dy2;
> ++        dx2 = -dx2; dy2 = -dy2;
> ++    }
> ++    /* Sort delta vectors so dxy1 is left of dxy2. */
> ++    if (dx1 * dy2 > dx2 * dy1) {
> ++        double v = dx1; dx1 = dx2; dx2 = v;
> ++               v = dy1; dy1 = dy2; dy2 = v;
> ++    }
> ++    PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2);
> ++    iy1 = (jint) floor(y0 + 0.5);
> ++    iy2 = (jint) floor(y0 + dy1 + dy2 + 0.5);
> ++
> ++    pPrim = GetNativePrim(env, self);
> ++    if (pPrim == NULL) {
> ++        return;
> ++    }
> ++    pixel = GrPrim_Sg2dGetPixel(env, sg2d);
> ++    if (pPrim->pCompType->getCompInfo != NULL) {
> ++        GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);
> ++    }
> ++
> ++    sdOps = SurfaceData_GetOps(env, sData);
> ++    if (sdOps == NULL) {
> ++        return;
> ++    }
> ++
> ++    GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
> ++    SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
> ++    if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
> ++        rasInfo.bounds.x2 <= rasInfo.bounds.x1)
> ++    {
> ++        return;
> ++    }
> ++
> ++    if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
> ++        return;
> ++    }
> ++
> ++    ix1 = rasInfo.bounds.x1;
> ++    iy1 = rasInfo.bounds.y1;
> ++    ix2 = rasInfo.bounds.x2;
> ++    iy2 = rasInfo.bounds.y2;
> ++    if (ix2 > ix1 && iy2 > iy1) {
> ++        sdOps->GetRasInfo(env, sdOps, &rasInfo);
> ++        if (rasInfo.rasBase) {
> ++            jdouble lslope = (dy1 == 0) ? 0 : dx1 / dy1;
> ++            jdouble rslope = (dy2 == 0) ? 0 : dx2 / dy2;
> ++            jlong ldx = DblToLong(lslope);
> ++            jlong rdx = DblToLong(rslope);
> ++            jint cy1, cy2, loy, hiy;
> ++            dx1 += x0;
> ++            dy1 += y0;
> ++            dx2 += x0;
> ++            dy2 += y0;
> ++            cy1 = (jint) floor(dy1 + 0.5);
> ++            cy2 = (jint) floor(dy2 + 0.5);
> ++
> ++            /* Top triangular portion. */
> ++            loy = iy1;
> ++            hiy = (cy1 < cy2) ? cy1 : cy2;
> ++            if (hiy > iy2) hiy = iy2;
> ++            if (loy < hiy) {
> ++                jlong lx = PGRAM_INIT_X(loy, x0, y0, lslope);
> ++                jlong rx = PGRAM_INIT_X(loy, x0, y0, rslope);
> ++                (*pPrim->funcs.fillparallelogram)(&rasInfo,
> ++                                                  ix1, loy, ix2, hiy,
> ++                                                  lx, ldx, rx, rdx,
> ++                                                  pixel, pPrim, &compInfo);
> ++            }
> ++
> ++            /* Middle parallelogram portion, which way does it slant? */
> ++            if (cy1 < cy2) {
> ++                /* Middle parallelogram portion, slanted to right. */
> ++                /* left leg turned a corner at y0+dy1 */
> ++                /* right leg continuing on its initial trajectory from y0 */
> ++                loy = cy1;
> ++                hiy = cy2;
> ++                if (loy < iy1) loy = iy1;
> ++                if (hiy > iy2) hiy = iy2;
> ++                if (loy < hiy) {
> ++                    jlong lx = PGRAM_INIT_X(loy, dx1, dy1, rslope);
> ++                    jlong rx = PGRAM_INIT_X(loy,  x0,  y0, rslope);
> ++                    (*pPrim->funcs.fillparallelogram)(&rasInfo,
> ++                                                      ix1, loy, ix2, hiy,
> ++                                                      lx, rdx, rx, rdx,
> ++                                                      pixel, pPrim, &compInfo);
> ++                }
> ++            } else if (cy2 < cy1) {
> ++                /* Middle parallelogram portion, slanted to left. */
> ++                /* left leg continuing on its initial trajectory from y0 */
> ++                /* right leg turned a corner at y0+dy2 */
> ++                loy = cy2;
> ++                hiy = cy1;
> ++                if (loy < iy1) loy = iy1;
> ++                if (hiy > iy2) hiy = iy2;
> ++                if (loy < hiy) {
> ++                    jlong lx = PGRAM_INIT_X(loy,  x0,  y0, lslope);
> ++                    jlong rx = PGRAM_INIT_X(loy, dx2, dy2, lslope);
> ++                    (*pPrim->funcs.fillparallelogram)(&rasInfo,
> ++                                                      ix1, loy, ix2, hiy,
> ++                                                      lx, ldx, rx, ldx,
> ++                                                      pixel, pPrim, &compInfo);
> ++                }
> ++            }
> ++
> ++            /* Bottom triangular portion. */
> ++            loy = (cy1 > cy2) ? cy1 : cy2;
> ++            if (loy < iy1) loy = iy1;
> ++            hiy = iy2;
> ++            if (loy < hiy) {
> ++                /* left leg turned its corner at y0+dy1, now moving right */
> ++                /* right leg turned its corner at y0+dy2, now moving left */
> ++                jlong lx = PGRAM_INIT_X(loy, dx1, dy1, rslope);
> ++                jlong rx = PGRAM_INIT_X(loy, dx2, dy2, lslope);
> ++                (*pPrim->funcs.fillparallelogram)(&rasInfo,
> ++                                                  ix1, loy, ix2, hiy,
> ++                                                  lx, rdx, rx, ldx,
> ++                                                  pixel, pPrim, &compInfo);
> ++            }
> ++        }
> ++        SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
> ++    }
> ++    SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
> ++}
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -574,6 +574,8 @@
> +     { "sun/java2d/loops/ScaledBlit", SD_LOCK_READ, SD_LOCK_WRITE, NULL, NULL},
> +     { "sun/java2d/loops/FillRect", 0, SD_LOCK_WRITE, NULL, NULL},
> +     { "sun/java2d/loops/FillSpans", 0, SD_LOCK_PARTIAL_WRITE, NULL, NULL},
> ++    { "sun/java2d/loops/FillParallelogram", 0, SD_LOCK_PARTIAL_WRITE, NULL, NULL},
> ++    { "sun/java2d/loops/DrawParallelogram", 0, SD_LOCK_PARTIAL_WRITE, NULL, NULL},
> +     { "sun/java2d/loops/DrawLine", 0, SD_LOCK_PARTIAL_WRITE, NULL, NULL},
> +     { "sun/java2d/loops/DrawRect", 0, SD_LOCK_PARTIAL_WRITE, NULL, NULL},
> +     { "sun/java2d/loops/DrawPolygons", 0, SD_LOCK_PARTIAL_WRITE, NULL, NULL},
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h	Mon Dec 06 21:45:48 2010 -0800
> +@@ -334,6 +334,26 @@
> +                                    jint yfract, jint dyfract);
> + 
> + /*
> ++ * The signature of the inner loop function for a "FillParallelogram"
> ++ * Note that this same inner loop is used for native DrawParallelogram
> ++ * primitives.
> ++ * Note that these functions are paired with equivalent DrawLine
> ++ * inner loop functions to facilitate nicer looking and faster thin
> ++ * transformed drawrect calls.
> ++ */
> ++typedef void (FillParallelogramFunc)(SurfaceDataRasInfo *pRasInfo,
> ++                                     jint lox, jint loy, jint hix, jint hiy,
> ++                                     jlong leftx, jlong dleftx,
> ++                                     jlong rightx, jlong drightx,
> ++                                     jint pixel, struct _NativePrimitive *pPrim,
> ++                                     CompositeInfo *pCompInfo);
> ++
> ++typedef struct {
> ++    FillParallelogramFunc       *fillpgram;
> ++    DrawLineFunc                *drawline;
> ++} DrawParallelogramFuncs;
> ++
> ++/*
> +  * This structure contains all information for defining a single
> +  * native GraphicsPrimitive, including:
> +  * - The information about the type of the GraphicsPrimitive subclass.
> +@@ -363,6 +383,8 @@
> +         ScaleBlitFunc           *scaledblit;
> +         FillRectFunc            *fillrect;
> +         FillSpansFunc           *fillspans;
> ++        FillParallelogramFunc   *fillparallelogram;
> ++        DrawParallelogramFuncs  *drawparallelogram;
> +         DrawLineFunc            *drawline;
> +         MaskFillFunc            *maskfill;
> +         MaskBlitFunc            *maskblit;
> +@@ -393,6 +415,8 @@
> +     PrimitiveType       ScaledBlit;
> +     PrimitiveType       FillRect;
> +     PrimitiveType       FillSpans;
> ++    PrimitiveType       FillParallelogram;
> ++    PrimitiveType       DrawParallelogram;
> +     PrimitiveType       DrawLine;
> +     PrimitiveType       DrawRect;
> +     PrimitiveType       DrawPolygons;
> +@@ -536,6 +560,7 @@
> + #define LongOneHalf     (((jlong) 1) << 31)
> + #define IntToLong(i)    (((jlong) (i)) << 32)
> + #define DblToLong(d)    ((jlong) ((d) * IntToLong(1)))
> ++#define LongToDbl(l)    (((jdouble) l) / IntToLong(1))
> + #define WholeOfLong(l)  ((jint) ((l) >> 32))
> + #define FractOfLong(l)  ((jint) (l))
> + #define URShift(i, n)   (((juint) (i)) >> (n))
> +@@ -595,6 +620,10 @@
> + #define REGISTER_FILLSPANS(SRC, COMP, DST, FUNC) \
> +     REGISTER_PRIMITIVE(FillSpans, SRC, COMP, DST, FUNC)
> + 
> ++#define REGISTER_FILLPGRAM(SRC, COMP, DST, FUNC) \
> ++    REGISTER_PRIMITIVE(FillParallelogram, SRC, COMP, DST, FUNC), \
> ++    REGISTER_PRIMITIVE(DrawParallelogram, SRC, COMP, DST, FUNC)
> ++
> + #define REGISTER_LINE_PRIMITIVES(SRC, COMP, DST, FUNC) \
> +     REGISTER_PRIMITIVE(DrawLine, SRC, COMP, DST, FUNC), \
> +     REGISTER_PRIMITIVE(DrawRect, SRC, COMP, DST, FUNC), \
> +diff -r 1d4340015b85 -r 47cd69eff641 src/share/native/sun/java2d/loops/LoopMacros.h
> +--- openjdk.orig/jdk/src/share/native/sun/java2d/loops/LoopMacros.h	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/share/native/sun/java2d/loops/LoopMacros.h	Mon Dec 06 21:45:48 2010 -0800
> +@@ -607,6 +607,12 @@
> + 
> + #define NAME_TRANSFORMHELPER_FUNCS(TYPE) TYPE ## TransformHelperFuncs
> + 
> ++#define NAME_SOLID_FILLPGRAM(TYPE)       TYPE ## SetParallelogram
> ++#define NAME_SOLID_PGRAM_FUNCS(TYPE)     TYPE ## SetParallelogramFuncs
> ++
> ++#define NAME_XOR_FILLPGRAM(TYPE)         TYPE ## XorParallelogram
> ++#define NAME_XOR_PGRAM_FUNCS(TYPE)       TYPE ## XorParallelogramFuncs
> ++
> + /*
> +  * These macros conveniently name and declare the indicated native
> +  * primitive loop function for forward referencing.
> +@@ -689,6 +695,16 @@
> +     TransformHelperFunc NAME_TRANSFORMHELPER_BC(TYPE); \
> +     TransformHelperFuncs NAME_TRANSFORMHELPER_FUNCS(TYPE)
> + 
> ++#define DECLARE_SOLID_PARALLELOGRAM(TYPE) \
> ++    FillParallelogramFunc NAME_SOLID_FILLPGRAM(TYPE); \
> ++    DECLARE_SOLID_DRAWLINE(TYPE); \
> ++    DrawParallelogramFuncs NAME_SOLID_PGRAM_FUNCS(TYPE)
> ++
> ++#define DECLARE_XOR_PARALLELOGRAM(TYPE) \
> ++    FillParallelogramFunc NAME_XOR_FILLPGRAM(TYPE); \
> ++    DECLARE_XOR_DRAWLINE(TYPE); \
> ++    DrawParallelogramFuncs NAME_XOR_PGRAM_FUNCS(TYPE)
> ++
> + /*
> +  * These macros construct the necessary NativePrimitive structure
> +  * for the indicated native primitive loop function which will be
> +@@ -800,6 +816,18 @@
> +     REGISTER_PRIMITIVE(TransformHelper, TYPE, SrcNoEa, IntArgbPre, \
> +                        (AnyFunc *) &NAME_TRANSFORMHELPER_FUNCS(TYPE))
> + 
> ++#define REGISTER_SOLID_PARALLELOGRAM(TYPE) \
> ++    REGISTER_PRIMITIVE(FillParallelogram, AnyColor, SrcNoEa, TYPE, \
> ++                       NAME_SOLID_FILLPGRAM(TYPE)), \
> ++    REGISTER_PRIMITIVE(DrawParallelogram, AnyColor, SrcNoEa, TYPE, \
> ++                       (AnyFunc *) &NAME_SOLID_PGRAM_FUNCS(TYPE))
> ++
> ++#define REGISTER_XOR_PARALLELOGRAM(TYPE) \
> ++    REGISTER_PRIMITIVE(FillParallelogram, AnyColor, Xor, TYPE, \
> ++                       NAME_XOR_FILLPGRAM(TYPE)), \
> ++    REGISTER_PRIMITIVE(DrawParallelogram, AnyColor, Xor, TYPE, \
> ++                       (AnyFunc *) &NAME_XOR_PGRAM_FUNCS(TYPE))
> ++
> + /*
> +  * This macro defines an entire function to implement a Blit inner loop
> +  * for copying pixels of a common type from one buffer to another.
> +@@ -1265,6 +1293,51 @@
> + }
> + 
> + /*
> ++ * This macro defines an entire function to implement a FillParallelogram
> ++ * inner loop for tracing 2 diagonal edges (left and right) and setting
> ++ * those regions of pixels between them to a specific pixel value.
> ++ * No blending of the fill color is done with the pixels.
> ++ */
> ++#define DEFINE_SOLID_FILLPGRAM(DST) \
> ++void NAME_SOLID_FILLPGRAM(DST)(SurfaceDataRasInfo *pRasInfo, \
> ++                               jint lox, jint loy, jint hix, jint hiy, \
> ++                               jlong leftx, jlong dleftx, \
> ++                               jlong rightx, jlong drightx, \
> ++                               jint pixel, struct _NativePrimitive *pPrim, \
> ++                               CompositeInfo *pCompInfo) \
> ++{ \
> ++    Declare ## DST ## PixelData(pix) \
> ++    jint scan = pRasInfo->scanStride; \
> ++    DST ## DataType *pPix = PtrCoord(pRasInfo->rasBase, 0, 0, loy, scan); \
> ++ \
> ++    Extract ## DST ## PixelData(pixel, pix); \
> ++    while (loy < hiy) { \
> ++        jint lx = WholeOfLong(leftx); \
> ++        jint rx = WholeOfLong(rightx); \
> ++        if (lx < lox) lx = lox; \
> ++        if (rx > hix) rx = hix; \
> ++        while (lx < rx) { \
> ++            Store ## DST ## PixelData(pPix, lx, pixel, pix); \
> ++            lx++; \
> ++        } \
> ++        pPix = PtrAddBytes(pPix, scan); \
> ++        leftx += dleftx; \
> ++        rightx += drightx; \
> ++        loy++; \
> ++    } \
> ++}
> ++
> ++#define DEFINE_SOLID_DRAWPARALLELOGRAM_FUNCS(DST) \
> ++    DrawParallelogramFuncs NAME_SOLID_PGRAM_FUNCS(DST) = { \
> ++        NAME_SOLID_FILLPGRAM(DST), \
> ++        NAME_SOLID_DRAWLINE(DST), \
> ++    };
> ++
> ++#define DEFINE_SOLID_PARALLELOGRAM(DST) \
> ++    DEFINE_SOLID_FILLPGRAM(DST) \
> ++    DEFINE_SOLID_DRAWPARALLELOGRAM_FUNCS(DST)
> ++
> ++/*
> +  * This macro declares the bumpmajor and bumpminor variables used for the
> +  * DrawLine functions.
> +  */
> +diff -r 1d4340015b85 -r 47cd69eff641 src/solaris/native/sun/java2d/loops/java2d_Mlib.c
> +--- openjdk.orig/jdk/src/solaris/native/sun/java2d/loops/java2d_Mlib.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/solaris/native/sun/java2d/loops/java2d_Mlib.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -282,6 +282,50 @@
> + 
> + /***************************************************************/
> + 
> ++#define DEFINE_SET_PGRAM(FUNC, ANYTYPE, NCHAN)                      \
> ++void ADD_SUFF(ANYTYPE##FUNC)(SurfaceDataRasInfo *pRasInfo,          \
> ++                             jint lox, jint loy,                    \
> ++                             jint hix, jint hiy,                    \
> ++                             jlong leftx, jlong dleftx,             \
> ++                             jlong rightx, jlong drightx,           \
> ++                             jint pixel, NativePrimitive * pPrim,   \
> ++                             CompositeInfo * pCompInfo)             \
> ++{                                                                   \
> ++    mlib_image dst[1];                                              \
> ++    mlib_s32 dstScan = pRasInfo->scanStride;                        \
> ++    mlib_u8  *dstBase = (mlib_u8*)(pRasInfo->rasBase), *pdst;       \
> ++    mlib_s32 c_arr[4];                                              \
> ++                                                                    \
> ++    STORE_CONST_##NCHAN(c_arr, pixel);                              \
> ++    pdst = dstBase + loy*dstScan;                                   \
> ++                                                                    \
> ++    while (loy < hiy) {                                             \
> ++        jint lx = WholeOfLong(leftx);                               \
> ++        jint rx = WholeOfLong(rightx);                              \
> ++        if (lx < lox) lx = lox;                                     \
> ++        if (rx > hix) rx = hix;                                     \
> ++                                                                    \
> ++        MLIB_IMAGE_SET(dst, MLIB_##ANYTYPE, NCHAN_##ANYTYPE,        \
> ++                       rx-lx, 1, dstScan,                           \
> ++                       pdst + lx*ANYTYPE##PixelStride);             \
> ++                                                                    \
> ++        mlib_ImageClear(dst, c_arr);                                \
> ++                                                                    \
> ++        pdst = PtrAddBytes(pdst, dstScan);                          \
> ++        leftx += dleftx;                                            \
> ++        rightx += drightx;                                          \
> ++        loy++;                                                      \
> ++    }                                                               \
> ++}
> ++
> ++DEFINE_SET_PGRAM(SetParallelogram, Any3Byte, 3)
> ++DEFINE_SET_PGRAM(SetParallelogram, Any4Byte, 4)
> ++DEFINE_SET_PGRAM(SetParallelogram, AnyByte,  1)
> ++DEFINE_SET_PGRAM(SetParallelogram, AnyInt,   1)
> ++DEFINE_SET_PGRAM(SetParallelogram, AnyShort, 1)
> ++
> ++/***************************************************************/
> ++
> + #define SCALE_COPY(index, chan)         \
> +     pDst[chan] = pSrc[index]
> + 
> +diff -r 1d4340015b85 -r 47cd69eff641 src/solaris/native/sun/java2d/loops/vis_FuncArray.c
> +--- openjdk.orig/jdk/src/solaris/native/sun/java2d/loops/vis_FuncArray.c	Mon Dec 06 16:10:01 2010 -0800
> ++++ openjdk/jdk/src/solaris/native/sun/java2d/loops/vis_FuncArray.c	Mon Dec 06 21:45:48 2010 -0800
> +@@ -51,6 +51,7 @@
> + DEF_FUNC(AnyByteSetLine)
> + DEF_FUNC(AnyByteSetRect)
> + DEF_FUNC(AnyByteSetSpans)
> ++DEF_FUNC(AnyByteSetParallelogram)
> + DEF_FUNC(AnyByteXorLine)
> + DEF_FUNC(AnyByteXorRect)
> + DEF_FUNC(AnyByteXorSpans)
> +@@ -62,6 +63,7 @@
> + DEF_FUNC(AnyShortSetLine)
> + DEF_FUNC(AnyShortSetRect)
> + DEF_FUNC(AnyShortSetSpans)
> ++DEF_FUNC(AnyShortSetParallelogram)
> + DEF_FUNC(AnyShortXorLine)
> + DEF_FUNC(AnyShortXorRect)
> + DEF_FUNC(AnyShortXorSpans)
> +@@ -73,6 +75,7 @@
> + DEF_FUNC(Any3ByteSetLine)
> + DEF_FUNC(Any3ByteSetRect)
> + DEF_FUNC(Any3ByteSetSpans)
> ++DEF_FUNC(Any3ByteSetParallelogram)
> + DEF_FUNC(Any3ByteXorLine)
> + DEF_FUNC(Any3ByteXorRect)
> + DEF_FUNC(Any3ByteXorSpans)
> +@@ -84,6 +87,7 @@
> + DEF_FUNC(Any4ByteSetLine)
> + DEF_FUNC(Any4ByteSetRect)
> + DEF_FUNC(Any4ByteSetSpans)
> ++DEF_FUNC(Any4ByteSetParallelogram)
> + DEF_FUNC(Any4ByteXorLine)
> + DEF_FUNC(Any4ByteXorRect)
> + DEF_FUNC(Any4ByteXorSpans)
> +@@ -95,6 +99,7 @@
> + DEF_FUNC(AnyIntSetLine)
> + DEF_FUNC(AnyIntSetRect)
> + DEF_FUNC(AnyIntSetSpans)
> ++DEF_FUNC(AnyIntSetParallelogram)
> + DEF_FUNC(AnyIntXorLine)
> + DEF_FUNC(AnyIntXorRect)
> + DEF_FUNC(AnyIntXorSpans)
> +@@ -513,6 +518,7 @@
> +     ADD_FUNC(AnyByteSetLine),
> +     ADD_FUNC(AnyByteSetRect),
> +     ADD_FUNC(AnyByteSetSpans),
> ++    ADD_FUNC(AnyByteSetParallelogram),
> +     ADD_FUNC(AnyByteXorLine),
> +     ADD_FUNC(AnyByteXorRect),
> +     ADD_FUNC(AnyByteXorSpans),
> +@@ -524,6 +530,7 @@
> +     ADD_FUNC(AnyShortSetLine),
> +     ADD_FUNC(AnyShortSetRect),
> +     ADD_FUNC(AnyShortSetSpans),
> ++    ADD_FUNC(AnyShortSetParallelogram),
> +     ADD_FUNC(AnyShortXorLine),
> +     ADD_FUNC(AnyShortXorRect),
> +     ADD_FUNC(AnyShortXorSpans),
> +@@ -533,6 +540,7 @@
> +     ADD_FUNC(Any3ByteSetLine),
> +     ADD_FUNC(Any3ByteSetRect),
> +     ADD_FUNC(Any3ByteSetSpans),
> ++    ADD_FUNC(Any3ByteSetParallelogram),
> +     ADD_FUNC(Any3ByteXorLine),
> +     ADD_FUNC(Any3ByteXorRect),
> +     ADD_FUNC(Any3ByteXorSpans),
> +@@ -544,6 +552,7 @@
> +     ADD_FUNC(Any4ByteSetLine),
> +     ADD_FUNC(Any4ByteSetRect),
> +     ADD_FUNC(Any4ByteSetSpans),
> ++    ADD_FUNC(Any4ByteSetParallelogram),
> +     ADD_FUNC(Any4ByteXorLine),
> +     ADD_FUNC(Any4ByteXorRect),
> +     ADD_FUNC(Any4ByteXorSpans),
> +@@ -555,6 +564,7 @@
> +     ADD_FUNC(AnyIntSetLine),
> +     ADD_FUNC(AnyIntSetRect),
> +     ADD_FUNC(AnyIntSetSpans),
> ++    ADD_FUNC(AnyIntSetParallelogram),
> +     ADD_FUNC(AnyIntXorLine),
> +     ADD_FUNC(AnyIntXorRect),
> +     ADD_FUNC(AnyIntXorSpans),


-- 
Andrew :)

Free Java Software Engineer
Red Hat, Inc. (http://www.redhat.com)

Support Free Java!
Contribute to GNU Classpath and IcedTea
http://www.gnu.org/software/classpath
http://icedtea.classpath.org
PGP Key: F5862A37 (https://keys.indymedia.org/)
Fingerprint = EA30 D855 D50F 90CD F54D  0698 0713 C3ED F586 2A37



More information about the distro-pkg-dev mailing list