/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.layoutmgr; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.Constants; import org.apache.fop.fo.pagination.PageSequence; import org.apache.fop.fo.pagination.Region; import org.apache.fop.fo.pagination.SimplePageMaster; /** *
This class delivers Page instances. It also caches them as necessary. *
*Additional functionality makes sure that surplus instances that are requested by the * page breaker are properly discarded, especially in situations where hard breaks cause * blank pages. The reason for that: The page breaker sometimes needs to preallocate * additional pages since it doesn't know exactly until the end how many pages it really needs. *
*/ public class PageProvider implements Constants { private Log log = LogFactory.getLog(PageProvider.class); /** Indices are evaluated relative to the first page in the page-sequence. */ public static final int RELTO_PAGE_SEQUENCE = 0; /** Indices are evaluated relative to the first page in the current element list. */ public static final int RELTO_CURRENT_ELEMENT_LIST = 1; private int startPageOfPageSequence; private int startPageOfCurrentElementList; private int startColumnOfCurrentElementList; private List cachedPages = new java.util.ArrayList(); private int lastPageIndex = -1; private int indexOfCachedLastPage = -1; //Cache to optimize getAvailableBPD() calls private int lastRequestedIndex = -1; private int lastReportedBPD = -1; /** * AreaTreeHandler which activates the PSLM and controls * the rendering of its pages. */ private AreaTreeHandler areaTreeHandler; /** * fo:page-sequence formatting object being * processed by this class */ private PageSequence pageSeq; /** * Main constructor. * @param ath the area tree handler * @param ps The page-sequence the provider operates on */ public PageProvider(AreaTreeHandler ath, PageSequence ps) { this.areaTreeHandler = ath; this.pageSeq = ps; this.startPageOfPageSequence = ps.getStartingPageNumber(); } /** * The page breaker notifies the provider about the page number an element list starts * on so it can later retrieve PageViewports relative to this first page. * @param startPage the number of the first page for the element list. * @param startColumn the starting column number for the element list. */ public void setStartOfNextElementList(int startPage, int startColumn) { log.debug("start of the next element list is:" + " page=" + startPage + " col=" + startColumn); this.startPageOfCurrentElementList = startPage - startPageOfPageSequence + 1; this.startColumnOfCurrentElementList = startColumn; //Reset Cache this.lastRequestedIndex = -1; this.lastReportedBPD = -1; } /** * Sets the index of the last page. This is done as soon as the position of the last page * is known or assumed. * @param index the index relative to the first page in the page-sequence */ public void setLastPageIndex(int index) { this.lastPageIndex = index; } /** * Returns the available BPD for the part/page indicated by the index parameter. * The index is the part/page relative to the start of the current element list. * This method takes multiple columns into account. * @param index zero-based index of the requested part/page * @return the available BPD */ public int getAvailableBPD(int index) { //Special optimization: There may be many equal calls by the BreakingAlgorithm if (this.lastRequestedIndex == index) { if (log.isTraceEnabled()) { log.trace("getAvailableBPD(" + index + ") -> (cached) " + lastReportedBPD); } return this.lastReportedBPD; } int c = index; int pageIndex = 0; int colIndex = startColumnOfCurrentElementList; Page page = getPage( false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); while (c > 0) { colIndex++; if (colIndex >= page.getPageViewport().getCurrentSpan().getColumnCount()) { colIndex = 0; pageIndex++; page = getPage( false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); } c--; } this.lastRequestedIndex = index; this.lastReportedBPD = page.getPageViewport().getBodyRegion().getRemainingBPD(); if (log.isTraceEnabled()) { log.trace("getAvailableBPD(" + index + ") -> " + lastReportedBPD); } return this.lastReportedBPD; } /** * Returns the part index (0