You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PageBreaker.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. /* $Id$ */
  18. package org.apache.fop.layoutmgr;
  19. import java.util.List;
  20. import java.util.ListIterator;
  21. import org.apache.fop.area.Block;
  22. import org.apache.fop.area.BodyRegion;
  23. import org.apache.fop.area.Footnote;
  24. import org.apache.fop.area.PageViewport;
  25. import org.apache.fop.fo.Constants;
  26. import org.apache.fop.fo.FObj;
  27. import org.apache.fop.fo.pagination.Region;
  28. import org.apache.fop.fo.pagination.RegionBody;
  29. import org.apache.fop.fo.pagination.StaticContent;
  30. import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener;
  31. import org.apache.fop.traits.MinOptMax;
  32. /**
  33. * Handles the breaking of pages in an fo:flow
  34. */
  35. public class PageBreaker extends AbstractBreaker {
  36. private PageSequenceLayoutManager pslm;
  37. private boolean firstPart = true;
  38. private boolean pageBreakHandled;
  39. private boolean needColumnBalancing;
  40. private PageProvider pageProvider;
  41. private Block separatorArea;
  42. private boolean spanAllActive;
  43. /**
  44. * The FlowLayoutManager object, which processes
  45. * the single fo:flow of the fo:page-sequence
  46. */
  47. private FlowLayoutManager childFLM = null;
  48. private StaticContentLayoutManager footnoteSeparatorLM = null;
  49. /**
  50. * Construct page breaker.
  51. * @param pslm the page sequence layout manager
  52. */
  53. public PageBreaker(PageSequenceLayoutManager pslm) {
  54. this.pslm = pslm;
  55. this.pageProvider = pslm.getPageProvider();
  56. this.childFLM = pslm.getLayoutManagerMaker().makeFlowLayoutManager(
  57. pslm, pslm.getPageSequence().getMainFlow());
  58. }
  59. /** {@inheritDoc} */
  60. protected void updateLayoutContext(LayoutContext context) {
  61. int flowIPD = pslm.getCurrentPV().getCurrentSpan().getColumnWidth();
  62. context.setRefIPD(flowIPD);
  63. }
  64. /** {@inheritDoc} */
  65. protected LayoutManager getTopLevelLM() {
  66. return pslm;
  67. }
  68. /** {@inheritDoc} */
  69. protected PageProvider getPageProvider() {
  70. return pslm.getPageProvider();
  71. }
  72. /**
  73. * Starts the page breaking process.
  74. * @param flowBPD the constant available block-progression-dimension (used for every part)
  75. */
  76. void doLayout(int flowBPD) {
  77. doLayout(flowBPD, false);
  78. }
  79. /** {@inheritDoc} */
  80. protected PageBreakingLayoutListener createLayoutListener() {
  81. return new PageBreakingLayoutListener() {
  82. public void notifyOverflow(int part, int amount, FObj obj) {
  83. Page p = pageProvider.getPageFromColumnIndex(part);
  84. RegionBody body = (RegionBody)p.getSimplePageMaster().getRegion(
  85. Region.FO_REGION_BODY);
  86. BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
  87. body.getUserAgent().getEventBroadcaster());
  88. boolean canRecover = (body.getOverflow() != Constants.EN_ERROR_IF_OVERFLOW);
  89. boolean needClip = (body.getOverflow() == Constants.EN_HIDDEN
  90. || body.getOverflow() == Constants.EN_ERROR_IF_OVERFLOW);
  91. eventProducer.regionOverflow(this, body.getName(),
  92. p.getPageViewport().getPageNumberString(),
  93. amount, needClip, canRecover,
  94. body.getLocator());
  95. }
  96. };
  97. }
  98. /** {@inheritDoc} */
  99. protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) {
  100. needColumnBalancing = false;
  101. if (childLC.getNextSpan() != Constants.NOT_SET) {
  102. //Next block list will have a different span.
  103. nextSequenceStartsOn = childLC.getNextSpan();
  104. needColumnBalancing = childLC.getNextSpan() == Constants.EN_ALL
  105. && childLC.getDisableColumnBalancing() == Constants.EN_FALSE;
  106. }
  107. if (needColumnBalancing) {
  108. AbstractBreaker.log.debug(
  109. "Column balancing necessary for the next element list!!!");
  110. }
  111. return nextSequenceStartsOn;
  112. }
  113. /** {@inheritDoc} */
  114. protected int getNextBlockList(LayoutContext childLC,
  115. int nextSequenceStartsOn) {
  116. return getNextBlockList(childLC, nextSequenceStartsOn, null, null, null);
  117. }
  118. /** {@inheritDoc} */
  119. protected int getNextBlockList(LayoutContext childLC, int nextSequenceStartsOn,
  120. Position positionAtIPDChange, LayoutManager restartLM, List firstElements) {
  121. if (!firstPart) {
  122. // if this is the first page that will be created by
  123. // the current BlockSequence, it could have a break
  124. // condition that must be satisfied;
  125. // otherwise, we may simply need a new page
  126. handleBreakTrait(nextSequenceStartsOn);
  127. }
  128. firstPart = false;
  129. pageBreakHandled = true;
  130. pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
  131. pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
  132. return super.getNextBlockList(childLC, nextSequenceStartsOn, positionAtIPDChange,
  133. restartLM, firstElements);
  134. }
  135. private boolean containsFootnotes(List contentList, LayoutContext context) {
  136. boolean containsFootnotes = false;
  137. if (contentList != null) {
  138. ListIterator contentListIterator = contentList.listIterator();
  139. while (contentListIterator.hasNext()) {
  140. ListElement element = (ListElement) contentListIterator.next();
  141. if (element instanceof KnuthBlockBox
  142. && ((KnuthBlockBox) element).hasAnchors()) {
  143. // element represents a line with footnote citations
  144. containsFootnotes = true;
  145. LayoutContext footnoteContext = LayoutContext.copyOf(context);
  146. footnoteContext.setStackLimitBP(context.getStackLimitBP());
  147. footnoteContext.setRefIPD(pslm.getCurrentPV()
  148. .getRegionReference(Constants.FO_REGION_BODY).getIPD());
  149. List footnoteBodyLMs = ((KnuthBlockBox) element).getFootnoteBodyLMs();
  150. ListIterator footnoteBodyIterator = footnoteBodyLMs.listIterator();
  151. // store the lists of elements representing the footnote bodies
  152. // in the box representing the line containing their references
  153. while (footnoteBodyIterator.hasNext()) {
  154. FootnoteBodyLayoutManager fblm
  155. = (FootnoteBodyLayoutManager) footnoteBodyIterator.next();
  156. fblm.setParent(childFLM);
  157. fblm.initialize();
  158. ((KnuthBlockBox) element).addElementList(
  159. fblm.getNextKnuthElements(footnoteContext, alignment));
  160. }
  161. }
  162. }
  163. }
  164. return containsFootnotes;
  165. }
  166. private void handleFootnoteSeparator() {
  167. StaticContent footnoteSeparator;
  168. footnoteSeparator = pslm.getPageSequence().getStaticContent("xsl-footnote-separator");
  169. if (footnoteSeparator != null) {
  170. // the footnote separator can contain page-dependent content such as
  171. // page numbers or retrieve markers, so its areas cannot simply be
  172. // obtained now and repeated in each page;
  173. // we need to know in advance the separator bpd: the actual separator
  174. // could be different from page to page, but its bpd would likely be
  175. // always the same
  176. // create a Block area that will contain the separator areas
  177. separatorArea = new Block();
  178. separatorArea.setIPD(pslm.getCurrentPV()
  179. .getRegionReference(Constants.FO_REGION_BODY).getIPD());
  180. // create a StaticContentLM for the footnote separator
  181. footnoteSeparatorLM
  182. = pslm.getLayoutManagerMaker().makeStaticContentLayoutManager(
  183. pslm, footnoteSeparator, separatorArea);
  184. footnoteSeparatorLM.doLayout();
  185. footnoteSeparatorLength = MinOptMax.getInstance(separatorArea.getBPD());
  186. }
  187. }
  188. /** {@inheritDoc} */
  189. protected List getNextKnuthElements(LayoutContext context, int alignment) {
  190. List contentList = null;
  191. while (!childFLM.isFinished() && contentList == null) {
  192. contentList = childFLM.getNextKnuthElements(context, alignment);
  193. }
  194. // scan contentList, searching for footnotes
  195. if (containsFootnotes(contentList, context)) {
  196. // handle the footnote separator
  197. handleFootnoteSeparator();
  198. }
  199. return contentList;
  200. }
  201. /** {@inheritDoc} */
  202. protected List getNextKnuthElements(LayoutContext context, int alignment,
  203. Position positionAtIPDChange, LayoutManager restartAtLM) {
  204. List contentList = null;
  205. do {
  206. contentList = childFLM.getNextKnuthElements(context, alignment, positionAtIPDChange,
  207. restartAtLM);
  208. } while (!childFLM.isFinished() && contentList == null);
  209. // scan contentList, searching for footnotes
  210. if (containsFootnotes(contentList, context)) {
  211. // handle the footnote separator
  212. handleFootnoteSeparator();
  213. }
  214. return contentList;
  215. }
  216. /**
  217. * @return current display alignment
  218. */
  219. protected int getCurrentDisplayAlign() {
  220. return pslm.getCurrentPage().getSimplePageMaster().getRegion(
  221. Constants.FO_REGION_BODY).getDisplayAlign();
  222. }
  223. /**
  224. * @return whether or not this flow has more page break opportunities
  225. */
  226. protected boolean hasMoreContent() {
  227. return !childFLM.isFinished();
  228. }
  229. /**
  230. * Adds an area to the flow layout manager
  231. * @param posIter the position iterator
  232. * @param context the layout context
  233. */
  234. protected void addAreas(PositionIterator posIter, LayoutContext context) {
  235. if (footnoteSeparatorLM != null) {
  236. StaticContent footnoteSeparator = pslm.getPageSequence().getStaticContent(
  237. "xsl-footnote-separator");
  238. // create a Block area that will contain the separator areas
  239. separatorArea = new Block();
  240. separatorArea.setIPD(
  241. pslm.getCurrentPV().getRegionReference(Constants.FO_REGION_BODY).getIPD());
  242. // create a StaticContentLM for the footnote separator
  243. footnoteSeparatorLM = pslm.getLayoutManagerMaker().makeStaticContentLayoutManager(
  244. pslm, footnoteSeparator, separatorArea);
  245. footnoteSeparatorLM.doLayout();
  246. }
  247. childFLM.addAreas(posIter, context);
  248. }
  249. /**
  250. * {@inheritDoc}
  251. * This implementation checks whether to trigger column-balancing,
  252. * or whether to take into account a 'last-page' condition.
  253. */
  254. protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
  255. BlockSequence originalList, BlockSequence effectiveList) {
  256. if (needColumnBalancing) {
  257. //column balancing for the last part
  258. redoLayout(alg, partCount, originalList, effectiveList);
  259. return;
  260. }
  261. boolean lastPageMasterDefined = pslm.getPageSequence().hasPagePositionLast();
  262. if (!hasMoreContent()) {
  263. //last part is reached
  264. if (lastPageMasterDefined) {
  265. //last-page condition
  266. redoLayout(alg, partCount, originalList, effectiveList);
  267. return;
  268. }
  269. }
  270. //nothing special: just add the areas now
  271. addAreas(alg, partCount, originalList, effectiveList);
  272. }
  273. /**
  274. * Restart the algorithm at the break corresponding to the given partCount. Used to
  275. * re-do the part after the last break in case of either column-balancing or a last
  276. * page-master.
  277. */
  278. private void redoLayout(PageBreakingAlgorithm alg, int partCount,
  279. BlockSequence originalList, BlockSequence effectiveList) {
  280. int newStartPos = 0;
  281. int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount);
  282. if (restartPoint > 0) {
  283. //Add definitive areas for the parts before the
  284. //restarting point
  285. addAreas(alg, restartPoint, originalList, effectiveList);
  286. //Get page break from which we restart
  287. PageBreakPosition pbp = (PageBreakPosition)
  288. alg.getPageBreaks().get(restartPoint - 1);
  289. newStartPos = alg.par.getFirstBoxIndex(pbp.getLeafPos() + 1);
  290. //Handle page break right here to avoid any side-effects
  291. if (newStartPos > 0) {
  292. handleBreakTrait(Constants.EN_PAGE);
  293. }
  294. }
  295. AbstractBreaker.log.debug("Restarting at " + restartPoint
  296. + ", new start position: " + newStartPos);
  297. pageBreakHandled = true;
  298. //Update so the available BPD is reported correctly
  299. int currentPageNum = pslm.getCurrentPageNum();
  300. pageProvider.setStartOfNextElementList(currentPageNum,
  301. pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
  302. //Make sure we only add the areas we haven't added already
  303. effectiveList.ignoreAtStart = newStartPos;
  304. PageBreakingAlgorithm algRestart;
  305. if (needColumnBalancing) {
  306. AbstractBreaker.log.debug("Column balancing now!!!");
  307. AbstractBreaker.log.debug("===================================================");
  308. //Restart last page
  309. algRestart = new BalancingColumnBreakingAlgorithm(
  310. getTopLevelLM(), getPageProvider(), createLayoutListener(),
  311. alignment, Constants.EN_START, footnoteSeparatorLength,
  312. isPartOverflowRecoveryActivated(),
  313. pslm.getCurrentPV().getBodyRegion().getColumnCount());
  314. AbstractBreaker.log.debug("===================================================");
  315. } else {
  316. // Handle special page-master for last page
  317. BodyRegion currentBody = pageProvider.getPage(false, currentPageNum)
  318. .getPageViewport().getBodyRegion();
  319. setLastPageIndex(currentPageNum);
  320. BodyRegion lastBody = pageProvider.getPage(false, currentPageNum)
  321. .getPageViewport().getBodyRegion();
  322. lastBody.getMainReference().setSpans(currentBody.getMainReference().getSpans());
  323. AbstractBreaker.log.debug("Last page handling now!!!");
  324. AbstractBreaker.log.debug("===================================================");
  325. //Restart last page
  326. algRestart = new PageBreakingAlgorithm(
  327. getTopLevelLM(), getPageProvider(), createLayoutListener(),
  328. alg.getAlignment(), alg.getAlignmentLast(),
  329. footnoteSeparatorLength,
  330. isPartOverflowRecoveryActivated(), false, false);
  331. AbstractBreaker.log.debug("===================================================");
  332. }
  333. int optimalPageCount = algRestart.findBreakingPoints(effectiveList,
  334. newStartPos,
  335. 1, true, BreakingAlgorithm.ALL_BREAKS);
  336. AbstractBreaker.log.debug("restart: optimalPageCount= " + optimalPageCount
  337. + " pageBreaks.size()= " + algRestart.getPageBreaks().size());
  338. boolean fitsOnePage
  339. = optimalPageCount <= pslm.getCurrentPV()
  340. .getBodyRegion().getMainReference().getCurrentSpan().getColumnCount();
  341. if (needColumnBalancing) {
  342. if (!fitsOnePage) {
  343. AbstractBreaker.log.warn(
  344. "Breaking algorithm produced more columns than are available.");
  345. /* reenable when everything works
  346. throw new IllegalStateException(
  347. "Breaking algorithm must not produce more columns than available.");
  348. */
  349. }
  350. } else {
  351. if (fitsOnePage) {
  352. //Replace last page
  353. pslm.setCurrentPage(pageProvider.getPage(false, currentPageNum));
  354. } else {
  355. //Last page-master cannot hold the content.
  356. //Add areas now...
  357. addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList);
  358. //...and add a blank last page
  359. setLastPageIndex(currentPageNum + 1);
  360. pslm.setCurrentPage(pslm.makeNewPage(true));
  361. return;
  362. }
  363. }
  364. addAreas(algRestart, optimalPageCount, originalList, effectiveList);
  365. }
  366. private void setLastPageIndex(int currentPageNum) {
  367. int lastPageIndex = pslm.getForcedLastPageNum(currentPageNum);
  368. pageProvider.setLastPageIndex(lastPageIndex);
  369. }
  370. /** {@inheritDoc} */
  371. protected void startPart(BlockSequence list, int breakClass) {
  372. AbstractBreaker.log.debug("startPart() breakClass=" + getBreakClassName(breakClass));
  373. if (pslm.getCurrentPage() == null) {
  374. throw new IllegalStateException("curPage must not be null");
  375. }
  376. if (!pageBreakHandled) {
  377. //firstPart is necessary because we need the first page before we start the
  378. //algorithm so we have a BPD and IPD. This may subject to change later when we
  379. //start handling more complex cases.
  380. if (!firstPart) {
  381. // if this is the first page that will be created by
  382. // the current BlockSequence, it could have a break
  383. // condition that must be satisfied;
  384. // otherwise, we may simply need a new page
  385. handleBreakTrait(breakClass);
  386. }
  387. pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
  388. pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(),
  389. this.spanAllActive);
  390. }
  391. pageBreakHandled = false;
  392. // add static areas and resolve any new id areas
  393. // finish page and add to area tree
  394. firstPart = false;
  395. }
  396. /** {@inheritDoc} */
  397. protected void handleEmptyContent() {
  398. pslm.getCurrentPV().getPage().fakeNonEmpty();
  399. }
  400. /** {@inheritDoc} */
  401. protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
  402. // add footnote areas
  403. if (pbp.footnoteFirstListIndex < pbp.footnoteLastListIndex
  404. || pbp.footnoteFirstElementIndex <= pbp.footnoteLastElementIndex) {
  405. // call addAreas() for each FootnoteBodyLM
  406. for (int i = pbp.footnoteFirstListIndex; i <= pbp.footnoteLastListIndex; i++) {
  407. List elementList = alg.getFootnoteList(i);
  408. int firstIndex = (i == pbp.footnoteFirstListIndex
  409. ? pbp.footnoteFirstElementIndex : 0);
  410. int lastIndex = (i == pbp.footnoteLastListIndex
  411. ? pbp.footnoteLastElementIndex : elementList.size() - 1);
  412. SpaceResolver.performConditionalsNotification(elementList,
  413. firstIndex, lastIndex, -1);
  414. LayoutContext childLC = LayoutContext.newInstance();
  415. AreaAdditionUtil.addAreas(null,
  416. new KnuthPossPosIter(elementList, firstIndex, lastIndex + 1),
  417. childLC);
  418. }
  419. // set the offset from the top margin
  420. Footnote parentArea = pslm.getCurrentPV().getBodyRegion().getFootnote();
  421. int topOffset = pslm.getCurrentPV().getBodyRegion().getBPD() - parentArea.getBPD();
  422. if (separatorArea != null) {
  423. topOffset -= separatorArea.getBPD();
  424. }
  425. parentArea.setTop(topOffset);
  426. parentArea.setSeparator(separatorArea);
  427. }
  428. pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished();
  429. }
  430. /** {@inheritDoc} */
  431. protected LayoutManager getCurrentChildLM() {
  432. return childFLM;
  433. }
  434. /** {@inheritDoc} */
  435. protected void observeElementList(List elementList) {
  436. ElementListObserver.observe(elementList, "breaker",
  437. pslm.getFObj().getId());
  438. }
  439. /**
  440. * Depending on the kind of break condition, move to next column
  441. * or page. May need to make an empty page if next page would
  442. * not have the desired "handedness".
  443. * @param breakVal - value of break-before or break-after trait.
  444. */
  445. private void handleBreakTrait(int breakVal) {
  446. Page curPage = pslm.getCurrentPage();
  447. switch (breakVal) {
  448. case Constants.EN_ALL:
  449. //break due to span change in multi-column layout
  450. curPage.getPageViewport().createSpan(true);
  451. this.spanAllActive = true;
  452. return;
  453. case Constants.EN_NONE:
  454. curPage.getPageViewport().createSpan(false);
  455. this.spanAllActive = false;
  456. return;
  457. case Constants.EN_COLUMN:
  458. case Constants.EN_AUTO:
  459. case -1:
  460. PageViewport pv = curPage.getPageViewport();
  461. //Check if previous page was spanned
  462. boolean forceNewPageWithSpan = false;
  463. RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion(
  464. Constants.FO_REGION_BODY);
  465. forceNewPageWithSpan
  466. = (rb.getColumnCount() > 1
  467. && pv.getCurrentSpan().getColumnCount() == 1);
  468. if (forceNewPageWithSpan) {
  469. log.trace("Forcing new page with span");
  470. curPage = pslm.makeNewPage(false);
  471. curPage.getPageViewport().createSpan(true);
  472. } else if (pv.getCurrentSpan().hasMoreFlows()) {
  473. log.trace("Moving to next flow");
  474. pv.getCurrentSpan().moveToNextFlow();
  475. } else {
  476. log.trace("Making new page");
  477. /*curPage = */pslm.makeNewPage(false);
  478. }
  479. return;
  480. case Constants.EN_PAGE:
  481. default:
  482. log.debug("handling break-before after page " + pslm.getCurrentPageNum()
  483. + " breakVal=" + getBreakClassName(breakVal));
  484. if (needBlankPageBeforeNew(breakVal)) {
  485. log.trace("Inserting blank page");
  486. /*curPage = */pslm.makeNewPage(true);
  487. }
  488. if (needNewPage(breakVal)) {
  489. log.trace("Making new page");
  490. /*curPage = */pslm.makeNewPage(false);
  491. }
  492. }
  493. }
  494. /**
  495. * Check if a blank page is needed to accommodate
  496. * desired even or odd page number.
  497. * @param breakVal - value of break-before or break-after trait.
  498. */
  499. private boolean needBlankPageBeforeNew(int breakVal) {
  500. if (breakVal == Constants.EN_PAGE
  501. || (pslm.getCurrentPage().getPageViewport().getPage().isEmpty())) {
  502. // any page is OK or we already have an empty page
  503. return false;
  504. } else {
  505. /* IF we are on the kind of page we need, we'll need a new page. */
  506. if (pslm.getCurrentPageNum() % 2 == 0) { // even page
  507. return (breakVal == Constants.EN_EVEN_PAGE);
  508. } else { // odd page
  509. return (breakVal == Constants.EN_ODD_PAGE);
  510. }
  511. }
  512. }
  513. /**
  514. * See if need to generate a new page
  515. * @param breakVal - value of break-before or break-after trait.
  516. */
  517. private boolean needNewPage(int breakVal) {
  518. if (pslm.getCurrentPage().getPageViewport().getPage().isEmpty()) {
  519. if (breakVal == Constants.EN_PAGE) {
  520. return false;
  521. } else if (pslm.getCurrentPageNum() % 2 == 0) { // even page
  522. return (breakVal == Constants.EN_ODD_PAGE);
  523. } else { // odd page
  524. return (breakVal == Constants.EN_EVEN_PAGE);
  525. }
  526. } else {
  527. return true;
  528. }
  529. }
  530. }