[ 
https://issues.apache.org/jira/browse/FOP-3334?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Martin Leitner updated FOP-3334:
--------------------------------
    Attachment: minwidth-zero-viewport.fo
                areatree-fop-2.11-stock.xml
                areatree-fop-2.11-patched.xml
                minwidth-zero-viewport-fop-2.11.pdf

> min-width/min-height on fo:external-graphic is used as the fixed viewport 
> size, so min-width="0" collapses the viewport and graphics overlap
> --------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: FOP-3334
>                 URL: https://issues.apache.org/jira/browse/FOP-3334
>             Project: FOP
>          Issue Type: Bug
>          Components: layout/inline
>    Affects Versions: 2.11, main
>         Environment: Apache FOP 2.11 official binary distribution (SHA-512 
> verified), OpenJDK 21.0.2, Windows 11
>            Reporter: Martin Leitner
>            Priority: Major
>         Attachments: areatree-fop-2.11-patched.xml, 
> areatree-fop-2.11-stock.xml, minwidth-zero-viewport-fop-2.11.pdf, 
> minwidth-zero-viewport.fo
>
>
> h3. Summary
> An explicit {{min-width}} / {{min-height}} (or the equivalent 
> {{inline-progression-dimension.minimum}} / 
> {{block-progression-dimension.minimum}}) on {{fo:external-graphic}} is used 
> as the *fixed* viewport size instead of as a lower bound. With 
> {{min-width="0"}} the viewport becomes 0 wide while the image content keeps 
> its full width, so consecutive graphics are all painted at the same position 
> and overlap. {{min-height="0"}} does the same in the block-progression 
> direction.
> Since {{0}} is the initial value of {{min-width}} in XSL-FO 1.1, any tool 
> that writes the property out explicitly triggers this.
> h3. Steps to reproduce
> Attached {{minwidth-zero-viewport.fo}} is fully self-contained (the three 
> images are RFC 2397 {{data:}} URIs, so no external resources are needed).
> {code}
> fop -fo minwidth-zero-viewport.fo -pdf out.pdf
> fop -fo minwidth-zero-viewport.fo -at application/pdf out-at.xml
> {code}
> Block *A* draws three graphics (120x60, 90x60, 60x60 px) with no 
> {{min-width}}; block *B* draws the same three with {{min-width="0"}}.
> h3. Actual result (Apache FOP 2.11, official binary distribution)
> Viewport extents from the area tree, in millipoints:
> || id || min-* set || viewport ipd || viewport bpd || content pos ||
> | a-red | - | 120000 | 60000 | 0 0 120000 60000 |
> | a-green | - | 90000 | 60000 | 0 0 90000 60000 |
> | a-blue | - | 60000 | 60000 | 0 0 60000 60000 |
> | b-red | min-width="0" | *0* | 60000 | 0 0 120000 60000 |
> | b-green | min-width="0" | *0* | 60000 | 0 0 90000 60000 |
> | b-blue | min-width="0" | *0* | 60000 | 0 0 60000 60000 |
> | c-red | min-width="3in" | 216000 | 60000 | 0 0 120000 60000 |
> | d-red | min-height="0" | 120000 | *0* | 0 0 120000 60000 |
> | d-green | min-height="0" | 90000 | *0* | 0 0 90000 60000 |
> | d-blue | min-height="0" | 60000 | *0* | 0 0 60000 60000 |
> The {{b-*}} rows are the defect: the viewport is reported as {{ipd="0"}} 
> while its content placement is the full {{120000}} / {{90000}} / {{60000}} 
> wide image:
> {code:xml}
> <viewport ipd="0" bpd="60000" prod-id="b-red" pos="0 0 120000 60000">
>   <image prod-id="b-red" url="data:image/png;base64,..."/>
> </viewport>
> {code}
> Because each viewport advances the inline-progression position by 0, all 
> three images are painted on top of each other in the PDF. The {{c-red}} row 
> shows that a *non-zero* minimum does widen the viewport as expected, so only 
> the zero case is visibly broken - but the underlying cause is the same for 
> every explicit minimum.
> h3. Expected result
> A minimum is a lower bound, not the size. The viewport should be sized from 
> the content and then constrained by the minimum/maximum, i.e. {{max(content 
> extent, minimum)}} - which for {{min-width="0"}} yields the content width and 
> reproduces the same output as if the property were absent.
> h3. Cause
> {{min-width}} / {{min-height}} are not read directly. They are _extra 
> corresponding_ properties of {{inline-progression-dimension}} / 
> {{block-progression-dimension}} ({{FOPropertyMapping}}, the 
> {{setExtraCorresponding()}} calls for both dimension properties), and 
> {{DimensionPropertyMaker.compute()}} copies an explicit value into the 
> {{CP_MINIMUM}} subproperty of the length-range.
> {{ImageLayout.doLayout()}} then takes that minimum as the viewport extent 
> (2.11 lines 89-93, and 80-83 for the BPD):
> {code:java}
> len = 
> props.getInlineProgressionDimension().getMinimum(percentBaseContext).getLength();
> if (ipd == -1 && len.getEnum() != EN_AUTO) {
>     //Establish minimum viewport size
>     ipd = len.getValue(percentBaseContext);
> }
> {code}
> Because {{ipd}} is no longer {{-1}}, the content-driven sizing at lines 
> 163-171 is skipped:
> {code:java}
> //Adjust viewport if not explicit
> if (ipd == -1) {
>     ipd = constrainExtent(cwidth,
>             props.getInlineProgressionDimension(), props.getContentWidth());
> }
> {code}
> {{constrainExtent()}} is where the correct semantics already live - it 
> applies the maximum as a ceiling and the minimum as a floor ({{extent = 
> Math.max(extent, min)}}) - but it is only reached when no minimum was 
> specified.
> h3. Suggested fix
> Keep the provisional minimum-derived extent (the 
> {{content-width}}/{{content-height}} {{scale-*-to-fit}} branches rely on it) 
> but re-derive the final viewport extent through {{constrainExtent()}}:
> {code:java}
> int bpd = -1;
> int ipd = -1;
> boolean bpdFromMinimum = false;
> boolean ipdFromMinimum = false;
> ...
> // where the minimum is currently assigned, also set the corresponding flag
> ...
> //Adjust viewport if not explicit
> if (ipd == -1 || ipdFromMinimum) {
>     ipd = constrainExtent(cwidth,
>             props.getInlineProgressionDimension(), props.getContentWidth());
> }
> if (bpd == -1 || bpdFromMinimum) {
>     bpd = constrainExtent(cheight,
>             props.getBlockProgressionDimension(), props.getContentHeight());
> }
> {code}
> No change is needed in {{DimensionPropertyMaker}} or {{FOPropertyMapping}}; 
> the property-to-subproperty mapping is correct, only the layout consumption 
> is wrong.
> *Verified against the official 2.11 binary distribution* by compiling only 
> this patched class and putting it ahead of {{fop-core-2.11.jar}} on the 
> classpath. Attached {{areatree-fop-2.11-patched.xml}} is the result:
> * {{b-red}} / {{b-green}} / {{b-blue}} viewport ipd: {{0}} -> {{120000}} / 
> {{90000}} / {{60000}} (equal to the {{a-*}} reference, no overlap)
> * {{d-*}} viewport bpd: {{0}} -> {{60000}}
> * {{c-red}} (min-width="3in") unchanged at {{216000}} - the floor still 
> applies
> * {{a-*}} (no minimum) unchanged
> A side-case matrix produced identical area trees before and after the patch 
> for: {{inline-progression-dimension.minimum}} at 1in and 3in combined with 
> {{content-width="scale-to-fit"}}, {{scale-down-to-fit}} and 
> {{scale-up-to-fit}}; {{block-progression-dimension.minimum}} with 
> {{content-height="scale-to-fit"}}; an explicit {{.optimum}}; and a 
> conflicting {{min-width="4in" max-width="2in"}} pair. In particular the 
> {{external-graphic_size_1}} layout-engine testcase pattern 
> ({{inline-progression-dimension.minimum="1in"}} + 
> {{content-width="scale-to-fit"}}) is unaffected.
> h3. Related observation (not addressed by the patch above)
> {{min-width="0"}} combined with {{content-width="scale-to-fit"}} makes the 
> graphic disappear completely - no viewport or image area is generated at all 
> - both before and after the patch. The content extent is scaled to the 
> provisional zero viewport before the viewport is re-derived. This may deserve 
> separate treatment; it is not the overlap defect reported here.
> h3. Versions checked
> * 2.11 (latest release): reproduced by execution; {{ImageLayout}} lines 89-93 
> and 163-171 as quoted above.
> * 2.4, 2.8, 2.10: the same block is present in the published sources jars.
> * trunk HEAD (gitbox): the same block is present (shifted to lines ~95-97 by 
> the unrelated {{useParentIPDImageScaling}} addition).
> h3. Environment
> Apache FOP 2.11 binary distribution (SHA-512 verified against the published 
> checksum), OpenJDK 21.0.2, Windows 11.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to