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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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 = pslm.getLayoutManagerMaker().makeStaticContentLayoutManager(
  245. pslm, footnoteSeparator, separatorArea);
  246. footnoteSeparatorLM.doLayout();
  247. }
  248. childFLM.addAreas(posIter, context);
  249. }
  250. /**
  251. * {@inheritDoc}
  252. * This implementation checks whether to trigger column-balancing,
  253. * or whether to take into account a 'last-page' condition.
  254. */
  255. protected void doPhase3(PageBreakingAlgorithm alg, int partCount,
  256. BlockSequence originalList, BlockSequence effectiveList) {
  257. if (needColumnBalancing) {
  258. //column balancing for the last part
  259. redoLayout(alg, partCount, originalList, effectiveList);
  260. return;
  261. }
  262. boolean lastPageMasterDefined = pslm.getPageSequence().hasPagePositionLast();
  263. if (!hasMoreContent()) {
  264. //last part is reached
  265. if (lastPageMasterDefined) {
  266. //last-page condition
  267. redoLayout(alg, partCount, originalList, effectiveList);
  268. return;
  269. }
  270. }
  271. //nothing special: just add the areas now
  272. addAreas(alg, partCount, originalList, effectiveList);
  273. }
  274. /**
  275. * Restart the algorithm at the break corresponding to the given partCount. Used to
  276. * re-do the part after the last break in case of either column-balancing or a last
  277. * page-master.
  278. */
  279. private void redoLayout(PageBreakingAlgorithm alg, int partCount,
  280. BlockSequence originalList, BlockSequence effectiveList) {
  281. int newStartPos = 0;
  282. int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount);
  283. if (restartPoint > 0) {
  284. //Add definitive areas for the parts before the
  285. //restarting point
  286. addAreas(alg, restartPoint, originalList, effectiveList);
  287. //Get page break from which we restart
  288. PageBreakPosition pbp = (PageBreakPosition)
  289. alg.getPageBreaks().get(restartPoint - 1);
  290. newStartPos = pbp.getLeafPos() + 1;
  291. //Handle page break right here to avoid any side-effects
  292. if (newStartPos > 0) {
  293. handleBreakTrait(Constants.EN_PAGE);
  294. }
  295. }
  296. AbstractBreaker.log.debug("Restarting at " + restartPoint
  297. + ", new start position: " + newStartPos);
  298. pageBreakHandled = true;
  299. //Update so the available BPD is reported correctly
  300. int currentPageNum = pslm.getCurrentPageNum();
  301. pageProvider.setStartOfNextElementList(currentPageNum,
  302. pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
  303. //Make sure we only add the areas we haven't added already
  304. effectiveList.ignoreAtStart = newStartPos;
  305. PageBreakingAlgorithm algRestart;
  306. if (needColumnBalancing) {
  307. AbstractBreaker.log.debug("Column balancing now!!!");
  308. AbstractBreaker.log.debug("===================================================");
  309. //Restart last page
  310. algRestart = new BalancingColumnBreakingAlgorithm(
  311. getTopLevelLM(), getPageProvider(), createLayoutListener(),
  312. alignment, Constants.EN_START, footnoteSeparatorLength,
  313. isPartOverflowRecoveryActivated(),
  314. pslm.getCurrentPV().getBodyRegion().getColumnCount());
  315. AbstractBreaker.log.debug("===================================================");
  316. } else {
  317. // Handle special page-master for last page
  318. BodyRegion currentBody = pageProvider.getPage(false, currentPageNum)
  319. .getPageViewport().getBodyRegion();
  320. setLastPageIndex(currentPageNum);
  321. BodyRegion lastBody = pageProvider.getPage(false, currentPageNum)
  322. .getPageViewport().getBodyRegion();
  323. lastBody.getMainReference().setSpans(currentBody.getMainReference().getSpans());
  324. AbstractBreaker.log.debug("Last page handling now!!!");
  325. AbstractBreaker.log.debug("===================================================");
  326. //Restart last page
  327. algRestart = new PageBreakingAlgorithm(
  328. getTopLevelLM(), getPageProvider(), createLayoutListener(),
  329. alg.getAlignment(), alg.getAlignmentLast(),
  330. footnoteSeparatorLength,
  331. isPartOverflowRecoveryActivated(), false, false);
  332. AbstractBreaker.log.debug("===================================================");
  333. }
  334. int optimalPageCount = algRestart.findBreakingPoints(effectiveList,
  335. newStartPos,
  336. 1, true, BreakingAlgorithm.ALL_BREAKS);
  337. AbstractBreaker.log.debug("restart: optimalPageCount= " + optimalPageCount
  338. + " pageBreaks.size()= " + algRestart.getPageBreaks().size());
  339. boolean fitsOnePage
  340. = optimalPageCount <= pslm.getCurrentPV()
  341. .getBodyRegion().getMainReference().getCurrentSpan().getColumnCount();
  342. if (needColumnBalancing) {
  343. if (!fitsOnePage) {
  344. AbstractBreaker.log.warn(
  345. "Breaking algorithm produced more columns than are available.");
  346. /* reenable when everything works
  347. throw new IllegalStateException(
  348. "Breaking algorithm must not produce more columns than available.");
  349. */
  350. }
  351. } else {
  352. if (fitsOnePage) {
  353. //Replace last page
  354. pslm.setCurrentPage(pageProvider.getPage(false, currentPageNum));
  355. } else {
  356. //Last page-master cannot hold the content.
  357. //Add areas now...
  358. addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList);
  359. //...and add a blank last page
  360. setLastPageIndex(currentPageNum + 1);
  361. pslm.setCurrentPage(pslm.makeNewPage(true, true));
  362. return;
  363. }
  364. }
  365. addAreas(algRestart, optimalPageCount, originalList, effectiveList);
  366. }
  367. private void setLastPageIndex(int currentPageNum) {
  368. int lastPageIndex = pslm.getForcedLastPageNum(currentPageNum);
  369. pageProvider.setLastPageIndex(lastPageIndex);
  370. }
  371. /** {@inheritDoc} */
  372. protected void startPart(BlockSequence list, int breakClass) {
  373. AbstractBreaker.log.debug("startPart() breakClass=" + getBreakClassName(breakClass));
  374. if (pslm.getCurrentPage() == null) {
  375. throw new IllegalStateException("curPage must not be null");
  376. }
  377. if (!pageBreakHandled) {
  378. //firstPart is necessary because we need the first page before we start the
  379. //algorithm so we have a BPD and IPD. This may subject to change later when we
  380. //start handling more complex cases.
  381. if (!firstPart) {
  382. // if this is the first page that will be created by
  383. // the current BlockSequence, it could have a break
  384. // condition that must be satisfied;
  385. // otherwise, we may simply need a new page
  386. handleBreakTrait(breakClass);
  387. }
  388. pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
  389. pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(),
  390. this.spanAllActive);
  391. }
  392. pageBreakHandled = false;
  393. // add static areas and resolve any new id areas
  394. // finish page and add to area tree
  395. firstPart = false;
  396. }
  397. /** {@inheritDoc} */
  398. protected void handleEmptyContent() {
  399. pslm.getCurrentPV().getPage().fakeNonEmpty();
  400. }
  401. /** {@inheritDoc} */
  402. protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
  403. // add footnote areas
  404. if (pbp.footnoteFirstListIndex < pbp.footnoteLastListIndex
  405. || pbp.footnoteFirstElementIndex <= pbp.footnoteLastElementIndex) {
  406. // call addAreas() for each FootnoteBodyLM
  407. for (int i = pbp.footnoteFirstListIndex; i <= pbp.footnoteLastListIndex; i++) {
  408. List elementList = alg.getFootnoteList(i);
  409. int firstIndex = (i == pbp.footnoteFirstListIndex
  410. ? pbp.footnoteFirstElementIndex : 0);
  411. int lastIndex = (i == pbp.footnoteLastListIndex
  412. ? pbp.footnoteLastElementIndex : elementList.size() - 1);
  413. SpaceResolver.performConditionalsNotification(elementList,
  414. firstIndex, lastIndex, -1);
  415. LayoutContext childLC = new LayoutContext(0);
  416. AreaAdditionUtil.addAreas(null,
  417. new KnuthPossPosIter(elementList, firstIndex, lastIndex + 1),
  418. childLC);
  419. }
  420. // set the offset from the top margin
  421. Footnote parentArea = pslm.getCurrentPV().getBodyRegion().getFootnote();
  422. int topOffset = pslm.getCurrentPV().getBodyRegion().getBPD() - parentArea.getBPD();
  423. if (separatorArea != null) {
  424. topOffset -= separatorArea.getBPD();
  425. }
  426. parentArea.setTop(topOffset);
  427. parentArea.setSeparator(separatorArea);
  428. }
  429. pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished();
  430. }
  431. /** {@inheritDoc} */
  432. protected LayoutManager getCurrentChildLM() {
  433. return childFLM;
  434. }
  435. /** {@inheritDoc} */
  436. protected void observeElementList(List elementList) {
  437. ElementListObserver.observe(elementList, "breaker",
  438. pslm.getFObj().getId());
  439. }
  440. /**
  441. * Depending on the kind of break condition, move to next column
  442. * or page. May need to make an empty page if next page would
  443. * not have the desired "handedness".
  444. * @param breakVal - value of break-before or break-after trait.
  445. */
  446. private void handleBreakTrait(int breakVal) {
  447. Page curPage = pslm.getCurrentPage();
  448. switch (breakVal) {
  449. case Constants.EN_ALL:
  450. //break due to span change in multi-column layout
  451. curPage.getPageViewport().createSpan(true);
  452. this.spanAllActive = true;
  453. return;
  454. case Constants.EN_NONE:
  455. curPage.getPageViewport().createSpan(false);
  456. this.spanAllActive = false;
  457. return;
  458. case Constants.EN_COLUMN:
  459. case Constants.EN_AUTO:
  460. case Constants.EN_PAGE:
  461. case -1:
  462. PageViewport pv = curPage.getPageViewport();
  463. //Check if previous page was spanned
  464. boolean forceNewPageWithSpan = false;
  465. RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion(
  466. Constants.FO_REGION_BODY);
  467. forceNewPageWithSpan
  468. = (rb.getColumnCount() > 1
  469. && pv.getCurrentSpan().getColumnCount() == 1);
  470. if (forceNewPageWithSpan) {
  471. log.trace("Forcing new page with span");
  472. curPage = pslm.makeNewPage(false, false);
  473. curPage.getPageViewport().createSpan(true);
  474. } else if (pv.getCurrentSpan().hasMoreFlows()) {
  475. log.trace("Moving to next flow");
  476. pv.getCurrentSpan().moveToNextFlow();
  477. } else {
  478. log.trace("Making new page");
  479. /*curPage = */pslm.makeNewPage(false, false);
  480. }
  481. return;
  482. default:
  483. log.debug("handling break-before after page " + pslm.getCurrentPageNum()
  484. + " breakVal=" + getBreakClassName(breakVal));
  485. if (needBlankPageBeforeNew(breakVal)) {
  486. log.trace("Inserting blank page");
  487. /*curPage = */pslm.makeNewPage(true, false);
  488. }
  489. if (needNewPage(breakVal)) {
  490. log.trace("Making new page");
  491. /*curPage = */pslm.makeNewPage(false, false);
  492. }
  493. }
  494. }
  495. /**
  496. * Check if a blank page is needed to accomodate
  497. * desired even or odd page number.
  498. * @param breakVal - value of break-before or break-after trait.
  499. */
  500. private boolean needBlankPageBeforeNew(int breakVal) {
  501. if (breakVal == Constants.EN_PAGE
  502. || (pslm.getCurrentPage().getPageViewport().getPage().isEmpty())) {
  503. // any page is OK or we already have an empty page
  504. return false;
  505. } else {
  506. /* IF we are on the kind of page we need, we'll need a new page. */
  507. if (pslm.getCurrentPageNum() % 2 == 0) { // even page
  508. return (breakVal == Constants.EN_EVEN_PAGE);
  509. } else { // odd page
  510. return (breakVal == Constants.EN_ODD_PAGE);
  511. }
  512. }
  513. }
  514. /**
  515. * See if need to generate a new page
  516. * @param breakVal - value of break-before or break-after trait.
  517. */
  518. private boolean needNewPage(int breakVal) {
  519. if (pslm.getCurrentPage().getPageViewport().getPage().isEmpty()) {
  520. if (breakVal == Constants.EN_PAGE) {
  521. return false;
  522. } else if (pslm.getCurrentPageNum() % 2 == 0) { // even page
  523. return (breakVal == Constants.EN_ODD_PAGE);
  524. } else { // odd page
  525. return (breakVal == Constants.EN_EVEN_PAGE);
  526. }
  527. } else {
  528. return true;
  529. }
  530. }
  531. }