| /* |
| * 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.inline; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.fop.area.Area; |
| import org.apache.fop.area.Block; |
| import org.apache.fop.area.LineArea; |
| import org.apache.fop.area.inline.InlineArea; |
| import org.apache.fop.fo.Constants; |
| import org.apache.fop.fo.pagination.Title; |
| import org.apache.fop.layoutmgr.AbstractBaseLayoutManager; |
| import org.apache.fop.layoutmgr.KnuthElement; |
| import org.apache.fop.layoutmgr.KnuthPossPosIter; |
| import org.apache.fop.layoutmgr.KnuthSequence; |
| import org.apache.fop.layoutmgr.LayoutContext; |
| import org.apache.fop.layoutmgr.LayoutManager; |
| import org.apache.fop.layoutmgr.PageSequenceLayoutManager; |
| import org.apache.fop.layoutmgr.Position; |
| import org.apache.fop.layoutmgr.PositionIterator; |
| import org.apache.fop.layoutmgr.SpaceSpecifier; |
| |
| /** |
| * Content Layout Manager. |
| * For use with objects that contain inline areas such as |
| * leader use-content and title. |
| */ |
| public class ContentLayoutManager extends AbstractBaseLayoutManager |
| implements InlineLevelLayoutManager { |
| |
| /** |
| * logging instance |
| */ |
| private static Log log = LogFactory.getLog(ContentLayoutManager.class); |
| |
| private Area holder; |
| private int stackSize; |
| private LayoutManager parentLM; |
| private InlineLevelLayoutManager childLM = null; |
| |
| /** |
| * Constructs a new ContentLayoutManager |
| * |
| * @param area The parent area |
| * @param parentLM the parent layout manager |
| */ |
| public ContentLayoutManager(Area area, LayoutManager parentLM) { |
| holder = area; |
| this.parentLM = parentLM; |
| } |
| |
| /** |
| * Constructor using a fo:title formatting object and its PageSequenceLayoutManager parent. |
| * throws IllegalStateException if the foTitle has no children. |
| * TODO: convert IllegalStateException to FOPException; |
| * also in makeLayoutManager and makeContentLayoutManager and callers. |
| * @param pslm the PageSequenceLayoutManager parent of this LM |
| * @param foTitle the Title FO for which this LM is made |
| */ |
| public ContentLayoutManager(PageSequenceLayoutManager pslm, Title foTitle) { |
| // get breaks then add areas to title |
| this.parentLM = pslm; |
| holder = new LineArea(); |
| |
| // setUserAgent(foTitle.getUserAgent()); |
| |
| // use special layout manager to add the inline areas |
| // to the Title. |
| try { |
| LayoutManager lm = pslm.getLayoutManagerMaker().makeLayoutManager(foTitle); |
| addChildLM(lm); |
| fillArea(lm); |
| } catch (IllegalStateException e) { |
| log.warn("Title has no content"); |
| throw e; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void initialize() { |
| // Empty |
| } |
| |
| private void fillArea(LayoutManager curLM) { |
| |
| int ipd = 1000000; |
| |
| LayoutContext childLC = new LayoutContext(LayoutContext.NEW_AREA); |
| childLC.setLeadingSpace(new SpaceSpecifier(false)); |
| childLC.setTrailingSpace(new SpaceSpecifier(false)); |
| childLC.setRefIPD(ipd); |
| |
| int lineHeight = 14000; |
| int lead = 12000; |
| int follow = 2000; |
| |
| int halfLeading = (lineHeight - lead - follow) / 2; |
| // height before baseline |
| int lineLead = lead + halfLeading; |
| // maximum size of top and bottom alignment |
| int maxtb = follow + halfLeading; |
| // max size of middle alignment below baseline |
| int middlefollow = maxtb; |
| |
| stackSize = 0; |
| |
| List contentList = getNextKnuthElements(childLC, Constants.EN_START); |
| ListIterator contentIter = contentList.listIterator(); |
| while (contentIter.hasNext()) { |
| KnuthElement element = (KnuthElement) contentIter.next(); |
| if (element instanceof KnuthInlineBox) { |
| KnuthInlineBox box = (KnuthInlineBox) element; |
| // TODO handle alignment here? |
| } |
| } |
| |
| if (maxtb - lineLead > middlefollow) { |
| middlefollow = maxtb - lineLead; |
| } |
| |
| LayoutContext lc = new LayoutContext(0); |
| |
| lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); |
| lc.setLeadingSpace(new SpaceSpecifier(false)); |
| lc.setTrailingSpace(new SpaceSpecifier(false)); |
| KnuthPossPosIter contentPosIter = new KnuthPossPosIter(contentList, 0, contentList.size()); |
| curLM.addAreas(contentPosIter, lc); |
| } |
| |
| /** {@inheritDoc} */ |
| public void addAreas(PositionIterator posIter, LayoutContext context) { |
| // add the content areas |
| // the area width has already been adjusted, and it must remain unchanged |
| // so save its value before calling addAreas, and set it again afterwards |
| int savedIPD = ((InlineArea)holder).getIPD(); |
| // set to zero the ipd adjustment ratio, to avoid spaces in the pattern |
| // to be modified |
| LayoutContext childContext = new LayoutContext(context); |
| childContext.setIPDAdjust(0.0); |
| childLM.addAreas(posIter, childContext); |
| ((InlineArea)holder).setIPD(savedIPD); |
| } |
| |
| /** @return stack size */ |
| public int getStackingSize() { |
| return stackSize; |
| } |
| |
| /** {@inheritDoc} */ |
| public Area getParentArea(Area childArea) { |
| return holder; |
| } |
| |
| /** |
| * {@inheritDoc} |
| **/ |
| public void addChildArea(Area childArea) { |
| holder.addChildArea(childArea); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setParent(LayoutManager lm) { |
| parentLM = lm; |
| } |
| |
| /** {@inheritDoc} */ |
| public LayoutManager getParent() { |
| return this.parentLM; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean isFinished() { |
| return false; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setFinished(boolean isFinished) { |
| //to be done |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean createNextChildLMs(int pos) { |
| return false; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public List getChildLMs() { |
| List childLMs = new ArrayList(1); |
| childLMs.add(childLM); |
| return childLMs; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void addChildLM(LayoutManager lm) { |
| if (lm == null) { |
| return; |
| } |
| lm.setParent(this); |
| childLM = (InlineLevelLayoutManager)lm; |
| log.trace(this.getClass().getName() |
| + ": Adding child LM " + lm.getClass().getName()); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void addChildLMs(List newLMs) { |
| if (newLMs == null || newLMs.size() == 0) { |
| return; |
| } |
| ListIterator iter = newLMs.listIterator(); |
| while (iter.hasNext()) { |
| LayoutManager lm = (LayoutManager) iter.next(); |
| addChildLM(lm); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public List getNextKnuthElements(LayoutContext context, int alignment) { |
| List contentList = new LinkedList(); |
| List returnedList; |
| |
| childLM.initialize(); |
| while (!childLM.isFinished()) { |
| // get KnuthElements from childLM |
| returnedList = childLM.getNextKnuthElements(context, alignment); |
| |
| if (returnedList != null) { |
| // move elements to contentList, and accumulate their size |
| KnuthElement contentElement; |
| while (returnedList.size() > 0) { |
| Object obj = returnedList.remove(0); |
| if (obj instanceof KnuthSequence) { |
| KnuthSequence ks = (KnuthSequence)obj; |
| for (Iterator it = ks.iterator(); it.hasNext();) { |
| contentElement = (KnuthElement)it.next(); |
| stackSize += contentElement.getWidth(); |
| contentList.add(contentElement); |
| } |
| } else { |
| contentElement = (KnuthElement)obj; |
| stackSize += contentElement.getWidth(); |
| contentList.add(contentElement); |
| } |
| } |
| } |
| } |
| |
| setFinished(true); |
| return contentList; |
| } |
| |
| /** {@inheritDoc} */ |
| public List addALetterSpaceTo(List oldList) { |
| return oldList; |
| } |
| |
| /** {@inheritDoc} */ |
| public List addALetterSpaceTo(List oldList, int depth) { |
| return addALetterSpaceTo(oldList); |
| } |
| |
| /** {@inheritDoc} */ |
| public String getWordChars(Position pos) { |
| return ""; |
| } |
| |
| /** {@inheritDoc} */ |
| public void hyphenate(Position pos, HyphContext hc) { |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean applyChanges(List oldList) { |
| return false; |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean applyChanges(List oldList, int depth) { |
| return applyChanges(oldList); |
| } |
| |
| /** {@inheritDoc} */ |
| public List getChangedKnuthElements(List oldList, int alignment) { |
| return null; |
| } |
| |
| /** {@inheritDoc} */ |
| public List getChangedKnuthElements(List oldList, int alignment, int depth) { |
| return getChangedKnuthElements(oldList, alignment); |
| } |
| |
| /** {@inheritDoc} */ |
| public PageSequenceLayoutManager getPSLM() { |
| return parentLM.getPSLM(); |
| } |
| |
| // --------- Property Resolution related functions --------- // |
| |
| /** |
| * Returns the IPD of the content area |
| * @return the IPD of the content area |
| */ |
| public int getContentAreaIPD() { |
| return holder.getIPD(); |
| } |
| |
| /** |
| * Returns the BPD of the content area |
| * @return the BPD of the content area |
| */ |
| public int getContentAreaBPD() { |
| return holder.getBPD(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean getGeneratesReferenceArea() { |
| return false; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean getGeneratesBlockArea() { |
| return getGeneratesLineArea() || holder instanceof Block; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean getGeneratesLineArea() { |
| return holder instanceof LineArea; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Position notifyPos(Position pos) { |
| return pos; |
| } |
| |
| } |
| |