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-ffa450edef68tags/fop-1_0
@@ -8,3 +8,4 @@ org.apache.fop.render.awt.AWTRendererMaker | |||
org.apache.fop.render.print.PrintRendererMaker | |||
org.apache.fop.render.afp.AFPRendererMaker | |||
org.apache.fop.render.pcl.PCLRendererMaker | |||
org.apache.fop.render.intermediate.IFRendererMaker |
@@ -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; |
@@ -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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -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. | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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 | |||
} | |||
} |
@@ -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"; | |||
} |
@@ -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; |
@@ -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); | |||
} | |||
} |
@@ -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 | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); |
@@ -1 +0,0 @@ | |||
org.apache.fop.render.svg.SVGRendererMaker |
@@ -0,0 +1,2 @@ | |||
org.apache.fop.render.svg.SVGPainterMaker | |||
org.apache.fop.render.svg.SVGPrintPainterMaker |
@@ -0,0 +1,303 @@ | |||
/* | |||
* 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.svg; | |||
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.xmp.Metadata; | |||
import org.apache.fop.render.intermediate.AbstractXMLWritingIFPainter; | |||
import org.apache.fop.render.intermediate.IFException; | |||
import org.apache.fop.render.intermediate.IFState; | |||
import org.apache.fop.util.ColorUtil; | |||
/** | |||
* Abstract base class for SVG Painter implementations. | |||
*/ | |||
public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter | |||
implements SVGConstants { | |||
/** Holds the intermediate format state */ | |||
protected IFState state; | |||
private static final int MODE_NORMAL = 0; | |||
private static final int MODE_TEXT = 1; | |||
private int mode = MODE_NORMAL; | |||
/** {@inheritDoc} */ | |||
protected String getMainNamespace() { | |||
return NAMESPACE; | |||
} | |||
/** {@inheritDoc} */ | |||
public void startDocumentHeader() throws IFException { | |||
try { | |||
startElement("defs"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startDocumentHeader()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endDocumentHeader() throws IFException { | |||
try { | |||
endElement("defs"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startDocumentHeader()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageContent() throws IFException { | |||
this.state = IFState.create(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageContent() throws IFException { | |||
assert this.state.pop() == null; | |||
} | |||
/** {@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 { | |||
establish(MODE_NORMAL); | |||
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("g", atts); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startBox()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endBox() throws IFException { | |||
try { | |||
establish(MODE_NORMAL); | |||
endElement("g"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in endBox()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void startImage(Rectangle rect) throws IFException { | |||
//establish(MODE_NORMAL); | |||
// TODO Auto-generated method stub | |||
} | |||
/** {@inheritDoc} */ | |||
public void drawImage(String uri, Rectangle rect) throws IFException { | |||
//establish(MODE_NORMAL); | |||
// 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 { | |||
//establish(MODE_NORMAL); | |||
// TODO Auto-generated method stub | |||
} | |||
private static String toString(Paint paint) { | |||
//TODO Paint serialization: Fine-tune and extend! | |||
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 { | |||
establish(MODE_NORMAL); | |||
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 { | |||
establish(MODE_TEXT); | |||
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 { | |||
if (family != null) { | |||
state.setFontFamily(family); | |||
} | |||
if (style != null) { | |||
state.setFontStyle(style); | |||
} | |||
if (weight != null) { | |||
state.setFontWeight(weight.intValue()); | |||
} | |||
if (variant != null) { | |||
state.setFontVariant(variant); | |||
} | |||
if (size != null) { | |||
state.setFontSize(size.intValue()); | |||
} | |||
if (color != null) { | |||
state.setTextColor(color); | |||
} | |||
} | |||
private void leaveTextMode() throws SAXException { | |||
assert this.mode == MODE_TEXT; | |||
endElement("g"); | |||
this.mode = MODE_NORMAL; | |||
} | |||
private void establish(int newMode) throws SAXException { | |||
switch (newMode) { | |||
case MODE_TEXT: | |||
enterTextMode(); | |||
break; | |||
default: | |||
if (this.mode == MODE_TEXT) { | |||
leaveTextMode(); | |||
} | |||
} | |||
} | |||
private void enterTextMode() throws SAXException { | |||
if (state.isFontChanged() && this.mode == MODE_TEXT) { | |||
leaveTextMode(); | |||
} | |||
if (this.mode != MODE_TEXT) { | |||
startTextGroup(); | |||
this.mode = MODE_TEXT; | |||
} | |||
} | |||
private void startTextGroup() throws SAXException { | |||
AttributesImpl atts = new AttributesImpl(); | |||
atts.addAttribute("", "font-family", "font-family", | |||
CDATA, state.getFontFamily()); | |||
atts.addAttribute("", "font-style", "font-style", | |||
CDATA, state.getFontStyle()); | |||
atts.addAttribute("", "font-weight", "font-weight", | |||
CDATA, Integer.toString(state.getFontWeight())); | |||
atts.addAttribute("", "font-variant", "font-variant", | |||
CDATA, state.getFontVariant()); | |||
atts.addAttribute("", "font-size", "font-size", | |||
CDATA, Integer.toString(state.getFontSize())); | |||
atts.addAttribute("", "fill", "fill", | |||
CDATA, toString(state.getTextColor())); | |||
startElement("g", atts); | |||
state.resetFontChanged(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void handleExtensionObject(Object extension) throws IFException { | |||
if (extension instanceof Metadata) { | |||
Metadata meta = (Metadata)extension; | |||
try { | |||
establish(MODE_NORMAL); | |||
startElement("metadata"); | |||
meta.toSAX(this.handler); | |||
endElement("metadata"); | |||
} 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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
/* | |||
* 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.svg; | |||
import org.apache.fop.apps.MimeConstants; | |||
/** | |||
* Constants for the intermediate format. | |||
*/ | |||
public interface SVGConstants { | |||
/** MIME type for SVG. */ | |||
String MIME_TYPE = MimeConstants.MIME_SVG; | |||
/** MIME type for SVG Print. */ | |||
String MIME_SVG_PRINT = MimeConstants.MIME_SVG + ";profile=print"; | |||
/** File extension for SVG. */ | |||
String FILE_EXTENSION_SVG = "svg"; | |||
/** XML namespace for SVG. */ | |||
String NAMESPACE = "http://www.w3.org/2000/svg"; | |||
/** 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"; | |||
} |
@@ -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.svg; | |||
import java.awt.Dimension; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.lang.reflect.InvocationHandler; | |||
import java.lang.reflect.Method; | |||
import java.lang.reflect.Proxy; | |||
import javax.xml.parsers.DocumentBuilder; | |||
import javax.xml.parsers.DocumentBuilderFactory; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import javax.xml.transform.Result; | |||
import javax.xml.transform.Source; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerConfigurationException; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.dom.DOMResult; | |||
import javax.xml.transform.dom.DOMSource; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.sax.TransformerHandler; | |||
import javax.xml.transform.stream.StreamResult; | |||
import org.w3c.dom.Document; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.fop.render.bitmap.MultiFileRenderingUtil; | |||
import org.apache.fop.render.intermediate.DelegatingFragmentContentHandler; | |||
import org.apache.fop.render.intermediate.IFException; | |||
/** | |||
* IFPainter implementation that writes SVG. | |||
*/ | |||
public class SVGPainter extends AbstractSVGPainter { | |||
/** Helper class for generating multiple files */ | |||
private MultiFileRenderingUtil multiFileUtil; | |||
private StreamResult firstStream; | |||
private StreamResult currentStream; | |||
private Document reusedParts; | |||
/** | |||
* Default constructor. | |||
*/ | |||
public SVGPainter() { | |||
//nop | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean supportsPagesOutOfOrder() { | |||
return true; | |||
} | |||
/** {@inheritDoc} */ | |||
public void setResult(Result result) throws IFException { | |||
if (result instanceof StreamResult) { | |||
multiFileUtil = new MultiFileRenderingUtil(FILE_EXTENSION_SVG, | |||
getUserAgent().getOutputFile()); | |||
this.firstStream = (StreamResult)result; | |||
} else { | |||
throw new UnsupportedOperationException("Result is not supported: " + result); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void startDocument() throws IFException { | |||
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); | |||
builderFactory.setNamespaceAware(true); | |||
builderFactory.setValidating(false); | |||
try { | |||
DocumentBuilder builder = builderFactory.newDocumentBuilder(); | |||
this.reusedParts = builder.newDocument(); | |||
} catch (ParserConfigurationException e) { | |||
throw new IFException("Error while setting up a DOM for SVG generation", e); | |||
} | |||
try { | |||
TransformerHandler toDOMHandler = tFactory.newTransformerHandler(); | |||
toDOMHandler.setResult(new DOMResult(this.reusedParts)); | |||
this.handler = toDOMHandler; | |||
} catch (TransformerConfigurationException e) { | |||
throw new IFException( | |||
"Error while setting up a TransformerHandler for SVG generation", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endDocument() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageSequence(String id) throws IFException { | |||
//nop | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageSequence() throws IFException { | |||
//nop | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPage(int index, String name, Dimension size) throws IFException { | |||
OutputStream out; | |||
try { | |||
out = this.multiFileUtil.createOutputStream(index); | |||
} catch (IOException ioe) { | |||
throw new IFException("I/O exception while setting up output file", ioe); | |||
} | |||
if (out == null) { | |||
this.handler = createContentHandler(this.firstStream); | |||
} else { | |||
this.currentStream = new StreamResult(out); | |||
this.handler = createContentHandler(this.currentStream); | |||
} | |||
if (false) { | |||
final ContentHandler originalHandler = this.handler; | |||
this.handler = (ContentHandler)Proxy.newProxyInstance( | |||
ContentHandler.class.getClassLoader(), | |||
new Class[] {ContentHandler.class}, | |||
new InvocationHandler() { | |||
public Object invoke(Object proxy, Method method, Object[] args) | |||
throws Throwable { | |||
String methodName = method.getName(); | |||
System.out.println(methodName + ":"); | |||
if (args != null) { | |||
for (int i = 0; i < args.length; i++) { | |||
System.out.println(" " + args[i]); | |||
} | |||
} | |||
return method.invoke(originalHandler, args); | |||
} | |||
}); | |||
} | |||
try { | |||
handler.startDocument(); | |||
handler.startPrefixMapping("", NAMESPACE); | |||
handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); | |||
AttributesImpl atts = new AttributesImpl(); | |||
atts.addAttribute("", "version", "version", CDATA, "1.1"); //SVG 1.1 | |||
/* | |||
atts.addAttribute("", "index", "index", CDATA, Integer.toString(index)); | |||
atts.addAttribute("", "name", "name", CDATA, name); | |||
*/ | |||
atts.addAttribute("", "width", "width", CDATA, | |||
Float.toString(size.width / 1000f) + "pt"); | |||
atts.addAttribute("", "height", "height", CDATA, | |||
Float.toString(size.height / 1000f) + "pt"); | |||
atts.addAttribute("", "viewBox", "viewBox", CDATA, | |||
"0 0 " + Integer.toString(size.width) + " " + Integer.toString(size.height)); | |||
startElement("svg", atts); | |||
try { | |||
Transformer transformer = tFactory.newTransformer(); | |||
Source src = new DOMSource(this.reusedParts.getDocumentElement()); | |||
Result res = new SAXResult(new DelegatingFragmentContentHandler(this.handler)); | |||
transformer.transform(src, res); | |||
} catch (TransformerConfigurationException tce) { | |||
throw new IFException("Error setting up a Transformer", tce); | |||
} catch (TransformerException te) { | |||
if (te.getCause() instanceof SAXException) { | |||
throw (SAXException)te.getCause(); | |||
} else { | |||
throw new IFException("Error while serializing reused parts", te); | |||
} | |||
} | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startPage()", e); | |||
} | |||
} | |||
private void closeCurrentStream() { | |||
if (this.currentStream != null) { | |||
IOUtils.closeQuietly(currentStream.getOutputStream()); | |||
currentStream.setOutputStream(null); | |||
IOUtils.closeQuietly(currentStream.getWriter()); | |||
currentStream.setWriter(null); | |||
this.currentStream = null; | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageHeader() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageHeader() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageContent() throws IFException { | |||
super.startPageContent(); | |||
try { | |||
startElement("g"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startPageContent()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageContent() throws IFException { | |||
try { | |||
endElement("g"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in endPageContent()", e); | |||
} | |||
super.endPageContent(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageTrailer() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageTrailer() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPage() throws IFException { | |||
try { | |||
endElement("svg"); | |||
this.handler.endDocument(); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in endPage()", e); | |||
} | |||
closeCurrentStream(); | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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.svg; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.render.intermediate.AbstractIFPainterMaker; | |||
import org.apache.fop.render.intermediate.IFPainter; | |||
/** | |||
* Painter factory for SVG output. | |||
*/ | |||
public class SVGPainterMaker extends AbstractIFPainterMaker { | |||
private static final String[] MIMES = new String[] {SVGConstants.MIME_TYPE}; | |||
/** {@inheritDoc} */ | |||
public IFPainter makePainter(FOUserAgent ua) { | |||
return new SVGPainter(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean needsOutputStream() { | |||
return true; | |||
} | |||
/** {@inheritDoc} */ | |||
public String[] getSupportedMimeTypes() { | |||
return MIMES; | |||
} | |||
} |
@@ -0,0 +1,172 @@ | |||
/* | |||
* 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.svg; | |||
import java.awt.Dimension; | |||
import javax.xml.transform.Result; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.fop.render.intermediate.IFConstants; | |||
import org.apache.fop.render.intermediate.IFException; | |||
/** | |||
* IFPainter implementation that writes SVG Print. | |||
*/ | |||
public class SVGPrintPainter extends AbstractSVGPainter { | |||
/** | |||
* Default constructor. | |||
*/ | |||
public SVGPrintPainter() { | |||
//nop | |||
} | |||
/** | |||
* Creates a new SVGPrintPainter that sends the XML content it generates to the given | |||
* SAX ContentHandler. | |||
* @param result the JAXP Result object to receive the generated content | |||
* @throws IFException if an error occurs setting up the output | |||
*/ | |||
public SVGPrintPainter(Result result) throws IFException { | |||
setResult(result); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean supportsPagesOutOfOrder() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public void startDocument() throws IFException { | |||
try { | |||
handler.startDocument(); | |||
handler.startPrefixMapping("", NAMESPACE); | |||
handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE); | |||
handler.startPrefixMapping("if", IFConstants.NAMESPACE); | |||
AttributesImpl atts = new AttributesImpl(); | |||
atts.addAttribute("", "version", "version", CDATA, "1.2"); //SVG Print is SVG 1.2 | |||
startElement("svg", atts); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startDocument()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endDocument() throws IFException { | |||
try { | |||
endElement("svg"); | |||
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("pageSet", atts); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startPageSequence()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageSequence() throws IFException { | |||
try { | |||
endElement("pageSet"); | |||
} 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); | |||
*/ | |||
//NOTE: SVG Print doesn't support individual page sizes for each page | |||
atts.addAttribute(IFConstants.NAMESPACE, "width", "if:width", | |||
CDATA, Integer.toString(size.width)); | |||
atts.addAttribute(IFConstants.NAMESPACE, "height", "if:height", | |||
CDATA, Integer.toString(size.height)); | |||
atts.addAttribute(IFConstants.NAMESPACE, "viewBox", "if:viewBox", CDATA, | |||
"0 0 " + Integer.toString(size.width) + " " + Integer.toString(size.height)); | |||
startElement("page", atts); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startPage()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageHeader() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageHeader() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageContent() throws IFException { | |||
super.startPageContent(); | |||
try { | |||
startElement("g"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in startPageContent()", e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageContent() throws IFException { | |||
try { | |||
endElement("g"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in endPageContent()", e); | |||
} | |||
super.endPageContent(); | |||
} | |||
/** {@inheritDoc} */ | |||
public void startPageTrailer() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPageTrailer() throws IFException { | |||
} | |||
/** {@inheritDoc} */ | |||
public void endPage() throws IFException { | |||
try { | |||
endElement("page"); | |||
} catch (SAXException e) { | |||
throw new IFException("SAX error in endPage()", e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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.svg; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.render.intermediate.AbstractIFPainterMaker; | |||
import org.apache.fop.render.intermediate.IFPainter; | |||
/** | |||
* Painter factory for SVG Print output. | |||
*/ | |||
public class SVGPrintPainterMaker extends AbstractIFPainterMaker { | |||
private static final String[] MIMES = new String[] {SVGConstants.MIME_SVG_PRINT}; | |||
/** {@inheritDoc} */ | |||
public IFPainter makePainter(FOUserAgent ua) { | |||
return new SVGPrintPainter(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean needsOutputStream() { | |||
return true; | |||
} | |||
/** {@inheritDoc} */ | |||
public String[] getSupportedMimeTypes() { | |||
return MIMES; | |||
} | |||
} |