git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@709373 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -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; | |||
} | |||
} |
@@ -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/*<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); | |||
} | |||
/** | |||
@@ -306,160 +358,20 @@ public abstract class AbstractState implements Cloneable, Serializable { | |||
* @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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; |
@@ -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} */ |
@@ -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 |