aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorAdrian Cumiskey <acumiskey@apache.org>2008-10-31 09:58:46 +0000
committerAdrian Cumiskey <acumiskey@apache.org>2008-10-31 09:58:46 +0000
commitc550e0349a64c0c66d6cee0f2e6f1baa97e14ad2 (patch)
tree8fedc37f8646c29c40c78fff8ee627e3ba46e4be /src/java
parent6ba537ec897da9120a6105d6f4c5fc6aa48e7658 (diff)
downloadxmlgraphics-fop-c550e0349a64c0c66d6cee0f2e6f1baa97e14ad2.tar.gz
xmlgraphics-fop-c550e0349a64c0c66d6cee0f2e6f1baa97e14ad2.zip
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
Diffstat (limited to 'src/java')
-rw-r--r--src/java/org/apache/fop/AbstractData.java128
-rw-r--r--src/java/org/apache/fop/AbstractState.java232
-rw-r--r--src/java/org/apache/fop/StateStack.java31
-rw-r--r--src/java/org/apache/fop/afp/AFPState.java8
-rw-r--r--src/java/org/apache/fop/pdf/PDFState.java22
-rw-r--r--src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java13
-rw-r--r--src/java/org/apache/fop/render/afp/AFPRenderer.java20
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java32
8 files changed, 284 insertions, 202 deletions
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/*<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;
}
}
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