Lines 20-26
Link Here
|
20 |
package org.apache.fop.layoutmgr; |
20 |
package org.apache.fop.layoutmgr; |
21 |
|
21 |
|
22 |
import java.util.ArrayList; |
22 |
import java.util.ArrayList; |
23 |
import java.util.Iterator; |
|
|
24 |
import java.util.LinkedList; |
23 |
import java.util.LinkedList; |
25 |
import java.util.List; |
24 |
import java.util.List; |
26 |
import java.util.ListIterator; |
25 |
import java.util.ListIterator; |
Lines 45-84
Link Here
|
45 |
/** List of PageBreakPosition elements. */ |
44 |
/** List of PageBreakPosition elements. */ |
46 |
private LinkedList<PageBreakPosition> pageBreaks = null; |
45 |
private LinkedList<PageBreakPosition> pageBreaks = null; |
47 |
|
46 |
|
48 |
/** Footnotes which are cited between the currently considered active node (previous |
47 |
private final class Footnotes { |
49 |
* break) and the current considered break. Its type is |
48 |
|
50 |
* List<List<KnuthElement>>, it contains the sequences of KnuthElement |
49 |
// demerits for a page break that splits a footnote |
51 |
* representing the footnotes bodies. |
50 |
static final int SPLIT_FOOTNOTE_DEMERITS = 5000; |
52 |
*/ |
51 |
// demerits for a page break that defers a whole footnote to the following page |
53 |
private List<List<KnuthElement>> footnotesList = null; |
52 |
static final int DEFERRED_FOOTNOTE_DEMERITS = 10000; |
54 |
/** Cumulated bpd of unhandled footnotes. */ |
53 |
|
55 |
private List<Integer> lengthList = null; |
54 |
// the length of the footnote separator |
56 |
/** Length of all the footnotes which will be put on the current page. */ |
55 |
private MinOptMax separatorLength = null; |
|
|
56 |
|
57 |
private int totalFootnotesLength = 0; |
57 |
/** Footnotes which are cited between the currently considered active node (previous |
|
|
58 |
* break) and the current considered break. Its type is |
59 |
* List<List<KnuthElement>>, it contains the sequences of KnuthElement |
60 |
* representing the footnotes bodies. |
61 |
*/ |
62 |
private List<List<KnuthElement>> footnotesList = null; |
63 |
/** Cumulated bpd of unhandled footnotes. */ |
64 |
private List<Integer> lengthList = null; |
65 |
/** Length of all the footnotes which will be put on the current page. */ |
58 |
/** |
66 |
private int totalLength = 0; |
59 |
* Length of all the footnotes which have already been inserted, up to the currently |
67 |
|
60 |
* considered element. That is, footnotes from the currently considered page plus |
|
|
61 |
* footnotes from its preceding pages. |
62 |
*/ |
63 |
private int insertedFootnotesLength = 0; |
68 |
/** |
|
|
69 |
* Length of all the footnotes which have already been inserted, up to the currently |
70 |
* considered element. That is, footnotes from the currently considered page plus |
71 |
* footnotes from its preceding pages. |
72 |
*/ |
|
|
73 |
private int insertedFootnotesLength; |
64 |
|
74 |
|
65 |
/** True if footnote citations have been met since the beginning of the page sequence. */ |
75 |
/** True if footnote citations have been met since the beginning of the page sequence. */ |
66 |
private boolean footnotesPending = false; |
76 |
private boolean footnotesPending = false; |
67 |
/** True if the elements met after the previous break point contain footnote citations. */ |
77 |
/** True if the elements met after the previous break point contain footnote citations. */ |
68 |
private boolean newFootnotes = false; |
78 |
private boolean newFootnotes = false; |
69 |
/** Index of the first footnote met after the previous break point. */ |
79 |
/** Index of the first footnote met after the previous break point. */ |
70 |
private int firstNewFootnoteIndex = 0; |
80 |
private int firstNewFootnoteIndex = 0; |
71 |
/** Index of the last footnote inserted on the current page. */ |
81 |
/** Index of the last footnote inserted on the current page. */ |
72 |
private int footnoteListIndex = 0; |
82 |
private int listIndex; |
73 |
/** Index of the last element of the last footnote inserted on the current page. */ |
83 |
/** Index of the last element of the last footnote inserted on the current page. */ |
74 |
private int footnoteElementIndex = -1; |
84 |
private int elementIndex; |
75 |
|
85 |
|
76 |
// demerits for a page break that splits a footnote |
86 |
private Footnotes() { |
77 |
private int splitFootnoteDemerits = 5000; |
87 |
} |
78 |
// demerits for a page break that defers a whole footnote to the following page |
|
|
79 |
private int deferredFootnoteDemerits = 10000; |
80 |
private MinOptMax footnoteSeparatorLength = null; |
81 |
|
88 |
|
|
|
89 |
void initialize() { |
90 |
footnotes.insertedFootnotesLength = 0; |
91 |
footnotes.listIndex = 0; |
92 |
footnotes.elementIndex = -1; |
93 |
} |
94 |
|
95 |
/** |
96 |
* Handles the footnotes cited inside a block-level box. Updates footnotesList and the |
97 |
* value of totalLength with the lengths of the given footnotes. |
98 |
* @param elementLists list of KnuthElement sequences corresponding to the footnotes |
99 |
* bodies |
100 |
*/ |
101 |
void handleFootnotes(List<List<KnuthElement>> elementLists) { |
102 |
// initialization |
103 |
if (!footnotesPending) { |
104 |
footnotesPending = true; |
105 |
footnotesList = new ArrayList<List<KnuthElement>>(); |
106 |
lengthList = new ArrayList<Integer>(); |
107 |
totalLength = 0; |
108 |
} |
109 |
if (!newFootnotes) { |
110 |
newFootnotes = true; |
111 |
firstNewFootnoteIndex = footnotesList.size(); |
112 |
} |
113 |
|
114 |
// compute the total length of the footnotes |
115 |
for (List<KnuthElement> noteList : elementLists) { |
116 |
|
117 |
//Space resolution (Note: this does not respect possible stacking constraints |
118 |
//between footnotes!) |
119 |
SpaceResolver.resolveElementList(noteList); |
120 |
|
121 |
footnotesList.add(noteList); |
122 |
int noteLength = ElementListUtils.calcContentLength(noteList); |
123 |
int prevLength = (lengthList == null || lengthList.isEmpty()) |
124 |
? 0 |
125 |
: ListUtil.getLast(lengthList); |
126 |
if (lengthList != null) { |
127 |
lengthList.add(prevLength + noteLength); |
128 |
} |
129 |
totalLength += noteLength; |
130 |
} |
131 |
} |
132 |
|
133 |
void resetFootnotes(int fromIndex, int toIndex) { |
134 |
newFootnotes = false; |
135 |
if (footnotesPending) { |
136 |
// remove from footnotesList the note lists that will be met |
137 |
// after the restarting point |
138 |
KnuthElement resetElement; |
139 |
int start = footnotesList.size(); |
140 |
int end = start; |
141 |
for (int j = toIndex; j >= fromIndex; j--) { |
142 |
resetElement = getElement(j); |
143 |
if (resetElement instanceof KnuthBlockBox |
144 |
&& ((KnuthBlockBox) resetElement).hasAnchors()) { |
145 |
start -= ((KnuthBlockBox) resetElement).getElementLists().size(); |
146 |
} |
147 |
} |
148 |
footnotesList.subList(start, end).clear(); |
149 |
lengthList.subList(start, end).clear(); |
150 |
// update totalLength |
151 |
totalLength = (lengthList.isEmpty() ? 0 : ListUtil.getLast(lengthList)); |
152 |
// update footnotesPending; |
153 |
footnotesPending = !footnotesList.isEmpty(); |
154 |
listIndex = footnotesList.size() - 1; |
155 |
elementIndex = (listIndex < 0 |
156 |
? -1 : getList(listIndex).size() - 1); |
157 |
} |
158 |
} |
159 |
|
160 |
int getDifference(KnuthPageNode pageNode, int elementIndex) { |
161 |
|
162 |
int contentWidth = totalWidth - pageNode.totalWidth; |
163 |
|
164 |
int totalIntrusions = 0; |
165 |
|
166 |
// compute the total length of the footnotes not yet inserted |
167 |
int allFootnotes = totalLength; |
168 |
KnuthPageNode lastPageNode = pageNode; |
169 |
while (lastPageNode != null |
170 |
&& !pageProvider.endPage(lastPageNode.line - 1)) { |
171 |
lastPageNode = (KnuthPageNode) lastPageNode.previous; |
172 |
} |
173 |
allFootnotes -= (lastPageNode == null ? 0 : lastPageNode.totalFootnotes); |
174 |
|
175 |
if (allFootnotes > 0) { |
176 |
// this page/column contains some footnote citations |
177 |
// add the footnote separator width |
178 |
totalIntrusions += separatorLength.getOpt(); |
179 |
totalIntrusions += allFootnotes; |
180 |
insertedFootnotesLength = totalLength; |
181 |
listIndex = footnotesList.size() - 1; |
182 |
this.elementIndex = getList(listIndex).size() - 1; |
183 |
|
184 |
int availableWidth = getLineWidth(pageNode.line); |
185 |
if ((contentWidth + totalIntrusions) > availableWidth) { |
186 |
// see if part of the footnotes can be deferred |
187 |
boolean canDeferOldFN = canDeferOldFootnotes(pageNode, elementIndex); |
188 |
if (canDeferOldFN || newFootnotes) { |
189 |
availableWidth -= (contentWidth + separatorLength.getOpt()); |
190 |
int footnoteSplit = (availableWidth <= 0 ? 0 |
191 |
: getFootnoteSplit(pageNode, availableWidth, canDeferOldFN)); |
192 |
if (footnoteSplit > 0) { |
193 |
// the total of content + separator + all footnotes does not fit, but |
194 |
// it is allowed to break or even defer footnotes if either: |
195 |
// - there are new footnotes in the last piece of content, and |
196 |
// there is space to add at least a piece of the first one |
197 |
// - or the previous page break deferred some footnote lines, and |
198 |
// this is the first feasible break; in this case it is allowed |
199 |
// to break and defer, if necessary, old and new footnotes |
200 |
totalIntrusions -= allFootnotes; |
201 |
totalIntrusions += footnoteSplit; |
202 |
insertedFootnotesLength = pageNode.totalFootnotes + footnoteSplit; |
203 |
// listIndex has been set in getFootnoteSplit() |
204 |
// elementIndex has been set in getFootnoteSplit() |
205 |
} else { |
206 |
// there is no space to add even the smallest piece of footnote, |
207 |
// the whole allFootnotes length was added, so this breakpoint |
208 |
// will be discarded |
209 |
} |
210 |
} else { |
211 |
// we are trying to add a piece of content with no footnotes and |
212 |
// it does not fit in the page, because of previous footnote bodies |
213 |
// that cannot be broken: |
214 |
// the whole allFootnotes length was added, so this breakpoint |
215 |
// will be discarded |
216 |
} |
217 |
} |
218 |
} else { |
219 |
// all footnotes have already been placed on previous pages |
220 |
} |
221 |
|
222 |
return totalIntrusions; |
223 |
} |
224 |
|
225 |
int getDemerits() { |
226 |
int demerits = 0; |
227 |
if (footnotes.listIndex < footnotes.footnotesList.size() - 1) { |
228 |
// add demerits for the deferred footnotes |
229 |
demerits += (footnotes.footnotesList.size() - 1 - footnotes.listIndex) |
230 |
* DEFERRED_FOOTNOTE_DEMERITS; |
231 |
} |
232 |
if (footnotes.elementIndex |
233 |
< getList(footnotes.listIndex).size() - 1) { |
234 |
// add demerits for the footnote split between pages |
235 |
demerits += SPLIT_FOOTNOTE_DEMERITS; |
236 |
} |
237 |
return demerits; |
238 |
} |
239 |
|
240 |
boolean deferredFootnotes(int listIndex, int elementIndex, int length) { |
241 |
return ((newFootnotes |
242 |
&& firstNewFootnoteIndex != 0 |
243 |
&& (listIndex < firstNewFootnoteIndex - 1 |
244 |
|| elementIndex < getList(listIndex).size() - 1)) |
245 |
|| length < totalLength); |
246 |
} |
247 |
|
248 |
int getFootnoteSplit(int availableLength) { |
249 |
return getFootnoteSplit(listIndex, |
250 |
elementIndex, |
251 |
totalLength, |
252 |
availableLength, true); |
253 |
} |
254 |
|
255 |
int getFootnoteSplit(KnuthPageNode activeNode, int availableLength, |
256 |
boolean canDeferOldFootnotes) { |
257 |
return getFootnoteSplit(activeNode.footnoteListIndex, |
258 |
activeNode.footnoteElementIndex, |
259 |
activeNode.totalFootnotes, |
260 |
availableLength, canDeferOldFootnotes); |
261 |
} |
262 |
|
263 |
int getFootnoteSplit(int prevListIndex, int prevElementIndex, int prevLength, |
264 |
int availableLength, boolean canDeferOldFootnotes) { |
265 |
|
266 |
// the split should contain a piece of the last footnote |
267 |
// together with all previous, not yet inserted footnotes; |
268 |
// but if this is not possible, try adding as much content as possible |
269 |
int splitLength = 0; |
270 |
ListIterator<KnuthElement> noteListIterator; |
271 |
KnuthElement element; |
272 |
boolean somethingAdded = false; |
273 |
|
274 |
// prevListIndex and prevElementIndex points to the last footnote element |
275 |
// already placed in a page: advance to the next element |
276 |
int listIndex = prevListIndex; |
277 |
int elementIndex = prevElementIndex; |
278 |
if (elementIndex == getList(listIndex).size() - 1) { |
279 |
listIndex++; |
280 |
elementIndex = 0; |
281 |
} else { |
282 |
elementIndex++; |
283 |
} |
284 |
|
285 |
// try adding whole notes |
286 |
if (footnotesList.size() - 1 > listIndex) { |
287 |
// add the previous footnotes: these cannot be broken or deferred |
288 |
if (!canDeferOldFootnotes && newFootnotes && firstNewFootnoteIndex > 0) { |
289 |
splitLength = lengthList.get(firstNewFootnoteIndex - 1) - prevLength; |
290 |
listIndex = firstNewFootnoteIndex; |
291 |
elementIndex = 0; |
292 |
} |
293 |
// try adding the new footnotes |
294 |
while (lengthList.get(listIndex) - prevLength <= availableLength) { |
295 |
splitLength = lengthList.get(listIndex) - prevLength; |
296 |
somethingAdded = true; |
297 |
listIndex++; |
298 |
elementIndex = 0; |
299 |
} |
300 |
// as this method is called only if it is not possible to insert |
301 |
// all footnotes, at this point listIndex and elementIndex points to |
302 |
// an existing element, the next one we will try to insert |
303 |
} |
304 |
|
305 |
// try adding a split of the next note |
306 |
noteListIterator = getList(listIndex).listIterator(elementIndex); |
307 |
|
308 |
int prevSplitLength = 0; |
309 |
int prevIndex = -1; |
310 |
int index = -1; |
311 |
|
312 |
while (!somethingAdded || splitLength <= availableLength) { |
313 |
if (!somethingAdded) { |
314 |
somethingAdded = true; |
315 |
} else { |
316 |
prevSplitLength = splitLength; |
317 |
prevIndex = index; |
318 |
} |
319 |
|
320 |
// get a sub-sequence from the note element list |
321 |
boolean boxPreceding = false; |
322 |
while (noteListIterator.hasNext()) { |
323 |
// as this method is called only if it is not possible to insert |
324 |
// all footnotes, and we have already tried (and failed) to insert |
325 |
// this whole footnote, the while loop will never reach the end |
326 |
// of the note sequence |
327 |
element = noteListIterator.next(); |
328 |
if (element.isBox()) { |
329 |
// element is a box |
330 |
splitLength += element.getWidth(); |
331 |
boxPreceding = true; |
332 |
} else if (element.isGlue()) { |
333 |
// element is a glue |
334 |
if (boxPreceding) { |
335 |
// end of the sub-sequence |
336 |
index = noteListIterator.previousIndex(); |
337 |
break; |
338 |
} |
339 |
boxPreceding = false; |
340 |
splitLength += element.getWidth(); |
341 |
} else { |
342 |
// element is a penalty |
343 |
if (element.getPenalty() < KnuthElement.INFINITE) { |
344 |
// end of the sub-sequence |
345 |
index = noteListIterator.previousIndex(); |
346 |
break; |
347 |
} |
348 |
} |
349 |
} |
350 |
} |
351 |
|
352 |
// if prevSplitLength is 0, this means that the available length isn't enough |
353 |
// to insert even the smallest split of the last footnote, so we cannot end a |
354 |
// page here |
355 |
// if prevSplitLength is > 0 we can insert some footnote content in this page |
356 |
// and insert the remaining in the following one |
357 |
//TODO: check this conditional, as the first one is always false...? |
358 |
if (!somethingAdded) { |
359 |
// there was not enough space to add a piece of the first new footnote |
360 |
// this is not a good break |
361 |
prevSplitLength = 0; |
362 |
} else if (prevSplitLength > 0) { |
363 |
// prevIndex is -1 if we have added only some whole footnotes |
364 |
this.listIndex = (prevIndex != -1) ? listIndex : listIndex - 1; |
365 |
this.elementIndex = (prevIndex != -1) |
366 |
? prevIndex |
367 |
: getList(this.listIndex).size() - 1; |
368 |
} |
369 |
return prevSplitLength; |
370 |
} |
371 |
|
372 |
boolean footnotesRemaining() { |
373 |
return insertedFootnotesLength < totalLength; |
374 |
} |
375 |
|
376 |
int currentLength() { |
377 |
return lengthList.get(listIndex); |
378 |
} |
379 |
|
380 |
List<KnuthElement> getList(int index) { |
381 |
return footnotesList.get(index); |
382 |
} |
383 |
} |
384 |
|
385 |
private Footnotes footnotes; |
386 |
|
82 |
// the method noBreakBetween(int, int) uses these variables |
387 |
// the method noBreakBetween(int, int) uses these variables |
83 |
// to store parameters and result of the last call, in order |
388 |
// to store parameters and result of the last call, in order |
84 |
// to reuse them and take less time |
389 |
// to reuse them and take less time |
Lines 130-136
Link Here
|
130 |
this.pageProvider = pageProvider; |
435 |
this.pageProvider = pageProvider; |
131 |
this.layoutListener = layoutListener; |
436 |
this.layoutListener = layoutListener; |
132 |
best = new BestPageRecords(); |
437 |
best = new BestPageRecords(); |
133 |
this.footnoteSeparatorLength = footnoteSeparatorLength; |
438 |
this.footnotes = new Footnotes(); |
|
|
439 |
this.footnotes.separatorLength = footnoteSeparatorLength; |
134 |
this.autoHeight = autoHeight; |
440 |
this.autoHeight = autoHeight; |
135 |
this.favorSinglePart = favorSinglePart; |
441 |
this.favorSinglePart = favorSinglePart; |
136 |
} |
442 |
} |
Lines 165-171
Link Here
|
165 |
this.footnoteElementIndex = footnoteElementIndex; |
471 |
this.footnoteElementIndex = footnoteElementIndex; |
166 |
} |
472 |
} |
167 |
|
473 |
|
168 |
} |
474 |
@Override |
|
|
475 |
public String toString() { |
476 |
StringBuilder sb = new StringBuilder(super.toString()); |
477 |
sb.deleteCharAt(sb.length() - 1); |
478 |
sb.append(" totalFootnotes:").append(totalFootnotes); |
479 |
sb.append(" footnoteList:").append(footnoteListIndex); |
480 |
sb.append(" footnoteElement:").append(footnoteElementIndex).append('>'); |
481 |
return sb.toString(); |
|
|
482 |
} |
483 |
} |
169 |
|
484 |
|
170 |
/** |
485 |
/** |
171 |
* this class stores information about how the nodes |
486 |
* this class stores information about how the nodes |
Lines 183-191
Link Here
|
183 |
super.addRecord(demerits, node, adjust, |
498 |
super.addRecord(demerits, node, adjust, |
184 |
availableShrink, availableStretch, |
499 |
availableShrink, availableStretch, |
185 |
difference, fitness); |
500 |
difference, fitness); |
186 |
bestFootnotesLength[fitness] = insertedFootnotesLength; |
501 |
bestFootnotesLength[fitness] = footnotes.insertedFootnotesLength; |
187 |
bestFootnoteListIndex[fitness] = footnoteListIndex; |
502 |
bestFootnoteListIndex[fitness] = footnotes.listIndex; |
188 |
bestFootnoteElementIndex[fitness] = footnoteElementIndex; |
503 |
bestFootnoteElementIndex[fitness] = footnotes.elementIndex; |
189 |
} |
504 |
} |
190 |
|
505 |
|
191 |
public int getFootnotesLength(int fitness) { |
506 |
public int getFootnotesLength(int fitness) { |
Lines 205-213
Link Here
|
205 |
@Override |
520 |
@Override |
206 |
protected void initialize() { |
521 |
protected void initialize() { |
207 |
super.initialize(); |
522 |
super.initialize(); |
208 |
insertedFootnotesLength = 0; |
523 |
footnotes.initialize(); |
209 |
footnoteListIndex = 0; |
|
|
210 |
footnoteElementIndex = -1; |
211 |
} |
524 |
} |
212 |
|
525 |
|
213 |
/** |
526 |
/** |
Lines 279-285
Link Here
|
279 |
return super.compareNodes(node1, node2); |
592 |
return super.compareNodes(node1, node2); |
280 |
} |
593 |
} |
281 |
|
594 |
|
282 |
/** {@inheritDoc} */ |
|
|
283 |
@Override |
595 |
@Override |
284 |
protected KnuthNode createNode(int position, // CSOK: ParameterNumber |
596 |
protected KnuthNode createNode(int position, // CSOK: ParameterNumber |
285 |
int line, int fitness, |
597 |
int line, int fitness, |
Lines 288-299
Link Here
|
288 |
int difference, double totalDemerits, KnuthNode previous) { |
600 |
int difference, double totalDemerits, KnuthNode previous) { |
289 |
return new KnuthPageNode(position, line, fitness, |
601 |
return new KnuthPageNode(position, line, fitness, |
290 |
totalWidth, totalStretch, totalShrink, |
602 |
totalWidth, totalStretch, totalShrink, |
291 |
insertedFootnotesLength, footnoteListIndex, footnoteElementIndex, |
603 |
footnotes.insertedFootnotesLength, |
|
|
604 |
footnotes.listIndex, |
605 |
footnotes.elementIndex, |
292 |
adjustRatio, availableShrink, availableStretch, |
606 |
adjustRatio, availableShrink, availableStretch, |
293 |
difference, totalDemerits, previous); |
607 |
difference, totalDemerits, previous); |
294 |
} |
608 |
} |
295 |
|
609 |
|
296 |
/** {@inheritDoc} */ |
|
|
297 |
@Override |
610 |
@Override |
298 |
protected KnuthNode createNode(int position, int line, int fitness, |
611 |
protected KnuthNode createNode(int position, int line, int fitness, |
299 |
int totalWidth, int totalStretch, int totalShrink) { |
612 |
int totalWidth, int totalStretch, int totalShrink) { |
Lines 317-326
Link Here
|
317 |
super.handleBox(box); |
630 |
super.handleBox(box); |
318 |
if (box instanceof KnuthBlockBox |
631 |
if (box instanceof KnuthBlockBox |
319 |
&& ((KnuthBlockBox) box).hasAnchors()) { |
632 |
&& ((KnuthBlockBox) box).hasAnchors()) { |
320 |
handleFootnotes(((KnuthBlockBox) box).getElementLists()); |
633 |
footnotes.handleFootnotes(((KnuthBlockBox) box).getElementLists()); |
321 |
if (!newFootnotes) { |
634 |
if (!footnotes.newFootnotes) { |
322 |
newFootnotes = true; |
635 |
footnotes.newFootnotes = true; |
323 |
firstNewFootnoteIndex = footnotesList.size() - 1; |
636 |
footnotes.firstNewFootnoteIndex = footnotes.footnotesList.size() - 1; |
324 |
} |
637 |
} |
325 |
} |
638 |
} |
326 |
} |
639 |
} |
Lines 348-434
Link Here
|
348 |
} |
661 |
} |
349 |
} |
662 |
} |
350 |
|
663 |
|
351 |
/** |
|
|
352 |
* Handles the footnotes cited inside a block-level box. Updates footnotesList and the |
353 |
* value of totalFootnotesLength with the lengths of the given footnotes. |
354 |
* @param elementLists list of KnuthElement sequences corresponding to the footnotes |
355 |
* bodies |
356 |
*/ |
357 |
private void handleFootnotes(List<List<KnuthElement>> elementLists) { |
358 |
// initialization |
359 |
if (!footnotesPending) { |
360 |
footnotesPending = true; |
361 |
footnotesList = new ArrayList<List<KnuthElement>>(); |
362 |
lengthList = new ArrayList<Integer>(); |
363 |
totalFootnotesLength = 0; |
364 |
} |
365 |
if (!newFootnotes) { |
366 |
newFootnotes = true; |
367 |
firstNewFootnoteIndex = footnotesList.size(); |
368 |
} |
369 |
|
370 |
// compute the total length of the footnotes |
371 |
for (List<KnuthElement> noteList : elementLists) { |
372 |
|
373 |
//Space resolution (Note: this does not respect possible stacking constraints |
374 |
//between footnotes!) |
375 |
SpaceResolver.resolveElementList(noteList); |
376 |
|
377 |
int noteLength = 0; |
378 |
footnotesList.add(noteList); |
379 |
for (KnuthElement element : noteList) { |
380 |
if (element.isBox() || element.isGlue()) { |
381 |
noteLength += element.getWidth(); |
382 |
} |
383 |
} |
384 |
int prevLength = (lengthList == null || lengthList.isEmpty()) |
385 |
? 0 |
386 |
: ListUtil.getLast(lengthList); |
387 |
if (lengthList != null) { |
388 |
lengthList.add(prevLength + noteLength); |
389 |
} |
390 |
totalFootnotesLength += noteLength; |
391 |
} |
392 |
} |
393 |
|
394 |
/** {@inheritDoc} */ |
395 |
@Override |
664 |
@Override |
396 |
protected int restartFrom(KnuthNode restartingNode, int currentIndex) { |
665 |
protected int restartFrom(KnuthNode restartingNode, int currentIndex) { |
397 |
int returnValue = super.restartFrom(restartingNode, currentIndex); |
666 |
int returnValue = super.restartFrom(restartingNode, currentIndex); |
398 |
newFootnotes = false; |
667 |
footnotes.resetFootnotes(restartingNode.position, currentIndex); |
399 |
if (footnotesPending) { |
|
|
400 |
// remove from footnotesList the note lists that will be met |
401 |
// after the restarting point |
402 |
for (int j = currentIndex; j >= restartingNode.position; j--) { |
403 |
final KnuthElement resetElement = getElement(j); |
404 |
if (resetElement instanceof KnuthBlockBox |
405 |
&& ((KnuthBlockBox) resetElement).hasAnchors()) { |
406 |
resetFootnotes(((KnuthBlockBox) resetElement).getElementLists()); |
407 |
} |
408 |
} |
409 |
} |
410 |
return returnValue; |
668 |
return returnValue; |
411 |
} |
669 |
} |
412 |
|
670 |
|
413 |
private void resetFootnotes(List<List<KnuthElement>> elementLists) { |
|
|
414 |
for (int i = 0; i < elementLists.size(); i++) { |
415 |
ListUtil.removeLast(footnotesList); |
416 |
ListUtil.removeLast(lengthList); |
417 |
|
418 |
// update totalFootnotesLength |
419 |
if (!lengthList.isEmpty()) { |
420 |
totalFootnotesLength = ListUtil.getLast(lengthList); |
421 |
} else { |
422 |
totalFootnotesLength = 0; |
423 |
} |
424 |
} |
425 |
// update footnotesPending; |
426 |
if (footnotesList.size() == 0) { |
427 |
footnotesPending = false; |
428 |
} |
429 |
} |
430 |
|
431 |
/** {@inheritDoc} */ |
432 |
@Override |
671 |
@Override |
433 |
protected void considerLegalBreak(KnuthElement element, int elementIdx) { |
672 |
protected void considerLegalBreak(KnuthElement element, int elementIdx) { |
434 |
if (element.isPenalty()) { |
673 |
if (element.isPenalty()) { |
Lines 454-463
Link Here
|
454 |
} |
693 |
} |
455 |
} |
694 |
} |
456 |
super.considerLegalBreak(element, elementIdx); |
695 |
super.considerLegalBreak(element, elementIdx); |
457 |
newFootnotes = false; |
696 |
footnotes.newFootnotes = false; |
458 |
} |
697 |
} |
459 |
|
698 |
|
460 |
/** {@inheritDoc} */ |
|
|
461 |
@Override |
699 |
@Override |
462 |
protected boolean elementCanEndLine(KnuthElement element, int line, int difference) { |
700 |
protected boolean elementCanEndLine(KnuthElement element, int line, int difference) { |
463 |
if (!(element.isPenalty()) || pageProvider == null) { |
701 |
if (!(element.isPenalty()) || pageProvider == null) { |
Lines 490-563
Link Here
|
490 |
} |
728 |
} |
491 |
} |
729 |
} |
492 |
|
730 |
|
493 |
/** {@inheritDoc} */ |
|
|
494 |
@Override |
731 |
@Override |
495 |
protected int computeDifference(KnuthNode activeNode, KnuthElement element, |
732 |
protected int computeDifference(KnuthNode activeNode, KnuthElement element, |
496 |
int elementIndex) { |
733 |
int elementIndex) { |
497 |
KnuthPageNode pageNode = (KnuthPageNode) activeNode; |
734 |
|
498 |
int actualWidth = totalWidth - pageNode.totalWidth; |
735 |
int diff = super.computeDifference(activeNode, element, elementIndex); |
499 |
int footnoteSplit; |
736 |
//getLineWidth() for auto-height parts return 0 so the diff will be negative |
500 |
boolean canDeferOldFN; |
737 |
//...but we don't want to shrink in this case. Stick to optimum. |
501 |
if (element.isPenalty()) { |
738 |
return (autoHeight && (diff < 0) ? 0 : diff); |
502 |
actualWidth += element.getWidth(); |
|
|
503 |
} |
739 |
} |
504 |
if (footnotesPending) { |
740 |
|
505 |
// compute the total length of the footnotes not yet inserted |
741 |
@Override |
506 |
int allFootnotes = totalFootnotesLength - pageNode.totalFootnotes; |
742 |
protected boolean hasOutOfLineIntrusions() { |
507 |
if (allFootnotes > 0) { |
743 |
return footnotes.footnotesPending; |
508 |
// this page contains some footnote citations |
|
|
509 |
// add the footnote separator width |
510 |
actualWidth += footnoteSeparatorLength.getOpt(); |
511 |
if (actualWidth + allFootnotes <= getLineWidth(activeNode.line)) { |
512 |
// there is enough space to insert all footnotes: |
513 |
// add the whole allFootnotes length |
514 |
actualWidth += allFootnotes; |
515 |
insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes; |
516 |
footnoteListIndex = footnotesList.size() - 1; |
517 |
footnoteElementIndex |
518 |
= getFootnoteList(footnoteListIndex).size() - 1; |
519 |
} else if (((canDeferOldFN = canDeferOldFootnotes // CSOK: InnerAssignment |
520 |
(pageNode, elementIndex)) |
521 |
|| newFootnotes) |
522 |
&& (footnoteSplit = getFootnoteSplit // CSOK: InnerAssignment |
523 |
(pageNode, getLineWidth(activeNode.line) - actualWidth, |
524 |
canDeferOldFN)) > 0) { |
525 |
// it is allowed to break or even defer footnotes if either: |
526 |
// - there are new footnotes in the last piece of content, and |
527 |
// there is space to add at least a piece of the first one |
528 |
// - or the previous page break deferred some footnote lines, and |
529 |
// this is the first feasible break; in this case it is allowed |
530 |
// to break and defer, if necessary, old and new footnotes |
531 |
actualWidth += footnoteSplit; |
532 |
insertedFootnotesLength = pageNode.totalFootnotes + footnoteSplit; |
533 |
// footnoteListIndex has been set in getFootnoteSplit() |
534 |
// footnoteElementIndex has been set in getFootnoteSplit() |
535 |
} else { |
536 |
// there is no space to add the smallest piece of footnote, |
537 |
// or we are trying to add a piece of content with no footnotes and |
538 |
// it does not fit in the page, because of previous footnote bodies |
539 |
// that cannot be broken: |
540 |
// add the whole allFootnotes length, so this breakpoint will be discarded |
541 |
actualWidth += allFootnotes; |
542 |
insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes; |
543 |
footnoteListIndex = footnotesList.size() - 1; |
544 |
footnoteElementIndex |
545 |
= getFootnoteList(footnoteListIndex).size() - 1; |
546 |
} |
744 |
} |
|
|
745 |
|
746 |
@Override |
747 |
protected int getOutOfLineIntrusions(KnuthNode activeNode, int elementIndex) { |
748 |
|
749 |
assert (activeNode != null); |
750 |
KnuthPageNode pageNode = (KnuthPageNode) activeNode; |
751 |
int totalIntrusions = 0; |
752 |
|
753 |
if (footnotes.footnotesPending) { |
754 |
totalIntrusions += footnotes.getDifference(pageNode, elementIndex); |
547 |
} else { |
755 |
} else { |
548 |
// all footnotes have already been placed on previous pages |
|
|
549 |
} |
550 |
} else { |
551 |
// there are no footnotes |
756 |
// there are no footnotes |
552 |
} |
757 |
} |
553 |
int diff = getLineWidth(activeNode.line) - actualWidth; |
758 |
|
554 |
if (autoHeight && diff < 0) { |
759 |
return totalIntrusions; |
555 |
//getLineWidth() for auto-height parts return 0 so the diff will be negative |
|
|
556 |
return 0; //...but we don't want to shrink in this case. Stick to optimum. |
557 |
} else { |
558 |
return diff; |
559 |
} |
760 |
} |
560 |
} |
|
|
561 |
|
761 |
|
562 |
/** |
762 |
/** |
563 |
* Checks whether footnotes from preceding pages may be deferred to the page after |
763 |
* Checks whether footnotes from preceding pages may be deferred to the page after |
Lines 569-576
Link Here
|
569 |
*/ |
769 |
*/ |
570 |
private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) { |
770 |
private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) { |
571 |
return (noBreakBetween(node.position, contentElementIndex) |
771 |
return (noBreakBetween(node.position, contentElementIndex) |
572 |
&& deferredFootnotes(node.footnoteListIndex, |
772 |
&& footnotes.deferredFootnotes(node.footnoteListIndex, |
573 |
node.footnoteElementIndex, node.totalFootnotes)); |
773 |
node.footnoteElementIndex, node.totalFootnotes)); |
574 |
} |
774 |
} |
575 |
|
775 |
|
576 |
/** |
776 |
/** |
Lines 624-789
Link Here
|
624 |
return storedValue; |
824 |
return storedValue; |
625 |
} |
825 |
} |
626 |
|
826 |
|
627 |
/** |
|
|
628 |
* Returns true if their are (pieces of) footnotes to be typeset on the current page. |
629 |
* @param listIndex index of the last inserted footnote for the currently considered |
630 |
* active node |
631 |
* @param elementIndex index of the last element of the last inserted footnote |
632 |
* @param length total length of all footnotes inserted so far |
633 |
*/ |
634 |
private boolean deferredFootnotes(int listIndex, int elementIndex, int length) { |
635 |
return ((newFootnotes |
636 |
&& firstNewFootnoteIndex != 0 |
637 |
&& (listIndex < firstNewFootnoteIndex - 1 |
638 |
|| elementIndex < getFootnoteList(listIndex).size() - 1)) |
639 |
|| length < totalFootnotesLength); |
640 |
} |
641 |
|
642 |
/** |
643 |
* Tries to split the flow of footnotes to put one part on the current page. |
644 |
* @param activeNode currently considered previous page break |
645 |
* @param availableLength available space for footnotes |
646 |
* @param canDeferOldFootnotes |
647 |
* @return ... |
648 |
*/ |
649 |
private int getFootnoteSplit(KnuthPageNode activeNode, int availableLength, |
650 |
boolean canDeferOldFootnotes) { |
651 |
return getFootnoteSplit(activeNode.footnoteListIndex, |
652 |
activeNode.footnoteElementIndex, |
653 |
activeNode.totalFootnotes, |
654 |
availableLength, canDeferOldFootnotes); |
655 |
} |
656 |
|
657 |
/** |
658 |
* Tries to split the flow of footnotes to put one part on the current page. |
659 |
* @param prevListIndex index of the last footnote on the previous page |
660 |
* @param prevElementIndex index of the last element of the last footnote |
661 |
* @param prevLength total length of footnotes inserted so far |
662 |
* @param availableLength available space for footnotes on this page |
663 |
* @param canDeferOldFootnotes |
664 |
* @return ... |
665 |
*/ |
666 |
private int getFootnoteSplit(int prevListIndex, int prevElementIndex, int prevLength, |
667 |
int availableLength, boolean canDeferOldFootnotes) { |
668 |
if (availableLength <= 0) { |
669 |
return 0; |
670 |
} else { |
671 |
// the split should contain a piece of the last footnote |
672 |
// together with all previous, not yet inserted footnotes; |
673 |
// but if this is not possible, try adding as much content as possible |
674 |
int splitLength = 0; |
675 |
ListIterator<KnuthElement> noteListIterator; |
676 |
KnuthElement element; |
677 |
boolean somethingAdded = false; |
678 |
|
679 |
// prevListIndex and prevElementIndex points to the last footnote element |
680 |
// already placed in a page: advance to the next element |
681 |
int listIndex = prevListIndex; |
682 |
int elementIndex = prevElementIndex; |
683 |
if (elementIndex == getFootnoteList(listIndex).size() - 1) { |
684 |
listIndex++; |
685 |
elementIndex = 0; |
686 |
} else { |
687 |
elementIndex++; |
688 |
} |
689 |
|
690 |
// try adding whole notes |
691 |
if (footnotesList.size() - 1 > listIndex) { |
692 |
// add the previous footnotes: these cannot be broken or deferred |
693 |
if (!canDeferOldFootnotes && newFootnotes && firstNewFootnoteIndex > 0) { |
694 |
splitLength = lengthList.get(firstNewFootnoteIndex - 1) - prevLength; |
695 |
listIndex = firstNewFootnoteIndex; |
696 |
elementIndex = 0; |
697 |
} |
698 |
// try adding the new footnotes |
699 |
while (lengthList.get(listIndex) - prevLength |
700 |
<= availableLength) { |
701 |
splitLength = lengthList.get(listIndex) - prevLength; |
702 |
somethingAdded = true; |
703 |
listIndex++; |
704 |
elementIndex = 0; |
705 |
} |
706 |
// as this method is called only if it is not possible to insert |
707 |
// all footnotes, at this point listIndex and elementIndex points to |
708 |
// an existing element, the next one we will try to insert |
709 |
} |
710 |
|
711 |
// try adding a split of the next note |
712 |
noteListIterator = getFootnoteList(listIndex).listIterator(elementIndex); |
713 |
|
714 |
int prevSplitLength = 0; |
715 |
int prevIndex = -1; |
716 |
int index = -1; |
717 |
|
718 |
while (!(somethingAdded && splitLength > availableLength)) { |
719 |
if (!somethingAdded) { |
720 |
somethingAdded = true; |
721 |
} else { |
722 |
prevSplitLength = splitLength; |
723 |
prevIndex = index; |
724 |
} |
725 |
// get a sub-sequence from the note element list |
726 |
boolean boxPreceding = false; |
727 |
while (noteListIterator.hasNext()) { |
728 |
// as this method is called only if it is not possible to insert |
729 |
// all footnotes, and we have already tried (and failed) to insert |
730 |
// this whole footnote, the while loop will never reach the end |
731 |
// of the note sequence |
732 |
element = noteListIterator.next(); |
733 |
if (element.isBox()) { |
734 |
// element is a box |
735 |
splitLength += element.getWidth(); |
736 |
boxPreceding = true; |
737 |
} else if (element.isGlue()) { |
738 |
// element is a glue |
739 |
if (boxPreceding) { |
740 |
// end of the sub-sequence |
741 |
index = noteListIterator.previousIndex(); |
742 |
break; |
743 |
} |
744 |
boxPreceding = false; |
745 |
splitLength += element.getWidth(); |
746 |
} else { |
747 |
// element is a penalty |
748 |
if (element.getPenalty() < KnuthElement.INFINITE) { |
749 |
// end of the sub-sequence |
750 |
index = noteListIterator.previousIndex(); |
751 |
break; |
752 |
} |
753 |
} |
754 |
} |
755 |
} |
756 |
|
757 |
// if prevSplitLength is 0, this means that the available length isn't enough |
758 |
// to insert even the smallest split of the last footnote, so we cannot end a |
759 |
// page here |
760 |
// if prevSplitLength is > 0 we can insert some footnote content in this page |
761 |
// and insert the remaining in the following one |
762 |
//TODO: check this conditional, as the first one is always false...? |
763 |
if (!somethingAdded) { |
764 |
// there was not enough space to add a piece of the first new footnote |
765 |
// this is not a good break |
766 |
prevSplitLength = 0; |
767 |
} else if (prevSplitLength > 0) { |
768 |
// prevIndex is -1 if we have added only some whole footnotes |
769 |
footnoteListIndex = (prevIndex != -1) ? listIndex : listIndex - 1; |
770 |
footnoteElementIndex = (prevIndex != -1) |
771 |
? prevIndex |
772 |
: getFootnoteList(footnoteListIndex).size() - 1; |
773 |
} |
774 |
return prevSplitLength; |
775 |
} |
776 |
} |
777 |
|
778 |
/** {@inheritDoc} */ |
779 |
@Override |
827 |
@Override |
780 |
protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) { |
828 |
protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) { |
781 |
// compute the adjustment ratio |
829 |
// compute the adjustment ratio |
782 |
if (difference > 0) { |
830 |
if (difference > 0) { |
783 |
int maxAdjustment = totalStretch - activeNode.totalStretch; |
831 |
int maxAdjustment = totalStretch - activeNode.totalStretch; |
784 |
// add the footnote separator stretch if some footnote content will be added |
832 |
// add the footnote separator stretch if some footnote content will be added |
785 |
if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) { |
833 |
if (((KnuthPageNode) activeNode).totalFootnotes < footnotes.totalLength) { |
786 |
maxAdjustment += footnoteSeparatorLength.getStretch(); |
834 |
maxAdjustment += footnotes.separatorLength.getStretch(); |
787 |
} |
835 |
} |
788 |
if (maxAdjustment > 0) { |
836 |
if (maxAdjustment > 0) { |
789 |
return (double) difference / maxAdjustment; |
837 |
return (double) difference / maxAdjustment; |
Lines 793-800
Link Here
|
793 |
} else if (difference < 0) { |
841 |
} else if (difference < 0) { |
794 |
int maxAdjustment = totalShrink - activeNode.totalShrink; |
842 |
int maxAdjustment = totalShrink - activeNode.totalShrink; |
795 |
// add the footnote separator shrink if some footnote content will be added |
843 |
// add the footnote separator shrink if some footnote content will be added |
796 |
if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) { |
844 |
if (((KnuthPageNode) activeNode).totalFootnotes < footnotes.totalLength) { |
797 |
maxAdjustment += footnoteSeparatorLength.getShrink(); |
845 |
maxAdjustment += footnotes.separatorLength.getShrink(); |
798 |
} |
846 |
} |
799 |
if (maxAdjustment > 0) { |
847 |
if (maxAdjustment > 0) { |
800 |
return (double) difference / maxAdjustment; |
848 |
return (double) difference / maxAdjustment; |
Lines 806-812
Link Here
|
806 |
} |
854 |
} |
807 |
} |
855 |
} |
808 |
|
856 |
|
809 |
/** {@inheritDoc} */ |
|
|
810 |
@Override |
857 |
@Override |
811 |
protected double computeDemerits(KnuthNode activeNode, KnuthElement element, |
858 |
protected double computeDemerits(KnuthNode activeNode, KnuthElement element, |
812 |
int fitnessClass, double r) { |
859 |
int fitnessClass, double r) { |
Lines 814-832
Link Here
|
814 |
// compute demerits |
861 |
// compute demerits |
815 |
double f = Math.abs(r); |
862 |
double f = Math.abs(r); |
816 |
f = 1 + 100 * f * f * f; |
863 |
f = 1 + 100 * f * f * f; |
|
|
864 |
|
817 |
if (element.isPenalty()) { |
865 |
if (element.isPenalty()) { |
818 |
double penalty = element.getPenalty(); |
866 |
double penalty = element.getPenalty(); |
819 |
if (penalty >= 0) { |
867 |
if (penalty >= 0) { |
820 |
f += penalty; |
868 |
f += penalty; |
821 |
demerits = f * f; |
|
|
822 |
} else if (!element.isForcedBreak()) { |
869 |
} else if (!element.isForcedBreak()) { |
823 |
demerits = f * f - penalty * penalty; |
870 |
demerits -= penalty * penalty; |
824 |
} else { |
|
|
825 |
demerits = f * f; |
826 |
} |
871 |
} |
827 |
} else { |
|
|
828 |
demerits = f * f; |
829 |
} |
872 |
} |
|
|
873 |
demerits += f * f; |
830 |
|
874 |
|
831 |
if (element.isPenalty() && ((KnuthPenalty) element).isPenaltyFlagged() |
875 |
if (element.isPenalty() && ((KnuthPenalty) element).isPenaltyFlagged() |
832 |
&& getElement(activeNode.position).isPenalty() |
876 |
&& getElement(activeNode.position).isPenalty() |
Lines 840-873
Link Here
|
840 |
demerits += incompatibleFitnessDemerit; |
884 |
demerits += incompatibleFitnessDemerit; |
841 |
} |
885 |
} |
842 |
|
886 |
|
843 |
if (footnotesPending) { |
887 |
if (footnotes.footnotesPending) { |
844 |
if (footnoteListIndex < footnotesList.size() - 1) { |
888 |
demerits += footnotes.getDemerits(); |
845 |
// add demerits for the deferred footnotes |
|
|
846 |
demerits += (footnotesList.size() - 1 - footnoteListIndex) |
847 |
* deferredFootnoteDemerits; |
848 |
} |
889 |
} |
849 |
if (footnoteListIndex < footnotesList.size()) { |
|
|
850 |
if (footnoteElementIndex |
851 |
< getFootnoteList(footnoteListIndex).size() - 1) { |
852 |
// add demerits for the footnote split between pages |
853 |
demerits += splitFootnoteDemerits; |
854 |
} |
855 |
} else { |
856 |
//TODO Why can this happen in the first place? Does anybody know? See #44160 |
857 |
} |
858 |
} |
859 |
demerits += activeNode.totalDemerits; |
890 |
demerits += activeNode.totalDemerits; |
860 |
return demerits; |
891 |
return demerits; |
861 |
} |
892 |
} |
862 |
|
893 |
|
863 |
/** {@inheritDoc} */ |
|
|
864 |
@Override |
894 |
@Override |
865 |
protected void finish() { |
895 |
protected void finish() { |
866 |
for (int i = startLine; i < endLine; i++) { |
896 |
for (int i = startLine; i < endLine; i++) { |
867 |
for (KnuthPageNode node = (KnuthPageNode) getNode(i); |
897 |
for (KnuthPageNode node = (KnuthPageNode) getNode(i); |
868 |
node != null; |
898 |
node != null; |
869 |
node = (KnuthPageNode) node.next) { |
899 |
node = (KnuthPageNode) node.next) { |
870 |
if (node.totalFootnotes < totalFootnotesLength) { |
900 |
if (node.totalFootnotes < footnotes.totalLength) { |
871 |
// layout remaining footnote bodies |
901 |
// layout remaining footnote bodies |
872 |
createFootnotePages(node); |
902 |
createFootnotePages(node); |
873 |
} |
903 |
} |
Lines 877-926
Link Here
|
877 |
|
907 |
|
878 |
private void createFootnotePages(KnuthPageNode lastNode) { |
908 |
private void createFootnotePages(KnuthPageNode lastNode) { |
879 |
|
909 |
|
880 |
insertedFootnotesLength = lastNode.totalFootnotes; |
910 |
footnotes.insertedFootnotesLength = lastNode.totalFootnotes; |
881 |
footnoteListIndex = lastNode.footnoteListIndex; |
911 |
footnotes.listIndex = lastNode.footnoteListIndex; |
882 |
footnoteElementIndex = lastNode.footnoteElementIndex; |
912 |
footnotes.elementIndex = lastNode.footnoteElementIndex; |
883 |
int availableBPD = getLineWidth(lastNode.line); |
913 |
int availableBPD = getLineWidth(lastNode.line); |
884 |
int split = 0; |
|
|
885 |
KnuthPageNode prevNode = lastNode; |
914 |
KnuthPageNode prevNode = lastNode; |
886 |
|
915 |
|
887 |
// create pages containing the remaining footnote bodies |
916 |
// create pages containing the remaining footnote bodies |
888 |
while (insertedFootnotesLength < totalFootnotesLength) { |
917 |
while (footnotes.footnotesRemaining()) { |
889 |
final int tmpLength = lengthList.get(footnoteListIndex); |
918 |
final int remaining = footnotes.currentLength() - footnotes.insertedFootnotesLength; |
|
|
919 |
|
890 |
// try adding some more content |
920 |
// try adding some more content |
891 |
if ((tmpLength - insertedFootnotesLength) <= availableBPD) { |
921 |
if (remaining <= availableBPD) { |
892 |
// add a whole footnote |
922 |
// all fits, so just add everything |
893 |
availableBPD -= tmpLength - insertedFootnotesLength; |
923 |
availableBPD -= remaining; |
894 |
insertedFootnotesLength = tmpLength; |
924 |
footnotes.insertedFootnotesLength = footnotes.currentLength(); |
895 |
footnoteElementIndex |
925 |
footnotes.elementIndex |
896 |
= getFootnoteList(footnoteListIndex).size() - 1; |
926 |
= getFootnoteList(footnotes.listIndex).size() - 1; |
897 |
} else if ((split = getFootnoteSplit // CSOK: InnerAssignment |
927 |
} else { |
898 |
(footnoteListIndex, footnoteElementIndex, |
928 |
int split = footnotes.getFootnoteSplit(availableBPD); |
899 |
insertedFootnotesLength, availableBPD, true)) > 0) { |
929 |
if (split > 0) { |
900 |
// add a piece of a footnote |
930 |
// add a piece of a footnote |
901 |
availableBPD -= split; |
931 |
availableBPD -= split; |
902 |
insertedFootnotesLength += split; |
932 |
footnotes.insertedFootnotesLength += split; |
903 |
// footnoteListIndex has already been set in getFootnoteSplit() |
933 |
// listIndex has already been set in getFootnoteSplit() |
904 |
// footnoteElementIndex has already been set in getFootnoteSplit() |
934 |
// elementIndex has already been set in getFootnoteSplit() |
905 |
} else { |
935 |
} else { |
906 |
// cannot add any content: create a new node and start again |
936 |
// cannot add any content: create a new node and start again |
907 |
KnuthPageNode node = (KnuthPageNode) |
937 |
KnuthPageNode node = (KnuthPageNode) |
908 |
createNode(lastNode.position, prevNode.line + 1, 1, |
938 |
createNode(lastNode.position, prevNode.line + 1, 1, |
909 |
insertedFootnotesLength - prevNode.totalFootnotes, |
939 |
footnotes.insertedFootnotesLength - prevNode.totalFootnotes, |
910 |
0, 0, |
940 |
0, 0, |
911 |
0, 0, 0, |
941 |
0, 0, 0, |
912 |
0, 0, prevNode); |
942 |
0, 0, prevNode); |
913 |
addNode(node.line, node); |
943 |
addNode(node.line, node); |
914 |
removeNode(prevNode.line, prevNode); |
944 |
removeNode(prevNode.line, prevNode); |
915 |
|
945 |
|
916 |
prevNode = node; |
946 |
prevNode = node; |
917 |
availableBPD = getLineWidth(node.line); |
947 |
availableBPD = getLineWidth(node.line); |
918 |
} |
948 |
} |
919 |
} |
949 |
} |
|
|
950 |
} |
951 |
|
920 |
// create the last node |
952 |
// create the last node |
921 |
KnuthPageNode node = (KnuthPageNode) |
953 |
KnuthPageNode node = (KnuthPageNode) |
922 |
createNode(lastNode.position, prevNode.line + 1, 1, |
954 |
createNode(lastNode.position, prevNode.line + 1, 1, |
923 |
totalFootnotesLength - prevNode.totalFootnotes, 0, 0, |
955 |
footnotes.totalLength - prevNode.totalFootnotes, 0, 0, |
924 |
0, 0, 0, |
956 |
0, 0, 0, |
925 |
0, 0, prevNode); |
957 |
0, 0, prevNode); |
926 |
addNode(node.line, node); |
958 |
addNode(node.line, node); |
Lines 960-971
Link Here
|
960 |
pageBreaks.subList(0, pageBreaks.size() - 1).clear(); |
992 |
pageBreaks.subList(0, pageBreaks.size() - 1).clear(); |
961 |
} |
993 |
} |
962 |
|
994 |
|
963 |
/** {@inheritDoc} */ |
|
|
964 |
@Override |
995 |
@Override |
965 |
public void updateData1(int total, double demerits) { |
996 |
public void updateData1(int total, double demerits) { |
966 |
} |
997 |
} |
967 |
|
998 |
|
968 |
/** {@inheritDoc} */ |
|
|
969 |
@Override |
999 |
@Override |
970 |
public void updateData2(KnuthNode bestActiveNode, |
1000 |
public void updateData2(KnuthNode bestActiveNode, |
971 |
KnuthSequence sequence, |
1001 |
KnuthSequence sequence, |
Lines 1011-1017
Link Here
|
1011 |
// compute the indexes of the first footnote list and the first element in that list |
1041 |
// compute the indexes of the first footnote list and the first element in that list |
1012 |
int firstListIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex; |
1042 |
int firstListIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex; |
1013 |
int firstElementIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex; |
1043 |
int firstElementIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex; |
1014 |
if (footnotesList != null |
1044 |
if (footnotes.footnotesList != null |
1015 |
&& firstElementIndex == getFootnoteList(firstListIndex).size() - 1) { |
1045 |
&& firstElementIndex == getFootnoteList(firstListIndex).size() - 1) { |
1016 |
// advance to the next list |
1046 |
// advance to the next list |
1017 |
firstListIndex++; |
1047 |
firstListIndex++; |
Lines 1034-1040
Link Here
|
1034 |
ratio, difference)); |
1064 |
ratio, difference)); |
1035 |
} |
1065 |
} |
1036 |
|
1066 |
|
1037 |
/** {@inheritDoc} */ |
|
|
1038 |
@Override |
1067 |
@Override |
1039 |
protected int filterActiveNodes() { |
1068 |
protected int filterActiveNodes() { |
1040 |
// leave only the active node with fewest total demerits |
1069 |
// leave only the active node with fewest total demerits |
Lines 1066-1072
Link Here
|
1066 |
* @return the element-list |
1095 |
* @return the element-list |
1067 |
*/ |
1096 |
*/ |
1068 |
protected final List<KnuthElement> getFootnoteList(int index) { |
1097 |
protected final List<KnuthElement> getFootnoteList(int index) { |
1069 |
return footnotesList.get(index); |
1098 |
return footnotes.getList(index); |
1070 |
} |
1099 |
} |
1071 |
|
1100 |
|
1072 |
/** @return the associated top-level formatting object. */ |
1101 |
/** @return the associated top-level formatting object. */ |
Lines 1074-1080
Link Here
|
1074 |
return topLevelLM.getFObj(); |
1103 |
return topLevelLM.getFObj(); |
1075 |
} |
1104 |
} |
1076 |
|
1105 |
|
1077 |
/** {@inheritDoc} */ |
|
|
1078 |
@Override |
1106 |
@Override |
1079 |
protected int getLineWidth(int line) { |
1107 |
protected int getLineWidth(int line) { |
1080 |
int bpd; |
1108 |
int bpd; |
Lines 1104-1116
Link Here
|
1104 |
|
1132 |
|
1105 |
} |
1133 |
} |
1106 |
|
1134 |
|
1107 |
/** {@inheritDoc} */ |
|
|
1108 |
@Override |
1135 |
@Override |
1109 |
protected int getIPDdifference() { |
1136 |
protected int getIPDdifference() { |
1110 |
return ipdDifference; |
1137 |
return ipdDifference; |
1111 |
} |
1138 |
} |
1112 |
|
1139 |
|
1113 |
/** {@inheritDoc} */ |
|
|
1114 |
@Override |
1140 |
@Override |
1115 |
protected int handleIpdChange() { |
1141 |
protected int handleIpdChange() { |
1116 |
log.trace("Best node for ipd change:" + bestNodeForIPDChange); |
1142 |
log.trace("Best node for ipd change:" + bestNodeForIPDChange); |