JDK-8048782 : OpenJDK: PiscesCache : xmax/ymax rounding up can cause RasterFormatException
  • Type: Bug
  • Component: client-libs
  • Sub-Component: 2d
  • Affected Version: 8,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-06-30
  • Updated: 2019-05-30
  • Resolved: 2015-03-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9 Other
9 b56Fixed openjdk8u222Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description
http://mail.openjdk.java.net/pipermail/2d-dev/2014-June/004652.html

reports the following OpenJDK only bug :-

>  * The bug is related to sun.java2d.pisces.PiscesCache constructor
>   * that accepts '(int minx,int miny,int maxx,int maxy)' arguments:
>  * the internal 'bboxX1' and 'bboxY1' are set to values one greater
> * than given maximum X and Y values.


>I think so because this is a Pure Java issue, it seems to be a simple
> "off by one pixel" kind of error, and because all the other pipe
> implementations except 'AAShapePipe' seem to work, and also because
> corresponding OracleJDK implementation works.
 
The test program supplied demonstrates the exception

Exception in thread "main" java.awt.image.RasterFormatException: (x + width) is
outside raster
        at sun.awt.image.IntegerInterleavedRaster.createWritableChild(IntegerInterleavedRaster.java:467)
        at sun.awt.image.IntegerInterleavedRaster.createChild(IntegerInterleavedRaster.java:514)
        at sun.java2d.pipe.GeneralCompositePipe.renderPathTile(GeneralCompositePipe.java:106)
        at sun.java2d.pipe.AAShapePipe.renderTiles(AAShapePipe.java:201)
        at sun.java2d.pipe.AAShapePipe.renderPath(AAShapePipe.java:159)
        at sun.java2d.pipe.AAShapePipe.fill(AAShapePipe.java:68)
        at sun.java2d.pipe.PixelToParallelogramConverter.fill(PixelToParallelogramConverter.java:164)
        at sun.java2d.pipe.ValidatePipe.fill(ValidatePipe.java:160)
        at sun.java2d.SunGraphics2D.fill(SunGraphics2D.java:2491)
        at OpenJDKFillBug.main(OpenJDKFillBug.java:121)


import java.awt.Color;
import java.awt.Composite;
import java.awt.CompositeContext;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;

/**
 * Test program that demonstrates a bug in OpenJDK 1.7.0.60 (and
 * probably in all other OpenJDK versions, too).
 *
 * @see #main(String[])
 *
 * @author Rami H����nninen
 */

public class OpenJDKFillBug
{
  /**
   * Test program that demonstrates a bug in OpenJDK 1.7.0.60 (and
   * probably in all other OpenJDK versions, too). To see the bug, simply run
   * the 'main' program with OpenJDK. The bug makes the 'g2d.fill'
   * method fail with the following exception:
   * 
   * <PRE>
   * Exception in thread "main" java.awt.image.RasterFormatException: (x + width) is outside raster
   *   at sun.awt.image.IntegerInterleavedRaster.createWritableChild(IntegerInterleavedRaster.java:467)
   *   at sun.awt.image.IntegerInterleavedRaster.createChild(IntegerInterleavedRaster.java:514)
   *   at sun.java2d.pipe.GeneralCompositePipe.renderPathTile(GeneralCompositePipe.java:106)
   *   at sun.java2d.pipe.AAShapePipe.renderTiles(AAShapePipe.java:201)
   *   at sun.java2d.pipe.AAShapePipe.renderPath(AAShapePipe.java:159)
   *   at sun.java2d.pipe.AAShapePipe.fill(AAShapePipe.java:68)
   *   at sun.java2d.pipe.PixelToParallelogramConverter.fill(PixelToParallelogramConverter.java:164)
   *   at sun.java2d.pipe.ValidatePipe.fill(ValidatePipe.java:160)
   *   at sun.java2d.SunGraphics2D.fill(SunGraphics2D.java:2466)
   *   at OpenJDKFillBug.main(OpenJDKFillBug.java:55)
   * </PRE>
   * 
   * The bug is OpenJDK specific. This program runs with Oracle JDK
   * just fine (it still does not do anything sensible, but it does
   * not fail with a RasterFormatException, either).
   * 
   * <P>
   * 
   * The bug is related to sun.java2d.pisces.PiscesCache constructor
   * that accepts '(int minx,int miny,int maxx,int maxy)' arguments:
   * the internal 'bboxX1' and 'bboxY1' are set to values one greater
   * than given maximum X and Y values. Those maximum values are then
   * later used in AAShapePipe' class 'renderTiles' method, where a
   * Y/X loop eventually calls 'GeneralCompositePipe' class
   * 'renderPathTile' method. In that method, the operation will
   * eventually call 'IntegerInterleavedRaster' class
   * 'createWritableChild' method with arguments:
   * 
   * <UL>
   * <LI>x=800
   * <LI>y=0
   * <LI>width=2 (this value is too high: should be 1)
   * <LI>height=32
   * <LI>x0=0
   * <LI>y0=0
   * <LI>bandList[]=null
   * </UL>
   * 
   * This calls for a sub-raster with bounds that fall outside the
   * original raster, and therefore the 'createWritableChild' method
   * correctly throws 'RasterFormatException'.
   * 
   * <P>
   * 
   * The bug is closely related to the use of a custom Composite
   * implementation, which are quite rare. The application where this
   * bug was first detected implements a high-quality PDF rendering
   * engine that needs custom Composite operations to properly
   * implement PDF advanced color blending and masking operators.
   */

  public static void main(String args[])
  {
    BufferedImage bi = new BufferedImage(801,1202,BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = bi.createGraphics();
    GeneralPath gp = new GeneralPath();
    AffineTransform m = new AffineTransform(2.483489907915543,
                                            0.0,
                                            0.0,
                                            -2.4844977263331955,
                                            0.0,
                                            1202.0);
    Composite c = new CustomComposite();

    gp.moveTo(-4.511, -14.349);
    gp.lineTo(327.489, -14.349);
    gp.lineTo(327.489, 494.15);
    gp.lineTo(-4.511, 494.15);
    gp.closePath();
    
    g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
                         RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                         RenderingHints.VALUE_RENDER_QUALITY);
    g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
                         RenderingHints.VALUE_COLOR_RENDER_QUALITY);
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST,
                         Integer.valueOf(140));
    g2d.setRenderingHint(RenderingHints.KEY_DITHERING,
                         RenderingHints.VALUE_DITHER_ENABLE);
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                         RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                         RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                         RenderingHints.VALUE_STROKE_NORMALIZE);
    g2d.setPaint(Color.red);
    g2d.setComposite(c);
    g2d.setTransform(m);
    g2d.fill(gp);
    g2d.dispose();
  }
  
  // === CustomComposite ===

  /**
   * Dummy custom Composite implementation.
   */

  public static class CustomComposite implements Composite
  {
    @Override
    public CompositeContext createContext(ColorModel srcColorModel,
                                          ColorModel dstColorModel,
                                          RenderingHints hints)
    {
      return new CustomCompositeContext();
    }
  
    // === CustomCompositeContext ===

    /**
     * Dummy custom CompositeContext implementation.
     */
    
    public static class CustomCompositeContext implements CompositeContext
    {

      @Override
      public void dispose()
      {
        // NOP
      }

      @Override
      public void compose(Raster src,Raster dstIn,WritableRaster dstOut)
      {
        // NOP
      }
    }
  }
}

Comments
Fix Request Low risk. Patch applies cleanly and has its own test.
19-03-2019

Not affecting oracle jdk8 or 9 yet. Moving back to sustaining as the issue is seen in jdk7.
19-02-2015