blob: 1733f7b3d3b620110f494d346d198a76c13ef21e [file] [log] [blame]
/*
* 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.area.inline;
import java.io.Serializable;
import java.util.List;
import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.Trait;
import org.apache.fop.complexscripts.bidi.InlineRun;
/**
* Inline Area
* This area is for all inline areas that can be placed
* in a line area.
*/
public class InlineArea extends Area {
private static final long serialVersionUID = -8940066479810170980L;
/**
* this class stores information about potential adjustments
* that can be used in order to re-compute adjustments when a
* page-number or a page-number-citation is resolved
*/
// @SuppressFBWarnings("SE_INNER_CLASS")
protected class InlineAdjustingInfo implements Serializable {
private static final long serialVersionUID = -5601387735459712149L;
/** stretch of the inline area */
protected int availableStretch;
/** shrink of the inline area */
protected int availableShrink;
/** total adjustment (= ipd - width of fixed elements) */
protected int adjustment;
/**
* Constructor
*
* @param stretch the available space for stretching
* @param shrink the available space for shrinking
* @param adj space adjustment type
*/
protected InlineAdjustingInfo(int stretch, int shrink, int adj) {
availableStretch = stretch;
availableShrink = shrink;
adjustment = adj;
}
/**
* Apply the variation factor
*
* @param variationFactor the factor by which the adjustment is to be changed
* @return the IPD increase
*/
protected int applyVariationFactor(double variationFactor) {
int oldAdjustment = adjustment;
adjustment *= variationFactor;
return adjustment - oldAdjustment;
}
}
/**
* offset position from before edge of parent area
*/
protected int blockProgressionOffset;
/**
* parent area
* it is needed in order to recompute adjust ratio and indents
* when a page-number or a page-number-citation is resolved
*/
private Area parentArea;
/**
* ipd variation of child areas: if this area has not already
* been added and cannot notify its parent area, store the variation
* and wait for the parent area to be set
*/
private int storedIPDVariation;
/**
* The adjustment information object
*/
protected InlineAdjustingInfo adjustingInfo;
/**
* Default constructor for inline area.
*/
public InlineArea() {
this (0, -1);
}
/**
* Instantiate inline area.
* @param blockProgressionOffset a block progression offset or zero
* @param bidiLevel a resolved bidi level or -1
*/
protected InlineArea(int blockProgressionOffset, int bidiLevel) {
this.blockProgressionOffset = blockProgressionOffset;
setBidiLevel(bidiLevel);
}
/**
* @return the adjustment information object
*/
public InlineAdjustingInfo getAdjustingInfo() {
return adjustingInfo;
}
/**
* Create a new adjustment information object
* @param stretch the available space for stretching
* @param shrink the available space for shrinking
* @param adjustment space adjustment type
*/
public void setAdjustingInfo(int stretch, int shrink, int adjustment) {
adjustingInfo = new InlineAdjustingInfo(stretch, shrink, adjustment);
}
/**
* Sets the adjustment information from an existing object
* @param adjustingInfo the existing adjustment object
*/
public void setAdjustingInfo(InlineAdjustingInfo adjustingInfo) {
this.adjustingInfo = adjustingInfo;
}
/**
* Modify the adjustment value in the adjustment information object
* @param adjustment the new adjustment value
*/
public void setAdjustment(int adjustment) {
if (adjustingInfo != null) {
adjustingInfo.adjustment = adjustment;
}
}
/**
* Increase the inline progression dimensions of this area.
* This is used for inline parent areas that contain mulitple child areas.
*
* @param ipd the inline progression to increase by
*/
public void increaseIPD(int ipd) {
this.ipd += ipd;
}
/**
* Set the block progression offset of this inline area.
* This is used to set the offset of the inline area
* which is relative to the before edge of the parent area.
*
* @param blockProgressionOffset the offset
*/
public void setBlockProgressionOffset(int blockProgressionOffset) {
this.blockProgressionOffset = blockProgressionOffset;
}
/**
* Get the block progression offset of this inline area.
* This returns the offset of the inline area
* relative to the before edge of the parent area.
*
* @return the blockProgressionOffset
*/
public int getBlockProgressionOffset() {
return blockProgressionOffset;
}
/**
* @param parentArea The parentArea to set.
*/
public void setParentArea(Area parentArea) {
this.parentArea = parentArea;
}
/**
* @return Returns the parentArea.
*/
public Area getParentArea() {
return parentArea;
}
/**
* Set the parent for the child area.
*
* {@inheritDoc}
*/
@Override
public void addChildArea(Area childArea) {
super.addChildArea(childArea);
if (childArea instanceof InlineArea) {
((InlineArea) childArea).setParentArea(this);
}
}
/** @return true if the inline area is underlined. */
public boolean hasUnderline() {
return getTraitAsBoolean(Trait.UNDERLINE);
}
/** @return true if the inline area is overlined. */
public boolean hasOverline() {
return getTraitAsBoolean(Trait.OVERLINE);
}
/** @return true if the inline area has a line through. */
public boolean hasLineThrough() {
return getTraitAsBoolean(Trait.LINETHROUGH);
}
/** @return true if the inline area is blinking. */
public boolean isBlinking() {
return getTraitAsBoolean(Trait.BLINK);
}
/**
* recursively apply the variation factor to all descendant areas
* @param variationFactor the variation factor that must be applied to adjustments
* @param lineStretch the total stretch of the line
* @param lineShrink the total shrink of the line
* @return true if there is an UnresolvedArea descendant
*/
public boolean applyVariationFactor(double variationFactor,
int lineStretch, int lineShrink) {
// default behaviour: update the IPD and return false
if (adjustingInfo != null) {
setIPD(getIPD() + adjustingInfo.applyVariationFactor(variationFactor));
}
return false;
}
/**
* Apply IPD variation.
* @param ipdVariation the variation
*/
public void handleIPDVariation(int ipdVariation) {
if (log.isTraceEnabled()) {
log.trace("Handling IPD variation for " + getClass().getSimpleName()
+ ": increase by " + ipdVariation + " mpt.");
}
if (ipdVariation != 0) {
increaseIPD(ipdVariation);
notifyIPDVariation(ipdVariation);
}
}
/**
* notify the parent area about the ipd variation of this area
* or of a descendant area
* @param ipdVariation the difference between new and old ipd
*/
protected void notifyIPDVariation(int ipdVariation) {
Area parentArea = getParentArea();
if (parentArea instanceof InlineArea) {
((InlineArea) parentArea).handleIPDVariation(ipdVariation);
} else if (parentArea instanceof LineArea) {
((LineArea) parentArea).handleIPDVariation(ipdVariation);
} else if (parentArea == null) {
// parent area not yet set: store the variations
storedIPDVariation += ipdVariation;
}
}
/**
* Returns the offset that this area would have if its offset and size were taking
* children areas into account. The bpd of an inline area is taken from its nominal
* font and doesn't depend on the bpds of its children elements. However, in the case
* of a basic-link element we want the active area to cover all of the children
* elements.
*
* @return the offset that this area would have if the before-edge of its
* content-rectangle were coinciding with the <q>beforest</q> before-edge of its
* children allocation-rectangles.
* @see #getVirtualBPD()
* @see BasicLinkArea
*/
int getVirtualOffset() {
return getBlockProgressionOffset();
}
/**
* Returns the block-progression-dimension that this area would have if it were taking
* its children elements into account. See {@linkplain #getVirtualOffset()}.
*
* @return the bpd
*/
int getVirtualBPD() {
return getBPD();
}
/**
* Collection bidi inline runs.
* @param runs current list of inline runs
* @return modified list of inline runs, having appended new run
*/
public List collectInlineRuns(List runs) {
assert runs != null;
runs.add(new InlineRun(this, new int[] {getBidiLevel()}));
return runs;
}
/**
* Determine if inline area IA is an ancestor inline area or same as this area.
* @param ia inline area to test
* @return true if specified inline area is an ancestor or same as this area
*/
public boolean isAncestorOrSelf(InlineArea ia) {
return (ia == this) || isAncestor(ia);
}
/**
* Determine if inline area IA is an ancestor inline area of this area.
* @param ia inline area to test
* @return true if specified inline area is an ancestor of this area
*/
public boolean isAncestor(InlineArea ia) {
for (Area p = getParentArea(); p != null;) {
if (p == ia) {
return true;
} else if (p instanceof InlineArea) {
p = ((InlineArea) p).getParentArea();
} else {
p = null;
}
}
return false;
}
}