From c550e0349a64c0c66d6cee0f2e6f1baa97e14ad2 Mon Sep 17 00:00:00 2001 From: Adrian Cumiskey Date: Fri, 31 Oct 2008 09:58:46 +0000 Subject: [PATCH] Fix for test/layoutengine/standard-testcases/block-container_absolute-position_fixed.xml. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@709373 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/AbstractData.java | 128 ++++++++++ src/java/org/apache/fop/AbstractState.java | 232 ++++++------------ src/java/org/apache/fop/StateStack.java | 31 +++ src/java/org/apache/fop/afp/AFPState.java | 8 +- src/java/org/apache/fop/pdf/PDFState.java | 22 +- .../render/AbstractPathOrientedRenderer.java | 13 +- .../apache/fop/render/afp/AFPRenderer.java | 20 +- .../apache/fop/render/pdf/PDFRenderer.java | 32 +-- 8 files changed, 284 insertions(+), 202 deletions(-) create mode 100644 src/java/org/apache/fop/AbstractData.java create mode 100644 src/java/org/apache/fop/StateStack.java diff --git a/src/java/org/apache/fop/AbstractData.java b/src/java/org/apache/fop/AbstractData.java new file mode 100644 index 000000000..b689165a0 --- /dev/null +++ b/src/java/org/apache/fop/AbstractData.java @@ -0,0 +1,128 @@ +package org.apache.fop; + +import java.awt.Color; +import java.awt.geom.AffineTransform; +import java.io.Serializable; + +/** + * A base state data holding object + */ +public abstract class AbstractData implements Cloneable, Serializable { + + private static final long serialVersionUID = 5208418041189828624L; + + /** The current color */ + protected Color color = null; + + /** The current background color */ + protected Color backColor = null; + + /** The current font name */ + protected String fontName = null; + + /** The current font size */ + protected int fontSize = 0; + + /** The current line width */ + protected float lineWidth = 0; + + /** The dash array for the current basic stroke (line type) */ + protected float[] dashArray = null; + + /** The current transform */ + protected AffineTransform transform = null; + + /** + * Returns a newly create data object + * + * @return a new data object + */ + protected abstract AbstractData instantiate(); + + /** + * Concatenate the given AffineTransform with the current thus creating + * a new viewport. Note that all concatenation operations are logged + * so they can be replayed if necessary (ex. for block-containers with + * "fixed" positioning. + * + * @param at Transformation to perform + */ + public void concatenate(AffineTransform at) { + getTransform().concatenate(at); + } + + /** + * Get the current AffineTransform. + * + * @return the current transform + */ + public AffineTransform getTransform() { + if (transform == null) { + transform = new AffineTransform(); + } + return transform; + } + + /** + * Sets the current AffineTransform. + */ + public void setTransform(AffineTransform baseTransform) { + this.transform = baseTransform; + } + + /** + * Resets the current AffineTransform. + */ + public void clearTransform() { + transform = new AffineTransform(); + } + + /** + * Returns the derived rotation from the current transform + * + * @return the derived rotation from the current transform + */ + public int getDerivedRotation() { + AffineTransform at = getTransform(); + double sx = at.getScaleX(); + double sy = at.getScaleY(); + double shx = at.getShearX(); + double shy = at.getShearY(); + int rotation = 0; + if (sx == 0 && sy == 0 && shx > 0 && shy < 0) { + rotation = 270; + } else if (sx < 0 && sy < 0 && shx == 0 && shy == 0) { + rotation = 180; + } else if (sx == 0 && sy == 0 && shx < 0 && shy > 0) { + rotation = 90; + } else { + rotation = 0; + } + return rotation; + } + + /** {@inheritDoc} */ + public Object clone() { + AbstractData data = instantiate(); + data.color = this.color; + data.backColor = this.backColor; + data.fontName = this.fontName; + data.fontSize = this.fontSize; + data.lineWidth = this.lineWidth; + data.dashArray = this.dashArray; + data.transform = new AffineTransform(this.transform); + return data; + } + + /** {@inheritDoc} */ + public String toString() { + return "color=" + color + + ", backColor=" + backColor + + ", fontName=" + fontName + + ", fontSize=" + fontSize + + ", lineWidth=" + lineWidth + + ", dashArray=" + dashArray + + ", transform=" + transform; + } + +} \ No newline at end of file diff --git a/src/java/org/apache/fop/AbstractState.java b/src/java/org/apache/fop/AbstractState.java index 851c50e76..74719e8f8 100644 --- a/src/java/org/apache/fop/AbstractState.java +++ b/src/java/org/apache/fop/AbstractState.java @@ -23,8 +23,8 @@ import java.awt.Color; import java.awt.geom.AffineTransform; import java.io.Serializable; import java.util.Arrays; -import java.util.Collection; import java.util.Iterator; +import java.util.List; import java.util.Stack; @@ -33,11 +33,13 @@ import java.util.Stack; */ public abstract class AbstractState implements Cloneable, Serializable { + private static final long serialVersionUID = 5998356138437094188L; + /** current state data */ - private AbstractData currentData = null; + private AbstractData data = null; /** the state stack */ - private StateStack stateStack = null; + private StateStack stateStack = new StateStack(); /** * Instantiates a new state data object @@ -59,10 +61,10 @@ public abstract class AbstractState implements Cloneable, Serializable { * @return the currently valid state */ public AbstractData getData() { - if (currentData == null) { - currentData = instantiateData(); + if (data == null) { + data = instantiateData(); } - return currentData; + return data; } /** @@ -212,7 +214,7 @@ public abstract class AbstractState implements Cloneable, Serializable { */ public AffineTransform getTransform() { AffineTransform at = new AffineTransform(); - for (Iterator iter = getStateStack().iterator(); iter.hasNext();) { + for (Iterator iter = stateStack.iterator(); iter.hasNext();) { AbstractData data = (AbstractData)iter.next(); AffineTransform stackTrans = data.getTransform(); at.concatenate(stackTrans); @@ -242,10 +244,10 @@ public abstract class AbstractState implements Cloneable, Serializable { * @return the base transform, or null if the state stack is empty */ public AffineTransform getBaseTransform() { - if (getStateStack().isEmpty()) { + if (stateStack.isEmpty()) { return null; } else { - AbstractData baseData = (AbstractData)getStateStack().get(0); + AbstractData baseData = (AbstractData)stateStack.get(0); return (AffineTransform) baseData.getTransform().clone(); } } @@ -260,12 +262,20 @@ public abstract class AbstractState implements Cloneable, Serializable { } /** - * Resets the current AffineTransform. + * Resets the current AffineTransform to the Base AffineTransform. */ public void resetTransform() { - getData().resetTransform(); + getData().setTransform(getBaseTransform()); + } + + /** + * Clears the current AffineTransform to the Identity AffineTransform + */ + public void clearTransform() { + getData().clearTransform(); } + /** * Push the current state onto the stack. * This call should be used when the Q operator is used @@ -273,7 +283,7 @@ public abstract class AbstractState implements Cloneable, Serializable { */ public void push() { AbstractData copy = (AbstractData)getData().clone(); - getStateStack().push(copy); + stateStack.push(copy); } /** @@ -284,20 +294,62 @@ public abstract class AbstractState implements Cloneable, Serializable { * @return the restored state, null if the stack is empty */ public AbstractData pop() { - if (!getStateStack().isEmpty()) { - this.currentData = (AbstractData)getStateStack().pop(); - return this.currentData; + if (!stateStack.isEmpty()) { + setData((AbstractData)stateStack.pop()); + return this.data; } else { return null; } } + /** + * Pushes all state data in the given list to the stack + * + * @param dataList a state data list + */ + public void pushAll(List/**/ dataList) { + Iterator it = dataList.iterator(); + while (it.hasNext()) { + // save current data on stack + push(); + setData((AbstractData)it.next()); + } + } + + /** + * Pops all state data from the stack + * + * @return a list of state data popped from the stack + */ + public List/**/ popAll() { + List/**/ dataList = new java.util.ArrayList/**/(); + AbstractData data; + while (true) { + data = getData(); + if (pop() == null) { + break; + } + // insert because of stack-popping + dataList.add(0, data); + } + return dataList; + } + + /** + * Sets the current state data + * + * @param currentData state data + */ + protected void setData(AbstractData data) { + this.data = data; + } + /** * Clears the state stack */ public void clear() { - getStateStack().clear(); - currentData = null; + stateStack.clear(); + setData(null); } /** @@ -306,160 +358,20 @@ public abstract class AbstractState implements Cloneable, Serializable { * @return the state stack */ protected Stack/**/ getStateStack() { - if (stateStack == null) { - stateStack = new StateStack(); - } - return stateStack; + return this.stateStack; } /** {@inheritDoc} */ public Object clone() { AbstractState state = instantiateState(); state.stateStack = new StateStack(this.stateStack); - state.currentData = (AbstractData)this.currentData.clone(); + state.data = (AbstractData)this.data.clone(); return state; } /** {@inheritDoc} */ public String toString() { return ", stateStack=" + stateStack - + ", currentData=" + currentData; - } - - /** - * A base state data holding object - */ - public abstract class AbstractData implements Cloneable, Serializable { - - private static final long serialVersionUID = 5208418041189828624L; - - /** The current color */ - private Color color = null; - - /** The current background color */ - private Color backColor = null; - - /** The current font name */ - private String fontName = null; - - /** The current font size */ - private int fontSize = 0; - - /** The current line width */ - private float lineWidth = 0; - - /** The dash array for the current basic stroke (line type) */ - private float[] dashArray = null; - - /** The current transform */ - private AffineTransform transform = null; - - /** - * Concatenate the given AffineTransform with the current thus creating - * a new viewport. Note that all concatenation operations are logged - * so they can be replayed if necessary (ex. for block-containers with - * "fixed" positioning. - * - * @param at Transformation to perform - */ - public void concatenate(AffineTransform at) { - getTransform().concatenate(at); - } - - /** - * Get the current AffineTransform. - * - * @return the current transform - */ - public AffineTransform getTransform() { - if (transform == null) { - transform = new AffineTransform(); - } - return transform; - } - - /** - * Resets the current AffineTransform. - */ - public void resetTransform() { - transform = getBaseTransform(); -// transform = new AffineTransform(); - } - - /** - * Returns the derived rotation from the current transform - * - * @return the derived rotation from the current transform - */ - public int getDerivedRotation() { - AffineTransform at = getTransform(); - double sx = at.getScaleX(); - double sy = at.getScaleY(); - double shx = at.getShearX(); - double shy = at.getShearY(); - int rotation = 0; - if (sx == 0 && sy == 0 && shx > 0 && shy < 0) { - rotation = 270; - } else if (sx < 0 && sy < 0 && shx == 0 && shy == 0) { - rotation = 180; - } else if (sx == 0 && sy == 0 && shx < 0 && shy > 0) { - rotation = 90; - } else { - rotation = 0; - } - return rotation; - } - - /** {@inheritDoc} */ - public Object clone() { - AbstractData data = instantiateData(); - data.color = this.color; - data.backColor = this.backColor; - data.fontName = this.fontName; - data.fontSize = this.fontSize; - data.lineWidth = this.lineWidth; - data.dashArray = this.dashArray; - data.transform = new AffineTransform(this.transform); - return data; - } - - /** {@inheritDoc} */ - public String toString() { - return "color=" + color - + ", backColor=" + backColor - + ", fontName=" + fontName - + ", fontSize=" + fontSize - + ", lineWidth=" + lineWidth - + ", dashArray=" + dashArray - + ", transform=" + transform; - } - } - - /** - * No copy constructor for java.util.Stack so extended and implemented one. - */ - private class StateStack extends java.util.Stack { - - private static final long serialVersionUID = 4897178211223823041L; - - /** - * Default constructor - */ - public StateStack() { - super(); - } - - /** - * Copy constructor - * - * @param c initial contents of stack - */ - public StateStack(Collection c) { - elementCount = c.size(); - // 10% for growth - elementData = new Object[ - (int)Math.min((elementCount * 110L) / 100, Integer.MAX_VALUE)]; - c.toArray(elementData); - } + + ", currentData=" + data; } } diff --git a/src/java/org/apache/fop/StateStack.java b/src/java/org/apache/fop/StateStack.java new file mode 100644 index 000000000..0c73b4829 --- /dev/null +++ b/src/java/org/apache/fop/StateStack.java @@ -0,0 +1,31 @@ +package org.apache.fop; + +import java.util.Collection; + +/** + * No copy constructor for java.util.Stack so extended and implemented one. + */ +class StateStack extends java.util.Stack { + + private static final long serialVersionUID = 4897178211223823041L; + + /** + * Default constructor + */ + public StateStack() { + super(); + } + + /** + * Copy constructor + * + * @param c initial contents of stack + */ + public StateStack(Collection c) { + elementCount = c.size(); + // 10% for growth + elementData = new Object[ + (int)Math.min((elementCount * 110L) / 100, Integer.MAX_VALUE)]; + c.toArray(elementData); + } +} \ No newline at end of file diff --git a/src/java/org/apache/fop/afp/AFPState.java b/src/java/org/apache/fop/afp/AFPState.java index 9de3a0c05..7e63ea01e 100644 --- a/src/java/org/apache/fop/afp/AFPState.java +++ b/src/java/org/apache/fop/afp/AFPState.java @@ -21,6 +21,7 @@ package org.apache.fop.afp; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.AbstractData; import org.apache.fop.AbstractState; /** @@ -483,7 +484,7 @@ public class AFPState extends org.apache.fop.AbstractState implements Cloneable /** * Block level state data */ - private class AFPData extends org.apache.fop.AbstractState.AbstractData { + private class AFPData extends org.apache.fop.AbstractData { private static final long serialVersionUID = -1789481244175275686L; /** The current fill status */ @@ -506,6 +507,11 @@ public class AFPState extends org.apache.fop.AbstractState implements Cloneable + ", imageUri=" + imageUri + "}"; } + + /** {@inheritDoc} */ + protected AbstractData instantiate() { + return new AFPData(); + } } } \ No newline at end of file diff --git a/src/java/org/apache/fop/pdf/PDFState.java b/src/java/org/apache/fop/pdf/PDFState.java index 138458552..3804c189a 100644 --- a/src/java/org/apache/fop/pdf/PDFState.java +++ b/src/java/org/apache/fop/pdf/PDFState.java @@ -19,12 +19,13 @@ package org.apache.fop.pdf; -import java.util.Iterator; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.Area; import java.awt.geom.GeneralPath; +import java.util.Iterator; +import org.apache.fop.AbstractData; import org.apache.fop.AbstractState; /** @@ -165,7 +166,19 @@ public class PDFState extends org.apache.fop.AbstractState { return new PDFState(); } - private class PDFData extends org.apache.fop.AbstractState.AbstractData { + /** + * Push the current state onto the stack. + * This call should be used when the q operator is used + * so that the state is known when popped. + */ + public void push() { + AbstractData data = getData(); + AbstractData copy = (AbstractData)data.clone(); + data.clearTransform(); + getStateStack().add(copy); + } + + private class PDFData extends org.apache.fop.AbstractData { private static final long serialVersionUID = 3527950647293177764L; @@ -206,6 +219,11 @@ public class PDFState extends org.apache.fop.AbstractState { + ", clip=" + clip + ", gstate=" + gstate; } + + /** {@inheritDoc} */ + protected AbstractData instantiate() { + return new PDFData(); + } } } diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index 0496cf740..e74a8f319 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -486,14 +486,14 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { CTM ctm = bv.getCTM(); int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); - if (bv.getPositioning() == Block.ABSOLUTE - || bv.getPositioning() == Block.FIXED) { + int positioning = bv.getPositioning(); + if (positioning == Block.ABSOLUTE || positioning == Block.FIXED) { //For FIXED, we need to break out of the current viewports to the //one established by the page. We save the state stack for restoration //after the block-container has been painted. See below. List breakOutList = null; - if (bv.getPositioning() == Block.FIXED) { + if (positioning == Block.FIXED) { breakOutList = breakOutOfStateStack(); } @@ -564,8 +564,11 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { restoreGraphicsState(); } - if (breakOutList != null) { - restoreStateStackAfterBreakOut(breakOutList); + //For FIXED, we need to restore break out now we are done + if (positioning == Block.FIXED) { + if (breakOutList != null) { + restoreStateStackAfterBreakOut(breakOutList); + } } currentIPPosition = saveIP; diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index d0737ed70..03945dfee 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -169,7 +169,6 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { private AFPRectanglePainter rectanglePainter; - /** * Constructor for AFPRenderer. */ @@ -509,28 +508,13 @@ public class AFPRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ public void restoreStateStackAfterBreakOut(List breakOutList) { log.debug("Block.FIXED --> restoring context after break-out"); - AbstractState.AbstractData data; - Iterator it = breakOutList.iterator(); - while (it.hasNext()) { - data = (AbstractState.AbstractData)it.next(); - saveGraphicsState(); - concatenateTransformationMatrix(data.getTransform()); - } + state.pushAll(breakOutList); } /** {@inheritDoc} */ protected List breakOutOfStateStack() { log.debug("Block.FIXED --> break out"); - List breakOutList = new java.util.ArrayList(); - AbstractState.AbstractData data; - while (true) { - data = state.getData(); - if (state.pop() == null) { - break; - } - breakOutList.add(0, data); //Insert because of stack-popping - } - return breakOutList; + return state.popAll(); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index cc1caea03..9f60d3c86 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -40,17 +40,7 @@ import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.IOUtils; - -import org.apache.xmlgraphics.image.loader.ImageException; -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageManager; -import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.image.loader.util.ImageUtil; -import org.apache.xmlgraphics.xmp.Metadata; -import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; -import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; - -import org.apache.fop.AbstractState; +import org.apache.fop.AbstractData; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; @@ -118,6 +108,14 @@ import org.apache.fop.render.RendererContext; import org.apache.fop.util.CharUtilities; import org.apache.fop.util.ColorProfileUtil; import org.apache.fop.util.ColorUtil; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; +import org.apache.xmlgraphics.xmp.Metadata; +import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; +import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; /** * Renderer that renders areas to PDF. @@ -263,7 +261,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { protected Map filterMap; /** Image handler registry */ - private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry(); + private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry(); /** * create the PDF renderer @@ -1095,8 +1093,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { * @return the saved state stack to recreate later */ protected List breakOutOfStateStack() { +// return currentState.popAll(); List breakOutList = new java.util.ArrayList(); - AbstractState.AbstractData data; + AbstractData data; while (true) { data = currentState.getData(); if (currentState.pop() == null) { @@ -1117,10 +1116,11 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { */ protected void restoreStateStackAfterBreakOut(List breakOutList) { comment("------ restoring context after break-out..."); - AbstractState.AbstractData data; +// currentState.pushAll(breakOutList); + AbstractData data; Iterator i = breakOutList.iterator(); while (i.hasNext()) { - data = (AbstractState.AbstractData)i.next(); + data = (AbstractData)i.next(); saveGraphicsState(); AffineTransform at = data.getTransform(); concatenateTransformationMatrix(at); @@ -1609,7 +1609,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { endTextObject(); putImage(url, pos, foreignAttributes); } - + /** * Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced. * @param uri URL of the bitmap -- 2.39.5