[OpenJDK 2D-Dev] [9] RFR JDK-6842011: StackOverflowError printing landscape with scale and transform

prasanta sadhukhan prasanta.sadhukhan at oracle.com
Thu May 26 10:49:00 UTC 2016

Hi Phil,

On 5/25/2016 10:10 PM, Philip Race wrote:
> I am OK with committing the clarifying javadoc as part of this fix
> and filing a new RFE for the new method - to be fixed at some later date.
> However before this fix can be committed you need to make sure
> we have consistent behaviour across platforms and we do not have that yet
In mac, unlike RasterPrinterJob which does the transform using the 
following code
/            pathGraphics.transform(scaleTransform);//
//                // user (0,0) should be origin of page, not imageable 
//pathGraphics.translate(-getPhysicalPrintableX(paper) / xScale,//
//-getPhysicalPrintableY(paper) / yScale);//
//                pathGraphics.transform(new 
/CPrinterJob does not do this transforms, it straightway goes to native 
printloop code
  so when scalex = g2d.getTransform().getScaleX(); is called the 
transform returned is identity transform (as was the case in linux too 
before the above transform code is executed) so getScaleX/Y returns 1 as 
m00,m11=1 .
So, since the transform is not invalid unlike linux, mac prints ok.

> -phil.
> On 5/23/16, 3:57 PM, Phil Race wrote:
>> On 05/23/2016 03:33 PM, Jim Graham wrote:
>>> Though, they are likely to think this API is doing that.  We have a 
>>> visibility problem here to make sure that any work going forward is 
>>> more likely to see the new method and ignore this one.  I don't 
>>> think we'll win there on naming alone, but we can make the javadocs 
>>> look very intimidating so if they are using completion they may get 
>>> scared and hopefully see the other method before they just accept 
>>> the completion. Perhaps we can try to make the alphabetic sorting 
>>> have the new methods appear first in the list?
>> getScaleFactorX() should sort ahead of getScaleX()
>> -phil.
>>> In FX we were smart and went with very dry "getMxy()" style names 
>>> that won't attract attention...
>>>             ...jim
>>> On 5/23/2016 3:16 PM, Phil Race wrote:
>>>> What we have here might happen when developer A writes some UI code
>>>> without any conception that a 90 degree rotation may be in effect and
>>>> then developer B
>>>> comes along and adds printing support .. and the implementation 
>>>> rotates it.
>>>> So an out-of-the-box advertised API that does what dev A really meant
>>>> would be helpful.
>>>> -phil.
>>>> On 05/23/2016 11:52 AM, Jim Graham wrote:
>>>>> I think we need to go a bit further and change the way we describe
>>>>> them.  If we perhaps get very technical about how it is returning one
>>>>> element of the scaling equations/matrix then they will be discouraged
>>>>> from finding a simple use for it.  I'll try to come up with some
>>>>> wording today or tomorrow and it would be good to apply it to all 
>>>>> 6 of
>>>>> the getters uniformly.  Something like:
>>>>> Returns element M## of the transformation matrix which controls how
>>>>> the output XY coordinates are affected by the input XY coordinates.
>>>>> Then on the getScaleXY methods add a "Note, this method will not
>>>>> return the amount by which input XY coordinates will be stretched or
>>>>> contracted since a 90 degree rotation will cause all of its
>>>>> contribution to be redirected into the other axis. Properly
>>>>> determining the full scale of the matrix involves analyzing both this
>>>>> factor and the ...".
>>>>> There is where it would be good to have the new methods ready to 
>>>>> go so
>>>>> we can then immediately say ", such as in the getScalingFactorXY()
>>>>> method" or have an @see to send them where they need to go. That
>>>>> doesn't mean we can't do this documentation refresh now, but we might
>>>>> want to make those new methods a high priority to get done soon.  
>>>>> (I'm
>>>>> guessing/hoping we can add small "fixup" APIs like that after FC 
>>>>> since
>>>>> it doesn't really represent a "feature"...?)
>>>>>             ...jim
>>>>> On 5/22/16 11:53 PM, prasanta sadhukhan wrote:
>>>>>> Hi Jim,
>>>>>> On 5/21/2016 3:20 AM, Jim Graham wrote:
>>>>>>> We should acknowledge that the test case is buggy anyway.  It is 
>>>>>>> not
>>>>>>> computing the scale of a transform correctly,
>>>>>>> though that is likely due to the unfortunate naming we chose for 
>>>>>>> our
>>>>>>> methods.
>>>>>>> If you are looking for "the amount by which an X coordinate is
>>>>>>> stretched or contracted", you have to compute a
>>>>>>> distance formula on all of the elements of the X transform
>>>>>>> equation.  We don't have a method to do that for the
>>>>>>> caller.  If we did, we might call it something very similar to
>>>>>>> "getScaleX()".
>>>>>>> Unfortunately, we have a method named "getScaleX()" which one might
>>>>>>> think does that, but it doesn't.
>>>>>>> While I think we should prevent a stack overflow here, it's really
>>>>>>> more of "making sure a program bug is caught early
>>>>>>> and with a more sane response", than "fixing a valid test case".
>>>>>>> Also, we should consider adding a method to do the right
>>>>>>> calculation, and document the existing getScaleX() to point
>>>>>>> out that it cannot be used to determine "the stretchiness of X
>>>>>>> coordinates" or something more appropriately worded...
>>>>>> I have documented the anomalies in getScaleX()/getScaley().
>>>>>> http://cr.openjdk.java.net/~psadhukhan/6842011/webrev.01/
>>>>>> I will create a bug to address this scaling calculation of a
>>>>>> transform in affinetransform (as it is in geom package and
>>>>>> not a printing issue par se). Will that be ok?
>>>>>> Regards
>>>>>> Prasanta
>>>>>>>             ...jim
>>>>>>> On 5/20/16 4:27 AM, prasanta sadhukhan wrote:
>>>>>>>> Hi Phil,
>>>>>>>> When we call print() it calls RasterPrinterJob#printPage() which
>>>>>>>> sets peekGraphics.transform([4.16,0,0][0,4.16,0]) as
>>>>>>>> obtained from xscale=4.16 [getXRes()=300 / 72.0] ,yscale=4.16
>>>>>>>> It calls SunGraphics2D.transform which was identity transform 
>>>>>>>> [1.0,
>>>>>>>> 0.0, 0.0] [0.0, 1.0, 0.0] calls
>>>>>>>> transform.concatenate(peekgraphicsTx) and stores as
>>>>>>>> ([4.16,0,0][0,4.16,0])
>>>>>>>> Then RasterPrinterJob#printPage() again calls
>>>>>>>> peekGraphics.transform(new AffineTransform(page.getMatrix()));
>>>>>>>> where page.getMatrix() returns 0.0, -1.0, 1.0, 0.0, 0.0, 841.88 
>>>>>>>> and
>>>>>>>> peekGraphics transform now becomes [0.0, 1.0, 0.0]
>>>>>>>> [-1.0, 0.0, 841.88]
>>>>>>>> which calls SunGraphics2D#transform() where it again does
>>>>>>>> transform.concatenate(peekgraphicsTx)
>>>>>>>> so the transform becomes [m00=0, m01=4.16, m02=0][m10=-4.16, 
>>>>>>>> m11=0,
>>>>>>>> m12=3507.873]
>>>>>>>> Now scaleX obtains value from g2d.getTransform().getScaleX() which
>>>>>>>> returns SunGraphics2D stored transform.m00 which is 0
>>>>>>>> and scaleY is m11=0 so scaleX,scaleY becomes 0.
>>>>>>>> Regards
>>>>>>>> Prasanta
>>>>>>>> On 5/19/2016 4:03 AM, Phil Race wrote:
>>>>>>>>> It sounds like scalex & scaley are 0 and are then used in
>>>>>>>>> calculations which
>>>>>>>>> results in the NaN ? So why are they zero to begin with ?
>>>>>>>>> -phil.
>>>>>>>>> On 5/16/2016 3:32 AM, prasanta sadhukhan wrote:
>>>>>>>>>> Hi All,
>>>>>>>>>> Please review a fix for jdk9 whereby it is seen that
>>>>>>>>>> A StackOverflowError occurs when printing in landscape
>>>>>>>>>> orientation with a scaled and transformed graphics object.
>>>>>>>>>>  at sun.print.PSPrinterJob.prepDrawing(PSPrinterJob.java:1610)
>>>>>>>>>>     at sun.print.PSPrinterJob.beginPath(PSPrinterJob.java:1319)
>>>>>>>>>>     at
>>>>>>>>>> sun.print.PSPrinterJob.convertToPSPath(PSPrinterJob.java:1793)
>>>>>>>>>>     at
>>>>>>>>>> sun.print.PSPrinterJob$GState.emitPSClip(PSPrinterJob.java:1718)
>>>>>>>>>>     at 
>>>>>>>>>> sun.print.PSPrinterJob.prepDrawing(PSPrinterJob.java:1625)
>>>>>>>>>>  at sun.print.PSPrinterJob.beginPath(PSPrinterJob.java:1319)
>>>>>>>>>>     at
>>>>>>>>>> sun.print.PSPrinterJob.convertToPSPath(PSPrinterJob.java:1793)
>>>>>>>>>>     at
>>>>>>>>>> sun.print.PSPrinterJob$GState.emitPSClip(PSPrinterJob.java:1718)
>>>>>>>>>>     at 
>>>>>>>>>> sun.print.PSPrinterJob.prepDrawing(PSPrinterJob.java:1625)
>>>>>>>>>> Bug: https://bugs.openjdk.java.net/browse/JDK-6842011
>>>>>>>>>> webrev: 
>>>>>>>>>> http://cr.openjdk.java.net/~psadhukhan/6842011/webrev.00/
>>>>>>>>>> StackOverflowError is occuring because the scalex, scaley for
>>>>>>>>>> landscape orientation was 0 so when the testcase tries
>>>>>>>>>> to scale with these scale factors
>>>>>>>>>> using g2d.scale( 1 / scalex, 1 / scaley );
>>>>>>>>>> it creates a AffineTransform of NaN transformation. Now, In
>>>>>>>>>> linux, when the PS print drawing information is being
>>>>>>>>>> prepared, it calls prepDrawing() where it checks
>>>>>>>>>> getGState().mTransform.equals(mLastTransform) and since NaN
>>>>>>>>>> values cannot be compared it results in "false", causing
>>>>>>>>>> erroneous "grestore" postscript command to be issued and 
>>>>>>>>>> remove a
>>>>>>>>>> GState from the stack so isOuterGState() becomes
>>>>>>>>>> true which causes emitPSClip() to be called which calls
>>>>>>>>>> prepDrawing() again via convertToPSPath() , beginPath() and 
>>>>>>>>>> since
>>>>>>>>>> isOuterState() returns true due to transform not
>>>>>>>>>> being equal it again calls emitPSClip() causing a recursion.
>>>>>>>>>> The fix was to check if transform is NaN and do not fill the
>>>>>>>>>> devicePath if it is so, so that erroeous drawing is not
>>>>>>>>>> done.
>>>>>>>>>> So, it will print out a blank page.
>>>>>>>>>> In windows, the testcase prints out a blank page. In mac, the
>>>>>>>>>> testcase prints a 2x2 rectangle.
>>>>>>>>>> Regards
>>>>>>>>>> Prasanta

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/2d-dev/attachments/20160526/8cf5cbbf/attachment.html>

More information about the 2d-dev mailing list