Jason Harrop created FOP-3348:
---------------------------------
Summary: A block nested in an inline loses the lines after it, and
FOP throws a NullPointerException in TraitSetter.setVisibility, when line
breaking runs again (after a float, or on a page of a different IPD)
Key: FOP-3348
URL: https://issues.apache.org/jira/browse/FOP-3348
Project: FOP
Issue Type: Bug
Components: layout/line
Affects Versions: main, 2.11
Reporter: Jason Harrop
LineLayoutManager keeps a paragraph's Knuth sequences in knuthParagraphs. A
block nested in an inline gives it a block-level sequence between two inline
ones. postProcessLineBreaks passes that block-level sequence's elements upward
as the same objects it stores, wrapping each in place:
{code:java}
tempElement.setPosition(notifyPos(new NonLeafPosition(this,
tempElement.getPosition())));
{code}
The enclosing block and flow managers wrap the same objects in place again
(BlockStackingLayoutManager.wrapPositionElements).
Line breaking runs a second time over the stored paragraphs in two cases: the
content after a float (PageBreaker.handleFloatLayout restarts after it), and
the restart after a change of IPD. The elements still carry the first pass's
wrapping, so they are wrapped twice. With a float, the nested block's chain
came out LineLM > FlowLM > BlockLM > LineLM > InlineLM > BlockLM, where it
should be LineLM > InlineLM > BlockLM.
LineLayoutManager.addBlockArea unwraps one level, reaches the
FlowLayoutManager, and so re-enters the enclosing block's addAreas. That inner
call flushes the block's area and sets curBlockArea to null. Back in the outer
call, the line after the nested block reaches addChildArea, which drops it
silently while the area is null. Then TraitSetter.setVisibility(curBlockArea,
...) throws the NullPointerException. A null check there would stop the
exception and lose the text.
h3. To reproduce
1. A float, then a paragraph with a block inside an inline:
{code:xml}
<fo:block><fo:float float="start"><fo:block-container width="100pt"
height="60pt">
<fo:block>Float</fo:block></fo:block-container></fo:float>Some text beside
it.</fo:block>
<fo:block>Before <fo:inline>the run<fo:block
linefeed-treatment="preserve">
</fo:block>after
the break and on.</fo:inline></fo:block>
{code}
2. Without a float: the same paragraph breaking onto a page whose region-body
is narrower (a page-sequence-master whose later pages have a larger
margin-left).
Both throw on 2.11 and on main. Without the float, or with pages of equal
width, the same FO lays out completely.
h3. Fix
Before wrapping such an element, walk its chain of NonLeafPositions. If one of
them belongs to this manager, an earlier pass left it there, so start again
from the position inside it. On a first pass none does, so nothing changes.
Only NonLeafPositions are walked: the wrapping is made of them, and a
TableContentPosition returns itself from getPosition().
Tests: layout tests inline_block_nested_float_relayout.xml (the float form) and
inline_block_nested_ipd_relayout.xml (the page-width form). Both fail with the
NullPointerException before the fix. With it, the layout engine suite passes on
main (743 standard test cases; the 34 in disabled-testcases.xml do not run).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)