[OpenJDK 2D-Dev] [9] Review request for 8160124 SunGraphics2D.hitClip() can give wrong result for floating point scale
Sergey Bylokhov
Sergey.Bylokhov at oracle.com
Tue Jul 26 21:50:24 UTC 2016
On 13.07.16 5:42, Jim Graham wrote:
> What does the compClip end up being in that case?
BufferedImage bi = new
BufferedImage(10,10,BufferedImage.TYPE_INT_ARGB);
SunGraphics2D graphics = (SunGraphics2D) bi.createGraphics();
graphics.scale(1.5, 1.5);
graphics.setClip(1, 1, 0, 0);
System.out.println("clip = " + graphics.getClip().getBounds2D());
System.out.println("clip.isEmpty = " +
graphics.getClip().getBounds2D().isEmpty());
boolean hit = graphics.hitClip(1, 1, 1, 1);
System.out.println("hit = " + hit);
System.out.println("compClip = " + graphics.getCompClip());
System.out.println("compClip.isEmpty = " +
graphics.getCompClip().isEmpty());
The output:
clip = java.awt.geom.Rectangle2D$Double[x=1.0,y=1.0,w=0.0,h=0.0]
clip.isEmpty = true
hit = true
compClip = Region[[1, 1 => 2, 2]]
compClip.isEmpty = false
So the graphics.getClip() returns empty clip, but compClip is not empty.
It seems this occurs when we intersect usrClip
=[x=1.5,y=1.5,w=0.0,h=0.0] and devClip=Region[[0, 0 => 10, 10]] because
result is clipRegion=Region[[1, 1 => 2, 2]]
The code in question is:
protected void validateCompClip() {
.....
clipRegion = devClip.getIntersection(usrClip.getBounds());
.....
}
The usrClip.getBounds() method will change [x=1.5,y=1.5,w=0.0,h=0.0] to
[x=1,y=1,w=1,h=1], so the empty Rectangle2D became non-empty.
>
> ...jim
>
> On 7/4/16 1:12 AM, Sergey Bylokhov wrote:
>> On 01.07.16 2:49, Jim Graham wrote:
>>> How is it returning true? If the clip really is empty, then
>>> intersectsQuickCheck() should never return true. Or are you saying that
>>> an empty clip shape produces a non-empty composite clip region?
>>
>>
>> This code will test such situation:
>> BufferedImage bi = new
>> BufferedImage(10,10,BufferedImage.TYPE_INT_ARGB);
>> Graphics2D graphics = bi.createGraphics();
>> graphics.scale(1.5, 1.5);
>> graphics.setClip(1, 1, 0, 0);
>> System.out.println("empty = " +
>> graphics.getClip().getBounds2D().isEmpty());
>> boolean hit = graphics.hitClip(1, 1, 1, 1);
>> System.out.println("hit = " + hit);
>>
>> if "graphics.scale(1.5, 1.5);" will be removed then correct false will
>> be printed. In both cases the clip will be empty
>> but hitCLip will return different result in case of scaled SG2D.
>>
>>>
>>> ...jim
>>>
>>> On 06/30/2016 10:02 AM, Sergey Bylokhov wrote:
>>>> It looks strange that the empty clip became "non-empty"(at least
>>>> hitClip
>>>> reports this) when we apply transform to it, no? I guess that at the
>>>> beginning of hitClip() we should check that the clip.isEmpty(), and we
>>>> should return "false" in this case(I think this is not strictly related
>>>> to this bug)?
>>>>
>>>> On 24.06.16 1:14, Jim Graham wrote:
>>>>> Think of this method as asking:
>>>>>
>>>>> I don't want you to waste a lot of time, but tell me if it is silly
>>>>> for
>>>>> me to even consider rendering something with these bounds.
>>>>>
>>>>> And the answer is either "Oh, yeah, it is inconceivable that those
>>>>> bounds would be rendered", or "Not sure, maybe, just render it and
>>>>> see". There may be some cases where it knows "I know for sure that
>>>>> lots
>>>>> of stuff will render through the clip", but that is not where the
>>>>> divining line is here in terms of when the answer becomes true - it
>>>>> becomes true when there is a chance that it might render something.
>>>>>
>>>>> Arguably, the user-space comparison against the user-space clip
>>>>> that you
>>>>> added here can never be accurate even if you allow for "false
>>>>> positives". The clip is rasterized and whole pixels are chosen
>>>>> based on
>>>>> various criteria that affect clip rasterization. Thus, while the
>>>>> theoretical clip is at N.5, our rasterization choice has us render
>>>>> anything that hits pixel N, even if the contribution of the rendered
>>>>> primitive is only for the first half of N. That pixel might be
>>>>> rendered
>>>>> if anything hits any part of it, depending on what rendering operation
>>>>> is being done.
>>>>>
>>>>> So, your "fix" actually breaks the functionality because it is quite
>>>>> possible that something with a bounding box that stops before N.5
>>>>> might
>>>>> affect pixel N and cause it to be rendered even though your new answer
>>>>> suggested that it wouldn't happen. Your code might actually cause a
>>>>> bug, not fix one.
>>>>>
>>>>> (There are also some potential theoretical failures related to how AA
>>>>> and STROKE_CONTROL might perturb our rendering, effects which are
>>>>> ignore
>>>>> by the current implementation of hitClip(), however I believe that all
>>>>> of those effects fit within the current implementation - it's just
>>>>> that
>>>>> I don't think anyone has ever proven this, or written an exhaustive
>>>>> test
>>>>> suite to verify that none of our rendering hints can perturb rendering
>>>>> by enough to create some surprises here...)
>>>>>
>>>>> ...jim
>>>>>
>>>>> On 6/23/16 3:00 PM, Jim Graham wrote:
>>>>>> Since "return true" would be a compliant implementation of
>>>>>> Graphics.hitClip(), this is not a bug...
>>>>>>
>>>>>> Read the documentation, it is allowed to use fast math that can
>>>>>> return
>>>>>> true when technically the answer is false...
>>>>>>
>>>>>> ...jim
>>>>>>
>>>>>> On 6/23/16 5:04 AM, Alexandr Scherbatiy wrote:
>>>>>>>
>>>>>>> Hello,
>>>>>>>
>>>>>>> Could you review the fix:
>>>>>>> bug: https://bugs.openjdk.java.net/browse/JDK-8160124
>>>>>>> webrev: http://cr.openjdk.java.net/~alexsch/8160124/webrev.00
>>>>>>>
>>>>>>> Let's set the clip [x=5, y=5, width=5, height=5] to a graphics and
>>>>>>> call the hitClip() with the passed rectangle [x=0,
>>>>>>> y=0, width=5, height=5].
>>>>>>>
>>>>>>> The result is false for the graphics with scale 1 and true if the
>>>>>>> scale is floating point 1.5.
>>>>>>>
>>>>>>> This is because the transformed clip which has floating point
>>>>>>> bounds [7.5, 7.5, 7.5, 7.5] for the scale 1.5 has bounds
>>>>>>> with rounded down upper-left and rounded up lower-right corners [7,
>>>>>>> 7, 8, 8] which now intersects with the transformed
>>>>>>> rectangle [0, 0, 7.5, 7.5].
>>>>>>>
>>>>>>> The proposed fix adds additional check for the user clip and the
>>>>>>> user rectangle intersection if the intersection with
>>>>>>> the region clip passes.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Alexandr.
>>>>>>>
>>>>>>>
>>>>
>>>>
>>
>>
--
Best regards, Sergey.
More information about the 2d-dev
mailing list