Hi,

I've been looking at JDK-6513150 (Zero scale AffineTransforms gives NPE in
SunGraphics2D.getClipBounds()), where some internal code never expects
getClip() to return null, which it does when the graphics transform
specified by the user is not invertible. I have a fix ready, but this issue
raises an interesting question which I want to get some feedback on.

What is the correct / expected behavior of the three getClip*() methods
when the user has set a non-invertible transform? Right now the user clip
is stored in transformed format (usrClip) and then the transformation is
reversed whenever the user wants to retrieve it. This causes issues when
the transform cannot be inverted (e.g. a scale transformation where one or
both of the scale components is zero):

> var image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); ==>
BufferedImage@20398b7c: type = 1 DirectColorModel ... 0 yOff = 0
dataOffset[0] 0
> var g2d = image.createGraphics(); ==>
sun.java2d.SunGraphics2D[font=java.awt.Font[famil ...
.Color[r=255,g=255,b=255]]
> g2d.getClip() ==> null
> g2d.setClip(new Rectangle(50, 50, 50, 50))
> g2d.getClip() ==> *java.awt.Rectangle[x=50,y=50,width=50,height=50]*
> g2d.scale(0, 1)
> g2d.getClip() ==> *null*
> g2d.setTransform(new AffineTransform())
> g2d.getClip() ==> *java.awt.Rectangle[x=50,y=50,width=50,height=50]*

Is this considered OK and expected? I imagine it could surprise users quite
a bit. I'm especially thinking of the not-uncommon pattern:

Shape oldClip = g2d.getClip();
g2d.setClip(newClip);
try {
    // DO OTHER WORK
} finally {
    g2d.setClip(oldClip);
}

With this behavior, what should have been a sure-fire way to guarantee that
the Graphics2D object is returned to its original state doesn't always
work, and may in fact clear the user clip unexpectedly.

What do you guys think? Is it worth looking at either storing the user clip
internally in an untransformed state (usrClip) and transforming as needed,
or storing both versions of the user clip internally? If not, should we
document this behavior somewhere? I see that drawRenderedImage and
drawImage in SunGraphics2D call out undefined behavior when non-invertible
transforms are used. Perhaps we could do something similar, though the
cause-and-effect are more spread out in this case (all of the different
transformation methods can cause downstream surprising behavior in all of
the different clipping methods).

Take care,

Daniel

Reply via email to