diff options
Diffstat (limited to 'src')
26 files changed, 1433 insertions, 252 deletions
diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java new file mode 100644 index 000000000..32e2bce1e --- /dev/null +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -0,0 +1,676 @@ +/* + * 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.awt.geom.Rectangle2D; +import java.util.Stack; +import java.util.StringTokenizer; + +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.area.Trait.Background; +import org.apache.fop.area.Trait.Color; +import org.apache.fop.area.inline.AbstractTextArea; +import org.apache.fop.area.inline.Character; +import org.apache.fop.area.inline.ForeignObject; +import org.apache.fop.area.inline.Image; +import org.apache.fop.area.inline.InlineBlockParent; +import org.apache.fop.area.inline.InlineParent; +import org.apache.fop.area.inline.Leader; +import org.apache.fop.area.inline.Space; +import org.apache.fop.area.inline.SpaceArea; +import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.inline.Viewport; +import org.apache.fop.area.inline.WordArea; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.ElementMappingRegistry; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.image.FopImage; +import org.apache.fop.image.ImageFactory; +import org.apache.fop.traits.BorderProps; +import org.apache.fop.util.DefaultErrorListener; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * This is a parser for the area tree XML (intermediate format) which is used to reread an area + * tree (or part of it) into memory again for rendering to the final output format. + */ +public class AreaTreeParser { + + /** Logger instance */ + protected static Log log = LogFactory.getLog(AreaTreeParser.class); + + private static SAXTransformerFactory tFactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + /** + * Parses an intermediate file (area tree XML) into an AreaTreeModel instance by adding + * pages to it. + * @param src the Source instance pointing to the intermediate file + * @param treeModel the AreaTreeModel that the parsed pages are added to + * @param userAgent the user agent + * @throws TransformerException if an error occurs while parsing the area tree XML + */ + public void parse(Source src, AreaTreeModel treeModel, FOUserAgent userAgent) + throws TransformerException { + Transformer transformer = tFactory.newTransformer(); + transformer.setErrorListener(new DefaultErrorListener(log)); + + SAXResult res = new SAXResult(getContentHandler(treeModel, userAgent)); + + transformer.transform(src, res); + } + + /** + * Creates a new ContentHandler instance that you can send the area tree XML to. The parsed + * pages are added to the AreaTreeModel instance you pass in as a parameter. + * @param treeModel the AreaTreeModel that the parsed pages are added to + * @param userAgent the user agent + * @return the ContentHandler instance to receive the SAX stream from the area tree XML + */ + public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) { + //TODO Retrieve this instance from the environment class once it has been created. + ElementMappingRegistry elementMappingRegistry = new ElementMappingRegistry(userAgent); + return new Handler(treeModel, userAgent, elementMappingRegistry); + } + + private static class Handler extends DefaultHandler { + + private AreaTreeModel treeModel; + private FOUserAgent userAgent; + private ElementMappingRegistry elementMappingRegistry; + + private Attributes lastAttributes; + private StringBuffer content = new StringBuffer(); + + private PageViewport currentPageViewport; + private Stack areaStack = new Stack(); + private boolean firstFlow; + + private Stack delegateStack = new Stack(); + private ContentHandler delegate; + private DOMImplementation domImplementation; + + public Handler(AreaTreeModel treeModel, FOUserAgent userAgent, + ElementMappingRegistry elementMappingRegistry) { + this.treeModel = treeModel; + this.userAgent = userAgent; + this.elementMappingRegistry = elementMappingRegistry; + } + + private static Rectangle2D parseRect(String rect) { + StringTokenizer tokenizer = new StringTokenizer(rect, " "); + return new Rectangle2D.Double( + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken())); + } + + private Area findAreaType(Class clazz) { + if (areaStack.size() > 0) { + int pos = areaStack.size() - 1; + Object obj = null; + while (pos >= 0 && !(clazz.isInstance(obj = areaStack.get(pos)))) { + pos--; + } + if (pos >= 0) { + return (Area)obj; + } + } + return null; + } + + private RegionViewport getCurrentRegionViewport() { + return (RegionViewport)findAreaType(RegionViewport.class); + } + + private BodyRegion getCurrentBodyRegion() { + return (BodyRegion)findAreaType(BodyRegion.class); + } + + private BlockParent getCurrentBlockParent() { + return (BlockParent)findAreaType(BlockParent.class); + } + + private AbstractTextArea getCurrentText() { + return (AbstractTextArea)findAreaType(AbstractTextArea.class); + } + + private Viewport getCurrentViewport() { + return (Viewport)findAreaType(Viewport.class); + } + + /** @see org.xml.sax.helpers.DefaultHandler */ + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (delegate != null) { + delegateStack.push(qName); + delegate.startElement(uri, localName, qName, attributes); + } else if (domImplementation != null) { + TransformerHandler handler; + try { + handler = tFactory.newTransformerHandler(); + } catch (TransformerConfigurationException e) { + throw new SAXException("Error creating a new TransformerHandler", e); + } + Document doc = domImplementation.createDocument(uri, qName, null); + //It's easier to work with an empty document, so remove the root element + doc.removeChild(doc.getDocumentElement()); + handler.setResult(new DOMResult(doc)); + Area parent = (Area)areaStack.peek(); + ((ForeignObject)parent).setDocument(doc); + + //activate delegate for nested foreign document + this.delegate = handler; + delegateStack.push(qName); + delegate.startDocument(); + delegate.startElement(uri, localName, qName, attributes); + } else { + lastAttributes = attributes; + boolean handled = true; + if ("".equals(uri)) { + if ("areaTree".equals(localName)) { + //nop + } else if ("pageSequence".equals(localName)) { + treeModel.startPageSequence(null); + } else if ("pageViewport".equals(localName)) { + if (currentPageViewport != null) { + throw new IllegalStateException("currentPageViewport must be null"); + } + Rectangle2D viewArea = parseRect(attributes.getValue("bounds")); + currentPageViewport = new PageViewport(viewArea, attributes.getValue("nr")); + } else if ("page".equals(localName)) { + Page p = new Page(); + currentPageViewport.setPage(p); + } else if ("regionViewport".equals(localName)) { + RegionViewport rv = getCurrentRegionViewport(); + if (rv != null) { + throw new IllegalStateException("Current RegionViewport must be null"); + } + Rectangle2D viewArea = parseRect(attributes.getValue("rect")); + rv = new RegionViewport(viewArea); + rv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); + setAreaAttributes(attributes, rv); + setTraits(attributes, rv); + areaStack.push(rv); + } else if ("regionBefore".equals(localName)) { + pushNewRegionReference(attributes, Constants.FO_REGION_BEFORE); + } else if ("regionAfter".equals(localName)) { + pushNewRegionReference(attributes, Constants.FO_REGION_AFTER); + } else if ("regionStart".equals(localName)) { + pushNewRegionReference(attributes, Constants.FO_REGION_START); + } else if ("regionEnd".equals(localName)) { + pushNewRegionReference(attributes, Constants.FO_REGION_END); + } else if ("regionBody".equals(localName)) { + BodyRegion body = getCurrentBodyRegion(); + if (body != null) { + throw new IllegalStateException("Current BodyRegion must be null"); + } + String regionName = attributes.getValue("name"); + int columnCount = getAttributeAsInteger(attributes, "columnCount", 1); + int columnGap = getAttributeAsInteger(attributes, "columnGap", 0); + RegionViewport rv = getCurrentRegionViewport(); + body = new BodyRegion(Constants.FO_REGION_BODY, + regionName, rv, columnCount, columnGap); + body.setCTM(getAttributeAsCTM(attributes, "ctm")); + setAreaAttributes(attributes, body); + rv.setRegionReference(body); + currentPageViewport.getPage().setRegionViewport( + Constants.FO_REGION_BODY, rv); + areaStack.push(body); + } else if ("mainReference".equals(localName)) { + //mainReference is created by the BodyRegion + setAreaAttributes(attributes, getCurrentBodyRegion().getMainReference()); + } else if ("span".equals(localName)) { + int ipd = getAttributeAsInteger(attributes, "ipd", 0); + int columnCount = getAttributeAsInteger(attributes, "columnCount", 1); + BodyRegion body = getCurrentBodyRegion(); + Span span = new Span(columnCount, + body.getColumnGap(), ipd); + setAreaAttributes(attributes, span); + body.getMainReference().getSpans().add(span); + firstFlow = true; + } else if ("flow".equals(localName)) { + BodyRegion body = getCurrentBodyRegion(); + if (!firstFlow) { + body.getMainReference().getCurrentSpan().moveToNextFlow(); + } else { + firstFlow = false; + } + NormalFlow flow = body.getMainReference().getCurrentSpan().getCurrentFlow(); + setAreaAttributes(attributes, flow); + areaStack.push(flow); + } else if ("footnote".equals(localName)) { + areaStack.push(getCurrentBodyRegion().getFootnote()); + } else if ("beforeFloat".equals(localName)) { + areaStack.push(getCurrentBodyRegion().getBeforeFloat()); + } else if ("block".equals(localName)) { + boolean isViewport = getAttributeAsBoolean(attributes, + "is-viewport-area", false); + Block block; + if (isViewport) { + BlockViewport bv = new BlockViewport(); + bv.setClip(getAttributeAsBoolean(attributes, "clipped", false)); + bv.setCTM(getAttributeAsCTM(attributes, "ctm")); + if (bv.getPositioning() != BlockViewport.RELATIVE) { + bv.setXOffset( + getAttributeAsInteger(attributes, "left-position", 0)); + bv.setYOffset( + getAttributeAsInteger(attributes, "top-position", 0)); + } + block = bv; + } else { + block = new Block(); + } + String positioning = attributes.getValue("positioning"); + if ("absolute".equalsIgnoreCase(positioning)) { + block.setPositioning(Block.ABSOLUTE); + } else if ("fixed".equalsIgnoreCase(positioning)) { + block.setPositioning(Block.FIXED); + } else if ("relative".equalsIgnoreCase(positioning)) { + block.setPositioning(Block.RELATIVE); + } else { + block.setPositioning(Block.STACK); + } + if (attributes.getValue("left-offset") != null) { + block.setXOffset(getAttributeAsInteger(attributes, "left-offset", 0)); + } + if (attributes.getValue("top-offset") != null) { + block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0)); + } + setAreaAttributes(attributes, block); + setTraits(attributes, block); + Area parent = (Area)areaStack.peek(); + //BlockParent parent = getCurrentBlockParent(); + parent.addChildArea(block); + areaStack.push(block); + } else if ("lineArea".equals(localName)) { + LineArea line = new LineArea(); + setAreaAttributes(attributes, line); + setTraits(attributes, line); + BlockParent parent = getCurrentBlockParent(); + parent.addChildArea(line); + areaStack.push(line); + } else if ("inlineparent".equals(localName)) { + InlineParent ip = new InlineParent(); + ip.setOffset(getAttributeAsInteger(attributes, "offset", 0)); + setAreaAttributes(attributes, ip); + setTraits(attributes, ip); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(ip); + areaStack.push(ip); + } else if ("inlineblockparent".equals(localName)) { + InlineBlockParent ibp = new InlineBlockParent(); + ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0)); + setAreaAttributes(attributes, ibp); + setTraits(attributes, ibp); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(ibp); + areaStack.push(ibp); + } else if ("text".equals(localName)) { + if (getCurrentText() != null) { + throw new IllegalStateException("Current Text must be null"); + } + TextArea text = new TextArea(); + setAreaAttributes(attributes, text); + setTraits(attributes, text); + text.setBaselineOffset(getAttributeAsInteger(attributes, "baseline", 0)); + text.setTextLetterSpaceAdjust(getAttributeAsInteger(attributes, + "tlsadjust", 0)); + text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes, + "twsadjust", 0)); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(text); + areaStack.push(text); + } else if ("word".equals(localName)) { + //handled in endElement + } else if ("space".equals(localName)) { + //handled in endElement + } else if ("char".equals(localName)) { + //handled in endElement + } else if ("leader".equals(localName)) { + Leader leader = new Leader(); + setAreaAttributes(attributes, leader); + setTraits(attributes, leader); + leader.setOffset(getAttributeAsInteger(attributes, "offset", 0)); + String ruleStyle = attributes.getValue("ruleStyle"); + if (ruleStyle != null) { + leader.setRuleStyle(ruleStyle); + } + leader.setRuleThickness( + getAttributeAsInteger(attributes, "ruleThickness", 0)); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(leader); + } else if ("viewport".equals(localName)) { + Viewport viewport = new Viewport(null); + setAreaAttributes(attributes, viewport); + setTraits(attributes, viewport); + viewport.setContentPosition(getAttributeAsRectangle2D(attributes, "pos")); + viewport.setClip(getAttributeAsBoolean(attributes, "clip", false)); + viewport.setOffset(getAttributeAsInteger(attributes, "offset", 0)); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(viewport); + areaStack.push(viewport); + } else if ("image".equals(localName)) { + String url = attributes.getValue("url"); + Image image = new Image(url); + setAreaAttributes(attributes, image); + setTraits(attributes, image); + getCurrentViewport().setContent(image); + } else if ("foreignObject".equals(localName)) { + String ns = attributes.getValue("ns"); + this.domImplementation + = elementMappingRegistry.getDOMImplementationForNamespace(ns); + if (this.domImplementation == null) { + throw new SAXException("No DOMImplementation could be" + + " identified to handle namespace: " + ns); + } + ForeignObject foreign = new ForeignObject(ns); + setAreaAttributes(attributes, foreign); + setTraits(attributes, foreign); + getCurrentViewport().setContent(foreign); + areaStack.push(foreign); + } else { + handled = false; + } + } else { + handled = false; + } + if (!handled) { + throw new SAXException("Unhandled element " + localName + + " in namespace: " + uri); + } + } + } + + private void pushNewRegionReference(Attributes attributes, int side) { + String regionName = attributes.getValue("name"); + RegionViewport rv = getCurrentRegionViewport(); + RegionReference reg = new RegionReference(side, + regionName, rv); + reg.setCTM(getAttributeAsCTM(attributes, "ctm")); + setAreaAttributes(attributes, reg); + rv.setRegionReference(reg); + currentPageViewport.getPage().setRegionViewport( + side, rv); + areaStack.push(reg); + } + + private void assertObjectOfClass(Object obj, Class clazz) { + if (!clazz.isInstance(obj)) { + throw new IllegalStateException("Object is not an instance of " + + clazz.getName() + " but of " + obj.getClass().getName()); + } + } + + /** @see org.xml.sax.helpers.DefaultHandler */ + public void endElement(String uri, String localName, String qName) throws SAXException { + if (delegate != null) { + delegate.endElement(uri, localName, qName); + delegateStack.pop(); + if (delegateStack.size() == 0) { + delegate.endDocument(); + delegate = null; + domImplementation = null; + } + } else { + if ("".equals(uri)) { + if ("pageSequence".equals(localName)) { + //end page-sequence + } else if ("page".equals(localName)) { + treeModel.addPage(currentPageViewport); + currentPageViewport = null; + } else if ("pageViewport".equals(localName)) { + //nop + } else if ("regionViewport".equals(localName)) { + assertObjectOfClass(areaStack.pop(), RegionViewport.class); + } else if ("regionBefore".equals(localName)) { + assertObjectOfClass(areaStack.pop(), RegionReference.class); + } else if ("regionAfter".equals(localName)) { + assertObjectOfClass(areaStack.pop(), RegionReference.class); + } else if ("regionStart".equals(localName)) { + assertObjectOfClass(areaStack.pop(), RegionReference.class); + } else if ("regionEnd".equals(localName)) { + assertObjectOfClass(areaStack.pop(), RegionReference.class); + } else if ("regionBody".equals(localName)) { + assertObjectOfClass(areaStack.pop(), BodyRegion.class); + } else if ("flow".equals(localName)) { + assertObjectOfClass(areaStack.pop(), NormalFlow.class); + } else if ("footnote".equals(localName)) { + assertObjectOfClass(areaStack.pop(), Footnote.class); + } else if ("beforeFloat".equals(localName)) { + assertObjectOfClass(areaStack.pop(), BeforeFloat.class); + } else if ("block".equals(localName)) { + assertObjectOfClass(areaStack.pop(), Block.class); + } else if ("lineArea".equals(localName)) { + assertObjectOfClass(areaStack.pop(), LineArea.class); + } else if ("inlineparent".equals(localName)) { + assertObjectOfClass(areaStack.pop(), InlineParent.class); + } else if ("inlineblockparent".equals(localName)) { + assertObjectOfClass(areaStack.pop(), InlineBlockParent.class); + } else if ("text".equals(localName)) { + assertObjectOfClass(areaStack.pop(), TextArea.class); + } else if ("word".equals(localName)) { + int offset = getAttributeAsInteger(lastAttributes, "offset", 0); + String txt = content.toString(); + WordArea word = new WordArea(txt, offset); + AbstractTextArea text = getCurrentText(); + word.setParentArea(text); + text.addChildArea(word); + } else if ("space".equals(localName)) { + int offset = getAttributeAsInteger(lastAttributes, "offset", 0); + String txt = content.toString(); + //TODO the isAdjustable parameter is currently not used/implemented + if (txt.length() > 0) { + SpaceArea space = new SpaceArea(txt.charAt(0), offset, false); + AbstractTextArea text = getCurrentText(); + space.setParentArea(text); + text.addChildArea(space); + } else { + Space space = new Space(); + setAreaAttributes(lastAttributes, space); + setTraits(lastAttributes, space); + space.setOffset(getAttributeAsInteger(lastAttributes, "offset", 0)); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(space); + } + } else if ("char".equals(localName)) { + String txt = content.toString(); + Character ch = new Character(txt.charAt(0)); + setAreaAttributes(lastAttributes, ch); + setTraits(lastAttributes, ch); + ch.setOffset(getAttributeAsInteger(lastAttributes, "offset", 0)); + ch.setBaselineOffset(getAttributeAsInteger(lastAttributes, "baseline", 0)); + Area parent = (Area)areaStack.peek(); + parent.addChildArea(ch); + } else if ("viewport".equals(localName)) { + assertObjectOfClass(areaStack.pop(), Viewport.class); + } else if ("foreignObject".equals(localName)) { + assertObjectOfClass(areaStack.pop(), ForeignObject.class); + } + } else { + //log.debug("Ignoring " + localName + " in namespace: " + uri); + } + content.setLength(0); //Reset text buffer (see characters()) + } + } + + private void setAreaAttributes(Attributes attributes, Area area) { + area.setIPD(Integer.parseInt(attributes.getValue("ipd"))); + area.setBPD(Integer.parseInt(attributes.getValue("bpd"))); + } + + private void setTraits(Attributes attributes, Area area) { + for (int i = 0, c = Trait.TRAIT_LIST.length; i < c; i++) { + Object trait = Trait.TRAIT_LIST[i]; + Class cl = Trait.getTraitClass(trait); + if (cl == Boolean.class) { + String value = attributes.getValue(Trait.getTraitName(trait)); + if (value != null) { + area.addTrait(trait, Boolean.valueOf(value)); + } + } else if (cl == Integer.class) { + String value = attributes.getValue(Trait.getTraitName(trait)); + if (value != null) { + area.addTrait(trait, new Integer(value)); + } + } else if (cl == String.class) { + String value = attributes.getValue(Trait.getTraitName(trait)); + if (value != null) { + area.addTrait(trait, value); + } + } else if (cl == FontTriplet.class) { + String fontName = attributes.getValue("font-name"); + if (fontName != null) { + String fontStyle = attributes.getValue("font-style"); + int fontWeight = getAttributeAsInteger( + attributes, "font-weight", Font.NORMAL); + area.addTrait(trait, + new FontTriplet(fontName, fontStyle, fontWeight)); + } + } else if (cl == Color.class) { + String value = attributes.getValue(Trait.getTraitName(trait)); + if (value != null) { + area.addTrait(trait, Color.valueOf(value)); + } + } else if (cl == Background.class) { + String value = attributes.getValue(Trait.getTraitName(trait)); + if (value != null) { + Background bkg = new Background(); + Color col = Color.valueOf(attributes.getValue("bkg-color")); + if (col != null) { + bkg.setColor(col); + } + String url = attributes.getValue("bkg-img"); + if (url != null) { + bkg.setURL(url); + + ImageFactory fact = ImageFactory.getInstance(); + FopImage img = fact.getImage(url, userAgent); + if (img == null) { + log.error("Background image not available: " + url); + } else { + // load dimensions + if (!img.load(FopImage.DIMENSIONS)) { + log.error("Cannot read background image dimensions: " + + url); + } + } + bkg.setFopImage(img); + + String repeat = attributes.getValue("bkg-repeat"); + if (repeat != null) { + bkg.setRepeat(repeat); + } + bkg.setHoriz(getAttributeAsInteger(attributes, + "bkg-horz-offset", 0)); + bkg.setVertical(getAttributeAsInteger(attributes, + "bkg-vert-offset", 0)); + } + area.addTrait(trait, bkg); + } + } else if (cl == BorderProps.class) { + String value = attributes.getValue(Trait.getTraitName(trait)); + if (value != null) { + area.addTrait(trait, BorderProps.valueOf(value)); + } + } + } + } + + private boolean getAttributeAsBoolean(Attributes attributes, String name, + boolean defaultValue) { + String s = attributes.getValue(name); + if (s == null) { + return defaultValue; + } else { + return Boolean.valueOf(s).booleanValue(); + } + } + + private int getAttributeAsInteger(Attributes attributes, String name, + int defaultValue) { + String s = attributes.getValue(name); + if (s == null) { + return defaultValue; + } else { + return Integer.parseInt(s); + } + } + + private CTM getAttributeAsCTM(Attributes attributes, String name) { + String s = attributes.getValue(name).trim(); + if (s.startsWith("[") && s.endsWith("]")) { + s = s.substring(1, s.length() - 1); + StringTokenizer tokenizer = new StringTokenizer(s, " "); + double[] values = new double[] { + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken())}; + return new CTM(values[0], values[1], values[2], values[3], values[4], values[5]); + } else { + throw new IllegalArgumentException("CTM must be surrounded by square brackets"); + } + } + + private Rectangle2D getAttributeAsRectangle2D(Attributes attributes, String name) { + String s = attributes.getValue(name).trim(); + StringTokenizer tokenizer = new StringTokenizer(s, " "); + double[] values = new double[] { + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken()), + Double.parseDouble(tokenizer.nextToken())}; + return new Rectangle2D.Double(values[0], values[1], values[2], values[3]); + } + + /** @see org.xml.sax.ContentHandler#characters(char[], int, int) */ + public void characters(char[] ch, int start, int length) throws SAXException { + if (delegate != null) { + delegate.characters(ch, start, length); + } else { + content.append(ch, start, length); + } + } + + } + +} diff --git a/src/java/org/apache/fop/area/BeforeFloat.java b/src/java/org/apache/fop/area/BeforeFloat.java index 2db35a635..4ebbaf296 100644 --- a/src/java/org/apache/fop/area/BeforeFloat.java +++ b/src/java/org/apache/fop/area/BeforeFloat.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -61,6 +61,7 @@ public class BeforeFloat extends BlockParent { return h; } + /** @see org.apache.fop.area.BlockParent#isEmpty() */ public boolean isEmpty() { return true; // before floats are not yet implemented } diff --git a/src/java/org/apache/fop/area/Block.java b/src/java/org/apache/fop/area/Block.java index 700334e77..f51bb7efc 100644 --- a/src/java/org/apache/fop/area/Block.java +++ b/src/java/org/apache/fop/area/Block.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -77,13 +77,10 @@ public class Block extends BlockParent { * @param autoHeight increase the height of the block. */ public void addBlock(Block block, boolean autoHeight) { - if (children == null) { - children = new ArrayList(); - } if (autoHeight) { bpd += block.getAllocBPD(); } - children.add(block); + addChildArea(block); } /** @@ -92,11 +89,8 @@ public class Block extends BlockParent { * @param line the line area to add */ public void addLineArea(LineArea line) { - if (children == null) { - children = new ArrayList(); - } bpd += line.getAllocBPD(); - children.add(line); + addChildArea(line); } /** diff --git a/src/java/org/apache/fop/area/BlockParent.java b/src/java/org/apache/fop/area/BlockParent.java index 63b35ca24..fe6650dbc 100644 --- a/src/java/org/apache/fop/area/BlockParent.java +++ b/src/java/org/apache/fop/area/BlockParent.java @@ -52,16 +52,21 @@ public class BlockParent extends Area { // orientation if reference area private int orientation = ORIENT_0; + /** @see org.apache.fop.area.Area#addChildArea(org.apache.fop.area.Area) */ + public void addChildArea(Area childArea) { + if (children == null) { + children = new ArrayList(); + } + children.add(childArea); + } + /** * Add the block area to this block parent. * * @param block the child block area to add */ public void addBlock(Block block) { - if (children == null) { - children = new ArrayList(); - } - children.add(block); + addChildArea(block); } /** @@ -74,6 +79,15 @@ public class BlockParent extends Area { } /** + * Check whether there are child areas. + * + * @return the result. + */ + public boolean isEmpty() { + return children == null || children.size() == 0; + } + + /** * Set the X offset of this block parent area. * * @param off the x offset of the block parent area diff --git a/src/java/org/apache/fop/area/Footnote.java b/src/java/org/apache/fop/area/Footnote.java index 735dfaf25..afa12afaf 100644 --- a/src/java/org/apache/fop/area/Footnote.java +++ b/src/java/org/apache/fop/area/Footnote.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -18,9 +18,6 @@ package org.apache.fop.area; -import java.util.ArrayList; -import java.util.List; - // may combine with before float into a conditional area /** @@ -80,29 +77,9 @@ public class Footnote extends BlockParent { * @param child the block area. */ public void addBlock(Block child) { - if (children == null) { - children = new ArrayList(); - } + addChildArea(child); this.setBPD(this.getBPD() + child.getBPD()); - children.add(child); - } - - /** - * Get all child areas. - * - * @return the list of child areas. Maybe null. - */ - public List getChildAreas() { - return children; } - /** - * Check whether there are child areas. - * - * @return the result. - */ - public boolean isEmpty() { - return children == null || children.size() == 0; - } } diff --git a/src/java/org/apache/fop/area/LineArea.java b/src/java/org/apache/fop/area/LineArea.java index 15d22548f..e19e71374 100644 --- a/src/java/org/apache/fop/area/LineArea.java +++ b/src/java/org/apache/fop/area/LineArea.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -57,13 +57,13 @@ public class LineArea extends Area { private LineAdjustingInfo adjustingInfo = null; - private int stacking = LR; + //private int stacking = LR; // contains inline areas // has start indent and length, dominant baseline, height private int startIndent; // this is the offset for the dominant baseline - private int baseLine; + //private int baseLine; // this class can contain the dominant char styling info // this means that many renderers can optimise a bit @@ -82,6 +82,8 @@ public class LineArea extends Area { * a new LineAdjustingInfo object is created * @param alignment alignment of this line * @param diff difference between content width and line width + * @param stretch the available stretch for any adjustments + * @param shrink the available shrink for any adjustments */ public LineArea(int alignment, int diff, int stretch, int shrink) { @@ -185,7 +187,8 @@ public class LineArea extends Area { break; case Constants.EN_JUSTIFY: // compute variation factor - adjustingInfo.variationFactor *= (float) (adjustingInfo.difference - ipdVariation) / adjustingInfo.difference; + adjustingInfo.variationFactor *= (float) (adjustingInfo.difference - ipdVariation) + / adjustingInfo.difference; adjustingInfo.difference -= ipdVariation; // if the LineArea has already been added to the area tree, // call finalize(); otherwise, wait for the LineLM to call it diff --git a/src/java/org/apache/fop/area/Page.java b/src/java/org/apache/fop/area/Page.java index cc920b993..a0ad2e877 100644 --- a/src/java/org/apache/fop/area/Page.java +++ b/src/java/org/apache/fop/area/Page.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -187,7 +187,7 @@ public class Page implements Serializable, Cloneable { * @param areaclass the area class of the region to set * @param port the region viewport to set */ - private void setRegionViewport(int areaclass, RegionViewport port) { + public void setRegionViewport(int areaclass, RegionViewport port) { if (areaclass == Constants.FO_REGION_BEFORE) { regionBefore = port; } else if (areaclass == Constants.FO_REGION_START) { diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java index f1daaa2f1..b516b3446 100644 --- a/src/java/org/apache/fop/area/PageViewport.java +++ b/src/java/org/apache/fop/area/PageViewport.java @@ -108,6 +108,16 @@ public class PageViewport implements Resolvable, Cloneable { } /** + * Constructor used by the area tree parser. + * @param viewArea the view area + * @param pageStr String representation of the page number + */ + public PageViewport(Rectangle2D viewArea, String pageStr) { + this.viewArea = viewArea; + this.pageNumberString = pageStr; + } + + /** * Get the view area rectangle of this viewport. * @return the rectangle for this viewport */ @@ -122,6 +132,14 @@ public class PageViewport implements Resolvable, Cloneable { public Page getPage() { return page; } + + /** + * Sets the page object for this PageViewport. + * @param page the page + */ + public void setPage(Page page) { + this.page = page; + } /** * Get the page number of this page. diff --git a/src/java/org/apache/fop/area/RegionReference.java b/src/java/org/apache/fop/area/RegionReference.java index b643db4dc..eb85fc4b8 100644 --- a/src/java/org/apache/fop/area/RegionReference.java +++ b/src/java/org/apache/fop/area/RegionReference.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -67,6 +67,11 @@ public class RegionReference extends Area implements Cloneable { regionViewport = parent; } + /** @see org.apache.fop.area.Area#addChildArea(org.apache.fop.area.Area) */ + public void addChildArea(Area child) { + blocks.add(child); + } + /** * Set the Coordinate Transformation Matrix which transforms content * coordinates in this region reference area which are specified in @@ -125,7 +130,7 @@ public class RegionReference extends Area implements Cloneable { * @param block the block area to add */ public void addBlock(Block block) { - blocks.add(block); + addChildArea(block); } /** diff --git a/src/java/org/apache/fop/area/RenderPagesModel.java b/src/java/org/apache/fop/area/RenderPagesModel.java index 3f44ee736..f4ae85fe7 100644 --- a/src/java/org/apache/fop/area/RenderPagesModel.java +++ b/src/java/org/apache/fop/area/RenderPagesModel.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -113,8 +113,11 @@ public class RenderPagesModel extends AreaTreeModel { try { renderer.renderPage(page); } catch (Exception e) { - // use error handler to handle this FOP or IO Exception - log.error(e); + //TODO use error handler to handle this FOP or IO Exception or propagate exception + String err = "Error while rendering page " + page.getPageNumberString(); + log.error(err, e); + throw new IllegalStateException("Fatal error occurred. Cannot continue. " + + e.getClass().getName() + ": " + err); } page.clear(); } else { diff --git a/src/java/org/apache/fop/area/Trait.java b/src/java/org/apache/fop/area/Trait.java index 0dd1c5681..a58d527a9 100644 --- a/src/java/org/apache/fop/area/Trait.java +++ b/src/java/org/apache/fop/area/Trait.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -202,6 +202,9 @@ public class Trait implements Serializable { public static final Integer LINETHROUGH_COLOR = new Integer(36); private static final Map TRAIT_INFO = new HashMap(); + + /** The list of simple traits in order to avoid iterators */ + public static final Object[] TRAIT_LIST; private static class TraitInfo { private String name; @@ -232,19 +235,19 @@ public class Trait implements Serializable { new TraitInfo("font", FontTriplet.class)); TRAIT_INFO.put(FONT_SIZE, new TraitInfo("font-size", Integer.class)); - TRAIT_INFO.put(COLOR, new TraitInfo("color", String.class)); + TRAIT_INFO.put(COLOR, new TraitInfo("color", Color.class)); TRAIT_INFO.put(PROD_ID, new TraitInfo("prod-id", String.class)); TRAIT_INFO.put(BACKGROUND, new TraitInfo("background", Background.class)); TRAIT_INFO.put(UNDERLINE, new TraitInfo("underline-score", Boolean.class)); - TRAIT_INFO.put(UNDERLINE_COLOR, new TraitInfo("underline-score-color", String.class)); + TRAIT_INFO.put(UNDERLINE_COLOR, new TraitInfo("underline-score-color", Color.class)); TRAIT_INFO.put(OVERLINE, new TraitInfo("overline-score", Boolean.class)); - TRAIT_INFO.put(OVERLINE_COLOR, new TraitInfo("overline-score-color", String.class)); + TRAIT_INFO.put(OVERLINE_COLOR, new TraitInfo("overline-score-color", Color.class)); TRAIT_INFO.put(LINETHROUGH, new TraitInfo("through-score", Boolean.class)); - TRAIT_INFO.put(LINETHROUGH_COLOR, new TraitInfo("through-score-color", String.class)); + TRAIT_INFO.put(LINETHROUGH_COLOR, new TraitInfo("through-score-color", Color.class)); TRAIT_INFO.put(BLINK, new TraitInfo("blink", Boolean.class)); TRAIT_INFO.put(OFFSET, new TraitInfo("offset", Integer.class)); @@ -285,6 +288,8 @@ public class Trait implements Serializable { new TraitInfo("is-reference-area", Boolean.class)); TRAIT_INFO.put(IS_VIEWPORT_AREA, new TraitInfo("is-viewport-area", Boolean.class)); + + TRAIT_LIST = TRAIT_INFO.keySet().toArray(); } /** @@ -326,7 +331,7 @@ public class Trait implements Serializable { * @param oTraitCode the trait code to lookup * @return the class type for the trait */ - private static Class getTraitClass(Object oTraitCode) { + public static Class getTraitClass(Object oTraitCode) { TraitInfo ti = (TraitInfo) TRAIT_INFO.get(oTraitCode); return (ti != null ? ti.getClazz() : null); } @@ -496,6 +501,51 @@ public class Trait implements Serializable { } } + /** @see java.lang.Object#hashCode() */ + public int hashCode() { + return toString().hashCode(); + } + + /** @see java.lang.Object#equals(java.lang.Object) */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + if (obj instanceof ColorType) { + ColorType other = (ColorType)obj; + return getRed() == other.getRed() + && getGreen() == other.getGreen() + && getBlue() == other.getBlue() + && getAlpha() == other.getAlpha(); + } + } + return false; + } + + /** + * Returns a Color represtation of a string of the format "#RRGGBB". + * @param s the string + * @return the Color value + */ + public static Color valueOf(String s) { + if (s == null) { + return null; + } + if (!s.startsWith("#")) { + throw new IllegalArgumentException("Color must start with '#'"); + } + int r = Integer.parseInt(s.substring(1, 3), 16); + int g = Integer.parseInt(s.substring(3, 5), 16); + int b = Integer.parseInt(s.substring(5, 7), 16); + int a = 255; + if (s.length() > 7) { + a = Integer.parseInt(s.substring(7, 9), 16); + } + return new Color(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); + } + /** @see java.lang.Object#toString() */ public String toString() { StringBuffer sbuf = new StringBuffer(8); @@ -515,6 +565,13 @@ public class Trait implements Serializable { sbuf.append('0'); } sbuf.append(s); + if (alpha != 1) { + s = Integer.toHexString((int)(alpha * 255.0)); + if (s.length() == 1) { + sbuf.append('0'); + } + sbuf.append(s); + } return sbuf.toString(); } @@ -617,6 +674,14 @@ public class Trait implements Serializable { } /** + * Sets the image repetition behaviour for images. + * @param repeat The image repetition behaviour to set + */ + public void setRepeat(String repeat) { + setRepeat(getConstantForRepeat(repeat)); + } + + /** * Sets the URL to the background image. * @param url The URL to set */ @@ -640,7 +705,31 @@ public class Trait implements Serializable { this.vertical = vertical; } - /** + private String getRepeatString() { + switch (getRepeat()) { + case Constants.EN_REPEAT: return "repeat"; + case Constants.EN_REPEATX: return "repeat-x"; + case Constants.EN_REPEATY: return "repeat-y"; + case Constants.EN_NOREPEAT: return "no-repeat"; + default: throw new IllegalStateException("Illegal repeat style: " + getRepeat()); + } + } + + private static int getConstantForRepeat(String repeat) { + if ("repeat".equalsIgnoreCase(repeat)) { + return Constants.EN_REPEAT; + } else if ("repeat-x".equalsIgnoreCase(repeat)) { + return Constants.EN_REPEATX; + } else if ("repeat-y".equalsIgnoreCase(repeat)) { + return Constants.EN_REPEATY; + } else if ("no-repeat".equalsIgnoreCase(repeat)) { + return Constants.EN_NOREPEAT; + } else { + throw new IllegalStateException("Illegal repeat style: " + repeat); + } + } + + /** * Return the string for debugging. * @see java.lang.Object#toString() */ @@ -649,23 +738,7 @@ public class Trait implements Serializable { sb.append("color=").append(color); if (url != null) { sb.append(",url=").append(url); - sb.append(",repeat="); - switch (repeat) { - case Constants.EN_REPEAT: - sb.append("repeat"); - break; - case Constants.EN_REPEATX: - sb.append("repeat-x"); - break; - case Constants.EN_REPEATY: - sb.append("repeat-y"); - break; - case Constants.EN_NOREPEAT: - sb.append("no-repeat"); - break; - default: - sb.append("ILLEGAL!"); - } + sb.append(",repeat=").append(getRepeatString()); sb.append(",horiz=").append(horiz); sb.append(",vertical=").append(vertical); } diff --git a/src/java/org/apache/fop/area/inline/ForeignObject.java b/src/java/org/apache/fop/area/inline/ForeignObject.java index 7bf24963d..8a47be6e1 100644 --- a/src/java/org/apache/fop/area/inline/ForeignObject.java +++ b/src/java/org/apache/fop/area/inline/ForeignObject.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,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. @@ -29,6 +29,7 @@ import org.w3c.dom.Document; * This holds an xml document and the associated namespace. */ public class ForeignObject extends Area { + private Document doc; private String namespace; @@ -44,6 +45,23 @@ public class ForeignObject extends Area { } /** + * Create a new empty foreign object for which the DOM Document will be set later. + * + * @param ns the namespace of the document + */ + public ForeignObject(String ns) { + namespace = ns; + } + + /** + * Sets the DOM document for this foreign object. + * @param document the DOM document + */ + public void setDocument(Document document) { + this.doc = document; + } + + /** * Get the document for this foreign object. * * @return the xml document diff --git a/src/java/org/apache/fop/area/inline/InlineArea.java b/src/java/org/apache/fop/area/inline/InlineArea.java index 2f326823b..d4e0f47cf 100644 --- a/src/java/org/apache/fop/area/inline/InlineArea.java +++ b/src/java/org/apache/fop/area/inline/InlineArea.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. diff --git a/src/java/org/apache/fop/area/inline/InlineParent.java b/src/java/org/apache/fop/area/inline/InlineParent.java index 6444da8c4..122c8b2c9 100644 --- a/src/java/org/apache/fop/area/inline/InlineParent.java +++ b/src/java/org/apache/fop/area/inline/InlineParent.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -33,11 +33,9 @@ public class InlineParent extends InlineArea { */ protected List inlines = new ArrayList(); - /** - * An inline parent is a reference area somay have clipping - */ - protected boolean clip = false; - + /** Controls whether the IPD is automatically adjusted based on the area's children. */ + protected transient boolean autoSize; + /** * Create a new inline parent to add areas to. */ @@ -50,9 +48,14 @@ public class InlineParent extends InlineArea { * @param childArea the child area to add */ public void addChildArea(Area childArea) { + if (inlines.size() == 0) { + autoSize = (getIPD() == 0); + } if (childArea instanceof InlineArea) { inlines.add(childArea); - increaseIPD(((InlineArea) childArea).getAllocIPD()); + if (autoSize) { + increaseIPD(((InlineArea) childArea).getAllocIPD()); + } } } diff --git a/src/java/org/apache/fop/area/inline/Leader.java b/src/java/org/apache/fop/area/inline/Leader.java index f683b5af0..e68469b01 100644 --- a/src/java/org/apache/fop/area/inline/Leader.java +++ b/src/java/org/apache/fop/area/inline/Leader.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,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. @@ -50,6 +50,28 @@ public class Leader extends InlineArea { } /** + * Set the rule style of this leader area. + * @param style the rule style for the leader area (XSL enum values) + */ + public void setRuleStyle(String style) { + if ("dotted".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_DOTTED); + } else if ("dashed".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_DASHED); + } else if ("solid".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_SOLID); + } else if ("double".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_DOUBLE); + } else if ("groove".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_GROOVE); + } else if ("ridge".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_RIDGE); + } else if ("none".equalsIgnoreCase(style)) { + setRuleStyle(Constants.EN_NONE); + } + } + + /** * Set the rule thickness of the rule in miilipoints. * * @param rt the rule thickness in millipoints @@ -67,6 +89,21 @@ public class Leader extends InlineArea { return ruleStyle; } + /** @return the rule style as string */ + public String getRuleStyleAsString() { + switch (getRuleStyle()) { + case Constants.EN_DOTTED: return "dotted"; + case Constants.EN_DASHED: return "dashed"; + case Constants.EN_SOLID: return "solid"; + case Constants.EN_DOUBLE: return "double"; + case Constants.EN_GROOVE: return "groove"; + case Constants.EN_RIDGE: return "ridge"; + case Constants.EN_NONE: return "none"; + default: + throw new IllegalStateException("Unsupported rule style: " + getRuleStyle()); + } + } + /** * Get the rule thickness of the rule in miilipoints. * diff --git a/src/java/org/apache/fop/area/inline/Viewport.java b/src/java/org/apache/fop/area/inline/Viewport.java index c9c0b5b10..e8035a904 100644 --- a/src/java/org/apache/fop/area/inline/Viewport.java +++ b/src/java/org/apache/fop/area/inline/Viewport.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,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. @@ -35,7 +35,7 @@ public class Viewport extends InlineArea { private Area content; // clipping for the viewport private boolean clip = false; - // position of the cild area relative to this area + // position of the child area relative to this area private Rectangle2D contentPosition; /** @@ -84,6 +84,14 @@ public class Viewport extends InlineArea { } /** + * Sets the content area. + * @param content the content area + */ + public void setContent(Area content) { + this.content = content; + } + + /** * Get the content area for this viewport. * * @return the content area diff --git a/src/java/org/apache/fop/fo/ElementMapping.java b/src/java/org/apache/fop/fo/ElementMapping.java index 3501194ab..092a411f0 100644 --- a/src/java/org/apache/fop/fo/ElementMapping.java +++ b/src/java/org/apache/fop/fo/ElementMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,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. @@ -20,6 +20,11 @@ package org.apache.fop.fo; import java.util.HashMap; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.DOMImplementation; + /** * Abstract base class for Element Mappings (including FO Element Mappings) * which provide the framework of valid elements and attibutes for a given @@ -55,14 +60,50 @@ public abstract class ElementMapping { public String getNamespaceURI() { return namespaceURI; } + + /** + * Returns the DOMImplementation used by this ElementMapping. The value returned may be null + * for cases where no DOM is used to represent the element tree (XSL-FO, for example). This + * method is used by the intermediate format to instantiate the right kind of DOM document + * for foreign objects. For example, SVG handled through Apache Batik has to use a special + * DOMImplementation. + * @return the DOMImplementation used by this ElementMapping, may be null + */ + public DOMImplementation getDOMImplementation() { + return null; //For namespaces not used in foreign objects + } /** + * @return the default DOMImplementation when no specialized DOM is necessary. + */ + protected DOMImplementation getDefaultDOMImplementation() { + DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance(); + fact.setNamespaceAware(true); + fact.setValidating(false); + try { + return fact.newDocumentBuilder().getDOMImplementation(); + } catch (ParserConfigurationException e) { + throw new RuntimeException( + "Cannot return default DOM implementation: " + e.getMessage()); + } + } + + /** * Initializes the set of maker objects associated with this ElementMapping */ protected abstract void initialize(); + /** + * Base class for all Makers. It is responsible to return the right kind of FONode for a + * particular element. + */ public static class Maker { + /** + * Creates a new FONode (or rather a specialized subclass of it). + * @param parent the parent FONode + * @return the newly created FONode instance + */ public FONode make(FONode parent) { return null; } diff --git a/src/java/org/apache/fop/fo/ElementMappingRegistry.java b/src/java/org/apache/fop/fo/ElementMappingRegistry.java new file mode 100644 index 000000000..35224e7ae --- /dev/null +++ b/src/java/org/apache/fop/fo/ElementMappingRegistry.java @@ -0,0 +1,175 @@ +/* + * 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.fo; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fo.ElementMapping.Maker; +import org.apache.fop.util.Service; +import org.w3c.dom.DOMImplementation; +import org.xml.sax.Locator; + +/** + * This class keeps track of all configured ElementMapping implementations which are responsible + * for properly handling all kinds of different XML namespaces. + */ +public class ElementMappingRegistry { + + /** logging instance */ + protected Log log = LogFactory.getLog(ElementMappingRegistry.class); + + /** + * Table mapping element names to the makers of objects + * representing formatting objects. + */ + protected Map fobjTable = new java.util.HashMap(); + + /** + * Map of mapped namespaces and their associated ElementMapping instances. + */ + protected Map namespaces = new java.util.HashMap(); + + /** + * Main constructor. Adds all default element mapping as well as detects ElementMapping + * through the Service discovery. + * @param userAgent the user agent + */ + public ElementMappingRegistry(FOUserAgent userAgent) { + // Add standard element mappings + setupDefaultMappings(); + + // add additional ElementMappings defined within FOUserAgent + List addlEMs = userAgent.getAdditionalElementMappings(); + + if (addlEMs != null) { + for (int i = 0; i < addlEMs.size(); i++) { + addElementMapping((ElementMapping) addlEMs.get(i)); + } + } + } + + /** + * Sets all the element and property list mappings to their default values. + */ + private void setupDefaultMappings() { + addElementMapping("org.apache.fop.fo.FOElementMapping"); + addElementMapping("org.apache.fop.fo.extensions.svg.SVGElementMapping"); + addElementMapping("org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping"); + addElementMapping("org.apache.fop.fo.extensions.ExtensionElementMapping"); + addElementMapping("org.apache.fop.render.ps.extensions.PSExtensionElementMapping"); + + // add mappings from available services + Iterator providers = Service.providers(ElementMapping.class); + if (providers != null) { + while (providers.hasNext()) { + String str = (String)providers.next(); + try { + addElementMapping(str); + } catch (IllegalArgumentException e) { + log.warn("Error while adding element mapping", e); + } + + } + } + } + + /** + * Add the element mapping with the given class name. + * @param mappingClassName the class name representing the element mapping. + * @throws IllegalArgumentException if there was not such element mapping. + */ + public void addElementMapping(String mappingClassName) + throws IllegalArgumentException { + + try { + ElementMapping mapping + = (ElementMapping)Class.forName(mappingClassName).newInstance(); + addElementMapping(mapping); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Could not find " + + mappingClassName); + } catch (InstantiationException e) { + throw new IllegalArgumentException("Could not instantiate " + + mappingClassName); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Could not access " + + mappingClassName); + } catch (ClassCastException e) { + throw new IllegalArgumentException(mappingClassName + + " is not an ElementMapping"); + } + } + + private void addElementMapping(ElementMapping mapping) { + this.fobjTable.put(mapping.getNamespaceURI(), mapping.getTable()); + this.namespaces.put(mapping.getNamespaceURI().intern(), mapping); + } + + /** + * Finds the Maker used to create node objects of a particular type + * @param namespaceURI URI for the namespace of the element + * @param localName name of the Element + * @param locator the Locator instance for context information + * @return the ElementMapping.Maker that can create an FO object for this element + * @throws FOPException if a Maker could not be found for a bound namespace. + */ + public Maker findFOMaker(String namespaceURI, String localName, Locator locator) + throws FOPException { + Map table = (Map)fobjTable.get(namespaceURI); + Maker fobjMaker = null; + if (table != null) { + fobjMaker = (ElementMapping.Maker)table.get(localName); + // try default + if (fobjMaker == null) { + fobjMaker = (ElementMapping.Maker)table.get(ElementMapping.DEFAULT); + } + } + + if (fobjMaker == null) { + if (namespaces.containsKey(namespaceURI.intern())) { + throw new FOPException(FONode.errorText(locator) + + "No element mapping definition found for " + + FONode.getNodeString(namespaceURI, localName), locator); + } else { + log.warn("Unknown formatting object " + namespaceURI + "^" + localName); + fobjMaker = new UnknownXMLObj.Maker(namespaceURI); + } + } + return fobjMaker; + } + + /** + * Tries to determine the DOMImplementation that is used to handled a particular namespace. + * The method may return null for namespaces that don't result in a DOM. It is mostly used + * in namespaces occurring in foreign objects. + * @param namespaceURI the namespace URI + * @return the handling DOMImplementation, or null if not applicable + */ + public DOMImplementation getDOMImplementationForNamespace(String namespaceURI) { + ElementMapping mapping = (ElementMapping)this.namespaces.get(namespaceURI); + return mapping.getDOMImplementation(); + } + +} diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java index cc87fcca9..c0aa87a44 100644 --- a/src/java/org/apache/fop/fo/FOTreeBuilder.java +++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -19,10 +19,6 @@ package org.apache.fop.fo; import java.io.OutputStream; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -30,7 +26,6 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FormattingResults; import org.apache.fop.area.AreaTreeHandler; -import org.apache.fop.util.Service; import org.apache.fop.fo.ElementMapping.Maker; import org.apache.fop.fo.pagination.Root; import org.apache.fop.image.ImageFactory; @@ -48,22 +43,12 @@ import org.xml.sax.helpers.DefaultHandler; */ public class FOTreeBuilder extends DefaultHandler { - /** - * Table mapping element names to the makers of objects - * representing formatting objects. - */ - protected Map fobjTable = new java.util.HashMap(); - - /** - * logging instance - */ + /** logging instance */ protected Log log = LogFactory.getLog(FOTreeBuilder.class); - /** - * Set of mapped namespaces. - */ - protected Set namespaces = new java.util.HashSet(); - + /** The registry for ElementMapping instances */ + protected ElementMappingRegistry elementMappingRegistry; + /** * The root of the formatting object tree */ @@ -113,75 +98,7 @@ public class FOTreeBuilder extends DefaultHandler { } }); - // Add standard element mappings - setupDefaultMappings(); - - // add additional ElementMappings defined within FOUserAgent - List addlEMs = foUserAgent.getAdditionalElementMappings(); - - if (addlEMs != null) { - for (int i = 0; i < addlEMs.size(); i++) { - addElementMapping((ElementMapping) addlEMs.get(i)); - } - } - } - - /** - * Sets all the element and property list mappings to their default values. - * - */ - private void setupDefaultMappings() { - addElementMapping("org.apache.fop.fo.FOElementMapping"); - addElementMapping("org.apache.fop.fo.extensions.svg.SVGElementMapping"); - addElementMapping("org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping"); - addElementMapping("org.apache.fop.fo.extensions.ExtensionElementMapping"); - addElementMapping("org.apache.fop.render.ps.extensions.PSExtensionElementMapping"); - - // add mappings from available services - Iterator providers = Service.providers(ElementMapping.class); - if (providers != null) { - while (providers.hasNext()) { - String str = (String)providers.next(); - try { - addElementMapping(str); - } catch (IllegalArgumentException e) { - log.warn("Error while adding element mapping", e); - } - - } - } - } - - /** - * Add the element mapping with the given class name. - * @param mappingClassName the class name representing the element mapping. - * @throws IllegalArgumentException if there was not such element mapping. - */ - public void addElementMapping(String mappingClassName) - throws IllegalArgumentException { - - try { - ElementMapping mapping - = (ElementMapping)Class.forName(mappingClassName).newInstance(); - addElementMapping(mapping); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Could not find " - + mappingClassName); - } catch (InstantiationException e) { - throw new IllegalArgumentException("Could not instantiate " - + mappingClassName); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Could not access " - + mappingClassName); - } catch (ClassCastException e) { - throw new IllegalArgumentException(mappingClassName - + " is not an ElementMapping"); - } - } - - private void addElementMapping(ElementMapping mapping) { - this.fobjTable.put(mapping.getNamespaceURI(), mapping.getTable()); - this.namespaces.add(mapping.getNamespaceURI().intern()); + this.elementMappingRegistry = new ElementMappingRegistry(foUserAgent); } /** @@ -340,27 +257,7 @@ public class FOTreeBuilder extends DefaultHandler { * @throws FOPException if a Maker could not be found for a bound namespace. */ private Maker findFOMaker(String namespaceURI, String localName) throws FOPException { - Map table = (Map)fobjTable.get(namespaceURI); - Maker fobjMaker = null; - if (table != null) { - fobjMaker = (ElementMapping.Maker)table.get(localName); - // try default - if (fobjMaker == null) { - fobjMaker = (ElementMapping.Maker)table.get(ElementMapping.DEFAULT); - } - } - - if (fobjMaker == null) { - if (namespaces.contains(namespaceURI.intern())) { - throw new FOPException(FONode.errorText(locator) - + "No element mapping definition found for " - + FONode.getNodeString(namespaceURI, localName), locator); - } else { - log.warn("Unknown formatting object " + namespaceURI + "^" + localName); - fobjMaker = new UnknownXMLObj.Maker(namespaceURI); - } - } - return fobjMaker; + return elementMappingRegistry.findFOMaker(namespaceURI, localName, locator); } /** @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) */ diff --git a/src/java/org/apache/fop/fo/extensions/svg/BatikExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/svg/BatikExtensionElementMapping.java index 7b34d6c01..0fce5b8dd 100644 --- a/src/java/org/apache/fop/fo/extensions/svg/BatikExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/svg/BatikExtensionElementMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,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. @@ -24,19 +24,29 @@ import javax.xml.parsers.SAXParserFactory; import org.apache.batik.util.XMLResourceDescriptor; import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.FONode; +import org.w3c.dom.DOMImplementation; /** * This Element Mapping is for Batik SVG Extension elements * of the http://xml.apache.org/batik/ext namespace. */ public class BatikExtensionElementMapping extends ElementMapping { - public static String URI = "http://xml.apache.org/batik/ext"; + + /** Namespace URI for Batik extension elements */ + public static final String URI = "http://xml.apache.org/batik/ext"; + private boolean batikAvail = true; + /** Main constructor. */ public BatikExtensionElementMapping() { namespaceURI = URI; } + /** @see org.apache.fop.fo.ElementMapping#getDOMImplementation() */ + public DOMImplementation getDOMImplementation() { + return null; //no DOMImplementation necessary here + } + /** * Returns the fully qualified classname of an XML parser for * Batik classes that apparently need it (error messages, perhaps) @@ -83,4 +93,5 @@ public class BatikExtensionElementMapping extends ElementMapping { return new SVGElement(parent); } } + } diff --git a/src/java/org/apache/fop/fo/extensions/svg/SVGElementMapping.java b/src/java/org/apache/fop/fo/extensions/svg/SVGElementMapping.java index 6b477bf46..78fab53f8 100644 --- a/src/java/org/apache/fop/fo/extensions/svg/SVGElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/svg/SVGElementMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2004,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. @@ -26,6 +26,7 @@ import org.apache.fop.fo.ElementMapping; import org.apache.batik.util.XMLResourceDescriptor; import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.w3c.dom.DOMImplementation; /** * Setup the SVG element mapping. @@ -33,19 +34,28 @@ import org.apache.batik.dom.svg.SVGDOMImplementation; * that create the SVG Document. */ public class SVGElementMapping extends ElementMapping { - public static String URI = SVGDOMImplementation.SVG_NAMESPACE_URI; - private boolean batik = true; + + /** the SVG namespace */ + public static final String URI = SVGDOMImplementation.SVG_NAMESPACE_URI; + + private boolean batikAvailable = true; + /** Main constructor. */ public SVGElementMapping() { namespaceURI = URI; } + /** @see org.apache.fop.fo.ElementMapping#getDOMImplementation() */ + public DOMImplementation getDOMImplementation() { + return SVGDOMImplementation.getDOMImplementation(); + } + /** * Returns the fully qualified classname of an XML parser for * Batik classes that apparently need it (error messages, perhaps) * @return an XML parser classname */ - private final String getAParserClassName() { + private String getAParserClassName() { try { SAXParserFactory factory = SAXParserFactory.newInstance(); return factory.newSAXParser().getXMLReader().getClass().getName(); @@ -54,8 +64,9 @@ public class SVGElementMapping extends ElementMapping { } } + /** @see org.apache.fop.fo.ElementMapping#initialize() */ protected void initialize() { - if (foObjs == null && batik == true) { + if (foObjs == null && batikAvailable) { // this sets the parser that will be used // by default (SVGBrokenLinkProvider) // normally the user agent value is used @@ -69,7 +80,7 @@ public class SVGElementMapping extends ElementMapping { } catch (Throwable t) { // if the classes are not available // the DISPLAY is not checked - batik = false; + batikAvailable = false; } } } @@ -85,4 +96,5 @@ public class SVGElementMapping extends ElementMapping { return new SVGElement(parent); } } + } diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index 867158e6b..f8d22f3bb 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -165,6 +165,7 @@ public class LazyFont extends Typeface implements FontDescriptor { * @see org.apache.fop.fonts.Typeface#isMultiByte() */ public boolean isMultiByte() { + load(true); return realFont.isMultiByte(); } diff --git a/src/java/org/apache/fop/render/XMLHandlerRegistry.java b/src/java/org/apache/fop/render/XMLHandlerRegistry.java index e033c2d4e..1603f74ec 100644 --- a/src/java/org/apache/fop/render/XMLHandlerRegistry.java +++ b/src/java/org/apache/fop/render/XMLHandlerRegistry.java @@ -1,5 +1,5 @@ /*
- * Copyright 2005 The Apache Software Foundation.
+ * Copyright 2005-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.
@@ -117,9 +117,16 @@ public class XMLHandlerRegistry { XMLHandler handler;
List lst = (List)handlers.get(ns);
- if (lst == null) {
+ handler = getXMLHandler(renderer, lst);
+ if (handler == null) {
lst = (List)handlers.get(XMLHandler.HANDLE_ALL);
+ handler = getXMLHandler(renderer, lst);
}
+ return handler;
+ }
+
+ private XMLHandler getXMLHandler(Renderer renderer, List lst) {
+ XMLHandler handler;
if (lst != null) {
for (int i = 0, c = lst.size(); i < c; i++) {
//TODO Maybe add priorities later
@@ -132,7 +139,6 @@ public class XMLHandlerRegistry { return null; //No handler found
}
-
/**
* Discovers XMLHandler implementations through the classpath and dynamically
* registers them.
diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java index 2f7da2a08..1b9afc566 100644 --- a/src/java/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java @@ -40,6 +40,7 @@ import org.xml.sax.helpers.AttributesImpl; // FOP import org.apache.fop.render.PrintRenderer; +import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; import org.apache.fop.render.XMLHandler; import org.apache.fop.apps.FOUserAgent; @@ -60,6 +61,7 @@ import org.apache.fop.area.RegionReference; import org.apache.fop.area.RegionViewport; import org.apache.fop.area.Span; import org.apache.fop.area.Trait; +import org.apache.fop.area.Trait.Background; import org.apache.fop.area.inline.Container; import org.apache.fop.area.inline.ForeignObject; import org.apache.fop.area.inline.Image; @@ -72,6 +74,8 @@ import org.apache.fop.area.inline.Viewport; import org.apache.fop.area.inline.TextArea; import org.apache.fop.area.inline.SpaceArea; import org.apache.fop.area.inline.WordArea; +import org.apache.fop.fo.Constants; +import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.FontTriplet; @@ -99,6 +103,9 @@ public class XMLRenderer extends PrintRenderer { private boolean startedSequence = false; private RendererContext context; + /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */ + protected Renderer mimic; + /** TransformerHandler that the generated XML is written to */ protected TransformerHandler handler; @@ -137,10 +144,26 @@ public class XMLRenderer extends PrintRenderer { public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); - // - //userAgent.addExtensionHandler(); - XMLHandler handler = new XMLXMLHandler(); - userAgent.getXMLHandlerRegistry().addXMLHandler(handler); + XMLHandler xmlHandler = new XMLXMLHandler(); + userAgent.getXMLHandlerRegistry().addXMLHandler(xmlHandler); + } + + /** + * Call this method to make the XMLRenderer mimic a different renderer by using its font + * setup. This is useful when working with the intermediate format parser. + * @param renderer the renderer to mimic + */ + public void mimicRenderer(Renderer renderer) { + this.mimic = renderer; + } + + /** @see org.apache.fop.render.PrintRenderer#setupFontInfo(org.apache.fop.fonts.FontInfo) */ + public void setupFontInfo(FontInfo inFontInfo) { + if (mimic != null) { + mimic.setupFontInfo(inFontInfo); + } else { + super.setupFontInfo(inFontInfo); + } } /** @@ -280,6 +303,7 @@ public class XMLRenderer extends PrintRenderer { while (iter.hasNext()) { Map.Entry traitEntry = (Map.Entry) iter.next(); String name = Trait.getTraitName(traitEntry.getKey()); + Class clazz = Trait.getTraitClass(traitEntry.getKey()); if ("break-before".equals(name) || "break-after".equals(name)) { continue; } @@ -289,6 +313,38 @@ public class XMLRenderer extends PrintRenderer { addAttribute("font-name", triplet.getName()); addAttribute("font-style", triplet.getStyle()); addAttribute("font-weight", triplet.getWeight()); + } else if (clazz.equals(Background.class)) { + Background bkg = (Background)value; + //TODO Remove the following line (makes changes in the test checks necessary) + addAttribute(name, bkg.toString()); + if (bkg.getColor() != null) { + addAttribute("bkg-color", bkg.getColor().toString()); + } + if (bkg.getURL() != null) { + addAttribute("bkg-img", bkg.getURL()); + String repString; + int repeat = bkg.getRepeat(); + switch (repeat) { + case Constants.EN_REPEAT: + repString = "repeat"; + break; + case Constants.EN_REPEATX: + repString = "repeat-x"; + break; + case Constants.EN_REPEATY: + repString = "repeat-y"; + break; + case Constants.EN_NOREPEAT: + repString = "no-repeat"; + break; + default: + throw new IllegalStateException( + "Illegal value for repeat encountered: " + repeat); + } + addAttribute("bkg-repeat", repString); + addAttribute("bkg-horz-offset", bkg.getHoriz()); + addAttribute("bkg-vert-offset", bkg.getVertical()); + } } else { addAttribute(name, value.toString()); } @@ -404,6 +460,7 @@ public class XMLRenderer extends PrintRenderer { atts.clear(); addAreaAttributes(region); addTraitAttributes(region); + addAttribute("name", region.getRegionName()); addAttribute("ctm", region.getCTM().toString()); if (region.getRegionClass() == FO_REGION_BEFORE) { startElement("regionBefore", atts); @@ -414,8 +471,13 @@ public class XMLRenderer extends PrintRenderer { renderRegion(region); endElement("regionStart"); } else if (region.getRegionClass() == FO_REGION_BODY) { + BodyRegion body = (BodyRegion)region; + if (body.getColumnCount() != 1) { + addAttribute("columnGap", body.getColumnGap()); + addAttribute("columnCount", body.getColumnCount()); + } startElement("regionBody", atts); - renderBodyRegion((BodyRegion) region); + renderBodyRegion(body); endElement("regionBody"); } else if (region.getRegionClass() == FO_REGION_END) { startElement("regionEnd", atts); @@ -465,7 +527,9 @@ public class XMLRenderer extends PrintRenderer { atts.clear(); addAreaAttributes(mr); addTraitAttributes(mr); - addAttribute("columnGap", mr.getColumnGap()); + if (mr.getColumnCount() != 1) { + addAttribute("columnGap", mr.getColumnGap()); + } startElement("mainReference", atts); Span span = null; @@ -473,6 +537,9 @@ public class XMLRenderer extends PrintRenderer { for (int count = 0; count < spans.size(); count++) { span = (Span) spans.get(count); atts.clear(); + if (span.getColumnCount() != 1) { + addAttribute("columnCount", span.getColumnCount()); + } addAreaAttributes(span); addTraitAttributes(span); startElement("span", atts); @@ -506,14 +573,12 @@ public class XMLRenderer extends PrintRenderer { atts.clear(); addAreaAttributes(block); addTraitAttributes(block); + int positioning = block.getPositioning(); if (block instanceof BlockViewport) { BlockViewport bvp = (BlockViewport)block; boolean abspos = false; - if (bvp.getPositioning() == Block.ABSOLUTE) { - addAttribute("positioning", "absolute"); - abspos = true; - } else if (bvp.getPositioning() == Block.FIXED) { - addAttribute("positioning", "fixed"); + if (bvp.getPositioning() == Block.ABSOLUTE + || bvp.getPositioning() == Block.FIXED) { abspos = true; } if (abspos) { @@ -525,9 +590,6 @@ public class XMLRenderer extends PrintRenderer { addAttribute("clipped", "true"); } } else { - if (block.getPositioning() == Block.RELATIVE) { - addAttribute("positioning", "relative"); - } if (block.getXOffset() != 0) { addAttribute("left-offset", block.getXOffset()); } @@ -535,6 +597,18 @@ public class XMLRenderer extends PrintRenderer { addAttribute("top-offset", block.getYOffset()); } } + switch (positioning) { + case Block.RELATIVE: + addAttribute("positioning", "relative"); + break; + case Block.ABSOLUTE: + addAttribute("positioning", "absolute"); + break; + case Block.FIXED: + addAttribute("positioning", "fixed"); + break; + default: //nop + } startElement("block", atts); super.renderBlock(block); endElement("block"); @@ -563,6 +637,10 @@ public class XMLRenderer extends PrintRenderer { addAreaAttributes(viewport); addTraitAttributes(viewport); addAttribute("offset", viewport.getOffset()); + addAttribute("pos", viewport.getContentPosition()); + if (viewport.getClip()) { + addAttribute("clip", Boolean.toString(viewport.getClip())); + } startElement("viewport", atts); super.renderViewport(viewport); endElement("viewport"); @@ -576,7 +654,7 @@ public class XMLRenderer extends PrintRenderer { addAreaAttributes(image); addTraitAttributes(image); addAttribute("url", image.getURL()); - addAttribute("pos", pos); + //addAttribute("pos", pos); startElement("image", atts); endElement("image"); } @@ -600,10 +678,10 @@ public class XMLRenderer extends PrintRenderer { atts.clear(); addAreaAttributes(fo); addTraitAttributes(fo); - addAttribute("pos", pos); + String ns = fo.getNameSpace(); + addAttribute("ns", ns); startElement("foreignObject", atts); Document doc = fo.getDocument(); - String ns = fo.getNameSpace(); context.setProperty(XMLXMLHandler.HANDLER, handler); renderXML(context, doc, ns); endElement("foreignObject"); @@ -709,36 +787,11 @@ public class XMLRenderer extends PrintRenderer { * @see org.apache.fop.render.AbstractRenderer#renderLeader(Leader) */ protected void renderLeader(Leader area) { - String style = "solid"; - switch (area.getRuleStyle()) { - case EN_DOTTED: - style = "dotted"; - break; - case EN_DASHED: - style = "dashed"; - break; - case EN_SOLID: - break; - case EN_DOUBLE: - style = "double"; - break; - case EN_GROOVE: - style = "groove"; - break; - case EN_RIDGE: - style = "ridge"; - break; - case EN_NONE: - style = "none"; - break; - default: - style = "--NYI--"; - } atts.clear(); addAreaAttributes(area); addTraitAttributes(area); addAttribute("offset", area.getOffset()); - addAttribute("ruleStyle", style); + addAttribute("ruleStyle", area.getRuleStyleAsString()); addAttribute("ruleThickness", area.getRuleThickness()); startElement("leader", atts); endElement("leader"); diff --git a/src/java/org/apache/fop/traits/BorderProps.java b/src/java/org/apache/fop/traits/BorderProps.java index 8de33920f..32722cc8a 100644 --- a/src/java/org/apache/fop/traits/BorderProps.java +++ b/src/java/org/apache/fop/traits/BorderProps.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-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. @@ -21,8 +21,10 @@ package org.apache.fop.traits; import org.apache.fop.area.Trait; import org.apache.fop.datatypes.ColorType; import org.apache.fop.fo.Constants; +import org.apache.fop.fonts.FontTriplet; import java.io.Serializable; +import java.util.StringTokenizer; /** * Border properties. @@ -61,6 +63,17 @@ public class BorderProps implements Serializable { } /** + * Constructs a new BorderProps instance. + * @param style border style (one of the XSL enum values for border style) + * @param width border width + * @param color border color + * @param mode border mode ((one of SEPARATE, COLLAPSE_INNER and COLLAPSE_OUTER) + */ + public BorderProps(String style, int width, ColorType color, int mode) { + this(getConstantForStyle(style), width, color, mode); + } + + /** * @param bp the border properties or null * @return the effective width of the clipped part of the border */ @@ -88,6 +101,83 @@ public class BorderProps implements Serializable { } } + private static int getConstantForStyle(String style) { + if ("none".equalsIgnoreCase(style)) { + return Constants.EN_NONE; + } else if ("hidden".equalsIgnoreCase(style)) { + return Constants.EN_HIDDEN; + } else if ("dotted".equalsIgnoreCase(style)) { + return Constants.EN_DOTTED; + } else if ("dashed".equalsIgnoreCase(style)) { + return Constants.EN_DASHED; + } else if ("solid".equalsIgnoreCase(style)) { + return Constants.EN_SOLID; + } else if ("double".equalsIgnoreCase(style)) { + return Constants.EN_DOUBLE; + } else if ("groove".equalsIgnoreCase(style)) { + return Constants.EN_GROOVE; + } else if ("ridge".equalsIgnoreCase(style)) { + return Constants.EN_RIDGE; + } else if ("inset".equalsIgnoreCase(style)) { + return Constants.EN_INSET; + } else if ("outset".equalsIgnoreCase(style)) { + return Constants.EN_OUTSET; + } else { + throw new IllegalStateException("Illegal border style: " + style); + } + } + + /** @see java.lang.Object#hashCode() */ + public int hashCode() { + return toString().hashCode(); + } + + /** @see java.lang.Object#equals(java.lang.Object) */ + public boolean equals(Object obj) { + if (obj == null) { + return false; + } else if (obj == this) { + return true; + } else { + if (obj instanceof BorderProps) { + BorderProps other = (BorderProps)obj; + return (style == other.style) + && color.equals(other.color) + && width == other.width + && mode == other.mode; + } + } + return false; + } + + /** + * Returns a BorderProps represtation of a string of the format as written by + * BorderProps.toString(). + * @param s the string + * @return a BorderProps instance + */ + public static BorderProps valueOf(String s) { + if (s.startsWith("(") && s.endsWith(")")) { + s = s.substring(1, s.length() - 1); + StringTokenizer st = new StringTokenizer(s, ","); + String style = st.nextToken(); + String color = st.nextToken(); + int width = Integer.parseInt(st.nextToken()); + int mode = SEPARATE; + if (st.hasMoreTokens()) { + String ms = st.nextToken(); + if ("collapse-inner".equalsIgnoreCase(ms)) { + mode = COLLAPSE_INNER; + } else if ("collapse-outer".equalsIgnoreCase(ms)) { + mode = COLLAPSE_OUTER; + } + } + return new BorderProps(style, width, Trait.Color.valueOf(color), mode); + } else { + throw new IllegalArgumentException("BorderProps must be surrounded by parentheses"); + } + } + /** @see java.lang.Object#toString() */ public String toString() { StringBuffer sbuf = new StringBuffer(); @@ -108,4 +198,5 @@ public class BorderProps implements Serializable { sbuf.append(')'); return sbuf.toString(); } + } diff --git a/src/java/org/apache/fop/util/DefaultErrorListener.java b/src/java/org/apache/fop/util/DefaultErrorListener.java new file mode 100644 index 000000000..5e1a9cc37 --- /dev/null +++ b/src/java/org/apache/fop/util/DefaultErrorListener.java @@ -0,0 +1,64 @@ +/* + * 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.util; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; + +import org.apache.commons.logging.Log; + +/** + * Standard ErrorListener implementation for in-FOP use. Some Xalan-J versions don't properly + * re-throw exceptions. + */ +public class DefaultErrorListener implements ErrorListener { + + private Log log; + + /** + * Main constructor + * @param log the log instance to send log events to + */ + public DefaultErrorListener(Log log) { + this.log = log; + } + + /** + * @see javax.xml.transform.ErrorListener#warning(javax.xml.transform.TransformerException) + */ + public void warning(TransformerException exc) { + log.warn(exc.toString()); + } + + /** + * @see javax.xml.transform.ErrorListener#error(javax.xml.transform.TransformerException) + */ + public void error(TransformerException exc) throws TransformerException { + throw exc; + } + + /** + * @see javax.xml.transform.ErrorListener#fatalError(javax.xml.transform.TransformerException) + */ + public void fatalError(TransformerException exc) + throws TransformerException { + throw exc; + } + +}
\ No newline at end of file |