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