Skip to content

Commit eb335e3

Browse files
FOP-3192: Redo layout for multipage columns
1 parent add90d5 commit eb335e3

File tree

14 files changed

+373
-71
lines changed

14 files changed

+373
-71
lines changed

fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,4 +847,8 @@ public boolean isSimpleLineBreaking() {
847847
public boolean isSkipPagePositionOnlyAllowed() {
848848
return factory.isSkipPagePositionOnlyAllowed();
849849
}
850+
851+
public boolean isLegacySkipPagePositionOnly() {
852+
return factory.isLegacySkipPagePositionOnly();
853+
}
850854
}

fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public class FopConfParser {
5959
private static final String TABLE_BORDER_OVERPAINT = "table-border-overpaint";
6060
private static final String SIMPLE_LINE_BREAKING = "simple-line-breaking";
6161
private static final String SKIP_PAGE_POSITION_ONLY_ALLOWED = "skip-page-position-only-allowed";
62+
private static final String LEGACY_SKIP_PAGE_POSITION_ONLY = "legacy-skip-page-position-only";
6263

6364
private final Log log = LogFactory.getLog(FopConfParser.class);
6465

@@ -299,6 +300,14 @@ private void configure(final URI baseURI, final ResourceResolver resourceResolve
299300
LogUtil.handleException(log, e, false);
300301
}
301302
}
303+
if (cfg.getChild(LEGACY_SKIP_PAGE_POSITION_ONLY, false) != null) {
304+
try {
305+
fopFactoryBuilder.setLegacySkipPagePositionOnly(
306+
cfg.getChild(LEGACY_SKIP_PAGE_POSITION_ONLY).getValueAsBoolean());
307+
} catch (ConfigurationException e) {
308+
LogUtil.handleException(log, e, false);
309+
}
310+
}
302311

303312
// configure font manager
304313
new FontManagerConfigurator(cfg, baseURI, fopFactoryBuilder.getBaseURI(), resourceResolver)

fop-core/src/main/java/org/apache/fop/apps/FopFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ boolean isSkipPagePositionOnlyAllowed() {
244244
return config.isSkipPagePositionOnlyAllowed();
245245
}
246246

247+
boolean isLegacySkipPagePositionOnly() {
248+
return config.isLegacySkipPagePositionOnly();
249+
}
250+
247251
/**
248252
* Returns a new {@link Fop} instance. FOP will be configured with a default user agent
249253
* instance. Use this factory method if your output type requires an output stream.

fop-core/src/main/java/org/apache/fop/apps/FopFactoryBuilder.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,11 @@ public FopFactoryBuilder setSkipPagePositionOnlyAllowed(boolean b) {
355355
return this;
356356
}
357357

358+
public FopFactoryBuilder setLegacySkipPagePositionOnly(boolean b) {
359+
fopFactoryConfigBuilder.setLegacySkipPagePositionOnly(b);
360+
return this;
361+
}
362+
358363
public static class FopFactoryConfigImpl implements FopFactoryConfig {
359364

360365
private final EnvironmentProfile enviro;
@@ -401,6 +406,8 @@ public static class FopFactoryConfigImpl implements FopFactoryConfig {
401406

402407
private boolean skipPagePositionOnlyAllowed = true;
403408

409+
private boolean legacySkipPagePositionOnly;
410+
404411
private static final class ImageContextImpl implements ImageContext {
405412

406413
private final FopFactoryConfig config;
@@ -529,6 +536,10 @@ public boolean isSkipPagePositionOnlyAllowed() {
529536
return skipPagePositionOnlyAllowed;
530537
}
531538

539+
public boolean isLegacySkipPagePositionOnly() {
540+
return legacySkipPagePositionOnly;
541+
}
542+
532543
public Map<String, String> getHyphenationPatternNames() {
533544
return hyphPatNames;
534545
}
@@ -580,6 +591,8 @@ private interface FopFactoryConfigBuilder {
580591
void setSimpleLineBreaking(boolean b);
581592

582593
void setSkipPagePositionOnlyAllowed(boolean b);
594+
595+
void setLegacySkipPagePositionOnly(boolean b);
583596
}
584597

585598
private static final class CompletedFopFactoryConfigBuilder implements FopFactoryConfigBuilder {
@@ -675,6 +688,10 @@ public void setSimpleLineBreaking(boolean b) {
675688
public void setSkipPagePositionOnlyAllowed(boolean b) {
676689
throwIllegalStateException();
677690
}
691+
692+
public void setLegacySkipPagePositionOnly(boolean b) {
693+
throwIllegalStateException();
694+
}
678695
}
679696

680697
private static final class ActiveFopFactoryConfigBuilder implements FopFactoryConfigBuilder {
@@ -771,6 +788,10 @@ public void setSimpleLineBreaking(boolean b) {
771788
public void setSkipPagePositionOnlyAllowed(boolean b) {
772789
config.skipPagePositionOnlyAllowed = b;
773790
}
791+
792+
public void setLegacySkipPagePositionOnly(boolean b) {
793+
config.legacySkipPagePositionOnly = b;
794+
}
774795
}
775796

776797
}

fop-core/src/main/java/org/apache/fop/apps/FopFactoryConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ public interface FopFactoryConfig {
169169

170170
boolean isSkipPagePositionOnlyAllowed();
171171

172+
boolean isLegacySkipPagePositionOnly();
173+
172174
/** @return the hyphenation pattern names */
173175
Map<String, String> getHyphenationPatternNames();
174176

fop-core/src/main/java/org/apache/fop/layoutmgr/AbstractBreaker.java

Lines changed: 90 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -382,81 +382,86 @@ public boolean doLayout(int flowBPD, boolean autoHeight) {
382382
while (hasMoreContent()) {
383383
blockLists.clear();
384384

385-
//*** Phase 1: Get Knuth elements ***
386-
nextSequenceStartsOn = getNextBlockList(childLC, nextSequenceStartsOn);
387-
empty = empty && blockLists.size() == 0;
388-
389-
//*** Phases 2 and 3 ***
390-
log.debug("PLM> blockLists.size() = " + blockLists.size());
391-
for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
392-
blockList = blockLists.get(blockListIndex);
393-
394-
//debug code start
395-
if (log.isDebugEnabled()) {
396-
log.debug(" blockListIndex = " + blockListIndex);
397-
log.debug(" sequence starts on " + getBreakClassName(blockList.startOn));
398-
}
399-
observeElementList(blockList);
400-
//debug code end
401-
402-
//*** Phase 2: Alignment and breaking ***
403-
log.debug("PLM> start of algorithm (" + this.getClass().getName()
404-
+ "), flow BPD =" + flowBPD);
405-
PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
406-
getPageProvider(), createLayoutListener(),
407-
alignment, alignmentLast, footnoteSeparatorLength,
408-
isPartOverflowRecoveryActivated(), autoHeight, isSinglePartFavored());
409-
410-
alg.setConstantLineWidth(flowBPD);
411-
int optimalPageCount = alg.findBreakingPoints(blockList, 1, true,
412-
BreakingAlgorithm.ALL_BREAKS);
413-
boolean ipdChangesOnNextPage = (alg.getIPDdifference() != 0);
414-
boolean onLastPageAndIPDChanges = false;
415-
if (!ipdChangesOnNextPage) {
416-
onLastPageAndIPDChanges = (lastPageHasIPDChange(optimalPageCount) && !thereIsANonRestartableLM(alg)
417-
&& (shouldRedoLayout() || (wasLayoutRedone() && optimalPageCount > 1)));
418-
}
419-
if (shouldRedoLayoutWithoutPagePositionOnly(ipdChangesOnNextPage, optimalPageCount)) {
420-
return false;
421-
}
422-
if (alg.handlingFloat()) {
423-
nextSequenceStartsOn = handleFloatLayout(alg, optimalPageCount, blockList, childLC);
424-
} else if (ipdChangesOnNextPage || onLastPageAndIPDChanges) {
425-
boolean visitedBefore = false;
426-
if (onLastPageAndIPDChanges) {
427-
visitedBefore = wasLayoutRedone();
428-
prepareToRedoLayout(alg, optimalPageCount, blockList, blockList);
385+
try {
386+
//*** Phase 1: Get Knuth elements ***
387+
nextSequenceStartsOn = getNextBlockList(childLC, nextSequenceStartsOn);
388+
empty = empty && blockLists.size() == 0;
389+
390+
//*** Phases 2 and 3 ***
391+
log.debug("PLM> blockLists.size() = " + blockLists.size());
392+
for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
393+
blockList = blockLists.get(blockListIndex);
394+
395+
//debug code start
396+
if (log.isDebugEnabled()) {
397+
log.debug(" blockListIndex = " + blockListIndex);
398+
log.debug(" sequence starts on " + getBreakClassName(blockList.startOn));
429399
}
430-
431-
firstElementsForRestart = null;
432-
RestartAtLM restartAtLMClass = new RestartAtLM();
433-
LayoutManager restartAtLM = restartAtLMClass.getRestartAtLM(this, alg, ipdChangesOnNextPage,
434-
onLastPageAndIPDChanges, visitedBefore, blockList, 1);
435-
if (restartAtLMClass.invalidPosition) {
400+
observeElementList(blockList);
401+
//debug code end
402+
403+
//*** Phase 2: Alignment and breaking ***
404+
log.debug("PLM> start of algorithm (" + this.getClass().getName()
405+
+ "), flow BPD =" + flowBPD);
406+
PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
407+
getPageProvider(), createLayoutListener(),
408+
alignment, alignmentLast, footnoteSeparatorLength,
409+
isPartOverflowRecoveryActivated(), autoHeight, isSinglePartFavored());
410+
411+
alg.setConstantLineWidth(flowBPD);
412+
int optimalPageCount = alg.findBreakingPoints(blockList, 1, true,
413+
BreakingAlgorithm.ALL_BREAKS);
414+
boolean ipdChangesOnNextPage = (alg.getIPDdifference() != 0);
415+
boolean onLastPageAndIPDChanges = false;
416+
if (!ipdChangesOnNextPage) {
417+
onLastPageAndIPDChanges = (lastPageHasIPDChange(optimalPageCount)
418+
&& !thereIsANonRestartableLM(alg)
419+
&& (shouldRedoLayout() || (wasLayoutRedone() && optimalPageCount > 1)));
420+
}
421+
if (shouldRedoLayoutWithoutPagePositionOnly(ipdChangesOnNextPage, optimalPageCount, alg)) {
436422
return false;
437423
}
438-
if (restartAtLM == null || restartAtLM.getChildLMs().isEmpty()) {
424+
if (alg.handlingFloat()) {
425+
nextSequenceStartsOn = handleFloatLayout(alg, optimalPageCount, blockList, childLC);
426+
} else if (ipdChangesOnNextPage || onLastPageAndIPDChanges) {
427+
boolean visitedBefore = false;
428+
if (onLastPageAndIPDChanges) {
429+
visitedBefore = wasLayoutRedone();
430+
prepareToRedoLayout(alg, optimalPageCount, blockList, blockList);
431+
}
432+
439433
firstElementsForRestart = null;
440-
LayoutManager restartAtLM2 = new RestartAtLM().getRestartAtLM(this, alg, ipdChangesOnNextPage,
441-
onLastPageAndIPDChanges, visitedBefore, blockList, 0);
442-
if (restartAtLM2 != null) {
443-
restartAtLM = restartAtLM2;
434+
RestartAtLM restartAtLMClass = new RestartAtLM();
435+
LayoutManager restartAtLM = restartAtLMClass.getRestartAtLM(this, alg, ipdChangesOnNextPage,
436+
onLastPageAndIPDChanges, visitedBefore, blockList, 1);
437+
if (restartAtLMClass.invalidPosition) {
438+
return false;
444439
}
445-
}
446-
if (ipdChangesOnNextPage) {
447-
addAreas(alg, optimalPageCount, blockList, blockList);
448-
}
449-
blockLists.clear();
450-
blockListIndex = -1;
451-
nextSequenceStartsOn = getNextBlockList(childLC, Constants.EN_COLUMN, positionAtBreak,
452-
restartAtLM, firstElementsForRestart);
453-
} else {
454-
log.debug("PLM> optimalPageCount= " + optimalPageCount
455-
+ " pageBreaks.size()= " + alg.getPageBreaks().size());
440+
if (restartAtLM == null || restartAtLM.getChildLMs().isEmpty()) {
441+
firstElementsForRestart = null;
442+
LayoutManager restartAtLM2 = new RestartAtLM().getRestartAtLM(this, alg,
443+
ipdChangesOnNextPage, onLastPageAndIPDChanges, visitedBefore, blockList, 0);
444+
if (restartAtLM2 != null) {
445+
restartAtLM = restartAtLM2;
446+
}
447+
}
448+
if (ipdChangesOnNextPage) {
449+
addAreas(alg, optimalPageCount, blockList, blockList);
450+
}
451+
blockLists.clear();
452+
blockListIndex = -1;
453+
nextSequenceStartsOn = getNextBlockList(childLC, Constants.EN_COLUMN, positionAtBreak,
454+
restartAtLM, firstElementsForRestart);
455+
} else {
456+
log.debug("PLM> optimalPageCount= " + optimalPageCount
457+
+ " pageBreaks.size()= " + alg.getPageBreaks().size());
456458

457-
//*** Phase 3: Add areas ***
458-
doPhase3(alg, optimalPageCount, blockList, blockList);
459+
//*** Phase 3: Add areas ***
460+
doPhase3(alg, optimalPageCount, blockList, blockList);
461+
}
459462
}
463+
} catch (PagePositionOnlyException e) {
464+
return false;
460465
}
461466
}
462467

@@ -465,11 +470,26 @@ public boolean doLayout(int flowBPD, boolean autoHeight) {
465470
return true;
466471
}
467472

468-
private boolean shouldRedoLayoutWithoutPagePositionOnly(boolean ipdChangesOnNextPage, int optimalPageCount) {
473+
static class PagePositionOnlyException extends RuntimeException {
474+
}
475+
476+
private boolean shouldRedoLayoutWithoutPagePositionOnly(boolean ipdChangesOnNextPage, int optimalPageCount,
477+
PageBreakingAlgorithm alg) {
469478
if ((ipdChangesOnNextPage || hasMoreContent() || optimalPageCount > 1)
470479
&& pslm != null && pslm.getCurrentPage().isPagePositionOnly) {
480+
if (getPageProvider().foUserAgent.isLegacySkipPagePositionOnly()) {
481+
return true;
482+
}
471483
RegionBody rb = (RegionBody)pslm.getCurrentPage().getSimplePageMaster().getRegion(Constants.FO_REGION_BODY);
472-
return rb.getColumnCount() == 1;
484+
if (rb.getColumnCount() == 1) {
485+
return true;
486+
}
487+
int restartPoint = getPageProvider().getStartingPartIndexForLastPage(optimalPageCount);
488+
if (restartPoint > 0) {
489+
PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(restartPoint - 1);
490+
int newStartPos = alg.par.getFirstBoxIndex(pbp.getLeafPos() + 1);
491+
return newStartPos > 0;
492+
}
473493
}
474494
return false;
475495
}

fop-core/src/main/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im
6767
private int lastGeneratedPosition = -1;
6868
private int smallestPosNumberChecked = Integer.MAX_VALUE;
6969

70-
private boolean preserveChildrenAtEndOfLayout;
70+
private boolean preserveChildrenAtEndOfLayout = true;
7171

7272
/**
7373
* Abstract layout manager.

fop-core/src/main/java/org/apache/fop/layoutmgr/PageBreaker.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,10 @@ private void handleBreakTrait(int breakVal, boolean emptyContent) {
632632
log.trace("Moving to next flow");
633633
pv.getCurrentSpan().moveToNextFlow();
634634
} else {
635+
if (pslm.getCurrentPage().isPagePositionOnly
636+
&& !pslm.fobj.getUserAgent().isLegacySkipPagePositionOnly()) {
637+
throw new PagePositionOnlyException();
638+
}
635639
log.trace("Making new page");
636640
pslm.makeNewPage(false, emptyContent);
637641
}

fop-core/src/test/java/org/apache/fop/apps/MutableConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ public boolean isSkipPagePositionOnlyAllowed() {
145145
return delegate.isSkipPagePositionOnlyAllowed();
146146
}
147147

148+
public boolean isLegacySkipPagePositionOnly() {
149+
return delegate.isLegacySkipPagePositionOnly();
150+
}
151+
148152
public Map<String, String> getHyphenationPatternNames() {
149153
return delegate.getHyphenationPatternNames();
150154
}

fop-core/src/test/java/org/apache/fop/intermediate/TestAssistant.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ public FopFactory getFopFactory(Document testDoc) {
126126
builder.setTableBorderOverpaint(isTableBorderOverpaint(testDoc));
127127
builder.setSimpleLineBreaking(isSimpleLineBreaking(testDoc));
128128
builder.setSkipPagePositionOnlyAllowed(isSkipPagePositionOnlyAllowed(testDoc));
129+
builder.setLegacySkipPagePositionOnly(isLegacySkipPagePositionOnly(testDoc));
129130
return builder.build();
130131
}
131132

@@ -179,6 +180,15 @@ private boolean isSkipPagePositionOnlyAllowed(Document testDoc) {
179180
}
180181
}
181182

183+
private boolean isLegacySkipPagePositionOnly(Document testDoc) {
184+
try {
185+
String s = eval(testDoc, "/testcase/cfg/legacy-skip-page-position-only");
186+
return "true".equalsIgnoreCase(s);
187+
} catch (XPathExpressionException e) {
188+
throw new RuntimeException(e);
189+
}
190+
}
191+
182192
/**
183193
* Loads a test case into a DOM document.
184194
* @param testFile the test file

0 commit comments

Comments
 (0)