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

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