diff options
author | Jeremias Maerki <jeremias@apache.org> | 2008-07-16 09:10:02 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2008-07-16 09:10:02 +0000 |
commit | b11934f81509eafde584354e41981a656c3d4d39 (patch) | |
tree | 878c56ee5db1fa989ebb9fff4fbd56fb377c9964 /src/java/org/apache | |
parent | 8e94b3ad33854852846b6333e09e7cd38a2cc5e0 (diff) | |
download | xmlgraphics-fop-b11934f81509eafde584354e41981a656c3d4d39.tar.gz xmlgraphics-fop-b11934f81509eafde584354e41981a656c3d4d39.zip |
Renamed "iform" package to "intermediate" (iform was too cryptic for my taste)
Changed IFRenderer to work against the IFPainter interface.
Started IFPainter implementations for the IF format (IFSerializer), SVG 1.1 and SVG Print. They currently support very simple FOs only (like examples/fo/basic/simple.fo).
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@677204 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
17 files changed, 2145 insertions, 496 deletions
diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index ee2cba40c..5d2ea7915 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -45,7 +45,7 @@ import org.apache.fop.pdf.PDFEncryptionParams; import org.apache.fop.pdf.PDFXMode; import org.apache.fop.render.Renderer; import org.apache.fop.render.awt.AWTRenderer; -import org.apache.fop.render.iform.IFRenderer; +import org.apache.fop.render.intermediate.IFRenderer; import org.apache.fop.render.pdf.PDFRenderer; import org.apache.fop.render.print.PagesMode; import org.apache.fop.render.print.PrintRenderer; diff --git a/src/java/org/apache/fop/render/RendererFactory.java b/src/java/org/apache/fop/render/RendererFactory.java index d81f900e0..2706a723e 100644 --- a/src/java/org/apache/fop/render/RendererFactory.java +++ b/src/java/org/apache/fop/render/RendererFactory.java @@ -5,9 +5,9 @@ * The ASF licenses this file to You 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. @@ -16,7 +16,7 @@ */ /* $Id$ */ - + package org.apache.fop.render; import java.io.OutputStream; @@ -34,27 +34,31 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.FOEventHandler; +import org.apache.fop.render.intermediate.AbstractIFPainterMaker; +import org.apache.fop.render.intermediate.IFPainter; +import org.apache.fop.render.intermediate.IFRenderer; /** * Factory for FOEventHandlers and Renderers. */ public class RendererFactory { - + /** the logger */ private static Log log = LogFactory.getLog(RendererFactory.class); private Map rendererMakerMapping = new java.util.HashMap(); private Map eventHandlerMakerMapping = new java.util.HashMap(); - - + private Map painterMakerMapping = new java.util.HashMap(); + /** * Main constructor. */ public RendererFactory() { discoverRenderers(); discoverFOEventHandlers(); + discoverPainters(); } - + /** * Add a new RendererMaker. If another maker has already been registered for a * particular MIME type, this call overwrites the existing one. @@ -65,13 +69,13 @@ public class RendererFactory { for (int i = 0; i < mimes.length; i++) { //This overrides any renderer previously set for a MIME type if (rendererMakerMapping.get(mimes[i]) != null) { - log.trace("Overriding renderer for " + mimes[i] + log.trace("Overriding renderer for " + mimes[i] + " with " + maker.getClass().getName()); } rendererMakerMapping.put(mimes[i], maker); } } - + /** * Add a new FOEventHandlerMaker. If another maker has already been registered for a * particular MIME type, this call overwrites the existing one. @@ -82,13 +86,30 @@ public class RendererFactory { for (int i = 0; i < mimes.length; i++) { //This overrides any event handler previously set for a MIME type if (eventHandlerMakerMapping.get(mimes[i]) != null) { - log.trace("Overriding FOEventHandler for " + mimes[i] + log.trace("Overriding FOEventHandler for " + mimes[i] + " with " + maker.getClass().getName()); } eventHandlerMakerMapping.put(mimes[i], maker); } } - + + /** + * Add a new painter maker. If another maker has already been registered for a + * particular MIME type, this call overwrites the existing one. + * @param maker the painter maker + */ + public void addPainterMaker(AbstractIFPainterMaker maker) { + String[] mimes = maker.getSupportedMimeTypes(); + for (int i = 0; i < mimes.length; i++) { + //This overrides any renderer previously set for a MIME type + if (painterMakerMapping.get(mimes[i]) != null) { + log.trace("Overriding painter for " + mimes[i] + + " with " + maker.getClass().getName()); + } + painterMakerMapping.put(mimes[i], maker); + } + } + /** * Add a new RendererMaker. If another maker has already been registered for a * particular MIME type, this call overwrites the existing one. @@ -114,7 +135,7 @@ public class RendererFactory { + AbstractRendererMaker.class.getName()); } } - + /** * Add a new FOEventHandlerMaker. If another maker has already been registered for a * particular MIME type, this call overwrites the existing one. @@ -140,7 +161,33 @@ public class RendererFactory { + AbstractFOEventHandlerMaker.class.getName()); } } - + + /** + * Add a new painter maker. If another maker has already been registered for a + * particular MIME type, this call overwrites the existing one. + * @param className the fully qualified class name of the painter maker + */ + public void addPainterMaker(String className) { + try { + AbstractIFPainterMaker makerInstance + = (AbstractIFPainterMaker)Class.forName(className).newInstance(); + addPainterMaker(makerInstance); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Could not find " + + className); + } catch (InstantiationException e) { + throw new IllegalArgumentException("Could not instantiate " + + className); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Could not access " + + className); + } catch (ClassCastException e) { + throw new IllegalArgumentException(className + + " is not an " + + AbstractIFPainterMaker.class.getName()); + } + } + /** * Returns a RendererMaker which handles the given MIME type. * @param mime the requested output format @@ -151,7 +198,7 @@ public class RendererFactory { = (AbstractRendererMaker)rendererMakerMapping.get(mime); return maker; } - + /** * Returns a FOEventHandlerMaker which handles the given MIME type. * @param mime the requested output format @@ -162,7 +209,18 @@ public class RendererFactory { = (AbstractFOEventHandlerMaker)eventHandlerMakerMapping.get(mime); return maker; } - + + /** + * Returns a RendererMaker which handles the given MIME type. + * @param mime the requested output format + * @return the requested RendererMaker or null if none is available + */ + public AbstractIFPainterMaker getPainterMaker(String mime) { + AbstractIFPainterMaker maker + = (AbstractIFPainterMaker)painterMakerMapping.get(mime); + return maker; + } + /** * Creates a Renderer object based on render-type desired * @param userAgent the user agent for access to configuration @@ -170,27 +228,36 @@ public class RendererFactory { * @return the new Renderer instance * @throws FOPException if the renderer cannot be properly constructed */ - public Renderer createRenderer(FOUserAgent userAgent, String outputFormat) + public Renderer createRenderer(FOUserAgent userAgent, String outputFormat) throws FOPException { if (userAgent.getRendererOverride() != null) { return userAgent.getRendererOverride(); } else { AbstractRendererMaker maker = getRendererMaker(outputFormat); - if (maker == null) { - throw new UnsupportedOperationException( - "No renderer for the requested format available: " + outputFormat); - } - Renderer rend = maker.makeRenderer(userAgent); - rend.setUserAgent(userAgent); - RendererConfigurator configurator = maker.getConfigurator(userAgent); - if (configurator != null) { - configurator.configure(rend); + if (maker != null) { + Renderer rend = maker.makeRenderer(userAgent); + rend.setUserAgent(userAgent); + RendererConfigurator configurator = maker.getConfigurator(userAgent); + if (configurator != null) { + configurator.configure(rend); + } + return rend; + } else { + AbstractIFPainterMaker painterMaker = getPainterMaker(outputFormat); + if (painterMaker != null) { + IFRenderer rend = new IFRenderer(); + rend.setUserAgent(userAgent); + IFPainter painter = painterMaker.makePainter(userAgent); + rend.setPainter(painter); + return rend; + } else { + throw new UnsupportedOperationException( + "No renderer for the requested format available: " + outputFormat); + } } - return rend; } } - - + /** * Creates FOEventHandler instances based on the desired output. * @param userAgent the user agent for access to configuration @@ -199,36 +266,75 @@ public class RendererFactory { * @return the newly constructed FOEventHandler * @throws FOPException if the FOEventHandler cannot be properly constructed */ - public FOEventHandler createFOEventHandler(FOUserAgent userAgent, + public FOEventHandler createFOEventHandler(FOUserAgent userAgent, String outputFormat, OutputStream out) throws FOPException { if (userAgent.getFOEventHandlerOverride() != null) { return userAgent.getFOEventHandlerOverride(); } else { AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat); - if (maker == null) { + if (maker != null) { + return maker.makeFOEventHandler(userAgent, out); + } else { AbstractRendererMaker rendMaker = getRendererMaker(outputFormat); - if (rendMaker == null && userAgent.getRendererOverride() == null) { - throw new UnsupportedOperationException( - "Don't know how to handle \"" + outputFormat + "\" as an output format." - + " Neither an FOEventHandler, nor a Renderer could be found" - + " for this output format."); + AbstractIFPainterMaker painterMaker = null; + boolean outputStreamMissing = (userAgent.getRendererOverride() == null); + if (rendMaker == null) { + painterMaker = getPainterMaker(outputFormat); + outputStreamMissing &= (out == null) && (painterMaker.needsOutputStream()); } else { - if (out == null - && userAgent.getRendererOverride() == null - && rendMaker.needsOutputStream()) { + outputStreamMissing &= (out == null) && (rendMaker.needsOutputStream()); + } + if (userAgent.getRendererOverride() != null + || rendMaker != null + || painterMaker != null) { + if (outputStreamMissing) { throw new FOPException( "OutputStream has not been set"); } //Found a Renderer so we need to construct an AreaTreeHandler. return new AreaTreeHandler(userAgent, outputFormat, out); + } else { + throw new UnsupportedOperationException( + "Don't know how to handle \"" + outputFormat + "\" as an output format." + + " Neither an FOEventHandler, nor a Renderer could be found" + + " for this output format."); } - } else { - return maker.makeFOEventHandler(userAgent, out); } } } - + + /** + * Creates a {@code IFPainter} object based on render-type desired + * @param userAgent the user agent for access to configuration + * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). + * @return the new {@code IFPainter} instance + * @throws FOPException if the painter cannot be properly constructed + */ + public IFPainter createPainter(FOUserAgent userAgent, String outputFormat) + throws FOPException { + /* + if (userAgent.getIFPainterOverride() != null) { + return userAgent.getIFPainterOverride(); + } else { + */ + AbstractIFPainterMaker maker = getPainterMaker(outputFormat); + if (maker == null) { + throw new UnsupportedOperationException( + "No renderer for the requested format available: " + outputFormat); + } + IFPainter painter = maker.makePainter(userAgent); + painter.setUserAgent(userAgent); + //TODO Add configuration + /* + RendererConfigurator configurator = maker.getConfigurator(userAgent); + if (configurator != null) { + configurator.configure(painter); + }*/ + return painter; + //} + } + /** * @return an array of all supported MIME types */ @@ -242,10 +348,14 @@ public class RendererFactory { while (iter.hasNext()) { lst.add(((String)iter.next())); } + iter = this.painterMakerMapping.keySet().iterator(); + while (iter.hasNext()) { + lst.add(((String)iter.next())); + } Collections.sort(lst); return (String[])lst.toArray(new String[lst.size()]); } - + /** * Discovers Renderer implementations through the classpath and dynamically * registers them. @@ -259,7 +369,7 @@ public class RendererFactory { AbstractRendererMaker maker = (AbstractRendererMaker)providers.next(); try { if (log.isDebugEnabled()) { - log.debug("Dynamically adding maker for Renderer: " + log.debug("Dynamically adding maker for Renderer: " + maker.getClass().getName()); } addRendererMaker(maker); @@ -270,7 +380,7 @@ public class RendererFactory { } } } - + /** * Discovers FOEventHandler implementations through the classpath and dynamically * registers them. @@ -284,7 +394,7 @@ public class RendererFactory { AbstractFOEventHandlerMaker maker = (AbstractFOEventHandlerMaker)providers.next(); try { if (log.isDebugEnabled()) { - log.debug("Dynamically adding maker for FOEventHandler: " + log.debug("Dynamically adding maker for FOEventHandler: " + maker.getClass().getName()); } addFOEventHandlerMaker(maker); @@ -295,5 +405,30 @@ public class RendererFactory { } } } - + + /** + * Discovers {@code IFPainter} implementations through the classpath and dynamically + * registers them. + */ + private void discoverPainters() { + // add mappings from available services + Iterator providers + = Service.providers(IFPainter.class); + if (providers != null) { + while (providers.hasNext()) { + AbstractIFPainterMaker maker = (AbstractIFPainterMaker)providers.next(); + try { + if (log.isDebugEnabled()) { + log.debug("Dynamically adding maker for IFPainter: " + + maker.getClass().getName()); + } + addPainterMaker(maker); + } catch (IllegalArgumentException e) { + log.error("Error while adding maker for IFPainter", e); + } + + } + } + } + } diff --git a/src/java/org/apache/fop/render/iform/IFPainter.java b/src/java/org/apache/fop/render/iform/IFPainter.java deleted file mode 100644 index c648e8ebd..000000000 --- a/src/java/org/apache/fop/render/iform/IFPainter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.render.iform; - -import java.awt.Dimension; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; - -import org.xml.sax.ContentHandler; - -public interface IFPainter { - - //for foreign content and extensions - ContentHandler getContentHandler(); - - void startDocument(); - void endDocument(); - - void startDocumentHeader(); - void endDocumentHeader(); - - void startPageSequence(String id); - void endPageSequence(); - - void startPage(int index, String name); - void endPage(); - - void startPageHeader(); - void endPageHeader(); - - void startPageContent(); - void endPageContent(); - - void startPageTrailer(); - void addTarget(String name, int x, int y); - void endPageTrailer(); - - void startBox(AffineTransform transform, Dimension size, boolean clip); - void startBox(String transform, Dimension size, boolean clip); - //For transform, something like Batik's org.apache.batik.parser.TransformListHandler/Parser can be used - void endBox(); - - void setFont(String family, String style, Integer weight, String variant, Integer size, String color); - //All of setFont()'s parameters can be null if no state change is necessary - void drawText(int[] x, int[] y, String text); - void drawRect(Rectangle rect, String fill, String stroke); - void drawImage(String uri, Rectangle rect); //external images - void startImage(Rectangle rect); //followed by a SAX stream (SVG etc.) - void endImage(); - //etc. etc. -} diff --git a/src/java/org/apache/fop/render/iform/IFRenderer.java b/src/java/org/apache/fop/render/iform/IFRenderer.java deleted file mode 100644 index 3ff5a6f68..000000000 --- a/src/java/org/apache/fop/render/iform/IFRenderer.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.render.iform; - -import java.awt.Color; -import java.awt.color.ColorSpace; -import java.awt.geom.Rectangle2D; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.MimeConstants; -import org.apache.fop.area.Area; -import org.apache.fop.area.Block; -import org.apache.fop.area.BookmarkData; -import org.apache.fop.area.CTM; -import org.apache.fop.area.LineArea; -import org.apache.fop.area.PageViewport; -import org.apache.fop.area.Trait; -import org.apache.fop.area.Trait.Background; -import org.apache.fop.area.inline.ForeignObject; -import org.apache.fop.area.inline.Image; -import org.apache.fop.area.inline.InlineArea; -import org.apache.fop.area.inline.SpaceArea; -import org.apache.fop.area.inline.TextArea; -import org.apache.fop.area.inline.WordArea; -import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontTriplet; -import org.apache.fop.render.RendererContext; -import org.apache.fop.render.xml.AbstractXMLRenderer; -import org.xml.sax.SAXException; - -public class IFRenderer extends AbstractXMLRenderer { - - /** logging instance */ - protected static Log log = LogFactory.getLog("IFRenderer"); - - /** XML MIME type */ - public static final String IF_MIME_TYPE = MimeConstants.MIME_FOP_IF; - private boolean pageSeqStarted = false; - - private String currentText; - - private Area parentArea; - - /** - * Main constructor - */ - public IFRenderer() { - context = new RendererContext(this, IF_MIME_TYPE); - } - - /** - * {@inheritDoc} - */ - public void startRenderer(OutputStream outputStream) - throws IOException { - log.debug("Rendering areas to intermediate format XML"); - super.startRenderer(outputStream); - if (userAgent.getProducer() != null) { - comment("Produced by " + userAgent.getProducer()); - } - startElement("document"); - startElement("content"); - startElement("svg"); - } - - /** {@inheritDoc} */ - public void startPageSequence(LineArea seqTitle) { - if (pageSeqStarted) { - endElement("pageSet"); - } - pageSeqStarted = true; - startElement("pageSet"); - } - - /** - * {@inheritDoc} - */ - public void stopRenderer() throws IOException { - if (pageSeqStarted) { - endElement("pageSet"); - } - endElement("svg"); - endElement("content"); - endElement("document"); - super.stopRenderer(); - log.debug("Written out intermediate format XML"); - } - -// /** -// * {@inheritDoc} -// */ -// protected void renderFlow(NormalFlow flow) { -// log.debug("renderFlow() " + flow); -// super.renderFlow(flow); -// } -// - /** - * {@inheritDoc} - */ - protected void renderBlock(Block block) { - log.debug("renderBlock() " + block); - addTraitAttributes(block); - startElement("g", atts); - this.parentArea = block; - super.renderBlock(block); - this.parentArea = null; - endElement("g"); - } - - /** - * Renders an fo:foreing-object. - * @param fo the foreign object - * @param pos the position of the foreign object - * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) - */ - public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { - log.debug("renderForeignObject() fo=" + fo + ", pos=" + pos); - super.renderForeignObject(fo, pos); - } - - /** - * {@inheritDoc} - */ - public void renderPage(PageViewport page) throws IOException, FOPException { - log.debug("renderPage() " + page); - atts.clear(); - startElement("page"); - handlePageExtensionAttachments(page); - super.renderPage(page); - endElement("page"); - } - - private boolean parentHasTrait(Integer traitKey, Object trait) { - return ((parentArea != null - && parentArea.hasTrait(traitKey) - && parentArea.getTrait(traitKey).equals(trait))); - } - - /** - * Adds attributes from traits of an Area. - * @param area Area to extract traits from - */ - protected void addTraitAttributes(Area area) { - Object trait = area.getTrait(Trait.FONT); - if (trait != null && !parentHasTrait(Trait.FONT, trait)) { - FontTriplet fontTriplet = (FontTriplet)trait; - addAttribute("font-family", fontTriplet.getName()); - int weight = fontTriplet.getWeight(); - if (weight != Font.WEIGHT_NORMAL) { - addAttribute("font-weight", weight); - } - String style = fontTriplet.getStyle(); - if (!Font.STYLE_NORMAL.equals(style)) { - addAttribute("text-decoration", style); - } - } - trait = area.getTrait(Trait.FONT_SIZE); - if (trait != null && !parentHasTrait(Trait.FONT_SIZE, trait)) { - addAttribute("font-size", ((Integer)trait).intValue() / 1000); - } - trait = area.getTrait(Trait.COLOR); - if (trait != null && !parentHasTrait(Trait.COLOR, trait)) { - addColorAttribute("stroke", (Color)trait); - } - trait = area.getTrait(Trait.BACKGROUND); - if (trait != null && !parentHasTrait(Trait.BACKGROUND, trait)) { - addColorAttribute("fill", ((Background)trait).getColor()); - } - } - - private void addColorAttribute(String attrName, Color col) { - ColorSpace colSpace = col.getColorSpace(); - int colSpaceType = colSpace.getType(); - StringBuffer colStr = new StringBuffer(); - if (colSpace != null) { - if (colSpaceType == ColorSpace.TYPE_RGB) { - colStr.append("rgb("); - } else if (colSpaceType == ColorSpace.TYPE_CMYK) { - colStr.append("icc-color(myCMYK,"); - } else if (colSpaceType == ColorSpace.TYPE_GRAY) { - colStr.append("icc-color(myGRAY,"); - } - float[] colComp = col.getColorComponents(null); - for (int i = 0; i < colComp.length; i++) { - colStr.append((int)(colComp[i] * 255)); - colStr.append(","); - } - colStr.replace(colStr.length() - 1, colStr.length(), ")"); - } - addAttribute(attrName, colStr.toString()); - } - - /** - * {@inheritDoc} - */ - protected void renderText(TextArea text) { - log.debug("renderText() " + text); - atts.clear(); - this.currentText = ""; - addAttribute("x", text.getIPD()); - addAttribute("y", text.getAllocBPD()); - addTraitAttributes(text); - startElement("text", atts); - super.renderText(text); - try { - handler.characters(currentText.toCharArray(), 0, currentText.length()); - } catch (SAXException e) { - handleSAXException(e); - } - this.currentText = null; -// addAttribute("font-family", "Helvetica"); - endElement("text"); - } - - /** - * {@inheritDoc} - */ - protected void renderWord(WordArea word) { - log.debug("renderWord() " + word); - super.renderWord(word); - this.currentText += word.getWord(); - } - - /** - * {@inheritDoc} - */ - protected void renderSpace(SpaceArea space) { - log.debug("renderSpace() " + space); - super.renderSpace(space); - this.currentText += space.getSpace(); - } - - /** - * {@inheritDoc} - */ - public void renderImage(Image image, Rectangle2D pos) { - log.debug("renderImage() image=" + image + ", pos=" + pos); - super.renderImage(image, pos); - } - - protected void handleExtensionAttachments(List attachments) { - log.debug("handleExtensionAttachments() " + attachments); - if (attachments != null && attachments.size() > 0) { - } - } - - protected void endVParea() { - log.debug("endVParea()"); - } - - protected void renderInlineAreaBackAndBorders(InlineArea area) { - log.debug("renderInlineAreaBackAndBorders() " + area); - } - - protected void startVParea(CTM ctm, Rectangle2D clippingRect) { - log.debug("startVParea() ctm=" + ctm + ", rect=" + clippingRect); - } - - protected void renderBookmarkTree(BookmarkData odi) { - log.debug("renderBookmarkTree() odi=" + odi); - } - - /** {@inheritDoc} */ - public String getMimeType() { - return IF_MIME_TYPE; - } -} diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java new file mode 100644 index 000000000..9c9dda61a --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import org.apache.fop.apps.FOUserAgent; + +/** + * Abstract base class for IFPainter implementations. + */ +public abstract class AbstractIFPainter implements IFPainter { + + private FOUserAgent userAgent; + + /** + * Default constructor. + */ + public AbstractIFPainter() { + } + + /** {@inheritDoc} */ + public void setUserAgent(FOUserAgent ua) { + this.userAgent = ua; + } + + /** + * Returns the user agent. + * @return the user agent + */ + protected FOUserAgent getUserAgent() { + return this.userAgent; + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java new file mode 100644 index 000000000..273f90170 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainterMaker.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import org.apache.fop.apps.FOUserAgent; + +/** + * Base class for factory classes which instantiate {@code IFPainter}s and provide information + * about them. + */ +public abstract class AbstractIFPainterMaker { + + /** + * Instantiates a new {@code IFPainter}. + * @param userAgent the user agent + * @return the newly instantiated painter + */ + public abstract IFPainter makePainter(FOUserAgent userAgent); + + /** + * @return Indicates whether this painter requires an OutputStream to work with. + */ + public abstract boolean needsOutputStream(); + + /** + * @return an array of MIME types the painter supports. + */ + public abstract String[] getSupportedMimeTypes(); + + /** + * Returns a renderer config object that can be used to + * configure the painter. + * @param userAgent user agent + * @return a config object that can be used to configure the painter + */ + /* + public RendererConfigurator getConfigurator(FOUserAgent userAgent) { + return null; + }*/ + + /** + * Indicates whether a specific MIME type is supported by this painter. + * @param mimeType the MIME type (ex. "application/pdf") + * @return true if the MIME type is supported + */ + public boolean isMimeTypeSupported(String mimeType) { + String[] mimes = getSupportedMimeTypes(); + for (int i = 0; i < mimes.length; i++) { + if (mimes[i].equals(mimeType)) { + return true; + } + } + return false; + } +} diff --git a/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java new file mode 100644 index 000000000..166b6df20 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/AbstractXMLWritingIFPainter.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import java.awt.geom.AffineTransform; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * Abstract base class for XML-writing IFPainter implementations. + */ +public abstract class AbstractXMLWritingIFPainter extends AbstractIFPainter { + + private static final Attributes EMPTY_ATTS = new AttributesImpl(); + + /** Constant for the "CDATA" attribute type. */ + protected static final String CDATA = "CDATA"; + + /** + * Default SAXTransformerFactory that can be used by subclasses. + */ + protected SAXTransformerFactory tFactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + /** Main SAX ContentHandler to receive the generated SAX events. */ + protected ContentHandler handler; + + /** {@inheritDoc} */ + public ContentHandler getContentHandler() { + return this.handler; + } + + /** {@inheritDoc} */ + public void setResult(Result result) throws IFException { + if (result instanceof SAXResult) { + SAXResult saxResult = (SAXResult)result; + this.handler = saxResult.getHandler(); + } else { + this.handler = createContentHandler(result); + } + } + + /** + * Returns the main namespace used for generated XML content. + * @return the main namespace + */ + protected abstract String getMainNamespace(); + + /** + * Creates a ContentHandler for the given JAXP Result instance. + * @param result the JAXP Result instance + * @return the requested SAX ContentHandler + * @throws IFException if an error occurs setting up the output + */ + protected ContentHandler createContentHandler(Result result) throws IFException { + try { + TransformerHandler tHandler = tFactory.newTransformerHandler(); + Transformer transformer = tHandler.getTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + tHandler.setResult(result); + return tHandler; + } catch (TransformerConfigurationException tce) { + throw new IFException( + "Error while setting up the serializer for SVG output", tce); + } + } + + /* ---=== helper methods ===--- */ + + private static final String BASE_FORMAT = "0.################"; + + private static class DecimalFormatThreadLocal extends ThreadLocal { + + protected synchronized Object initialValue() { + DecimalFormat df = new DecimalFormat(BASE_FORMAT, new DecimalFormatSymbols(Locale.US)); + return df; + } + }; + + //DecimalFormat is not thread-safe! + private static final ThreadLocal DECIMAL_FORMAT = new DecimalFormatThreadLocal(); + + private static String format(double value) { + DecimalFormat df = (DecimalFormat)DECIMAL_FORMAT.get(); + return df.format(value); + } + + /** + * Converts an {@code AffineTransform} instance to an SVG style transform method. + * @param transform the transformation matrix + * @param sb the StringBuffer to write the transform method to + * @return the StringBuffer passed to this method + */ + protected StringBuffer toString(AffineTransform transform, StringBuffer sb) { + double[] matrix = new double[6]; + transform.getMatrix(matrix); + if (matrix[0] == 1 && matrix[3] == 1 && matrix[1] == 0 && matrix[2] == 0) { + sb.append("translate("); + sb.append(format(matrix[4])); + if (matrix[5] != 0) { + sb.append(',').append(format(matrix[5])); + } + } else { + sb.append("matrix("); + for (int i = 0; i < 6; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(format(matrix[i])); + } + } + sb.append(')'); + return sb; + } + + + /** + * Convenience method to generate a startElement SAX event. + * @param localName the local name of the element + * @param atts the attributes + * @throws SAXException if a SAX exception occurs + */ + protected void startElement(String localName, Attributes atts) throws SAXException { + handler.startElement(getMainNamespace(), localName, localName, atts); + } + + /** + * Convenience method to generate a startElement SAX event. + * @param localName the local name of the element + * @throws SAXException if a SAX exception occurs + */ + protected void startElement(String localName) throws SAXException { + handler.startElement(getMainNamespace(), localName, localName, EMPTY_ATTS); + } + + /** + * Convenience method to generate a endElement SAX event. + * @param localName the local name of the element + * @throws SAXException if a SAX exception occurs + */ + protected void endElement(String localName) throws SAXException { + handler.endElement(getMainNamespace(), localName, localName); + } + + /** + * Convenience method to generate an empty element. + * @param localName the local name of the element + * @param atts the attributes + * @throws SAXException if a SAX exception occurs + */ + protected void element(String localName, Attributes atts) throws SAXException { + handler.startElement(getMainNamespace(), localName, localName, atts); + handler.endElement(getMainNamespace(), localName, localName); + } + + /** + * Converts an array of integer coordinates into a space-separated string. + * @param coordinates the coordinates + * @return the space-separated array of coordinates + */ + protected String toString(int[] coordinates) { + if (coordinates == null) { + return ""; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0, c = coordinates.length; i < c; i++) { + if (i > 0) { + sb.append(' '); + } + sb.append(Integer.toString(coordinates[i])); + } + return sb.toString(); + } +} diff --git a/src/java/org/apache/fop/render/intermediate/DelegatingFragmentContentHandler.java b/src/java/org/apache/fop/render/intermediate/DelegatingFragmentContentHandler.java new file mode 100644 index 000000000..cbd6798da --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/DelegatingFragmentContentHandler.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.ext.LexicalHandler; + +import org.apache.fop.util.DelegatingContentHandler; + +/** + * This class is a {@code DelegatingContentHandler} subclass which swallows the + * {@code #startDocument()} and {@code #endDocument()} methods. This is useful for handling + * XML fragments. + */ +public class DelegatingFragmentContentHandler extends DelegatingContentHandler { + + /** + * Main constructor + * @param delegate the content handler to delegate the SAX events to + */ + public DelegatingFragmentContentHandler(ContentHandler delegate) { + setDelegateContentHandler(delegate); + if (delegate instanceof LexicalHandler) { + setDelegateLexicalHandler((LexicalHandler)delegate); + } + if (delegate instanceof DTDHandler) { + setDelegateDTDHandler((DTDHandler)delegate); + } + if (delegate instanceof EntityResolver) { + setDelegateEntityResolver((EntityResolver)delegate); + } + if (delegate instanceof ErrorHandler) { + setDelegateErrorHandler((ErrorHandler)delegate); + } + } + + /** {@inheritDoc} */ + public void startDocument() throws SAXException { + //nop/ignore + } + + /** {@inheritDoc} */ + public void endDocument() throws SAXException { + //nop/ignore + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/IFConstants.java b/src/java/org/apache/fop/render/intermediate/IFConstants.java new file mode 100644 index 000000000..4bd3a706e --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFConstants.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import org.apache.fop.apps.MimeConstants; + +/** + * Constants for the intermediate format. + */ +public interface IFConstants { + + /** MIME type of the intermediate format. */ + String MIME_TYPE = MimeConstants.MIME_FOP_IF; + + /** XML namespace of the intermediate format. */ + String NAMESPACE = "http://xmlgraphics.apache.org/fop/intermediate"; + + /** XML namespace. */ + String XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"; + + /** Namespace prefix for XLink */ + String XLINK_PREFIX = "xlink"; + /** XML namespace for XLink */ + String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink"; + + String EL_DOCUMENT = "document"; + String EL_HEADER = "header"; + String EL_PAGE_SEQUENCE = "page-sequence"; + String EL_PAGE = "page"; + String EL_PAGE_HEADER = "page-header"; + String EL_PAGE_TRAILER = "page-trailer"; + String EL_PAGE_CONTENT = "content"; + String EL_BOX = "box"; +} diff --git a/src/java/org/apache/fop/render/iform/IFContentHandler.java b/src/java/org/apache/fop/render/intermediate/IFContentHandler.java index 4c70c0d30..55c65d82a 100644 --- a/src/java/org/apache/fop/render/iform/IFContentHandler.java +++ b/src/java/org/apache/fop/render/intermediate/IFContentHandler.java @@ -5,9 +5,9 @@ * The ASF licenses this file to You 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. @@ -17,7 +17,7 @@ /* $Id$ */ -package org.apache.fop.render.iform; +package org.apache.fop.render.intermediate; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; diff --git a/src/java/org/apache/fop/render/intermediate/IFException.java b/src/java/org/apache/fop/render/intermediate/IFException.java new file mode 100644 index 000000000..c3f17f9ca --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFException.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +/** + * Exception thrown by code dealing with FOP's intermediate format. + */ +public class IFException extends Exception { + + private static final long serialVersionUID = 0L; + + /** + * Constructs a new exception with the specified detail message and + * cause. <p>Note that the detail message associated with + * <code>cause</code> is <i>not</i> automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A <tt>null</tt> value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + */ + public IFException(String message, Exception cause) { + super(message, cause); + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java new file mode 100644 index 000000000..83045b6bc --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; + +import javax.xml.transform.Result; + +import org.apache.fop.apps.FOUserAgent; + +/** + * Interface used to paint whole documents layouted by Apache FOP. + * <p> + * Call sequence: + * <p> + * <pre> + * startDocument() + * startDocumentHeader() + * [handleExtension()]* + * endDocumentHeader() + * [ + * startPageSequence() + * [ + * startPage() + * startPageHeader() + * [handleExtension()]* + * endPageHeader() + * startPageContent() + * (#pageContent)+ + * endPageContent() + * startPageTrailer() + * (addTarget())* + * endPageTrailer() + * endPage() + * ]* + * endPageSequence() + * ]* + * endDocument() + * + * #box: + * startBox() + * (#pageContent)+ + * endBox() + * + * #pageContent: + * ( + * setFont() | + * drawText() | + * drawRect() | + * drawImage() | + * TODO etc. etc. | + * handleExtensionObject() + * ) + * </pre> + */ +public interface IFPainter { + + /** + * Set the user agent. + * @param userAgent The user agent + */ + void setUserAgent(FOUserAgent userAgent); + + /** + * Sets the JAXP Result object to receive the generated content. + * @param result the JAXP Result object to receive the generated content + * @throws IFException if an error occurs setting up the output + */ + void setResult(Result result) throws IFException; + + /** + * Indicates whether the painter supports to handle the pages in mixed order rather than + * ascending order. + * @return true if out-of-order handling is supported + */ + boolean supportsPagesOutOfOrder(); + + /** + * Indicates the start of a document. This method may only be called once before any other + * event method. + * @throws IFException if an error occurs while handling this event + */ + void startDocument() throws IFException; + + /** + * Indicates the end of a document. This method may only be called once after the whole + * document has been handled. Implementations can release resources (close streams). It is + * an error to call any event method after this method. + * @throws IFException if an error occurs while handling this event + */ + void endDocument() throws IFException; + + /** + * Indicates the start of the document header. This method is called right after the + * {@code #startDocument()} method. Extensions sent to this painter between + * {@code #startDocumentHeader()} and {@code #endDocumentHeader()} apply to the document as + * a whole (like document metadata). + * @throws IFException if an error occurs while handling this event + */ + void startDocumentHeader() throws IFException; + + /** + * Indicates the end of the document header. This method is called before the first + * page sequence. + * @throws IFException if an error occurs while handling this event + */ + void endDocumentHeader() throws IFException; + + /** + * Indicates the start of a new page sequence. + * @param id the page sequence's identifier (or null if none is available) + * @throws IFException if an error occurs while handling this event + */ + void startPageSequence(String id) throws IFException; + /** + * Indicates the end of a page sequence. + * @throws IFException if an error occurs while handling this event + */ + void endPageSequence() throws IFException; + + /** + * Indicates the start of a new page. + * @param index the index of the page within the document (0-based) + * @param name the page name (usually the formatted page number) + * @param size the size of the page (equivalent to the MediaBox in PDF) + * @throws IFException if an error occurs while handling this event + */ + void startPage(int index, String name, Dimension size) throws IFException; + + /** + * Indicates the end of a page + * @throws IFException if an error occurs while handling this event + */ + void endPage() throws IFException; + + /** + * Indicates the start of the page header. + * @throws IFException if an error occurs while handling this event + */ + void startPageHeader() throws IFException; + + /** + * Indicates the end of the page header. + * @throws IFException if an error occurs while handling this event + */ + void endPageHeader() throws IFException; + + /** + * Indicates the start of the page content. + * @throws IFException if an error occurs while handling this event + */ + void startPageContent() throws IFException; + + /** + * Indicates the end of the page content. + * @throws IFException if an error occurs while handling this event + */ + void endPageContent() throws IFException; + + /** + * Indicates the start of the page trailer. The page trailer is used for writing down page + * elements which are only know after handling the page itself (like PDF targets). + * @throws IFException if an error occurs while handling this event + */ + void startPageTrailer() throws IFException; + + /** + * @todo Solve with extension because not all formats support that? + */ + void addTarget(String name, int x, int y) throws IFException; + + /** + * Indicates the end of the page trailer. + * @throws IFException if an error occurs while handling this event + */ + void endPageTrailer() throws IFException; + + void startBox(AffineTransform transform, Dimension size, boolean clip) throws IFException; + void startBox(AffineTransform[] transforms, Dimension size, boolean clip) throws IFException; + //For transform, Batik's org.apache.batik.parser.TransformListHandler/Parser can be used + void endBox() throws IFException; + + /** + * Updates the current font. + * @param family the font family (or null if there's no change) + * @param style the font style (or null if there's no change) + * @param weight the font weight (or null if there's no change) + * @param variant the font variant (or null if there's no change) + * @param size the font size (or null if there's no change) + * @param color the text color (or null if there's no change) + * @throws IFException if an error occurs while handling this event + */ + void setFont(String family, String style, Integer weight, String variant, Integer size, + Color color) throws IFException; + + /** + * Draws text. The initial coordinates (x and y) point to the starting point at the normal + * baseline of the font. The arrays (dx and dy) are optional and can be used to achieve + * effects like kerning. + * @param x X-coordinate of the starting point of the text + * @param y Y-coordinate of the starting point of the text + * @param dx an array of adjustment values for each character in X-direction + * @param dy an array of adjustment values for each character in Y-direction + * @param text the text + * @throws IFException if an error occurs while handling this event + */ + void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException; + + /** + * Draws a rectangle. Either fill or stroke has to be specified. + * @param rect the rectangle's coordinates and extent + * @param fill the fill paint (may be null) + * @param stroke the stroke color (may be null) + * @throws IFException if an error occurs while handling this event + */ + void drawRect(Rectangle rect, Paint fill, Color stroke) throws IFException; + void drawImage(String uri, Rectangle rect) throws IFException; //external images + void startImage(Rectangle rect) throws IFException; //followed by a SAX stream (SVG etc.) + void endImage() throws IFException; + //etc. etc. + + /** + * Handles an extension object. This can be a DOM document or any arbitrary + * object. If an implementation doesn't know how to handle a particular extension it is simply + * ignored. + * @param extension the extension object + * @throws IFException if an error occurs while handling this event + */ + void handleExtensionObject(Object extension) throws IFException; + + //TODO Prototype the following: + //ContentHandler handleExtension() throws Exception +} diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java new file mode 100644 index 000000000..83e7b5397 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -0,0 +1,565 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.xml.transform.stream.StreamResult; + +import org.xml.sax.SAXException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.java2d.GraphicContext; +import org.apache.xmlgraphics.xmp.Metadata; +import org.apache.xmlgraphics.xmp.schemas.DublinCoreAdapter; +import org.apache.xmlgraphics.xmp.schemas.DublinCoreSchema; +import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; +import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; + +import org.apache.fop.Version; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.area.Block; +import org.apache.fop.area.CTM; +import org.apache.fop.area.OffDocumentExtensionAttachment; +import org.apache.fop.area.OffDocumentItem; +import org.apache.fop.area.PageSequence; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.AbstractTextArea; +import org.apache.fop.area.inline.Image; +import org.apache.fop.area.inline.SpaceArea; +import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.inline.WordArea; +import org.apache.fop.fo.extensions.ExtensionAttachment; +import org.apache.fop.fo.extensions.xmp.XMPMetadata; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.fonts.LazyFont; +import org.apache.fop.fonts.Typeface; +import org.apache.fop.render.AbstractPathOrientedRenderer; +import org.apache.fop.render.Renderer; + +public class IFRenderer extends AbstractPathOrientedRenderer { + + /** logging instance */ + protected static Log log = LogFactory.getLog(IFRenderer.class); + + /** XML MIME type */ + public static final String IF_MIME_TYPE = MimeConstants.MIME_FOP_IF; + + private IFPainter painter; + + /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */ + protected Renderer mimic; + + private boolean inPageSequence = false; + + private Stack graphicContextStack = new Stack(); + private GraphicContext graphicContext = new GraphicContext(); + + private Metadata documentMetadata; + + /** + * Main constructor + */ + public IFRenderer() { + } + + /** {@inheritDoc} */ + public String getMimeType() { + return IF_MIME_TYPE; + } + + /** + * Sets the {@code IFPainter} to be used by the {@code IFRenderer}. + * @param painter the {@code IFPainter} + */ + public void setPainter(IFPainter painter) { + this.painter = painter; + } + + /** + * 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; + } + + /** {@inheritDoc} */ + public void setupFontInfo(FontInfo inFontInfo) { + if (mimic != null) { + mimic.setupFontInfo(inFontInfo); + } else { + super.setupFontInfo(inFontInfo); + } + } + + private void handleIFException(IFException ife) { + if (ife.getCause() instanceof SAXException) { + throw new RuntimeException(ife.getCause()); + } else { + throw new RuntimeException(ife); + } + } + + private void handleIFExceptionWithIOException(IFException ife) throws IOException { + if (ife.getCause() instanceof IOException) { + throw (IOException)ife.getCause(); + } else { + handleIFException(ife); + } + } + + /** + * Creates a default {@code IFPainter} when none has been set. + * @return the default IFPainter + */ + protected IFPainter createDefaultPainter() { + return new IFSerializer(); + } + + /** {@inheritDoc} */ + public void startRenderer(OutputStream outputStream) + throws IOException { + try { + if (outputStream != null) { + StreamResult result = new StreamResult(outputStream); + if (getUserAgent().getOutputFile() != null) { + result.setSystemId( + getUserAgent().getOutputFile().toURI().toURL().toExternalForm()); + } + if (this.painter == null) { + this.painter = new IFSerializer(); + } + this.painter.setUserAgent(getUserAgent()); + this.painter.setResult(result); + } + super.startRenderer(null); + if (log.isDebugEnabled()) { + log.debug("Rendering areas via painter (" + + this.painter.getClass().getName() + ")..."); + } + painter.startDocument(); + painter.startDocumentHeader(); + } catch (IFException e) { + handleIFExceptionWithIOException(e); + } + } + + /** {@inheritDoc} */ + public void stopRenderer() throws IOException { + try { + if (this.inPageSequence) { + painter.endPageSequence(); + this.inPageSequence = false; + } + painter.endDocument(); + } catch (IFException e) { + handleIFExceptionWithIOException(e); + } + super.stopRenderer(); + log.debug("Rendering finished."); + } + + /** {@inheritDoc} */ + public void processOffDocumentItem(OffDocumentItem odi) { + if (odi instanceof OffDocumentExtensionAttachment) { + ExtensionAttachment attachment = ((OffDocumentExtensionAttachment)odi).getAttachment(); + if (XMPMetadata.CATEGORY.equals(attachment.getCategory())) { + renderXMPMetadata((XMPMetadata)attachment); + } + } + } + + private void renderXMPMetadata(XMPMetadata metadata) { + this.documentMetadata = metadata.getMetadata(); + } + + /** {@inheritDoc} */ + public void startPageSequence(PageSequence pageSequence) { + try { + if (this.inPageSequence) { + painter.endPageSequence(); + } else { + if (this.documentMetadata == null) { + this.documentMetadata = createDefaultDocumentMetadata(); + } + painter.handleExtensionObject(this.documentMetadata); + painter.endDocumentHeader(); + this.inPageSequence = true; + } + //TODO Put the page-sequence's ID in the area tree + painter.startPageSequence(null); + } catch (IFException e) { + handleIFException(e); + } + } + + private Metadata createDefaultDocumentMetadata() { + Metadata xmp = new Metadata(); + DublinCoreAdapter dc = DublinCoreSchema.getAdapter(xmp); + if (getUserAgent().getTitle() != null) { + dc.setTitle(getUserAgent().getTitle()); + } + if (getUserAgent().getAuthor() != null) { + dc.addCreator(getUserAgent().getAuthor()); + } + if (getUserAgent().getKeywords() != null) { + dc.addSubject(getUserAgent().getKeywords()); + } + XMPBasicAdapter xmpBasic = XMPBasicSchema.getAdapter(xmp); + if (getUserAgent().getProducer() != null) { + xmpBasic.setCreatorTool(getUserAgent().getProducer()); + } else { + xmpBasic.setCreatorTool(Version.getVersion()); + } + xmpBasic.setMetadataDate(new java.util.Date()); + if (getUserAgent().getCreationDate() != null) { + xmpBasic.setCreateDate(getUserAgent().getCreationDate()); + } else { + xmpBasic.setCreateDate(xmpBasic.getMetadataDate()); + } + return xmp; + } + + /** {@inheritDoc} */ + public void renderPage(PageViewport page) throws IOException, FOPException { + if (log.isDebugEnabled()) { + log.debug("renderPage() " + page); + } + try { + Rectangle2D viewArea = page.getViewArea(); + Dimension dim = new Dimension( + (int)Math.ceil(viewArea.getWidth()), + (int)Math.ceil(viewArea.getHeight())); + painter.startPage(page.getPageIndex(), page.getPageNumberString(), dim); + painter.startPageHeader(); + //TODO Handle page header + painter.endPageHeader(); + painter.startPageContent(); + super.renderPage(page); + painter.endPageContent(); + painter.startPageTrailer(); + //TODO Handle page trailer + painter.endPageTrailer(); + painter.endPage(); + } catch (IFException e) { + handleIFException(e); + } + } + + /** {@inheritDoc} */ + protected void saveGraphicsState() { + graphicContextStack.push(graphicContext); + graphicContext = (GraphicContext)graphicContext.clone(); + } + + /** {@inheritDoc} */ + protected void restoreGraphicsState() { + graphicContext = (GraphicContext)graphicContextStack.pop(); + } + + /** {@inheritDoc} */ + protected List breakOutOfStateStack() { + log.debug("Block.FIXED --> break out"); + List breakOutList = new java.util.ArrayList(); + while (!this.graphicContextStack.empty()) { + breakOutList.add(0, this.graphicContext); + restoreGraphicsState(); + } + return breakOutList; + } + + /** {@inheritDoc} */ + protected void restoreStateStackAfterBreakOut(List breakOutList) { + log.debug("Block.FIXED --> restoring context after break-out"); + for (int i = 0, c = breakOutList.size(); i < c; i++) { + saveGraphicsState(); + this.graphicContext = (GraphicContext)breakOutList.get(i); + } + } + + /** {@inheritDoc} */ + protected void concatenateTransformationMatrix(AffineTransform at) { + if (!at.isIdentity()) { + graphicContext.transform(ptToMpt(at)); + } + } + + /** {@inheritDoc} */ + protected void beginTextObject() { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + protected void endTextObject() { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + protected void startVParea(CTM ctm, Rectangle2D clippingRect) { + if (log.isDebugEnabled()) { + log.debug("startVParea() ctm=" + ctm + ", rect=" + clippingRect); + } + saveGraphicsState(); + AffineTransform at = new AffineTransform(ctm.toArray()); + graphicContext.transform(at); + try { + painter.startBox(at, null, false); + } catch (IFException e) { + handleIFException(e); + } + if (log.isDebugEnabled()) { + log.debug("startVPArea: " + at + " --> " + graphicContext.getTransform()); + } + } + + /** {@inheritDoc} */ + protected void endVParea() { + log.debug("endVParea()"); + try { + painter.endBox(); + } catch (IFException e) { + handleIFException(e); + } + restoreGraphicsState(); + if (log.isDebugEnabled()) { + log.debug("endVPArea() --> " + graphicContext.getTransform()); + } + } + + protected void renderReferenceArea(Block block) { + // TODO Auto-generated method stub + } + + /** {@inheritDoc} */ + protected void renderBlock(Block block) { + if (log.isDebugEnabled()) { + log.debug("renderBlock() " + block); + } + super.renderBlock(block); + } + + private Typeface getTypeface(String fontName) { + Typeface tf = (Typeface) fontInfo.getFonts().get(fontName); + if (tf instanceof LazyFont) { + tf = ((LazyFont)tf).getRealFont(); + } + return tf; + } + + /** {@inheritDoc} */ + protected void renderText(TextArea text) { + if (log.isDebugEnabled()) { + log.debug("renderText() " + text); + } + renderInlineAreaBackAndBorders(text); + Color ct = (Color) text.getTrait(Trait.COLOR); + + beginTextObject(); + + String fontName = getInternalFontNameForArea(text); + int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); + + // This assumes that *all* CIDFonts use a /ToUnicode mapping + Typeface tf = getTypeface(fontName); + + FontTriplet triplet = (FontTriplet)text.getTrait(Trait.FONT); + try { + painter.setFont(triplet.getName(), triplet.getStyle(), new Integer(triplet.getWeight()), + "normal", new Integer(size), ct); + } catch (IFException e) { + handleIFException(e); + } + + super.renderText(text); + + int rx = currentIPPosition + text.getBorderAndPaddingWidthStart(); + int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset(); + renderTextDecoration(tf, size, text, bl, rx); + } + + /** {@inheritDoc} */ + protected void renderWord(WordArea word) { + Font font = getFontFromArea(word.getParentArea()); + String s = word.getWord(); + + renderText(s, word.getLetterAdjustArray(), + font, (AbstractTextArea)word.getParentArea()); + + super.renderWord(word); + } + + /** {@inheritDoc} */ + protected void renderSpace(SpaceArea space) { + Font font = getFontFromArea(space.getParentArea()); + String s = space.getSpace(); + + AbstractTextArea textArea = (AbstractTextArea)space.getParentArea(); + renderText(s, null, font, textArea); + + if (space.isAdjustable()) { + //Used for justified text, for example + int tws = -((TextArea) space.getParentArea()).getTextWordSpaceAdjust() + - 2 * textArea.getTextLetterSpaceAdjust(); + this.currentIPPosition -= tws; + } + super.renderSpace(space); + } + + /** + * Does low-level rendering of text. + * @param s text to render + * @param letterAdjust an array of widths for letter adjustment (may be null) + * @param font to font in use + * @param parentArea the parent text area to retrieve certain traits from + */ + protected void renderText(String s, + int[] letterAdjust, + Font font, AbstractTextArea parentArea) { + int curX = currentIPPosition; + float fontSize = font.getFontSize() / 1000f; + + int l = s.length(); + + int[] dx = new int[l]; + boolean hasDX = false; + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + float glyphAdjust = 0; + if (font.hasChar(ch)) { + int tls = (i < l - 1 ? parentArea.getTextLetterSpaceAdjust() : 0); + glyphAdjust -= tls; + } + curX += font.getCharWidth(ch); + if (letterAdjust != null && i < l - 1) { + glyphAdjust -= letterAdjust[i + 1]; + } + + float adjust = glyphAdjust / fontSize; + + if (adjust != 0) { + dx[i] = Math.round(adjust); + if (dx[i] != 0) { + hasDX = true; + } + } + curX += adjust; + } + try { + int rx = currentIPPosition + parentArea.getBorderAndPaddingWidthStart(); + int bl = currentBPPosition + parentArea.getOffset() + parentArea.getBaselineOffset(); + painter.drawText(rx, bl, (hasDX ? dx : null), null, s); + } catch (IFException e) { + handleIFException(e); + } + this.currentIPPosition = curX; + } + + /** {@inheritDoc} */ + public void renderImage(Image image, Rectangle2D pos) { + if (log.isDebugEnabled()) { + log.debug("renderImage() image=" + image + ", pos=" + pos); + } + super.renderImage(image, pos); + } + + protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) { + // TODO Auto-generated method stub + + } + + protected void clip() { + // TODO Auto-generated method stub + + } + + protected void clipRect(float x, float y, float width, float height) { + // TODO Auto-generated method stub + + } + + protected void closePath() { + // TODO Auto-generated method stub + + } + + protected void drawBorderLine(float x1, float y1, float x2, float y2, boolean horz, + boolean startOrBefore, int style, Color col) { + // TODO Auto-generated method stub + + } + + private Rectangle toMillipointRectangle(float x, float y, float width, float height) { + return new Rectangle( + (int)(x * 1000), (int)(y * 1000), (int)(width * 1000), (int)(height * 1000)); + } + + /** {@inheritDoc} */ + protected void fillRect(float x, float y, float width, float height) { + try { + painter.drawRect( + toMillipointRectangle(x, y, width, height), + this.graphicContext.getPaint(), null); + } catch (IFException e) { + handleIFException(e); + } + } + + /** {@inheritDoc} */ + protected void moveTo(float x, float y) { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + protected void lineTo(float x, float y) { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + protected void updateColor(Color col, boolean fill) { + if (fill) { + this.graphicContext.setPaint(col); + } else { + this.graphicContext.setColor(col); + } + + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/IFRendererMaker.java b/src/java/org/apache/fop/render/intermediate/IFRendererMaker.java new file mode 100644 index 000000000..eb70f3028 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFRendererMaker.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.AbstractRendererMaker; +import org.apache.fop.render.PrintRendererConfigurator; +import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfigurator; + +/** + * RendererMaker for the Intermediate Format Renderer. + */ +public class IFRendererMaker extends AbstractRendererMaker { + + private static final String[] MIMES = new String[] {MimeConstants.MIME_FOP_IF}; + + /**{@inheritDoc} */ + public Renderer makeRenderer(FOUserAgent userAgent) { + return new IFRenderer(); + } + + /**{@inheritDoc} */ + public RendererConfigurator getConfigurator(FOUserAgent userAgent) { + return new PrintRendererConfigurator(userAgent); + } + + /** {@inheritDoc} */ + public boolean needsOutputStream() { + return false; + } + + /** {@inheritDoc} */ + public String[] getSupportedMimeTypes() { + return MIMES; + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java new file mode 100644 index 000000000..41cecd1e7 --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -0,0 +1,363 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import org.apache.xmlgraphics.util.XMLizable; + +import org.apache.fop.util.ColorUtil; + +/** + * IFPainter implementation that serializes the intermediate format to XML. + */ +public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConstants { + + /** + * Default constructor. + */ + public IFSerializer() { + } + + /** {@inheritDoc} */ + protected String getMainNamespace() { + return NAMESPACE; + } + + /** {@inheritDoc} */ + public boolean supportsPagesOutOfOrder() { + return false; + //Theoretically supported but disabled to improve performance when + //rendering the IF to the final format later on + } + + /** {@inheritDoc} */ + public void startDocument() throws IFException { + try { + handler.startDocument(); + handler.startPrefixMapping("", NAMESPACE); + handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); + startElement(EL_DOCUMENT); + } catch (SAXException e) { + throw new IFException("SAX error in startDocument()", e); + } + } + + /** {@inheritDoc} */ + public void startDocumentHeader() throws IFException { + try { + startElement(EL_HEADER); + } catch (SAXException e) { + throw new IFException("SAX error in startDocumentHeader()", e); + } + } + + /** {@inheritDoc} */ + public void endDocumentHeader() throws IFException { + try { + endElement(EL_HEADER); + } catch (SAXException e) { + throw new IFException("SAX error in startDocumentHeader()", e); + } + } + + /** {@inheritDoc} */ + public void endDocument() throws IFException { + try { + endElement(EL_DOCUMENT); + handler.endDocument(); + } catch (SAXException e) { + throw new IFException("SAX error in endDocument()", e); + } + } + + /** {@inheritDoc} */ + public void startPageSequence(String id) throws IFException { + try { + AttributesImpl atts = new AttributesImpl(); + if (id != null) { + atts.addAttribute(XML_NAMESPACE, "id", "xml:id", CDATA, id); + } + startElement(EL_PAGE_SEQUENCE, atts); + } catch (SAXException e) { + throw new IFException("SAX error in startPageSequence()", e); + } + } + + /** {@inheritDoc} */ + public void endPageSequence() throws IFException { + try { + endElement(EL_PAGE_SEQUENCE); + } catch (SAXException e) { + throw new IFException("SAX error in endPageSequence()", e); + } + } + + /** {@inheritDoc} */ + public void startPage(int index, String name, Dimension size) throws IFException { + try { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "index", "index", CDATA, Integer.toString(index)); + atts.addAttribute("", "name", "name", CDATA, name); + atts.addAttribute("", "width", "width", CDATA, Integer.toString(size.width)); + atts.addAttribute("", "height", "height", CDATA, Integer.toString(size.height)); + startElement(EL_PAGE, atts); + } catch (SAXException e) { + throw new IFException("SAX error in startPage()", e); + } + } + + /** {@inheritDoc} */ + public void startPageHeader() throws IFException { + try { + startElement(EL_PAGE_HEADER); + } catch (SAXException e) { + throw new IFException("SAX error in startPageHeader()", e); + } + } + + /** {@inheritDoc} */ + public void endPageHeader() throws IFException { + try { + endElement(EL_PAGE_HEADER); + } catch (SAXException e) { + throw new IFException("SAX error in endPageHeader()", e); + } + } + + /** {@inheritDoc} */ + public void startPageContent() throws IFException { + try { + startElement(EL_PAGE_CONTENT); + } catch (SAXException e) { + throw new IFException("SAX error in startPageContent()", e); + } + } + + /** {@inheritDoc} */ + public void endPageContent() throws IFException { + try { + endElement(EL_PAGE_CONTENT); + } catch (SAXException e) { + throw new IFException("SAX error in endPageContent()", e); + } + } + + /** {@inheritDoc} */ + public void startPageTrailer() throws IFException { + try { + startElement(EL_PAGE_TRAILER); + } catch (SAXException e) { + throw new IFException("SAX error in startPageTrailer()", e); + } + } + + /** {@inheritDoc} */ + public void endPageTrailer() throws IFException { + try { + endElement(EL_PAGE_TRAILER); + } catch (SAXException e) { + throw new IFException("SAX error in endPageTrailer()", e); + } + } + + /** {@inheritDoc} */ + public void endPage() throws IFException { + try { + endElement(EL_PAGE); + } catch (SAXException e) { + throw new IFException("SAX error in endPage()", e); + } + } + + /** {@inheritDoc} */ + public void startBox(AffineTransform transform, Dimension size, boolean clip) + throws IFException { + StringBuffer sb = new StringBuffer(); + toString(transform, sb); + startBox(sb.toString(), size, clip); + } + + /** {@inheritDoc} */ + public void startBox(AffineTransform[] transforms, Dimension size, boolean clip) + throws IFException { + StringBuffer sb = new StringBuffer(); + for (int i = 0, c = transforms.length; i < c; i++) { + if (i > 0) { + sb.append(' '); + } + toString(transforms[i], sb); + } + startBox(sb.toString(), size, clip); + } + + private void startBox(String transform, Dimension size, boolean clip) throws IFException { + try { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "transform", "transform", CDATA, transform); + if (size != null) { + atts.addAttribute("", "width", "width", CDATA, Integer.toString(size.width)); + atts.addAttribute("", "height", "height", CDATA, Integer.toString(size.height)); + } + if (clip) { + atts.addAttribute("", "clip", "clip", CDATA, "true"); + } + startElement(EL_BOX, atts); + } catch (SAXException e) { + throw new IFException("SAX error in startBox()", e); + } + } + + /** {@inheritDoc} */ + public void endBox() throws IFException { + try { + endElement(EL_BOX); + } catch (SAXException e) { + throw new IFException("SAX error in endBox()", e); + } + } + + /** {@inheritDoc} */ + public void startImage(Rectangle rect) throws IFException { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + public void drawImage(String uri, Rectangle rect) throws IFException { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + public void endImage() throws IFException { + // TODO Auto-generated method stub + + } + + /** {@inheritDoc} */ + public void addTarget(String name, int x, int y) throws IFException { + // TODO Auto-generated method stub + + } + + private static String toString(Paint paint) { + if (paint instanceof Color) { + return ColorUtil.colorToString((Color)paint); + } else { + throw new UnsupportedOperationException("Paint not supported: " + paint); + } + } + + /** {@inheritDoc} */ + public void drawRect(Rectangle rect, Paint fill, Color stroke) throws IFException { + if (fill == null && stroke == null) { + return; + } + try { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "x", "x", CDATA, Integer.toString(rect.x)); + atts.addAttribute("", "y", "y", CDATA, Integer.toString(rect.y)); + atts.addAttribute("", "width", "width", CDATA, Integer.toString(rect.width)); + atts.addAttribute("", "height", "height", CDATA, Integer.toString(rect.height)); + if (fill != null) { + atts.addAttribute("", "fill", "fill", CDATA, toString(fill)); + } + if (stroke != null) { + atts.addAttribute("", "stroke", "sroke", CDATA, toString(stroke)); + } + element("rect", atts); + } catch (SAXException e) { + throw new IFException("SAX error in drawRect()", e); + } + } + + /** {@inheritDoc} */ + public void drawText(int x, int y, int[] dx, int[] dy, String text) throws IFException { + try { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "x", "x", CDATA, Integer.toString(x)); + atts.addAttribute("", "y", "y", CDATA, Integer.toString(y)); + if (dx != null) { + atts.addAttribute("", "dx", "dx", CDATA, toString(dx)); + } + if (dy != null) { + atts.addAttribute("", "dy", "dy", CDATA, toString(dy)); + } + startElement("text", atts); + char[] chars = text.toCharArray(); + handler.characters(chars, 0, chars.length); + endElement("text"); + } catch (SAXException e) { + throw new IFException("SAX error in setFont()", e); + } + } + + /** {@inheritDoc} */ + public void setFont(String family, String style, Integer weight, String variant, Integer size, + Color color) throws IFException { + try { + AttributesImpl atts = new AttributesImpl(); + if (family != null) { + atts.addAttribute("", "family", "family", CDATA, family); + } + if (style != null) { + atts.addAttribute("", "style", "style", CDATA, style); + } + if (weight != null) { + atts.addAttribute("", "weight", "weight", CDATA, weight.toString()); + } + if (variant != null) { + atts.addAttribute("", "variant", "variant", CDATA, variant); + } + if (size != null) { + atts.addAttribute("", "size", "size", CDATA, size.toString()); + } + if (color != null) { + atts.addAttribute("", "color", "color", CDATA, toString(color)); + } + element("font", atts); + } catch (SAXException e) { + throw new IFException("SAX error in setFont()", e); + } + } + + /** {@inheritDoc} */ + public void handleExtensionObject(Object extension) throws IFException { + if (extension instanceof XMLizable) { + try { + ((XMLizable)extension).toSAX(this.handler); + } catch (SAXException e) { + throw new IFException("SAX error while handling extension object", e); + } + } else { + throw new UnsupportedOperationException( + "Don't know how to handle extension object: " + extension); + } + } + +} diff --git a/src/java/org/apache/fop/render/intermediate/IFState.java b/src/java/org/apache/fop/render/intermediate/IFState.java new file mode 100644 index 000000000..aa073d03c --- /dev/null +++ b/src/java/org/apache/fop/render/intermediate/IFState.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.render.intermediate; + +import java.awt.Color; + +public class IFState { + + private IFState parent; + + private String fontFamily; + private int fontSize; + private String fontStyle; + private int fontWeight; + private String fontVariant; + private boolean fontChanged = true; + + private Color textColor; + + private IFState() { + //nop + } + + private IFState(IFState parent) { + this.parent = parent; + + this.fontFamily = parent.fontFamily; + this.fontSize = parent.fontSize; + this.fontStyle = parent.fontStyle; + this.fontWeight = parent.fontWeight; + this.fontVariant = parent.fontVariant; + + this.textColor = parent.textColor; + } + + public static IFState create() { + return new IFState(); + } + + public IFState push() { + return new IFState(this); + } + + public IFState pop() { + return this.parent; + } + + public boolean isFontChanged() { + return this.fontChanged; + } + + public void resetFontChanged() { + this.fontChanged = false; + } + + /** + * Returns the font family. + * @return the font family + */ + public String getFontFamily() { + return fontFamily; + } + + /** + * Sets the font family. + * @param family the new font family + */ + public void setFontFamily(String family) { + if (!family.equals(this.fontFamily)) { + this.fontChanged = true; + } + this.fontFamily = family; + } + + /** + * Returns the font size. + * @return the font size (in mpt) + */ + public int getFontSize() { + return fontSize; + } + + /** + * Sets the font size. + * @param size the new font size (in mpt) + */ + public void setFontSize(int size) { + if (size != this.fontSize) { + this.fontChanged = true; + } + this.fontSize = size; + } + + /** + * Returns the font style. + * @return the font style + */ + public String getFontStyle() { + return fontStyle; + } + + /** + * Set the font style + * @param style the new font style + */ + public void setFontStyle(String style) { + if (!style.equals(this.fontStyle)) { + this.fontChanged = true; + } + this.fontStyle = style; + } + + /** + * Returns the font weight. + * @return the font weight + */ + public int getFontWeight() { + return fontWeight; + } + + /** + * Sets the font weight + * @param weight the new font weight + */ + public void setFontWeight(int weight) { + if (weight != this.fontWeight) { + this.fontChanged = true; + } + this.fontWeight = weight; + } + + /** + * Returns the font variant. + * @return the font variant + */ + public String getFontVariant() { + return fontVariant; + } + + /** + * Sets the font variant. + * @param variant the new font variant + */ + public void setFontVariant(String variant) { + if (!variant.equals(this.fontVariant)) { + this.fontChanged = true; + } + this.fontVariant = variant; + } + + /** + * Returns the text color. + * @return the text color + */ + public Color getTextColor() { + return textColor; + } + + /** + * Sets the text color. + * @param color the new text color + */ + public void setTextColor(Color color) { + if (!color.equals(this.textColor)) { + this.fontChanged = true; + } + this.textColor = color; + } + + +} diff --git a/src/java/org/apache/fop/util/DelegatingContentHandler.java b/src/java/org/apache/fop/util/DelegatingContentHandler.java index 0b371483f..ff712a82b 100644 --- a/src/java/org/apache/fop/util/DelegatingContentHandler.java +++ b/src/java/org/apache/fop/util/DelegatingContentHandler.java @@ -38,9 +38,8 @@ import org.xml.sax.ext.LexicalHandler; * <p> * The ContentHandler is the only instance that is required. All others (DTDHandler, * EntityResolver, LexicalHandler and ErrorHandler) may be ignored. - * */ -public class DelegatingContentHandler +public class DelegatingContentHandler implements EntityResolver, DTDHandler, ContentHandler, LexicalHandler, ErrorHandler { private ContentHandler delegate; @@ -48,7 +47,7 @@ public class DelegatingContentHandler private DTDHandler dtdHandler; private LexicalHandler lexicalHandler; private ErrorHandler errorHandler; - + /** * Main constructor. */ @@ -62,7 +61,7 @@ public class DelegatingContentHandler public ContentHandler getDelegateContentHandler() { return this.delegate; } - + /** * Sets the delegate ContentHandler that all events are forwarded to. * @param handler the delegate instance @@ -70,7 +69,7 @@ public class DelegatingContentHandler public void setDelegateContentHandler(ContentHandler handler) { this.delegate = handler; } - + /** * Sets the delegate EntityResolver. * @param resolver the delegate instance @@ -78,7 +77,7 @@ public class DelegatingContentHandler public void setDelegateEntityResolver(EntityResolver resolver) { this.entityResolver = resolver; } - + /** * Sets the delegate DTDHandler. * @param handler the delegate instance @@ -86,7 +85,7 @@ public class DelegatingContentHandler public void setDelegateDTDHandler(DTDHandler handler) { this.dtdHandler = handler; } - + /** * Sets the delegate LexicalHandler. * @param handler the delegate instance @@ -94,7 +93,7 @@ public class DelegatingContentHandler public void setDelegateLexicalHandler(LexicalHandler handler) { this.lexicalHandler = handler; } - + /** * Sets the delegate ErrorHandler. * @param handler the delegate instance @@ -102,13 +101,12 @@ public class DelegatingContentHandler public void setDelegateErrorHandler(ErrorHandler handler) { this.errorHandler = handler; } - + // ==== EntityResolver - - /** - * {@inheritDoc} - */ - public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + + /** {@inheritDoc} */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { if (entityResolver != null) { return entityResolver.resolveEntity(publicId, systemId); } else { @@ -118,19 +116,15 @@ public class DelegatingContentHandler // ==== DTDHandler - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void notationDecl(String name, String publicId, String systemId) throws SAXException { if (dtdHandler != null) { dtdHandler.notationDecl(name, publicId, systemId); } } - /** - * {@inheritDoc} - */ - public void unparsedEntityDecl(String name, String publicId, String systemId, + /** {@inheritDoc} */ + public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException { if (dtdHandler != null) { dtdHandler.unparsedEntityDecl(name, publicId, systemId, notationName); @@ -138,174 +132,132 @@ public class DelegatingContentHandler } // ==== ContentHandler - - /** - * {@inheritDoc} - */ + + /** {@inheritDoc} */ public void setDocumentLocator(Locator locator) { delegate.setDocumentLocator(locator); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void startDocument() throws SAXException { delegate.startDocument(); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endDocument() throws SAXException { delegate.endDocument(); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void startPrefixMapping(String prefix, String uri) throws SAXException { delegate.startPrefixMapping(prefix, uri); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endPrefixMapping(String prefix) throws SAXException { delegate.endPrefixMapping(prefix); } - /** - * {@inheritDoc} - */ - public void startElement(String uri, String localName, String qName, + /** {@inheritDoc} */ + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { delegate.startElement(uri, localName, qName, atts); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endElement(String uri, String localName, String qName) throws SAXException { delegate.endElement(uri, localName, qName); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void characters(char[] ch, int start, int length) throws SAXException { delegate.characters(ch, start, length); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { delegate.ignorableWhitespace(ch, start, length); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void processingInstruction(String target, String data) throws SAXException { delegate.processingInstruction(target, data); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void skippedEntity(String name) throws SAXException { delegate.skippedEntity(name); } // ==== LexicalHandler - - /** - * {@inheritDoc} - */ + + /** {@inheritDoc} */ public void startDTD(String name, String publicId, String systemId) throws SAXException { if (lexicalHandler != null) { lexicalHandler.startDTD(name, publicId, systemId); } - + } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endDTD() throws SAXException { if (lexicalHandler != null) { lexicalHandler.endDTD(); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void startEntity(String name) throws SAXException { if (lexicalHandler != null) { lexicalHandler.startEntity(name); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endEntity(String name) throws SAXException { if (lexicalHandler != null) { lexicalHandler.endEntity(name); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void startCDATA() throws SAXException { if (lexicalHandler != null) { lexicalHandler.startCDATA(); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endCDATA() throws SAXException { if (lexicalHandler != null) { lexicalHandler.endCDATA(); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void comment(char[] ch, int start, int length) throws SAXException { if (lexicalHandler != null) { lexicalHandler.comment(ch, start, length); } } - + // ==== ErrorHandler - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void warning(SAXParseException exception) throws SAXException { if (errorHandler != null) { errorHandler.warning(exception); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void error(SAXParseException exception) throws SAXException { if (errorHandler != null) { errorHandler.error(exception); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void fatalError(SAXParseException exception) throws SAXException { if (errorHandler != null) { errorHandler.fatalError(exception); |