You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by gm...@apache.org on 2004/09/26 15:51:01 UTC

cvs commit: xml-fop/src/java/org/apache/fop/layoutmgr PageSequenceLayoutManager.java FlowLayoutManager.java StaticContentLayoutManager.java PageLayoutManager.java

gmazza      2004/09/26 06:51:01

  Modified:    src/java/org/apache/fop/area AreaTreeHandler.java
               src/java/org/apache/fop/fo/pagination PageSequence.java
                        PageSequenceMaster.java
               src/java/org/apache/fop/layoutmgr FlowLayoutManager.java
                        StaticContentLayoutManager.java
  Added:       src/java/org/apache/fop/layoutmgr
                        PageSequenceLayoutManager.java
  Removed:     src/java/org/apache/fop/layoutmgr PageLayoutManager.java
  Log:
  1.) Renamed PageLayoutManager to somewhat more intuitive PageSequenceLayoutManager.
  
  2.) Moved layout logic for the fo:title of an fo:page-sequence from AreaTreeHandler
  to PSLM.  Also moved page number initialization logic there.
  
  Comments most welcome.
  
  Revision  Changes    Path
  1.10      +20 -89    xml-fop/src/java/org/apache/fop/area/AreaTreeHandler.java
  
  Index: AreaTreeHandler.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/area/AreaTreeHandler.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- AreaTreeHandler.java	25 Sep 2004 21:55:36 -0000	1.9
  +++ AreaTreeHandler.java	26 Sep 2004 13:51:00 -0000	1.10
  @@ -39,10 +39,7 @@
   import org.apache.fop.fo.extensions.Outline;
   import org.apache.fop.fo.extensions.Bookmarks;
   import org.apache.fop.fo.pagination.PageSequence;
  -import org.apache.fop.fo.pagination.Title;
  -import org.apache.fop.layoutmgr.ContentLayoutManager;
  -import org.apache.fop.layoutmgr.InlineStackingLayoutManager;
  -import org.apache.fop.layoutmgr.PageLayoutManager;
  +import org.apache.fop.layoutmgr.PageSequenceLayoutManager;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  @@ -129,14 +126,6 @@
       }
   
       /**
  -     * Add a new page to the area tree.
  -     * @param page the page to add
  -     */
  -    public void addPage(PageViewport page) {
  -        model.addPage(page);
  -    }
  -
  -    /**
        * Add an id reference pointing to a page viewport.
        * @param id the id of the reference
        * @param pv the page viewport that contains the id reference
  @@ -343,10 +332,8 @@
        * The area tree then handles what happens with the pages.
        *
        * @param pageSequence the page sequence ending
  -     * @throws FOPException if there is an error formatting the pages
        */
       public void endPageSequence(PageSequence pageSequence) {
  -        //areaTree.setFontInfo(fontInfo);
   
           if (collectStatistics) {
               if (MEM_PROFILE_WITH_GC) {
  @@ -359,88 +346,32 @@
               }
           }
   
  -        addBookmarks(pageSequence.getRoot().getBookmarks());
  -        formatPageSequence(pageSequence);
  +        // If no main flow, nothing to layout!
  +        if (pageSequence.getMainFlow() != null) {
  +            addBookmarks(pageSequence.getRoot().getBookmarks());
  +            PageSequenceLayoutManager pageSLM 
  +                = new PageSequenceLayoutManager(this, pageSequence);
  +            pageSLM.run();
  +            pageSequence.setCurrentPageNumber(pageSLM.getPageCount());
  +        }
       }
   
       /**
  -     * Runs the formatting of this page sequence into the given area tree
  -     *
  -     * @param pageSeq the PageSequence to be formatted
  -     * @param areaTree the area tree to format this page sequence into
  -     * @throws FOPException if there is an error formatting the contents
  -     */
  -    private void formatPageSequence(PageSequence pageSeq) {
  -        LineArea title = null;
  -        if (pageSeq.getTitleFO() != null) {
  -            title = getTitleArea(pageSeq.getTitleFO());
  -        }
  -        
  +     * Add a new page to the area tree.
  +     * @param page the page to add
  +     */
  +    public void startPageSequence(LineArea title) {
           model.startPageSequence(title);
  -
  -        // Make a new PageLayoutManager and a FlowLayoutManager
  -        // Run the PLM in a thread
  -        // Wait for them to finish.
  -
  -        // If no main flow, nothing to layout!
  -        if (pageSeq.getMainFlow() == null) {
  -            return;
  -        }
  -
  -        // Initialize if already used?
  -        //    this.layoutMasterSet.resetPageMasters();
  -        if (pageSeq.getPageSequenceMaster() != null) {
  -            pageSeq.getPageSequenceMaster().reset();
  -        }
  -
  -        pageSeq.initPageNumber();
  -
  -        // This will layout pages and add them to the area tree
  -        PageLayoutManager pageLM = new PageLayoutManager(this, pageSeq);
  -        pageLM.setPageCounting(pageSeq.getCurrentPageNumber(),
  -                               pageSeq.getPageNumberGenerator());
  -
  -        // For now, skip the threading and just call run directly.
  -        pageLM.run();
  -
  -        // Thread layoutThread = new Thread(pageLM);
  -        //  layoutThread.start();
  -        // log.debug("Layout thread started");
  -        
  -        // // wait on both managers
  -        // try {
  -        //     layoutThread.join();
  -        //     log.debug("Layout thread done");
  -        // } catch (InterruptedException ie) {
  -        //     log.error("PageSequence.format() interrupted waiting on layout");
  -        // }
  -        
  -        pageSeq.setCurrentPageNumber(pageLM.getPageCount());
  -        // Tell the root the last page number we created.
  -        pageSeq.getRoot().setRunningPageNumberCounter(pageSeq.getCurrentPageNumber());
       }
   
       /**
  -     * @return the Title area
  -     */
  -    private LineArea getTitleArea(Title foTitle) {
  -        // get breaks then add areas to title
  -        LineArea title = new LineArea();
  -
  -        ContentLayoutManager clm = new ContentLayoutManager(title);
  -        clm.setUserAgent(foTitle.getUserAgent());
  -
  -        // use special layout manager to add the inline areas
  -        // to the Title.
  -        InlineStackingLayoutManager lm;
  -        lm = new InlineStackingLayoutManager(foTitle);
  -        clm.addChildLM(lm);
  -
  -        clm.fillArea(lm);
  -
  -        return title;
  +     * Add a new page to the area tree.
  +     * @param page the page to add
  +     */
  +    public void addPage(PageViewport page) {
  +        model.addPage(page);
       }
  -    
  +
       /**
        * Accessor for the currentLMList.
        * @return the currentLMList.
  
  
  
  1.46      +3 -0      xml-fop/src/java/org/apache/fop/fo/pagination/PageSequence.java
  
  Index: PageSequence.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/fo/pagination/PageSequence.java,v
  retrieving revision 1.45
  retrieving revision 1.46
  diff -u -r1.45 -r1.46
  --- PageSequence.java	13 Sep 2004 08:05:34 -0000	1.45
  +++ PageSequence.java	26 Sep 2004 13:51:00 -0000	1.46
  @@ -673,6 +673,9 @@
        */
       public void setCurrentPageNumber(int currentPageNumber) {
           this.currentPageNumber = currentPageNumber;
  +
  +        // Tell the root the last page number we created.
  +        root.setRunningPageNumberCounter(currentPageNumber);
       }
   
       /**
  
  
  
  1.23      +21 -24    xml-fop/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java
  
  Index: PageSequenceMaster.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/fo/pagination/PageSequenceMaster.java,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- PageSequenceMaster.java	7 Sep 2004 20:47:10 -0000	1.22
  +++ PageSequenceMaster.java	26 Sep 2004 13:51:00 -0000	1.23
  @@ -58,7 +58,27 @@
           super(parent);
       }
   
  -
  +    /**
  +     * @see org.apache.fop.fo.FObj#addProperties
  +     */
  +    protected void addProperties(Attributes attlist) throws SAXParseException {
  +        super.addProperties(attlist);
  +        subSequenceSpecifiers = new java.util.ArrayList();
  +        if (parent.getName().equals("fo:layout-master-set")) {
  +            this.layoutMasterSet = (LayoutMasterSet)parent;
  +            masterName = getPropString(PR_MASTER_NAME);
  +            if (masterName == null) {
  +                getLogger().warn("page-sequence-master does not have "
  +                                       + "a master-name and so is being ignored");
  +            } else {
  +                this.layoutMasterSet.addPageSequenceMaster(masterName, this);
  +            }
  +        } else {
  +            throw new SAXParseException("fo:page-sequence-master must be child "
  +                                   + "of fo:layout-master-set, not "
  +                                   + parent.getName(), locator);
  +        }
  +    }
   
       /**
        * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
  @@ -82,29 +102,6 @@
           if (childNodes == null) {
              missingChildElementError("(single-page-master-reference|" +
               "repeatable-page-master-reference|repeatable-page-master-alternatives)+");
  -        }
  -    }
  -
  -
  -    /**
  -     * @see org.apache.fop.fo.FObj#addProperties
  -     */
  -    protected void addProperties(Attributes attlist) throws SAXParseException {
  -        super.addProperties(attlist);
  -        subSequenceSpecifiers = new java.util.ArrayList();
  -        if (parent.getName().equals("fo:layout-master-set")) {
  -            this.layoutMasterSet = (LayoutMasterSet)parent;
  -            masterName = getPropString(PR_MASTER_NAME);
  -            if (masterName == null) {
  -                getLogger().warn("page-sequence-master does not have "
  -                                       + "a master-name and so is being ignored");
  -            } else {
  -                this.layoutMasterSet.addPageSequenceMaster(masterName, this);
  -            }
  -        } else {
  -            throw new SAXParseException("fo:page-sequence-master must be child "
  -                                   + "of fo:layout-master-set, not "
  -                                   + parent.getName(), locator);
           }
       }
   
  
  
  
  1.8       +1 -1      xml-fop/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  
  Index: FlowLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- FlowLayoutManager.java	15 May 2004 21:51:59 -0000	1.7
  +++ FlowLayoutManager.java	26 Sep 2004 13:51:00 -0000	1.8
  @@ -29,7 +29,7 @@
   
   /**
    * LayoutManager for an fo:flow object.
  - * Its parent LM is the PageLayoutManager.
  + * Its parent LM is the PageSequenceLayoutManager.
    * This LM is responsible for getting columns of the appropriate size
    * and filling them with block-level areas generated by its children.
    */
  
  
  
  1.5       +1 -1      xml-fop/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  
  Index: StaticContentLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- StaticContentLayoutManager.java	12 May 2004 23:19:52 -0000	1.4
  +++ StaticContentLayoutManager.java	26 Sep 2004 13:51:01 -0000	1.5
  @@ -28,7 +28,7 @@
   
   /**
    * LayoutManager for an fo:flow object.
  - * Its parent LM is the PageLayoutManager.
  + * Its parent LM is the PageSequenceLayoutManager.
    * This LM is responsible for getting columns of the appropriate size
    * and filling them with block-level areas generated by its children.
    */
  
  
  
  1.1                  xml-fop/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
  
  Index: PageSequenceLayoutManager.java
  ===================================================================
  /*
   * Copyright 1999-2004 The Apache Software Foundation.
   *
   * Licensed 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: PageSequenceLayoutManager.java,v 1.1 2004/09/26 13:51:01 gmazza Exp $ */
  
  package org.apache.fop.layoutmgr;
  
  import org.apache.fop.apps.FOPException;
  
  import org.apache.fop.area.CTM;
  import org.apache.fop.area.AreaTreeHandler;
  import org.apache.fop.area.AreaTreeModel;
  import org.apache.fop.area.Area;
  import org.apache.fop.area.PageViewport;
  import org.apache.fop.area.Flow;
  import org.apache.fop.area.LineArea;
  import org.apache.fop.area.Page;
  import org.apache.fop.area.RegionViewport;
  import org.apache.fop.area.RegionReference;
  import org.apache.fop.area.BodyRegion;
  import org.apache.fop.area.MainReference;
  import org.apache.fop.area.Span;
  import org.apache.fop.area.BeforeFloat;
  import org.apache.fop.area.Footnote;
  import org.apache.fop.area.Resolveable;
  import org.apache.fop.area.Trait;
  
  import org.apache.fop.datatypes.PercentBase;
  import org.apache.fop.datatypes.FODimension;
  
  import org.apache.fop.fo.FObj;
  import org.apache.fop.fo.Constants;
  import org.apache.fop.fo.flow.Marker;
  import org.apache.fop.fo.pagination.PageNumberGenerator;
  import org.apache.fop.fo.pagination.PageSequence;
  import org.apache.fop.fo.pagination.Region;
  import org.apache.fop.fo.pagination.SimplePageMaster;
  import org.apache.fop.fo.pagination.StaticContent;
  import org.apache.fop.fo.pagination.Title;
  import org.apache.fop.fo.properties.CommonBackground;
  import org.apache.fop.fo.properties.CommonBorderAndPadding;
  import org.apache.fop.fo.properties.CommonMarginBlock;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  import java.util.HashMap;
  import java.awt.Rectangle;
  import java.util.Iterator;
  import java.awt.geom.Rectangle2D;
  import org.apache.fop.traits.MinOptMax;
  
  /**
   * LayoutManager for a PageSequence and its flow.
   * It manages all page-related layout.
   */
  public class PageSequenceLayoutManager extends AbstractLayoutManager implements Runnable {
  
      private static class BlockBreakPosition extends LeafPosition {
          protected BreakPoss breakps;
  
          protected BlockBreakPosition(LayoutManager lm, BreakPoss bp) {
              super(lm, 0);
              breakps = bp;
          }
      }
  
      private PageNumberGenerator pageNumberGenerator;
      private int pageCount = 1;
      private String pageNumberString;
      private boolean isFirstPage = true;
  
      /** True if haven't yet laid out any pages.*/
      private boolean bFirstPage;
      /** Current page being worked on. */
      private PageViewport curPage;
  
      /** Body region of the current page */
      private BodyRegion curBody;
  
      /** Current span being filled */
      private Span curSpan;
  
      /** Number of columns in current span area. */
      private int curSpanColumns;
  
      /** Current flow-reference-area (column) being filled. */
      private Flow curFlow;
  
      private int flowBPD = 0;
      private int flowIPD = 0;
  
      /** Manager which handles a queue of all pages which are completely
       * laid out and ready for rendering, except for resolution of ID
       * references?
       */
      private AreaTreeHandler areaTreeHandler;
      private PageSequence pageSequence;
  
      /**
       * This is the SimplePageMaster that should be used to create the page. It
       * will be equal to the PageSequence's simplePageMaster, if it exists, or
       * to the correct member of the PageSequence's pageSequenceMaster, if that
       * exists instead.
       */
      private SimplePageMaster currentSimplePageMaster;
  
      /**
       * The collection of StaticContentLayoutManager objects that are associated
       * with this Page Sequence, keyed by flow-name.
       */
      private HashMap staticContentLMs = new HashMap(4);
  
      /**
       * This is the top level layout manager.
       * It is created by the PageSequence FO.
       *
       * @param areaTree the area tree to add pages to
       * @param pageseq the page sequence fo
       */
      public PageSequenceLayoutManager(AreaTreeHandler areaTreeHandler, PageSequence pageseq) {
          super(pageseq);
          this.areaTreeHandler = areaTreeHandler;
          pageSequence = pageseq;
          if (pageSequence.getPageSequenceMaster() != null) {
              pageSequence.getPageSequenceMaster().reset();
          }
      }
  
      /**
       * Set the page counting for this page sequence.
       * This sets the initial page number and the page number formatter.
       *
       * @param pc the starting page number
       * @param generator the page number generator
       */
      private void setPageCounting(int pc, PageNumberGenerator generator) {
          pageSequence.initPageNumber();
          pageCount = pc;
          pageNumberGenerator = generator;
          pageNumberString = pageNumberGenerator.makeFormattedPageNumber(pageCount);
      }
  
      /**
       * The layout process is designed to be able to be run in a thread.
       * In theory it can run at the same
       * time as FO tree generation, once the layout-master-set has been read.
       * We can arrange it so that the iterator over the fobj children waits
       * until the next child is available.
       * As it produces pages, it adds them to the AreaTree, where the
       * rendering process can also run in a parallel thread.
       */
      public void run() {
          setPageCounting(pageSequence.getCurrentPageNumber(),
              pageSequence.getPageNumberGenerator());
  
          LineArea title = null;
          if (pageSequence.getTitleFO() != null) {
              title = getTitleArea(pageSequence.getTitleFO());
          }
  
          areaTreeHandler.startPageSequence(title);
          doLayout();
          flush();
      }
  
      /**
       * Get the page count.
       * Used to get the last page number for reference for
       * the next page sequence.
       *
       * @return the page number
       */
      public int getPageCount() {
          return pageCount;
      }
  
      /**
       * @return the Title area
       */
      private LineArea getTitleArea(Title foTitle) {
          // get breaks then add areas to title
          LineArea title = new LineArea();
  
          ContentLayoutManager clm = new ContentLayoutManager(title);
          clm.setUserAgent(foTitle.getUserAgent());
  
          // use special layout manager to add the inline areas
          // to the Title.
          InlineStackingLayoutManager lm;
          lm = new InlineStackingLayoutManager(foTitle);
          clm.addChildLM(lm);
  
          clm.fillArea(lm);
  
          return title;
      }
  
      /**
       * Do the layout of this page sequence.
       * This completes the layout of the page sequence
       * which creates and adds all the pages to the area tree.
       */
      protected void doLayout() {
  
          log.debug("Starting layout");
          // this should be done another way
          makeNewPage(false, false);
          createBodyMainReferenceArea();
          createSpan(1);
          flowIPD = curFlow.getIPD();
  
          BreakPoss bp;
          LayoutContext childLC = new LayoutContext(0);
          while (!isFinished()) {
              if ((bp = getNextBreakPoss(childLC)) != null) {
                  addAreas((BlockBreakPosition)bp.getPosition());
                  // add static areas and resolve any new id areas
  
                  // finish page and add to area tree
                  finishPage();
                  pageCount++;
                  pageNumberString = pageNumberGenerator.makeFormattedPageNumber(pageCount);
              }
          }
          pageCount--;
          log.debug("Ending layout");
      }
  
      /**
       * Get the next break possibility.
       * This finds the next break for a page which is always at the end
       * of the page.
       *
       * @param context the layout context for finding breaks
       * @return the break for the page
       */
      public BreakPoss getNextBreakPoss(LayoutContext context) {
  
          LayoutManager curLM ; // currently active LM
  
          while ((curLM = getChildLM()) != null) {
              BreakPoss bp = null;
  
              LayoutContext childLC = new LayoutContext(0);
              childLC.setStackLimit(new MinOptMax(flowBPD));
              childLC.setRefIPD(flowIPD);
  
              if (!curLM.isFinished()) {
                  fobj.setLayoutDimension(PercentBase.REFERENCE_AREA_IPD, flowIPD);
                  fobj.setLayoutDimension(PercentBase.REFERENCE_AREA_BPD, flowBPD);
                  bp = curLM.getNextBreakPoss(childLC);
              }
              if (bp != null) {
                  return new BreakPoss(
                           new BlockBreakPosition(curLM, bp));
              }
          }
          setFinished(true);
          return null;
      }
  
      /**
       * Get the current page number string.
       * This returns the formatted string for the current page.
       *
       * @return the formatted page number string
       */
      public String getCurrentPageNumber() {
          return pageNumberString;
      }
  
      /**
       * Resolve a reference ID.
       * This resolves a reference ID and returns the first PageViewport
       * that contains the reference ID or null if reference not found.
       *
       * @param ref the reference ID to lookup
       * @return the first page viewport that contains the reference
       */
      public PageViewport resolveRefID(String ref) {
          List list = areaTreeHandler.getIDReferences(ref);
          if (list != null && list.size() > 0) {
              return (PageViewport)list.get(0);
          }
          return null;
      }
  
      /**
       * Add the areas to the current page.
       * Given the page break position this adds the areas to the current
       * page.
       *
       * @param bbp the block break position
       */
      public void addAreas(BlockBreakPosition bbp) {
          List list = new ArrayList();
          list.add(bbp.breakps);
          bbp.getLM().addAreas(new BreakPossPosIter(list, 0,
                                1), null);
      }
  
      /**
       * Add an ID reference to the current page.
       * When adding areas the area adds its ID reference.
       * For the page layout manager it adds the id reference
       * with the current page to the area tree.
       *
       * @param id the ID reference to add
       */
      public void addIDToPage(String id) {
          areaTreeHandler.addIDRef(id, curPage);
      }
  
      /**
       * Add an unresolved area to the layout manager.
       * The Page layout manager handles the unresolved ID
       * reference by adding to the current page and then adding
       * the page as a resolveable to the area tree.
       * This is so that the area tree can resolve the reference
       * and the page can serialize the resolvers if required.
       *
       * @param id the ID reference to add
       * @param res the resolveable object that needs resolving
       */
      public void addUnresolvedArea(String id, Resolveable res) {
          // add unresolved to tree
          // adds to the page viewport so it can serialize
          curPage.addUnresolvedID(id, res);
          areaTreeHandler.addUnresolvedID(id, curPage);
      }
  
      /**
       * Add the marker to the page layout manager.
       *
       * @param name the marker class name
       * @param lm the layout manager for the marker contents
       * @param start true if starting marker area, false for ending
       */
      public void addMarkerMap(Map marks, boolean start, boolean isfirst) {
          //getLogger().debug("adding markers: " + marks + ":" + start);
          // add markers to page on area tree
          curPage.addMarkers(marks, start, isfirst);
      }
  
      /**
       * Retrieve a marker from this layout manager.
       * If the boundary is page then it will only check the
       * current page. For page-sequence and document it will
       * lookup preceding pages from the area tree and try to find
       * a marker.
       *
       * @param name the marker class name to lookup
       * @param pos the position to locate the marker
       * @param boundary the boundary for locating the marker
       * @return the layout manager for the marker contents
       */
      public Marker retrieveMarker(String name, int pos, int boundary) {
          // get marker from the current markers on area tree
          Marker mark = (Marker)curPage.getMarker(name, pos);
          if (mark == null && boundary != RetrieveBoundary.PAGE) {
              // go back over pages until mark found
              // if document boundary then keep going
              boolean doc = boundary == RetrieveBoundary.DOCUMENT;
              AreaTreeModel atm = areaTreeHandler.getAreaTreeModel();
              int seq = atm.getPageSequenceCount();
              int page = atm.getPageCount(seq) - 1;
              while (page >= 0) {
                  PageViewport pv = atm.getPage(seq, page);
                  mark = (Marker)curPage.getMarker(name, pos);
                  if (mark != null) {
                      return mark;
                  }
                  page--;
                  if (page == -1 && doc && seq > 0) {
                      seq--;
                      page = atm.getPageCount(seq) - 1;
                  }
              }
          }
  
          return mark;
      }
  
      /**
       * For now, only handle normal flow areas.
       *
       * @param childArea the child area to add
       */
      public void addChild(Area childArea) {
          if (childArea == null) {
              return;
          }
          if (childArea.getAreaClass() == Area.CLASS_NORMAL) {
              placeFlowRefArea(childArea);
          } else {
               // todo: all the others!
          }
      }
  
      /**
       * Place a FlowReferenceArea into the current span. The FlowLM is
       * responsible for making sure that it will actually fit in the
       * current span area. In fact the area has already been added to the
       * current span, so we are just checking to see if the span is "full",
       * possibly moving to the next column or to the next page.
       *
       * @param area the area to place
       */
      protected void placeFlowRefArea(Area area) {
          // assert (curSpan != null);
          // assert (area == curFlow);
          // assert (curFlow == curSpan.getFlow(curSpan.getColumnCount()-1));
          // assert (area.getBPD().min < curSpan.getHeight());
          // Last column on this page is filled
          // See if the flow is full. The Flow LM can add an area before
          // it's full in the case of a break or a span.
          // Also in the case of a float to be placed. In that case, there
          // may be further material added later.
          // The Flow LM sets the "finished" flag on the Flow Area if it has
          // completely filled it. In this case, if on the last column
          // end the page.
          getParentArea(area);
          // Alternatively the child LM indicates to parent that it's full?
          //getLogger().debug("size: " + area.getAllocationBPD().max +
          //                   ":" + curSpan.getMaxBPD().min);
          /*if (area.getAllocationBPD().max >= curSpan.getMaxBPD().min) {
              // Consider it filled
              if (curSpan.getColumnCount() == curSpanColumns) {
                  finishPage();
              } else
                  curFlow = null; // Create new flow on next getParentArea()
          }*/
      }
  
      protected void placeAbsoluteArea(Area area) {
      }
  
  
      protected void placeBeforeFloat(Area area) {
      }
  
      protected void placeSideFloat(Area area) {
      }
  
      protected void placeFootnote(Area area) {
          // After doing this, reduce available space on the curSpan.
          // This has to be propagated to the curFlow (FlowLM) so that
          // it can adjust its limit for composition (or it just asks
          // curSpan for BPD before doing the break?)
          // If multi-column, we may have to balance to find more space
          // for a float. When?
      }
  
      private PageViewport makeNewPage(boolean bIsBlank, boolean bIsLast) {
          finishPage();
          try {
              curPage = createPage(bIsBlank, bIsLast);
              isFirstPage = false;
          } catch (FOPException fopex) { /* ???? */
              fopex.printStackTrace();
          }
  
          curPage.setPageNumber(getCurrentPageNumber());
          RegionViewport rv = curPage.getPage().getRegionViewport(
                      FO_REGION_BODY);
          curBody = (BodyRegion) rv.getRegion();
          flowBPD = (int) curBody.getBPD() -
              rv.getBorderAndPaddingWidthBefore() - rv.getBorderAndPaddingWidthAfter();
  
          return curPage;
      }
  
      private void layoutStaticContent(Region region, int regionClass) {
          if (region == null) {
              return;
          }
          StaticContent flow = pageSequence.getStaticContent(region.getRegionName());
          if (flow == null) {
              return;
          }
          RegionViewport reg = curPage.getPage().getRegionViewport(regionClass);
          if (reg == null) {
              log.error("no region viewport: shouldn't happen");
          }
          StaticContentLayoutManager lm = getStaticContentLayoutManager(flow);
          lm.initialize();
          lm.setRegionReference(reg.getRegion());
          lm.setParent(this);
          LayoutContext childLC = new LayoutContext(0);
          childLC.setStackLimit(new MinOptMax((int)curPage.getViewArea().getHeight()));
          childLC.setRefIPD(reg.getRegion().getIPD());
          while (!lm.isFinished()) {
              BreakPoss bp = lm.getNextBreakPoss(childLC);
              if (bp != null) {
                  List vecBreakPoss = new ArrayList();
                  vecBreakPoss.add(bp);
                  lm.addAreas(new BreakPossPosIter(vecBreakPoss, 0,
                                                    vecBreakPoss.size()), null);
              } else {
                log.error("bp==null  cls=" + regionClass);
              }
          }
          //lm.flush();
          lm.reset(null);
      }
  
      private void finishPage() {
          if (curPage == null) {
              return;
          }
          // Layout static content into the regions
          // Need help from pageseq for this
          layoutStaticContent(currentSimplePageMaster.getRegion(FO_REGION_BEFORE),
                              FO_REGION_BEFORE);
          layoutStaticContent(currentSimplePageMaster.getRegion(FO_REGION_AFTER),
                              FO_REGION_AFTER);
          layoutStaticContent(currentSimplePageMaster.getRegion(FO_REGION_START),
                              FO_REGION_START);
          layoutStaticContent(currentSimplePageMaster.getRegion(FO_REGION_END),
                              FO_REGION_END);
          // Queue for ID resolution and rendering
          areaTreeHandler.addPage(curPage);
          curPage = null;
          curBody = null;
          curSpan = null;
          curFlow = null;
      }
  
      /**
       * This is called from FlowLayoutManager when it needs to start
       * a new flow container (while generating areas).
       *
       * @param childArea The area for which a container is needed. It must be
       * some kind of block-level area. It must have area-class, break-before
       * and span properties set.
       * @return the parent area
       */
      public Area getParentArea(Area childArea) {
          int aclass = childArea.getAreaClass();
          if (aclass == Area.CLASS_NORMAL) {
              // todo: how to get properties from the Area???
              // Need span, break
              int breakVal = Constants.AUTO;
              Integer breakBefore = (Integer)childArea.getTrait(Trait.BREAK_BEFORE);
              if (breakBefore != null) {
                  breakVal = breakBefore.intValue();
              }
              if (breakVal != Constants.AUTO) {
                  // We may be forced to make new page
                  handleBreak(breakVal);
              } else if (curPage == null) {
                  makeNewPage(false, false);
              }
              // Now we should be on the right kind of page
              boolean bNeedSpan = false;
              int span = Constants.NONE; // childArea.getSpan()
              int numCols = 1;
              if (span == Constants.ALL) {
                  // Assume the number of columns is stored on the curBody object.
                  //numCols = curBody.getProperty(NUMBER_OF_COLUMNS);
              }
              if (curSpan == null) {
                  createBodyMainReferenceArea();
                  bNeedSpan = true;
              } else if (numCols != curSpanColumns) {
                  // todo: BALANCE EXISTING COLUMNS
                  if (curSpanColumns > 1) {
                      // balanceColumns();
                  }
                  bNeedSpan = true;
              }
              if (bNeedSpan) {
                  // Make a new span and the first flow
                  createSpan(numCols);
              } else if (curFlow == null) {
                  createFlow();
              }
              return curFlow;
          } else {
              if (curPage == null) {
                  makeNewPage(false, false);
              }
              // Now handle different kinds of areas
              if (aclass == Area.CLASS_BEFORE_FLOAT) {
                  BeforeFloat bf = curBody.getBeforeFloat();
                  if (bf == null) {
                      bf = new BeforeFloat();
                      curBody.setBeforeFloat(bf);
                  }
                  return bf;
              } else if (aclass == Area.CLASS_FOOTNOTE) {
                  Footnote fn = curBody.getFootnote();
                  if (fn == null) {
                      fn = new Footnote();
                      curBody.setFootnote(fn);
                  }
                  return fn;
              }
              // todo!!! other area classes (side-float, absolute, fixed)
              return null;
          }
      }
  
      /**
       * Depending on the kind of break condition, make new column
       * or page. May need to make an empty page if next page would
       * not have the desired "handedness".
       *
       * @param breakVal the break value to handle
       */
      private void handleBreak(int breakVal) {
          if (breakVal == Constants.COLUMN) {
              if (curSpan != null
                      && curSpan.getColumnCount() != curSpanColumns) {
                  // Move to next column
                  createFlow();
                  return;
              }
              // else need new page
              breakVal = Constants.PAGE;
          }
          if (needEmptyPage(breakVal)) {
              curPage = makeNewPage(true, false);
          }
          if (needNewPage(breakVal)) {
              curPage = makeNewPage(false, false);
          }
      }
  
      /**
       * If we have already started to layout content on a page,
       * and there is a forced break, see if we need to generate
       * an empty page.
       * Note that if not all content is placed, we aren't sure whether
       * it will flow onto another page or not, so we'd probably better
       * block until the queue of layoutable stuff is empty!
       */
      private boolean needEmptyPage(int breakValue) {
  
          if (breakValue == Constants.PAGE || curPage.getPage().isEmpty()) {
              // any page is OK or we already have an empty page
              return false;
          }
          else {
              /* IF we are on the kind of page we need, we'll need a new page. */
              if (pageCount%2 != 0) {
                  // Current page is odd
                  return (breakValue == Constants.ODD_PAGE);
              }
              else {
                  return (breakValue == Constants.EVEN_PAGE);
              }
          }
      }
  
      /**
       * See if need to generate a new page for a forced break condition.
       */
      private boolean needNewPage(int breakValue) {
          if (curPage.getPage().isEmpty()) {
              if (breakValue == Constants.PAGE) {
                  return false;
              }
              else if (pageCount%2 != 0) {
                  // Current page is odd
                  return (breakValue == Constants.EVEN_PAGE);
              }
              else {
                  return (breakValue == Constants.ODD_PAGE);
              }
          }
          else {
              return true;
          }
      }
  
      private void createBodyMainReferenceArea() {
          curBody.setMainReference(new MainReference());
      }
  
      private Flow createFlow() {
          curFlow = new Flow();
          curFlow.setIPD(curSpan.getIPD()); // adjust for columns
          //curFlow.setBPD(100000);
          // Set IPD and max BPD on the curFlow from curBody
          curSpan.addFlow(curFlow);
          return curFlow;
      }
  
      private void createSpan(int numCols) {
          // check number of columns (= all in Body or 1)
          // If already have a span, get its size and position (as MinMaxOpt)
          // This determines the position of the new span area
          // Attention: space calculation between the span areas.
  
          //MinOptMax newpos ;
          //if (curSpan != null) {
          //newpos = curSpan.getPosition(BPD);
          //newpos.add(curSpan.getDimension(BPD));
          //}
          //else newpos = new MinOptMax();
          curSpan = new Span(numCols);
          curSpanColumns = numCols;
          // get Width or Height as IPD for span
  
          RegionViewport rv = curPage.getPage().getRegionViewport(FO_REGION_BODY);
          int ipdWidth = (int) rv.getRegion().getIPD() -
              rv.getBorderAndPaddingWidthStart() - rv.getBorderAndPaddingWidthEnd();
  
          curSpan.setIPD(ipdWidth);
          //curSpan.setPosition(BPD, newpos);
          curBody.getMainReference().addSpan(curSpan);
          createFlow();
      }
  
      // See finishPage...
      protected void flush() {
          finishPage();
      }
  
      /**
       * Called when a new page is needed.
       *
       * @param bIsBlank If true, use a master for a blank page.
       * @param bIsLast If true, use the master for the last page in the sequence.
       * @return the page viewport created for the page number
       * @throws FOPException if there is an error creating page
       */
      private PageViewport createPage(boolean bIsBlank, boolean bIsLast)
                                     throws FOPException {
          currentSimplePageMaster = getSimplePageMasterToUse(bIsBlank);
          Region body = currentSimplePageMaster.getRegion(FO_REGION_BODY);
          if (!pageSequence.getMainFlow().getPropString(PR_FLOW_NAME).equals(body.getRegionName())) {
            throw new FOPException("Flow '" + pageSequence.getMainFlow().getPropString(PR_FLOW_NAME)
                                   + "' does not map to the region-body in page-master '"
                                   + currentSimplePageMaster.getMasterName() + "'");
          }
          PageViewport p = createPageAreas(currentSimplePageMaster);
          return p;
          // The page will have a viewport/reference area pair defined
          // for each region in the master.
          // Set up the page itself
  // SKIP ALL THIS FOR NOW!!!
  //             //pageSequence.root.setRunningPageNumberCounter(pageSequence.currentPageNumber);
  
  //             pageSequence.pageCount++;    // used for 'force-page-count' calculations
  
          // handle the 'force-page-count'
          //forcePage(areaTree, firstAvailPageNumber);
      }
  
      private SimplePageMaster getSimplePageMasterToUse(boolean bIsBlank)
              throws FOPException {
          if (pageSequence.getPageSequenceMaster() == null) {
              return pageSequence.getSimplePageMaster();
          }
          boolean isOddPage = ((pageCount % 2) == 1);
          return pageSequence.getPageSequenceMaster()
                .getNextSimplePageMaster(isOddPage, isFirstPage, bIsBlank);
      }
  
      private PageViewport createPageAreas(SimplePageMaster spm) {
          int pageWidth = spm.getPropLength(PR_PAGE_WIDTH);
          int pageHeight = spm.getPropLength(PR_PAGE_HEIGHT);
  
          // Set the page dimension as the toplevel containing block for margin.
          ((FObj) fobj.getParent()).setLayoutDimension(PercentBase.BLOCK_IPD, pageWidth);
          ((FObj) fobj.getParent()).setLayoutDimension(PercentBase.BLOCK_BPD, pageHeight);
  
          // Get absolute margin properties (top, left, bottom, right)
          CommonMarginBlock mProps = spm.getPropertyManager().getMarginProps();
  
        /* Create the page reference area rectangle (0,0 is at top left
         * of the "page media" and y increases
         * when moving towards the bottom of the page.
         * The media rectangle itself is (0,0,pageWidth,pageHeight).
         */
         Rectangle pageRefRect =
                 new Rectangle(mProps.marginLeft, mProps.marginTop,
                         pageWidth - mProps.marginLeft - mProps.marginRight,
                         pageHeight - mProps.marginTop - mProps.marginBottom);
  
         Page page = new Page();  // page reference area
  
         // Set up the CTM on the page reference area based on writing-mode
         // and reference-orientation
         FODimension reldims = new FODimension(0, 0);
         CTM pageCTM = CTM.getCTMandRelDims(spm.getPropertyManager().getAbsRefOrient(),
                 spm.getPropertyManager().getWritingMode(), pageRefRect, reldims);
  
         // Create a RegionViewport/ reference area pair for each page region
         for (Iterator regenum = spm.getRegions().values().iterator();
              regenum.hasNext();) {
             Region r = (Region)regenum.next();
             r.setLayoutDimension(PercentBase.BLOCK_IPD, pageWidth);
             r.setLayoutDimension(PercentBase.BLOCK_BPD, pageHeight);
             RegionViewport rvp = makeRegionViewport(r, reldims, pageCTM);
             if (r.getNameId() == FO_REGION_BODY) {
                 rvp.setRegion(makeRegionBodyReferenceArea(r, rvp.getViewArea()));
             } else {
                 rvp.setRegion(makeRegionReferenceArea(r, rvp.getViewArea()));
             }
             page.setRegionViewport(r.getNameId(), rvp);
         }
  
         return new PageViewport(page, new Rectangle(0, 0, pageWidth, pageHeight));
      }
  
      /**
       * Creates a RegionViewport Area object for this pagination Region.
       * @param reldims relative dimensions
       * @param pageCTM page coordinate transformation matrix
       * @return the new region viewport
       */
      private RegionViewport makeRegionViewport(Region r, FODimension reldims, CTM pageCTM) {
          Rectangle2D relRegionRect = r.getViewportRectangle(reldims);
          Rectangle2D absRegionRect = pageCTM.transform(relRegionRect);
          // Get the region viewport rectangle in absolute coords by
          // transforming it using the page CTM
          RegionViewport rv = new RegionViewport(absRegionRect);
          setRegionViewportTraits(r, rv);
          return rv;
      }
  
      /**
       * Set the region viewport traits.
       * The viewport has the border, background and
       * clipping overflow traits.
       *
       * @param r the region viewport
       */
      private void setRegionViewportTraits(Region r, RegionViewport rv) {
          // Common Border, Padding, and Background Properties
          CommonBorderAndPadding bap = r.getPropertyManager().getBorderAndPadding();
          CommonBackground bProps = r.getPropertyManager().getBackgroundProps();
          TraitSetter.addBorders(rv, bap);
          TraitSetter.addBackground(rv, bProps);
      }
  
      private RegionReference makeRegionBodyReferenceArea(Region r,
              Rectangle2D absRegVPRect) {
          // Should set some column stuff here I think, or put it elsewhere
          BodyRegion body = new BodyRegion();
          setRegionPosition(r, body, absRegVPRect);
          int columnCount =
                  r.getProperty(PR_COLUMN_COUNT).getNumber().intValue();
          if ((columnCount > 1) && (r.overflow == Overflow.SCROLL)) {
              // recover by setting 'column-count' to 1. This is allowed but
              // not required by the spec.
              log.error("Setting 'column-count' to 1 because "
                      + "'overflow' is set to 'scroll'");
              columnCount = 1;
          }
          body.setColumnCount(columnCount);
  
          int columnGap = r.getPropLength(PR_COLUMN_GAP);
          body.setColumnGap(columnGap);
          return body;
      }
  
      /**
       * Create the region reference area for this region master.
       * @param absRegVPRect The region viewport rectangle is "absolute" coordinates
       * where x=distance from left, y=distance from bottom, width=right-left
       * height=top-bottom
       * @return a new region reference area
       */
      private RegionReference makeRegionReferenceArea(Region r,
              Rectangle2D absRegVPRect) {
          RegionReference rr = new RegionReference(r.getNameId());
          setRegionPosition(r, rr, absRegVPRect);
          return rr;
      }
  
      /**
       * Set the region position inside the region viewport.
       * This sets the trasnform that is used to place the contents of
       * the region.
       *
       * @param r the region reference area
       * @param absRegVPRect the rectangle to place the region contents
       */
      private void setRegionPosition(Region r, RegionReference rr,
                                    Rectangle2D absRegVPRect) {
          FODimension reldims = new FODimension(0, 0);
          rr.setCTM(CTM.getCTMandRelDims(r.getPropertyManager().getAbsRefOrient(),
                  r.getPropertyManager().getWritingMode(), absRegVPRect, reldims));
          rr.setIPD(reldims.ipd);
          rr.setBPD(reldims.bpd);
      }
  
      /**
       * @return a StaticContent layout manager
       */
      private StaticContentLayoutManager getStaticContentLayoutManager(StaticContent sc) {
          StaticContentLayoutManager lm =
                  (StaticContentLayoutManager)staticContentLMs.get(sc.getPropString(PR_FLOW_NAME));
          if (lm != null) {
              return lm;
          }
          lm = new StaticContentLayoutManager();
          lm.setFObj(sc);
          staticContentLMs.put(sc.getPropString(PR_FLOW_NAME), lm);
          return lm;
      }
  
      /**
       * @return the apps.FOTreeHandler object controlling this generation
       */
      public AreaTreeHandler getAreaTreeHandler() {
          return areaTreeHandler;
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: fop-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: fop-cvs-help@xml.apache.org