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 18 package org.apache.fop.layoutmgr; 19 20 import java.util.LinkedList; 21 import java.util.List; 22 23 import org.apache.fop.area.Area; 24 import org.apache.fop.fo.Constants; 25 import org.apache.fop.fo.FObj; 26 import org.apache.fop.fo.flow.MultiSwitch; 27 28 public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { 29 30 static class WhitespaceManagementPosition extends Position { 31 32 private List<ListElement> knuthList; 33 WhitespaceManagementPosition(LayoutManager lm)34 public WhitespaceManagementPosition(LayoutManager lm) { 35 super(lm); 36 } 37 getPositionList()38 public List<Position> getPositionList() { 39 List<Position> positions = new LinkedList<Position>(); 40 if (knuthList != null && !knuthList.isEmpty()) { 41 SpaceResolver.performConditionalsNotification(knuthList, 0, knuthList.size() - 1, -1); 42 for (ListElement el : knuthList) { 43 if (el.getPosition() != null) { 44 positions.add(el.getPosition()); 45 } 46 } 47 } 48 return positions; 49 } 50 setKnuthList(List<ListElement> knuthList)51 public void setKnuthList(List<ListElement> knuthList) { 52 this.knuthList = knuthList; 53 } 54 getKnuthList()55 public List<ListElement> getKnuthList() { 56 return knuthList; 57 } 58 59 } 60 61 private interface KnuthElementsGenerator { getKnuthElements(LayoutContext context, int alignment)62 List<ListElement> getKnuthElements(LayoutContext context, int alignment); 63 } 64 65 private class DefaultKnuthListGenerator implements KnuthElementsGenerator { 66 getKnuthElements(LayoutContext context, int alignment)67 public List<ListElement> getKnuthElements(LayoutContext context, int alignment) { 68 List<ListElement> knuthList = new LinkedList<ListElement>(); 69 LayoutManager childLM = getChildLM(); 70 while (!childLM.isFinished()) { 71 LayoutContext childLC = makeChildLayoutContext(context); 72 List childElements = childLM.getNextKnuthElements(childLC, alignment); 73 if (childElements != null) { 74 List<ListElement> newList = new LinkedList<ListElement>(); 75 wrapPositionElements(childElements, newList); 76 knuthList.addAll(newList); 77 } 78 } 79 return knuthList; 80 } 81 82 } 83 84 private class WhitespaceManagement implements KnuthElementsGenerator { 85 86 @SuppressWarnings("unchecked") getKnuthElements(LayoutContext context, int alignment)87 public List<ListElement> getKnuthElements(LayoutContext context, int alignment) { 88 89 MultiSwitchLayoutManager mslm = MultiSwitchLayoutManager.this; 90 List<ListElement> knuthList = new LinkedList<ListElement>(); 91 WhitespaceManagementPenalty penalty = new WhitespaceManagementPenalty( 92 new WhitespaceManagementPosition(mslm)); 93 LayoutManager childLM; 94 while ((childLM = getChildLM()) != null) { 95 LayoutContext childLC = makeChildLayoutContext(context); 96 List<ListElement> childElements = new LinkedList<ListElement>(); 97 while (!childLM.isFinished()) { 98 childElements.addAll(childLM.getNextKnuthElements(childLC, alignment)); 99 } 100 List<ListElement> wrappedElements = new LinkedList<ListElement>(); 101 wrapPositionElements(childElements, wrappedElements); 102 // TODO Doing space resolution here is wrong. 103 SpaceResolver.resolveElementList(wrappedElements); 104 int contentLength = ElementListUtils.calcContentLength(wrappedElements); 105 penalty.addVariant(penalty.new Variant(wrappedElements, contentLength)); 106 } 107 // Prevent the penalty from being ignored if it is at the beginning of the content 108 knuthList.add(new KnuthBox(0, new Position(mslm), false)); 109 knuthList.add(penalty); 110 // Prevent the penalty from being ignored if it is at the end of the content 111 knuthList.add(new KnuthBox(0, new Position(mslm), false)); 112 return knuthList; 113 } 114 115 } 116 117 private KnuthElementsGenerator knuthGen; 118 MultiSwitchLayoutManager(FObj node)119 public MultiSwitchLayoutManager(FObj node) { 120 super(node); 121 MultiSwitch multiSwitchNode = (MultiSwitch) node; 122 if (multiSwitchNode.getAutoToggle() == Constants.EN_SELECT_FIRST_FITTING) { 123 knuthGen = new WhitespaceManagement(); 124 } else { 125 knuthGen = new DefaultKnuthListGenerator(); 126 } 127 } 128 129 @Override getNextKnuthElements(LayoutContext context, int alignment)130 public List<ListElement> getNextKnuthElements(LayoutContext context, int alignment) { 131 referenceIPD = context.getRefIPD(); 132 List<ListElement> knuthList = knuthGen.getKnuthElements(context, alignment); 133 setFinished(true); 134 return knuthList; 135 } 136 137 @Override getParentArea(Area childArea)138 public Area getParentArea(Area childArea) { 139 return parentLayoutManager.getParentArea(childArea); 140 } 141 142 @Override addChildArea(Area childArea)143 public void addChildArea(Area childArea) { 144 parentLayoutManager.addChildArea(childArea); 145 } 146 147 @Override addAreas(PositionIterator posIter, LayoutContext context)148 public void addAreas(PositionIterator posIter, LayoutContext context) { 149 LinkedList<Position> positionList = new LinkedList<Position>(); 150 while (posIter.hasNext()) { 151 Position pos = posIter.next(); 152 if (pos instanceof WhitespaceManagementPosition) { 153 positionList.addAll(((WhitespaceManagementPosition) pos).getPositionList()); 154 } else { 155 positionList.add(pos); 156 } 157 } 158 PositionIterator newPosIter = new PositionIterator(positionList.listIterator()); 159 AreaAdditionUtil.addAreas(this, newPosIter, context); 160 flush(); 161 } 162 163 } 164