1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id$ */
19 package org.apache.fop.layoutmgr;
20 
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.LinkedList;
24 
25 import org.apache.fop.events.EventBroadcaster;
26 
27 /**
28  * Class to find the restart layoutmanager for changing IPD
29  */
30 class RestartAtLM {
31     protected boolean invalidPosition;
32 
getRestartAtLM(AbstractBreaker breaker, PageBreakingAlgorithm alg, boolean ipdChangesOnNextPage, boolean onLastPageAndIPDChanges, boolean visitedBefore, AbstractBreaker.BlockSequence blockList, int start)33     protected LayoutManager getRestartAtLM(AbstractBreaker breaker, PageBreakingAlgorithm alg,
34                                            boolean ipdChangesOnNextPage, boolean onLastPageAndIPDChanges,
35                                            boolean visitedBefore, AbstractBreaker.BlockSequence blockList, int start) {
36         BreakingAlgorithm.KnuthNode optimalBreak = ipdChangesOnNextPage ? alg.getBestNodeBeforeIPDChange() : alg
37                 .getBestNodeForLastPage();
38         if (onLastPageAndIPDChanges && visitedBefore && breaker.originalRestartAtLM == null) {
39             optimalBreak = null;
40         }
41         int positionIndex = findPositionIndex(breaker, optimalBreak, alg, start);
42         if (ipdChangesOnNextPage || (breaker.positionAtBreak != null && breaker.positionAtBreak.getIndex() > -1)) {
43             breaker.firstElementsForRestart = Collections.EMPTY_LIST;
44             if (ipdChangesOnNextPage) {
45                 if (breaker.containsNonRestartableLM(breaker.positionAtBreak)) {
46                     if (alg.getIPDdifference() > 0) {
47                         EventBroadcaster eventBroadcaster = breaker.getCurrentChildLM().getFObj()
48                                 .getUserAgent().getEventBroadcaster();
49                         BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider
50                                 .get(eventBroadcaster);
51                         eventProducer.nonRestartableContentFlowingToNarrowerPage(this);
52                     }
53                     breaker.firstElementsForRestart = new LinkedList();
54                     boolean boxFound = false;
55                     Iterator iter = blockList.listIterator(positionIndex + 1);
56                     Position position = null;
57                     while (iter.hasNext()
58                             && (position == null || breaker.containsNonRestartableLM(position))) {
59                         positionIndex++;
60                         KnuthElement element = (KnuthElement) iter.next();
61                         position = element.getPosition();
62                         if (element.isBox()) {
63                             boxFound = true;
64                             breaker.firstElementsForRestart.add(element);
65                         } else if (boxFound) {
66                             breaker.firstElementsForRestart.add(element);
67                         }
68                     }
69                     if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) {
70                         /* Retrieve the original position wrapped into this space position */
71                         breaker.positionAtBreak = position.getPosition();
72                     } else {
73                         breaker.positionAtBreak = null;
74                     }
75                 }
76             }
77         }
78         LayoutManager restartAtLM = null;
79         if (ipdChangesOnNextPage || !(breaker.positionAtBreak != null && breaker.positionAtBreak.getIndex() > -1)) {
80             if (breaker.positionAtBreak != null && breaker.positionAtBreak.getIndex() == -1) {
81                 Position position;
82                 Iterator iter = blockList.listIterator(positionIndex + 1);
83                 do {
84                     KnuthElement nextElement = (KnuthElement) iter.next();
85                     position = nextElement.getPosition();
86                 } while (position == null
87                         || position instanceof SpaceResolver.SpaceHandlingPosition
88                         || position instanceof SpaceResolver.SpaceHandlingBreakPosition
89                         && position.getPosition().getIndex() == -1);
90                 LayoutManager surroundingLM = breaker.positionAtBreak.getLM();
91                 while (position.getLM() != surroundingLM) {
92                     position = position.getPosition();
93                 }
94                 if (position.getPosition() == null) {
95                     position.getLM().getFObj().setForceKeepTogether(true);
96                     invalidPosition = true;
97                     return null;
98                 }
99                 restartAtLM = position.getPosition().getLM();
100             }
101             if (onLastPageAndIPDChanges && restartAtLM != null) {
102                 if (breaker.originalRestartAtLM == null) {
103                     breaker.originalRestartAtLM = restartAtLM;
104                 } else {
105                     restartAtLM = breaker.originalRestartAtLM;
106                 }
107                 breaker.firstElementsForRestart = Collections.EMPTY_LIST;
108             }
109         }
110         if (onLastPageAndIPDChanges && !visitedBefore && breaker.positionAtBreak.getPosition() != null) {
111             restartAtLM = breaker.positionAtBreak.getPosition().getLM();
112         }
113         return restartAtLM;
114     }
115 
findPositionIndex(AbstractBreaker breaker, BreakingAlgorithm.KnuthNode optimalBreak, PageBreakingAlgorithm alg, int start)116     private int findPositionIndex(AbstractBreaker breaker, BreakingAlgorithm.KnuthNode optimalBreak,
117                                   PageBreakingAlgorithm alg, int start) {
118         int positionIndex = (optimalBreak != null) ? optimalBreak.position : start;
119         for (int i = positionIndex; i < alg.par.size(); i++) {
120             KnuthElement elementAtBreak = alg.getElement(i);
121             if (elementAtBreak.getPosition() == null) {
122                 elementAtBreak = alg.getElement(0);
123             }
124             breaker.positionAtBreak = elementAtBreak.getPosition();
125             /* Retrieve the original position wrapped into this space position */
126             breaker.positionAtBreak = breaker.positionAtBreak.getPosition();
127             if (breaker.positionAtBreak != null) {
128                 return i;
129             }
130         }
131         return positionIndex;
132     }
133 }
134