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

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