001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: LineArea.java 426576 2006-07-28 15:44:37Z jeremias $ */
019:
020: package org.apache.fop.area;
021:
022: import org.apache.fop.area.inline.InlineArea;
023: import org.apache.fop.fo.Constants;
024:
025: import java.io.Serializable;
026: import java.util.ArrayList;
027: import java.util.List;
028:
029: /**
030: * The line area.
031: * This is a line area that contains inline areas.
032: */
033: public class LineArea extends Area {
034:
035: /**
036: * this class stores information about line width and potential adjustments
037: * that can be used in order to re-compute adjustement and / or indents when a
038: * page-number or a page-number-citation is resolved
039: */
040: private class LineAdjustingInfo implements Serializable {
041: private int lineAlignment;
042: private int difference;
043: private int availableStretch;
044: private int availableShrink;
045: private double variationFactor;
046: private boolean bAddedToAreaTree;
047:
048: private LineAdjustingInfo(int alignment, int diff, int stretch,
049: int shrink) {
050: lineAlignment = alignment;
051: difference = diff;
052: availableStretch = stretch;
053: availableShrink = shrink;
054: variationFactor = 1.0;
055: bAddedToAreaTree = false;
056: }
057: }
058:
059: private LineAdjustingInfo adjustingInfo = null;
060:
061: // this class can contain the dominant char styling info
062: // this means that many renderers can optimise a bit
063:
064: private List inlineAreas = new ArrayList();
065:
066: /**
067: * default constructor:
068: * nothing to do
069: */
070: public LineArea() {
071: }
072:
073: /**
074: * constructor with extra parameters:
075: * a new LineAdjustingInfo object is created
076: * @param alignment alignment of this line
077: * @param diff difference between content width and line width
078: * @param stretch the available stretch for any adjustments
079: * @param shrink the available shrink for any adjustments
080: */
081: public LineArea(int alignment, int diff, int stretch, int shrink) {
082: adjustingInfo = new LineAdjustingInfo(alignment, diff, stretch,
083: shrink);
084: }
085:
086: /**
087: * Add a child area to this line area.
088: *
089: * @param childArea the inline child area to add
090: */
091: public void addChildArea(Area childArea) {
092: if (childArea instanceof InlineArea) {
093: addInlineArea((InlineArea) childArea);
094: // set the parent area for the child area
095: ((InlineArea) childArea).setParentArea(this );
096: }
097: }
098:
099: /**
100: * Add an inline child area to this line area.
101: *
102: * @param area the inline child area to add
103: */
104: public void addInlineArea(InlineArea area) {
105: inlineAreas.add(area);
106: }
107:
108: /**
109: * Get the inline child areas of this line area.
110: *
111: * @return the list of inline areas
112: */
113: public List getInlineAreas() {
114: return inlineAreas;
115: }
116:
117: /**
118: * Get the start indent of this line area.
119: * The start indent is used for offsetting the start of
120: * the inline areas for alignment or other indents.
121: *
122: * @return the start indent value
123: */
124: public int getStartIndent() {
125: if (hasTrait(Trait.START_INDENT)) {
126: return getTraitAsInteger(Trait.START_INDENT);
127: } else {
128: return 0;
129: }
130: }
131:
132: /**
133: * Updates the extents of the line area from its children.
134: */
135: public void updateExtentsFromChildren() {
136: int ipd = 0;
137: int bpd = 0;
138: for (int i = 0, len = inlineAreas.size(); i < len; i++) {
139: ipd = Math.max(ipd, ((InlineArea) inlineAreas.get(i))
140: .getAllocIPD());
141: bpd += ((InlineArea) inlineAreas.get(i)).getAllocBPD();
142: }
143: setIPD(ipd);
144: setBPD(bpd);
145: }
146:
147: /**
148: * receive notification about the ipd variation of a descendant area
149: * and perform the needed adjustment, according to the alignment;
150: * in particular:
151: * <ul>
152: * <li>left-aligned text needs no adjustement;</li>
153: * <li>right-aligned text and centered text are handled locally,
154: * adjusting the indent of this LineArea;</li>
155: * <li>justified text requires a more complex adjustment, as the
156: * variation factor computed on the basis of the total
157: * stretch and shrink of the line must be applied in every
158: * descendant leaf areas (text areas and leader areas).</li>
159: * </ul>
160: * @param ipdVariation the difference between old and new ipd
161: */
162: public void handleIPDVariation(int ipdVariation) {
163: switch (adjustingInfo.lineAlignment) {
164: case Constants.EN_START:
165: // nothing to do in this case
166: break;
167: case Constants.EN_CENTER:
168: // re-compute indent
169: addTrait(Trait.START_INDENT, new Integer(getStartIndent()
170: - ipdVariation / 2));
171: break;
172: case Constants.EN_END:
173: // re-compute indent
174: addTrait(Trait.START_INDENT, new Integer(getStartIndent()
175: - ipdVariation));
176: break;
177: case Constants.EN_JUSTIFY:
178: // compute variation factor
179: adjustingInfo.variationFactor *= (float) (adjustingInfo.difference - ipdVariation)
180: / adjustingInfo.difference;
181: adjustingInfo.difference -= ipdVariation;
182: // if the LineArea has already been added to the area tree,
183: // call finalize(); otherwise, wait for the LineLM to call it
184: if (adjustingInfo.bAddedToAreaTree) {
185: finalise();
186: }
187: break;
188: default:
189: throw new RuntimeException();
190: }
191: }
192:
193: /**
194: * apply the variation factor to all descendant areas
195: * and destroy the AdjustingInfo object if there are
196: * no UnresolvedAreas left
197: */
198: public void finalise() {
199: if (adjustingInfo.lineAlignment == Constants.EN_JUSTIFY) {
200: // justified line: apply the variation factor
201: boolean bUnresolvedAreasPresent = false;
202: // recursively apply variation factor to descendant areas
203: for (int i = 0, len = inlineAreas.size(); i < len; i++) {
204: bUnresolvedAreasPresent |= ((InlineArea) inlineAreas
205: .get(i)).applyVariationFactor(
206: adjustingInfo.variationFactor,
207: adjustingInfo.availableStretch,
208: adjustingInfo.availableShrink);
209: }
210: if (!bUnresolvedAreasPresent) {
211: // there are no more UnresolvedAreas:
212: // destroy the AdjustingInfo instance
213: adjustingInfo = null;
214: } else {
215: // this method will be called again later:
216: // the first time, it is called by the LineLM,
217: // afterwards it must be called by the LineArea itself
218: if (!adjustingInfo.bAddedToAreaTree) {
219: adjustingInfo.bAddedToAreaTree = true;
220: }
221: // reset the variation factor
222: adjustingInfo.variationFactor = 1.0;
223: }
224: } else {
225: // the line is not justified: the ipd variation has already
226: // been handled, modifying the line indent
227: }
228: }
229: }
|