/*
 * 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: LineArea.java 1761020 2016-09-16 11:17:35Z ssteiner $ */

package org.apache.fop.area;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.fop.area.inline.InlineArea;

import static org.apache.fop.fo.Constants.EN_CENTER;
import static org.apache.fop.fo.Constants.EN_END;
import static org.apache.fop.fo.Constants.EN_JUSTIFY;
import static org.apache.fop.fo.Constants.EN_START;

The line area. This is a line area that contains inline areas.
/** * The line area. * This is a line area that contains inline areas. */
public class LineArea extends Area { private static final long serialVersionUID = 7670235908329290684L;
this class stores information about line width and potential adjustments that can be used in order to re-compute adjustement and / or indents when a page-number or a page-number-citation is resolved
/** * this class stores information about line width and potential adjustments * that can be used in order to re-compute adjustement and / or indents when a * page-number or a page-number-citation is resolved */
// @SuppressFBWarnings("SE_INNER_CLASS") private final class LineAdjustingInfo implements Serializable { private static final long serialVersionUID = -6103629976229458273L; private int lineAlignment; private int difference; private int availableStretch; private int availableShrink; private double variationFactor; private boolean bAddedToAreaTree; private LineAdjustingInfo(int alignment, int diff, int stretch, int shrink) { lineAlignment = alignment; difference = diff; availableStretch = stretch; availableShrink = shrink; variationFactor = 1.0; bAddedToAreaTree = false; }
{@inheritDoc}
/** {@inheritDoc} */
public String toString() { return getClass().getSimpleName() + ": diff=" + difference + ", variation=" + variationFactor + ", stretch=" + availableStretch + ", shrink=" + availableShrink; } } private LineAdjustingInfo adjustingInfo; // this class can contain the dominant char styling info // this means that many renderers can optimise a bit private List<InlineArea> inlineAreas = new ArrayList<InlineArea>();
default constructor: nothing to do
/** * default constructor: * nothing to do */
public LineArea() { }
constructor with extra parameters: a new LineAdjustingInfo object is created
Params:
  • alignment – alignment of this line
  • diff – difference between content width and line width
  • stretch – the available stretch for any adjustments
  • shrink – the available shrink for any adjustments
/** * constructor with extra parameters: * a new LineAdjustingInfo object is created * @param alignment alignment of this line * @param diff difference between content width and line width * @param stretch the available stretch for any adjustments * @param shrink the available shrink for any adjustments */
public LineArea(int alignment, int diff, int stretch, int shrink) { adjustingInfo = new LineAdjustingInfo(alignment, diff, stretch, shrink); }
Add a child area to this line area.
Params:
  • childArea – the inline child area to add
/** * Add a child area to this line area. * * @param childArea the inline child area to add */
@Override public void addChildArea(Area childArea) { if (childArea instanceof InlineArea) { addInlineArea((InlineArea)childArea); // set the parent area for the child area ((InlineArea)childArea).setParentArea(this); } }
Add an inline child area to this line area.
Params:
  • area – the inline child area to add
/** * Add an inline child area to this line area. * * @param area the inline child area to add */
public void addInlineArea(InlineArea area) { inlineAreas.add(area); }

Set (en masse) the inline child areas of this line area.

Used by bidirectional processing after line area consituent reordering.

Params:
  • inlineAreas – the list of inline areas
/** * <p>Set (en masse) the inline child areas of this line area.</p> * <p> Used by bidirectional processing after line area consituent reordering.</p> * @param inlineAreas the list of inline areas */
public void setInlineAreas(List inlineAreas) { for (InlineArea ia : (Iterable<InlineArea>) inlineAreas) { Area pa = ia.getParentArea(); if (pa == null) { ia.setParentArea(this); } else { assert pa == this; } } this.inlineAreas = inlineAreas; }
Get the inline child areas of this line area.
Returns:the list of inline areas
/** * Get the inline child areas of this line area. * * @return the list of inline areas */
public List getInlineAreas() { return inlineAreas; }
Get the start indent of this line area. The start indent is used for offsetting the start of the inline areas for alignment or other indents.
Returns:the start indent value
/** * Get the start indent of this line area. * The start indent is used for offsetting the start of * the inline areas for alignment or other indents. * * @return the start indent value */
public int getStartIndent() { if (hasTrait(Trait.START_INDENT)) { return getTraitAsInteger(Trait.START_INDENT); } else { return 0; } }
Get the end indent of this line area. The end indent is used for offsetting the end of the inline areas for alignment or other indents.
Returns:the end indent value
/** * Get the end indent of this line area. * The end indent is used for offsetting the end of * the inline areas for alignment or other indents. * * @return the end indent value */
public int getEndIndent() { if (hasTrait(Trait.END_INDENT)) { return getTraitAsInteger(Trait.END_INDENT); } else { return 0; } }
Updates the extents of the line area from its children.
/** * Updates the extents of the line area from its children. */
public void updateExtentsFromChildren() { int ipd = 0; int bpd = 0; for (InlineArea inlineArea : inlineAreas) { ipd = Math.max(ipd, inlineArea.getAllocIPD()); bpd += inlineArea.getAllocBPD(); } setIPD(ipd); setBPD(bpd); }
receive notification about the ipd variation of a descendant area and perform the needed adjustment, according to the alignment; in particular:
  • left-aligned text needs no adjustement;
  • right-aligned text and centered text are handled locally, adjusting the indent of this LineArea;
  • justified text requires a more complex adjustment, as the variation factor computed on the basis of the total stretch and shrink of the line must be applied in every descendant leaf areas (text areas and leader areas).
Params:
  • ipdVariation – the difference between old and new ipd
/** * receive notification about the ipd variation of a descendant area * and perform the needed adjustment, according to the alignment; * in particular: * <ul> * <li>left-aligned text needs no adjustement;</li> * <li>right-aligned text and centered text are handled locally, * adjusting the indent of this LineArea;</li> * <li>justified text requires a more complex adjustment, as the * variation factor computed on the basis of the total * stretch and shrink of the line must be applied in every * descendant leaf areas (text areas and leader areas).</li> * </ul> * @param ipdVariation the difference between old and new ipd */
public void handleIPDVariation(int ipdVariation) { int si = getStartIndent(); int ei = getEndIndent(); switch (adjustingInfo.lineAlignment) { case EN_START: // adjust end indent addTrait(Trait.END_INDENT, ei - ipdVariation); break; case EN_CENTER: // adjust start and end indents addTrait(Trait.START_INDENT, si - ipdVariation / 2); addTrait(Trait.END_INDENT, ei - ipdVariation / 2); break; case EN_END: // adjust start indent addTrait(Trait.START_INDENT, si - ipdVariation); break; case EN_JUSTIFY: // compute variation factor adjustingInfo.variationFactor *= (float) (adjustingInfo.difference - ipdVariation) / adjustingInfo.difference; adjustingInfo.difference -= ipdVariation; // if the LineArea has already been added to the area tree, // call finalize(); otherwise, wait for the LineLM to call it if (adjustingInfo.bAddedToAreaTree) { finish(); } break; default: throw new RuntimeException(); } }
apply the variation factor to all descendant areas and destroy the AdjustingInfo object if there are no UnresolvedAreas left
/** * apply the variation factor to all descendant areas * and destroy the AdjustingInfo object if there are * no UnresolvedAreas left */
public void finish() { if (adjustingInfo.lineAlignment == EN_JUSTIFY) { if (log.isTraceEnabled()) { log.trace("Applying variation factor to justified line: " + adjustingInfo); } // justified line: apply the variation factor boolean bUnresolvedAreasPresent = false; // recursively apply variation factor to descendant areas for (InlineArea inlineArea : inlineAreas) { bUnresolvedAreasPresent |= inlineArea .applyVariationFactor(adjustingInfo.variationFactor, adjustingInfo.availableStretch, adjustingInfo.availableShrink); } if (!bUnresolvedAreasPresent) { // there are no more UnresolvedAreas: // destroy the AdjustingInfo instance adjustingInfo = null; } else { // this method will be called again later: // the first time, it is called by the LineLM, // afterwards it must be called by the LineArea itself if (!adjustingInfo.bAddedToAreaTree) { adjustingInfo.bAddedToAreaTree = true; } // reset the variation factor adjustingInfo.variationFactor = 1.0; } } else { // the line is not justified: the ipd variation has already // been handled, modifying the line indent } } public int getEffectiveIPD() { int maxIPD = 0; if (inlineAreas != null) { for (Area area : inlineAreas) { int effectiveIPD = area.getEffectiveIPD(); if (effectiveIPD > maxIPD) { maxIPD = effectiveIPD; } } } return maxIPD; } }