]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Extended PageViewport to carry foreign attributes.
authorJeremias Maerki <jeremias@apache.org>
Thu, 18 May 2006 12:44:15 +0000 (12:44 +0000)
committerJeremias Maerki <jeremias@apache.org>
Thu, 18 May 2006 12:44:15 +0000 (12:44 +0000)
Foreign attributes from simple-page-master are transferred to the PageViewport.
Added foreign attributes handling in AreaTreeParser.
Fixed proper generation of foreign attributes in XMLRenderer.
EvalCheck extended so it can use namespace prefix mappings in its context.
Test case for foreign attributes.

Paper source/tray support for PCL (pcl:paper-source="<tray-code>" on s-p-m)

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@407541 13f79535-47bb-0310-9956-ffa450edef68

13 files changed:
src/java/org/apache/fop/area/Area.java
src/java/org/apache/fop/area/AreaTreeObject.java [new file with mode: 0644]
src/java/org/apache/fop/area/AreaTreeParser.java
src/java/org/apache/fop/area/Page.java
src/java/org/apache/fop/area/PageViewport.java
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
src/java/org/apache/fop/render/xml/XMLRenderer.java
src/java/org/apache/fop/util/QName.java
src/sandbox/META-INF/services/org.apache.fop.fo.ElementMapping
src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java
src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java
test/java/org/apache/fop/layoutengine/EvalCheck.java
test/layoutengine/standard-testcases/foreign-attributes.xml [new file with mode: 0644]

index 6ac01420839c9be23b593992327e38037e0ce991..ab2136ac34be2be0c9b1e6f502e2d70ef720bed8 100644 (file)
 package org.apache.fop.area;
 
 import java.io.Serializable;
-
-import java.util.Collections;
-import java.util.Iterator;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fop.traits.BorderProps;
-import org.apache.fop.util.QName;
 
 // If the area appears more than once in the output
 // or if the area has external data it is cached
@@ -40,7 +36,7 @@ import org.apache.fop.util.QName;
 /**
  * Base object for all areas.
  */
-public class Area implements Serializable {
+public class Area extends AreaTreeObject implements Serializable {
     // stacking directions
     /**
      * Stacking left to right
@@ -132,9 +128,6 @@ public class Area implements Serializable {
      */
     protected Map props = null;
 
-    /** Foreign attributes */
-    protected Map foreignAttributes = null;
-    
     /**
      * logging instance
      */
@@ -462,57 +455,6 @@ public class Area implements Serializable {
         }
     }
     
-    /**
-     * Sets a foreign attribute.
-     * @param name the qualified name of the attribute
-     * @param value the attribute value
-     */
-    public void setForeignAttribute(QName name, String value) {
-        if (this.foreignAttributes == null) {
-            this.foreignAttributes = new java.util.HashMap();
-        }
-        this.foreignAttributes.put(name, value);
-    }
-    
-    /**
-     * Set foreign attributes from a Map.
-     * @param atts a Map with attributes (keys: QName, values: String)
-     */
-    public void setForeignAttributes(Map atts) {
-        if (atts.size() == 0) {
-            return;
-        }
-        Iterator iter = atts.keySet().iterator();
-        while (iter.hasNext()) {
-            QName qName = (QName)iter.next();
-            String value = (String)atts.get(qName);
-            //The casting is only to ensure type safety (too bad we can't use generics, yet) 
-            setForeignAttribute(qName, value);
-        }
-    }
-    
-    /**
-     * Returns the value of a foreign attribute on the area.
-     * @param name the qualified name of the attribute
-     * @return the attribute value or null if it isn't set
-     */
-    public String getForeignAttributeValue(QName name) {
-        if (this.foreignAttributes != null) {
-            return (String)this.foreignAttributes.get(name);
-        } else {
-            return null;
-        }
-    }
-    
-    /** @return the foreign attributes associated with this area */
-    public Map getForeignAttributes() {
-        if (this.foreignAttributes != null) {
-            return Collections.unmodifiableMap(this.foreignAttributes);
-        } else {
-            return Collections.EMPTY_MAP;
-        }
-    }
-    
     /** @see java.lang.Object#toString() */
     public String toString() {
         StringBuffer sb = new StringBuffer(super.toString());
diff --git a/src/java/org/apache/fop/area/AreaTreeObject.java b/src/java/org/apache/fop/area/AreaTreeObject.java
new file mode 100644 (file)
index 0000000..f8aed7a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.fop.util.QName;
+
+/**
+ * Abstract base class for all area tree objects.
+ */
+public abstract class AreaTreeObject {
+
+    /** Foreign attributes */
+    protected Map foreignAttributes = null;
+    
+    /**
+     * Sets a foreign attribute.
+     * @param name the qualified name of the attribute
+     * @param value the attribute value
+     */
+    public void setForeignAttribute(QName name, String value) {
+        if (this.foreignAttributes == null) {
+            this.foreignAttributes = new java.util.HashMap();
+        }
+        this.foreignAttributes.put(name, value);
+    }
+    
+    /**
+     * Set foreign attributes from a Map.
+     * @param atts a Map with attributes (keys: QName, values: String)
+     */
+    public void setForeignAttributes(Map atts) {
+        if (atts.size() == 0) {
+            return;
+        }
+        Iterator iter = atts.keySet().iterator();
+        while (iter.hasNext()) {
+            QName qName = (QName)iter.next();
+            String value = (String)atts.get(qName);
+            //The casting is only to ensure type safety (too bad we can't use generics, yet) 
+            setForeignAttribute(qName, value);
+        }
+    }
+    
+    /**
+     * Returns the value of a foreign attribute on the area.
+     * @param name the qualified name of the attribute
+     * @return the attribute value or null if it isn't set
+     */
+    public String getForeignAttributeValue(QName name) {
+        if (this.foreignAttributes != null) {
+            return (String)this.foreignAttributes.get(name);
+        } else {
+            return null;
+        }
+    }
+    
+    /** @return the foreign attributes associated with this area */
+    public Map getForeignAttributes() {
+        if (this.foreignAttributes != null) {
+            return Collections.unmodifiableMap(this.foreignAttributes);
+        } else {
+            return Collections.EMPTY_MAP;
+        }
+    }
+    
+    
+}
index a7f0812e3d472cf540e42609f5351a684edd4e5b..e0c27465568ce669234405a1dc877245a173eec5 100644 (file)
@@ -63,6 +63,7 @@ import org.apache.fop.util.ColorUtil;
 import org.apache.fop.util.ContentHandlerFactory;
 import org.apache.fop.util.ContentHandlerFactoryRegistry;
 import org.apache.fop.util.DefaultErrorListener;
+import org.apache.fop.util.QName;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
 import org.xml.sax.Attributes;
@@ -336,6 +337,7 @@ public class AreaTreeParser {
 
             public void startElement(Attributes attributes) {
                 LineArea line = new LineArea();
+                transferForeignObjects(attributes, line);
                 areaStack.push(line);
             }
 
@@ -367,6 +369,7 @@ public class AreaTreeParser {
                 currentPageViewport = new PageViewport(viewArea, 
                         pageNumber, pageNumberString,
                         pageMaster, blank);
+                transferForeignObjects(attributes, currentPageViewport);
                 currentPageViewport.setKey(key);
             }
 
@@ -394,6 +397,7 @@ public class AreaTreeParser {
                 }
                 Rectangle2D viewArea = parseRect(attributes.getValue("rect"));
                 rv = new RegionViewport(viewArea);
+                transferForeignObjects(attributes, rv);
                 rv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
                 setAreaAttributes(attributes, rv);
                 setTraits(attributes, rv, SUBSET_COMMON);
@@ -464,6 +468,7 @@ public class AreaTreeParser {
                 RegionViewport rv = getCurrentRegionViewport();
                 body = new BodyRegion(Constants.FO_REGION_BODY, 
                         regionName, rv, columnCount, columnGap);
+                transferForeignObjects(attributes, body);
                 body.setCTM(getAttributeAsCTM(attributes, "ctm"));
                 setAreaAttributes(attributes, body);
                 rv.setRegionReference(body);
@@ -487,6 +492,7 @@ public class AreaTreeParser {
                     firstFlow = false;
                 }
                 NormalFlow flow = body.getMainReference().getCurrentSpan().getCurrentFlow();
+                transferForeignObjects(attributes, flow);
                 setAreaAttributes(attributes, flow);
                 areaStack.push(flow);
             }
@@ -500,7 +506,9 @@ public class AreaTreeParser {
 
             public void startElement(Attributes attributes) {
                 //mainReference is created by the BodyRegion
-                setAreaAttributes(attributes, getCurrentBodyRegion().getMainReference());
+                MainReference mr = getCurrentBodyRegion().getMainReference();
+                transferForeignObjects(attributes, mr);
+                setAreaAttributes(attributes, mr);
             }
         }
 
@@ -512,6 +520,7 @@ public class AreaTreeParser {
                 BodyRegion body = getCurrentBodyRegion();
                 Span span = new Span(columnCount, 
                         body.getColumnGap(), ipd);
+                transferForeignObjects(attributes, span);
                 setAreaAttributes(attributes, span);
                 body.getMainReference().getSpans().add(span);
                 firstFlow = true;
@@ -521,7 +530,9 @@ public class AreaTreeParser {
         private class FootnoteMaker extends AbstractMaker {
 
             public void startElement(Attributes attributes) {
-                areaStack.push(getCurrentBodyRegion().getFootnote());
+                Footnote fn = getCurrentBodyRegion().getFootnote();
+                transferForeignObjects(attributes, fn);
+                areaStack.push(fn);
             }
             
             public void endElement() {
@@ -532,7 +543,9 @@ public class AreaTreeParser {
         private class BeforeFloatMaker extends AbstractMaker {
 
             public void startElement(Attributes attributes) {
-                areaStack.push(getCurrentBodyRegion().getBeforeFloat());
+                BeforeFloat bf = getCurrentBodyRegion().getBeforeFloat(); 
+                transferForeignObjects(attributes, bf);
+                areaStack.push(bf);
             }
             
             public void endElement() {
@@ -576,6 +589,7 @@ public class AreaTreeParser {
                 if (attributes.getValue("top-offset") != null) {
                     block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0));
                 }
+                transferForeignObjects(attributes, block);
                 setAreaAttributes(attributes, block);
                 setTraits(attributes, block, SUBSET_COMMON);
                 setTraits(attributes, block, SUBSET_BOX);
@@ -613,6 +627,7 @@ public class AreaTreeParser {
 
             public void startElement(Attributes attributes) {
                 InlineParent ip = new InlineParent();
+                transferForeignObjects(attributes, ip);
                 ip.setOffset(getAttributeAsInteger(attributes, "offset", 0));
                 setAreaAttributes(attributes, ip);
                 setTraits(attributes, ip, SUBSET_COMMON);
@@ -633,6 +648,7 @@ public class AreaTreeParser {
 
             public void startElement(Attributes attributes) {
                 InlineBlockParent ibp = new InlineBlockParent();
+                transferForeignObjects(attributes, ibp);
                 ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0));
                 setAreaAttributes(attributes, ibp);
                 setTraits(attributes, ibp, SUBSET_COMMON);
@@ -735,6 +751,7 @@ public class AreaTreeParser {
             public void endElement() {
                 String txt = content.toString();
                 Character ch = new Character(txt.charAt(0));
+                transferForeignObjects(lastAttributes, ch);
                 setAreaAttributes(lastAttributes, ch);
                 setTraits(lastAttributes, ch, SUBSET_COMMON);
                 setTraits(lastAttributes, ch, SUBSET_BOX);
@@ -751,6 +768,7 @@ public class AreaTreeParser {
 
             public void startElement(Attributes attributes) {
                 Leader leader = new Leader();
+                transferForeignObjects(attributes, leader);
                 setAreaAttributes(attributes, leader);
                 setTraits(attributes, leader, SUBSET_COMMON);
                 setTraits(attributes, leader, SUBSET_BOX);
@@ -775,6 +793,7 @@ public class AreaTreeParser {
 
             public void startElement(Attributes attributes) {
                 Viewport viewport = new Viewport(null);
+                transferForeignObjects(attributes, viewport);
                 setAreaAttributes(attributes, viewport);
                 setTraits(attributes, viewport, SUBSET_COMMON);
                 setTraits(attributes, viewport, SUBSET_BOX);
@@ -797,6 +816,7 @@ public class AreaTreeParser {
             public void startElement(Attributes attributes) {
                 String url = attributes.getValue("url");
                 Image image = new Image(url);
+                transferForeignObjects(attributes, image);
                 setAreaAttributes(attributes, image);
                 setTraits(attributes, image, SUBSET_COMMON);
                 getCurrentViewport().setContent(image);
@@ -814,6 +834,7 @@ public class AreaTreeParser {
                             + " identified to handle namespace: " + ns);
                 }
                 ForeignObject foreign = new ForeignObject(ns);
+                transferForeignObjects(attributes, foreign);
                 setAreaAttributes(attributes, foreign);
                 setTraits(attributes, foreign, SUBSET_COMMON);
                 getCurrentViewport().setContent(foreign);
@@ -825,17 +846,6 @@ public class AreaTreeParser {
             }            
         }
 
-        /*
-        private class ?Maker extends AbstractMaker {
-
-            public void startElement(Attributes attributes) {
-            }
-            
-            public void endElement() {
-            }            
-        }
-        */
-        
         // ====================================================================
         
 
@@ -844,6 +854,7 @@ public class AreaTreeParser {
             RegionViewport rv = getCurrentRegionViewport();
             RegionReference reg = new RegionReference(side, 
                     regionName, rv);
+            transferForeignObjects(attributes, reg);
             reg.setCTM(getAttributeAsCTM(attributes, "ctm"));
             setAreaAttributes(attributes, reg);
             rv.setRegionReference(reg);
@@ -1024,6 +1035,19 @@ public class AreaTreeParser {
             return new Rectangle2D.Double(values[0], values[1], values[2], values[3]);
         }
 
+        private void transferForeignObjects(Attributes atts, AreaTreeObject ato) {
+            for (int i = 0, c = atts.getLength(); i < c; i++) {
+                String ns = atts.getURI(i);
+                if (ns.length() > 0) {
+                    if ("http://www.w3.org/2000/xmlns/".equals(ns)) {
+                        continue;
+                    }
+                    QName qname = new QName(ns, atts.getQName(i));
+                    ato.setForeignAttribute(qname, atts.getValue(i));
+                }
+            }
+        }
+        
         /** @see org.xml.sax.ContentHandler#characters(char[], int, int) */
         public void characters(char[] ch, int start, int length) throws SAXException {
             if (delegate != null) {
index a0ad2e8777252f05084481ed6e391e3b6dfa3dde..fba37f506fb8b52163e8a30ffbf8572e8bc0504f 100644 (file)
@@ -45,7 +45,7 @@ import org.apache.fop.layoutmgr.TraitSetter;
  * The page is cloneable so the page master can make copies of
  * the top level page and regions.
  */
-public class Page implements Serializable, Cloneable {
+public class Page extends AreaTreeObject implements Serializable, Cloneable {
     // contains before, start, body, end and after regions
     private RegionViewport regionBefore = null;
     private RegionViewport regionStart = null;
index c4cbc768e51f534c950f2292f5c6cc4ce4455493..e2986855ace5b903067aa04c7a0e7acf9778f19c 100644 (file)
@@ -43,7 +43,7 @@ import org.apache.fop.fo.pagination.SimplePageMaster;
  * This is the level that creates the page.
  * The page (reference area) is then rendered inside the page object
  */
-public class PageViewport implements Resolvable, Cloneable {
+public class PageViewport extends AreaTreeObject implements Resolvable, Cloneable {
 
     private Page page;
     private Rectangle2D viewArea;
index 70a00bf6b76d64ce7803efdcad1c2bd5cc9cebbf..0fcb27b321dc80254cabecf54285464e072e5043 100644 (file)
@@ -1060,6 +1060,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
                 Page page = new Page(spm, index, pageNumberString, isBlank);
                 //Set unique key obtained from the AreaTreeHandler
                 page.getPageViewport().setKey(areaTreeHandler.generatePageViewportKey());
+                page.getPageViewport().setForeignAttributes(spm.getForeignAttributes());
                 cachedPages.add(page);
                 return page;
             } catch (FOPException e) {
index 00528bdc8c1f780fd5a56876db4b73f3e1486c29..b14f921989cd185b10a0559de8a641b12225cff8 100644 (file)
@@ -47,6 +47,7 @@ import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.area.Area;
+import org.apache.fop.area.AreaTreeObject;
 import org.apache.fop.area.BeforeFloat;
 import org.apache.fop.area.Block;
 import org.apache.fop.area.BlockViewport;
@@ -393,11 +394,25 @@ public class XMLRenderer extends PrintRenderer {
             }
         }
         
-        //Transfer foreign attributes
-        Iterator iter = area.getForeignAttributes().entrySet().iterator();
+        transferForeignObjects(area);
+    }
+
+    private void transferForeignObjects(AreaTreeObject ato) {
+        Map prefixes = new java.util.HashMap();
+        Iterator iter = ato.getForeignAttributes().entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry entry = (Map.Entry)iter.next();
+            QName qname = (QName)entry.getKey();
+            prefixes.put(qname.getPrefix(), qname.getNamespaceURI());
+            addAttribute(qname, (String)entry.getValue());
+        }
+        //Namespace declarations
+        iter = prefixes.entrySet().iterator();
         while (iter.hasNext()) {
             Map.Entry entry = (Map.Entry)iter.next();
-            addAttribute((QName)entry.getKey(), (String)entry.getValue());
+            String qn = "xmlns:" + (String)entry.getKey();
+            atts.addAttribute("", (String)entry.getKey(), qn, 
+                    CDATA, (String)entry.getValue());
         }
     }
 
@@ -492,6 +507,7 @@ public class XMLRenderer extends PrintRenderer {
         if (page.isBlank()) {
             addAttribute("blank", "true");
         }
+        transferForeignObjects(page);
         startElement("pageViewport", atts);
         startElement("page");
 
index ccfe0563848b2f0342cbb369389767d3ef655f09..91c9ab8127ae16581cb0c4c88b81eeb8e75665bb 100644 (file)
@@ -54,6 +54,30 @@ public class QName implements Serializable {
         this.hashCode = toHashString().hashCode();
     }
     
+    /**
+     * Main constructor.
+     * @param namespaceURI the namespace URI
+     * @param qName the qualified name
+     */
+    public QName(String namespaceURI, String qName) {
+        if (qName == null) {
+            throw new NullPointerException("Parameter localName must not be null");
+        }
+        if (qName.length() == 0) {
+            throw new IllegalArgumentException("Parameter localName must not be empty");
+        }
+        this.namespaceURI = namespaceURI;
+        int p = qName.indexOf(':');
+        if (p > 0) {
+            this.prefix = qName.substring(0, p);
+            this.localName = qName.substring(p + 1);
+        } else {
+            this.prefix = null;
+            this.localName = qName;
+        }
+        this.hashCode = toHashString().hashCode();
+    }
+    
     /** @return the namespace URI */
     public String getNamespaceURI() {
         return this.namespaceURI;
index d38bb6677d3f5b6115ac434c21c13d3f70e3028f..e64d0db596d4e81b9d7db05c5599b3c5f007473c 100644 (file)
@@ -1 +1,2 @@
-org.apache.fop.render.afp.extensions.AFPElementMapping
\ No newline at end of file
+org.apache.fop.render.afp.extensions.AFPElementMapping\r
+org.apache.fop.render.pcl.extensions.PCLElementMapping
\ No newline at end of file
index f8e1b09c40af4266c3f7d23d28931fa1031f6245..979644c86efc617a170c0a0786d5e23dddc0f09e 100644 (file)
@@ -200,6 +200,18 @@ public class PCLGenerator {
         writeCommand("&l" + selector + "A");
     }
 
+    /**
+     * Selects the paper source. The parameter is usually printer-specific. Usually, "1" is the 
+     * default tray, "2" is the manual paper feed, "3" is the manual envelope feed, "4" is the
+     * "lower" tray and "7" is "auto-select". Consult the technical reference for your printer
+     * for all available values.
+     * @param selector the integer representing the paper source/tray
+     * @throws IOException In case of an I/O error
+     */
+    public void selectPaperSource(int selector) throws IOException {
+        writeCommand("&l" + selector + "H");
+    }
+
     /**
      * Clears the horizontal margins.
      * @throws IOException In case of an I/O error
index 5bd30e2f845c8670b064334a242c1c0ebbb36cd9..0f3751a6431962b4087b01f7a19439b824a5cf26 100644 (file)
@@ -84,6 +84,7 @@ import org.apache.fop.render.RendererContextConstants;
 import org.apache.fop.render.java2d.FontMetricsMapper;
 import org.apache.fop.render.java2d.FontSetup;
 import org.apache.fop.render.java2d.Java2DRenderer;
+import org.apache.fop.render.pcl.extensions.PCLElementMapping;
 import org.apache.fop.traits.BorderProps;
 import org.apache.fop.util.QName;
 import org.apache.fop.util.UnitConv;
@@ -333,11 +334,22 @@ public class PCLRenderer extends PrintRenderer {
      */
     public void renderPage(PageViewport page) throws IOException, FOPException {
         saveGraphicsState();
+        
+        //Paper source
+        String paperSource = page.getForeignAttributeValue(
+                new QName(PCLElementMapping.NAMESPACE, null, "paper-source"));
+        if (paperSource != null) {
+            gen.selectPaperSource(Integer.parseInt(paperSource));
+        }
+        
+        //Page size
         final long pagewidth = Math.round(page.getViewArea().getWidth());
         final long pageheight = Math.round(page.getViewArea().getHeight());
         selectPageFormat(pagewidth, pageheight);
         
         super.renderPage(page);
+        
+        //Eject page
         gen.formFeed();
         restoreGraphicsState();
     }
index be71e50fbb90cf5cc5af17d17d55050af0ea5800..0b3d98afbfd26987e809842bb37c1a5dc28dfd06 100644 (file)
@@ -20,6 +20,8 @@ package org.apache.fop.layoutengine;
 
 import javax.xml.transform.TransformerException;
 
+import org.apache.xml.utils.PrefixResolver;
+import org.apache.xml.utils.PrefixResolverDefault;
 import org.apache.xpath.XPathAPI;
 import org.apache.xpath.objects.XObject;
 import org.w3c.dom.Node;
@@ -31,6 +33,7 @@ public class EvalCheck implements LayoutEngineCheck {
 
     private String expected;
     private String xpath;
+    private PrefixResolver prefixResolver;
     
     /**
      * Creates a new instance
@@ -49,13 +52,14 @@ public class EvalCheck implements LayoutEngineCheck {
     public EvalCheck(Node node) {
         this.expected = node.getAttributes().getNamedItem("expected").getNodeValue();
         this.xpath = node.getAttributes().getNamedItem("xpath").getNodeValue();
+        this.prefixResolver = new PrefixResolverDefault(node);
     }
     
     /** @see org.apache.fop.layoutengine.LayoutEngineCheck */
     public void check(LayoutResult result) {
         XObject res;
         try {
-            res = XPathAPI.eval(result.getAreaTree(), xpath);
+            res = XPathAPI.eval(result.getAreaTree(), xpath, prefixResolver);
         } catch (TransformerException e) {
             throw new RuntimeException("XPath evaluation failed: " + e.getMessage());
         }
@@ -72,5 +76,13 @@ public class EvalCheck implements LayoutEngineCheck {
     public String toString() {
         return "XPath: " + xpath;
     }
+
+    private class MyPrefixResolver extends PrefixResolverDefault {
+        
+        public MyPrefixResolver(Node xpathExpressionContext) {
+            super(xpathExpressionContext);
+        }
+        
+    }
     
 }
diff --git a/test/layoutengine/standard-testcases/foreign-attributes.xml b/test/layoutengine/standard-testcases/foreign-attributes.xml
new file mode 100644 (file)
index 0000000..4d848fc
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2006 The Apache Software Foundation
+
+  Licensed 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$ -->
+<testcase>
+  <info>
+    <p>
+      This test tests foreign attributes on various elements.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in" fox:foo="bar">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block id="eg">
+            <fo:external-graphic src="../../resources/images/bgimg300dpi.jpg" fox:alt="description"/>
+          </fo:block>
+          <fo:block id="bl">
+            <fo:basic-link external-destination="url(http://xmlgraphics.apache.org/fop/)" fox:blah="fop">FOP</fo:basic-link>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+    <eval expected="bar" xpath="//pageViewport[1]/@fox:foo"/>
+    <eval expected="description" xpath="//block[@prod-id='eg']//image/@fox:alt"/>
+    <!--eval expected="fop" xpath="//block[@prod-id='bl']/inlineparent/@fox:blah"/> NYI -->
+  </checks>
+</testcase>