--- /dev/null
+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
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;
*/
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
* @return the currently valid state
*/
public AbstractData getData() {
- if (currentData == null) {
- currentData = instantiateData();
+ if (data == null) {
+ data = instantiateData();
}
- return currentData;
+ return data;
}
/**
*/
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);
* @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();
}
}
}
/**
- * 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
*/
public void push() {
AbstractData copy = (AbstractData)getData().clone();
- getStateStack().push(copy);
+ stateStack.push(copy);
}
/**
* @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/*<AbstractData>*/ 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/*<AbstractData>*/ popAll() {
+ List/*<AbstractData>*/ dataList = new java.util.ArrayList/*<AbstractData>*/();
+ 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);
}
/**
* @return the state stack
*/
protected Stack/*<AbstractData>*/ 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;
}
}
--- /dev/null
+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
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.AbstractData;
import org.apache.fop.AbstractState;
/**
/**
* 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 */
+ ", imageUri=" + imageUri
+ "}";
}
+
+ /** {@inheritDoc} */
+ protected AbstractData instantiate() {
+ return new AFPData();
+ }
}
}
\ No newline at end of file
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;
/**
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;
+ ", clip=" + clip
+ ", gstate=" + gstate;
}
+
+ /** {@inheritDoc} */
+ protected AbstractData instantiate() {
+ return new PDFData();
+ }
}
}
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();
}
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;
private AFPRectanglePainter rectanglePainter;
-
/**
* Constructor for AFPRenderer.
*/
/** {@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} */
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;
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.
protected Map filterMap;
/** Image handler registry */
- private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
+ private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
/**
* create the PDF renderer
* @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) {
*/
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);
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