diff options
Diffstat (limited to 'src/java/org/apache/fop/render/ps')
29 files changed, 2009 insertions, 1453 deletions
diff --git a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java index 75ed0de52..aa0fc88b9 100644 --- a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java +++ b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java @@ -16,7 +16,7 @@ */ /* $Id$ */ - + package org.apache.fop.render.ps; @@ -91,28 +91,28 @@ public abstract class AbstractPSTranscoder extends AbstractFOPTranscoder { * @exception TranscoderException if an error occured while transcoding */ protected void transcode(Document document, String uri, - TranscoderOutput output) + TranscoderOutput output) throws TranscoderException { graphics = createDocumentGraphics2D(); if (!isTextStroked()) { - FontInfo fontInfo = new FontInfo(); - //TODO Do custom font configuration here somewhere/somehow - FontSetup.setup(fontInfo, null, null); + FontInfo fontInfo = new FontInfo(); + //TODO Do custom font configuration here somewhere/somehow + FontSetup.setup(fontInfo); graphics.setCustomTextHandler(new NativeTextHandler(graphics, fontInfo)); } super.transcode(document, uri, output); getLogger().trace("document size: " + width + " x " + height); - + // prepare the image to be painted - UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, + UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, document.getDocumentElement()); - float widthInPt = UnitProcessor.userSpaceToSVG(width, SVGLength.SVG_LENGTHTYPE_PT, + float widthInPt = UnitProcessor.userSpaceToSVG(width, SVGLength.SVG_LENGTHTYPE_PT, UnitProcessor.HORIZONTAL_LENGTH, uctx); int w = (int)(widthInPt + 0.5); - float heightInPt = UnitProcessor.userSpaceToSVG(height, SVGLength.SVG_LENGTHTYPE_PT, + float heightInPt = UnitProcessor.userSpaceToSVG(height, SVGLength.SVG_LENGTHTYPE_PT, UnitProcessor.HORIZONTAL_LENGTH, uctx); int h = (int)(heightInPt + 0.5); getLogger().trace("document size: " + w + "pt x " + h + "pt"); @@ -140,7 +140,7 @@ public abstract class AbstractPSTranscoder extends AbstractFOPTranscoder { throw new TranscoderException(ex); } } - + /** {@inheritDoc} */ protected BridgeContext createBridgeContext() { @@ -148,7 +148,7 @@ public abstract class AbstractPSTranscoder extends AbstractFOPTranscoder { if (!isTextStroked()) { TextHandler handler = graphics.getCustomTextHandler(); if (handler instanceof NativeTextHandler) { - NativeTextHandler nativeTextHandler = (NativeTextHandler)handler; + NativeTextHandler nativeTextHandler = (NativeTextHandler)handler; PSTextPainter textPainter = new PSTextPainter(nativeTextHandler); ctx.setTextPainter(textPainter); ctx.putBridge(new PSTextElementBridge(textPainter)); diff --git a/src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java b/src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java new file mode 100644 index 000000000..ab39966d4 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/ImageEncoderCCITTFax.java @@ -0,0 +1,71 @@ +/* + * 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.ps; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.xmlgraphics.image.codec.tiff.TIFFImage; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; +import org.apache.xmlgraphics.ps.ImageEncoder; + +/** + * ImageEncoder implementation for CCITT encoded images. + */ +public class ImageEncoderCCITTFax implements ImageEncoder { + + private final ImageRawCCITTFax ccitt; + + /** + * Main constructor. + * @param ccitt the CCITT encoded image + */ + public ImageEncoderCCITTFax(ImageRawCCITTFax ccitt) { + this.ccitt = ccitt; + } + + /** {@inheritDoc} */ + public void writeTo(OutputStream out) throws IOException { + ccitt.writeTo(out); + } + + /** {@inheritDoc} */ + public String getImplicitFilter() { + PSDictionary dict = new PSDictionary(); + dict.put("/Columns", new Integer(ccitt.getSize().getWidthPx())); + int compression = ccitt.getCompression(); + switch (compression) { + case TIFFImage.COMP_FAX_G3_1D : + dict.put("/K", new Integer(0)); + break; + case TIFFImage.COMP_FAX_G3_2D : + dict.put("/K", new Integer(1)); + break; + case TIFFImage.COMP_FAX_G4_2D : + dict.put("/K", new Integer(-1)); + break; + default: + throw new IllegalStateException( + "Invalid compression scheme: " + compression); + } + + return dict.toString() + " /CCITTFaxDecode"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java b/src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java new file mode 100644 index 000000000..ef4b9f16c --- /dev/null +++ b/src/java/org/apache/fop/render/ps/ImageEncoderJPEG.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.ps; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.ps.ImageEncoder; + +/** + * ImageEncoder implementation for JPEG images. + */ +public class ImageEncoderJPEG implements ImageEncoder { + private final ImageRawJPEG jpeg; + + /** + * Main constructor + * @param jpeg the JPEG image + */ + public ImageEncoderJPEG(ImageRawJPEG jpeg) { + this.jpeg = jpeg; + } + + /** {@inheritDoc} */ + public void writeTo(OutputStream out) throws IOException { + jpeg.writeTo(out); + } + + /** {@inheritDoc} */ + public String getImplicitFilter() { + return "<< >> /DCTDecode"; + } +}
\ No newline at end of file diff --git a/src/java/org/apache/fop/render/ps/NativeTextHandler.java b/src/java/org/apache/fop/render/ps/NativeTextHandler.java index 5b840484d..9f62097e9 100644 --- a/src/java/org/apache/fop/render/ps/NativeTextHandler.java +++ b/src/java/org/apache/fop/render/ps/NativeTextHandler.java @@ -38,16 +38,16 @@ import org.apache.xmlgraphics.ps.PSGenerator; public class NativeTextHandler implements PSTextHandler { private PSGraphics2D g2d; - + /** FontInfo containing all available fonts */ protected FontInfo fontInfo; /** Currently valid Font */ protected Font font; - + /** Overriding FontState */ protected Font overrideFont = null; - + /** the current (internal) font name */ protected String currentFontName; @@ -67,13 +67,13 @@ public class NativeTextHandler implements PSTextHandler { setupFontInfo(); } } - + private void setupFontInfo() { //Sets up a FontInfo with default fonts fontInfo = new FontInfo(); - FontSetup.setup(fontInfo, null, null); + FontSetup.setup(fontInfo); } - + /** * Return the font information associated with this object * @return the FontInfo object @@ -85,7 +85,7 @@ public class NativeTextHandler implements PSTextHandler { private PSGenerator getPSGenerator() { return this.g2d.getPSGenerator(); } - + /** {@inheritDoc} */ public void writeSetup() throws IOException { if (fontInfo != null) { @@ -99,9 +99,9 @@ public class NativeTextHandler implements PSTextHandler { } /** - * Draw a string to the PostScript document. The text is painted using + * Draw a string to the PostScript document. The text is painted using * text operations. - * {@inheritDoc} + * {@inheritDoc} */ public void drawString(String s, float x, float y) throws IOException { g2d.preparePainting(); @@ -112,7 +112,7 @@ public class NativeTextHandler implements PSTextHandler { this.font = this.overrideFont; this.overrideFont = null; } - + //Color and Font state g2d.establishColor(g2d.getColor()); establishCurrentFont(); @@ -130,14 +130,14 @@ public class NativeTextHandler implements PSTextHandler { gen.writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " moveto "); gen.writeln("1 -1 scale"); - + StringBuffer sb = new StringBuffer("("); escapeText(s, sb); sb.append(") t "); gen.writeln(sb.toString()); - - gen.restoreGraphicsState(); + + gen.restoreGraphicsState(); } private void escapeText(final String text, StringBuffer target) { @@ -157,7 +157,7 @@ public class NativeTextHandler implements PSTextHandler { int fontSize = 1000 * f.getSize(); String style = f.isItalic() ? "italic" : "normal"; int weight = f.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; - + FontTriplet triplet = fontInfo.findAdjustWeight(fontFamily, style, weight); if (triplet == null) { triplet = fontInfo.findAdjustWeight("sans-serif", style, weight); @@ -166,10 +166,10 @@ public class NativeTextHandler implements PSTextHandler { } private void establishCurrentFont() throws IOException { - if ((currentFontName != this.font.getFontName()) + if ((currentFontName != this.font.getFontName()) || (currentFontSize != this.font.getFontSize())) { PSGenerator gen = getPSGenerator(); - gen.writeln(this.font.getFontName() + " " + gen.writeln(this.font.getFontName() + " " + gen.formatDouble(font.getFontSize() / 1000f) + " F"); currentFontName = this.font.getFontName(); currentFontSize = this.font.getFontSize(); @@ -183,6 +183,6 @@ public class NativeTextHandler implements PSTextHandler { public void setOverrideFont(Font override) { this.overrideFont = override; } - + } diff --git a/src/java/org/apache/fop/render/ps/PSDictionary.java b/src/java/org/apache/fop/render/ps/PSDictionary.java index dbf7173a5..5a8f1ea14 100644 --- a/src/java/org/apache/fop/render/ps/PSDictionary.java +++ b/src/java/org/apache/fop/render/ps/PSDictionary.java @@ -1,312 +1,312 @@ -/*
- * 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.ps;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.StringTokenizer;
-
-/**
- * This class is used to encapsulate postscript dictionary objects.
- */
-public class PSDictionary extends java.util.HashMap {
-
- private static final long serialVersionUID = 815367222496219197L;
-
- /**
- * This class is used to parse dictionary strings.
- */
- private static class Maker {
-
- /**
- * Simple token holding class
- */
- private class Token {
- /**
- * start index in string
- */
- private int startIndex = -1;
-
- /**
- * end index in string
- */
- private int endIndex = -1;
-
- /**
- * token string value
- */
- private String value;
- }
-
- private static final String[][] BRACES = {
- {"<<", ">>"},
- {"[", "]"},
- {"{", "}"}
- };
-
- private static final int OPENING = 0;
- private static final int CLOSING = 1;
- private static final int DICTIONARY = 0;
- private static final int ARRAY = 1;
- private static final int PROCEDURE = 2;
-
- /**
- * Returns a Token containing the start, end index and value of the next token
- * found in a given string
- *
- * @param str
- * string to search
- * @param fromIndex
- * search from index
- * @return Token containing the start, end index and value of the next token
- */
- protected Token nextToken(String str, int fromIndex) {
- Token t = null;
- for (int i = fromIndex; i < str.length(); i++) {
- boolean isWhitespace = Character.isWhitespace(str.charAt(i));
- // start index found
- if (t == null && !isWhitespace) {
- t = new Token();
- t.startIndex = i;
- // end index found
- } else if (t != null && isWhitespace) {
- t.endIndex = i;
- break;
- }
- }
- // start index found
- if (t != null) {
- // end index not found so take end of string
- if (t.endIndex == -1) {
- t.endIndex = str.length();
- }
- t.value = str.substring(t.startIndex, t.endIndex);
- }
- return t;
- }
-
- /**
- * Returns the closing brace index from a given string searches from a
- * given index
- *
- * @param str
- * string to search
- * @param braces
- * string array of opening and closing brace
- * @param fromIndex
- * searches from index
- * @return matching brace index
- * @throws org.apache.fop.render.ps.PSDictionaryFormatException
- * thrown in the event that a parsing error occurred
- */
- private int indexOfMatchingBrace(String str, String[] braces,
- int fromIndex) throws PSDictionaryFormatException {
- final int len = str.length();
- if (braces.length != 2) {
- throw new PSDictionaryFormatException("Wrong number of braces");
- }
- for (int openCnt = 0, closeCnt = 0; fromIndex < len; fromIndex++) {
- if (str.startsWith(braces[OPENING], fromIndex)) {
- openCnt++;
- } else if (str.startsWith(braces[CLOSING], fromIndex)) {
- closeCnt++;
- if (openCnt > 0 && openCnt == closeCnt) {
- return fromIndex; // found
- }
- }
- }
- return -1; // not found
- }
-
- /**
- * Strips braces from complex object string
- *
- * @param str
- * String to parse
- * @param braces
- * String array containing opening and closing braces
- * @return String with braces stripped
- * @throws
- * org.apache.fop.render.ps.PSDictionaryFormatException object format exception
- */
- private String stripBraces(String str, String[] braces) throws PSDictionaryFormatException {
- // find first opening brace
- int firstIndex = str.indexOf(braces[OPENING]);
- if (firstIndex == -1) {
- throw new PSDictionaryFormatException(
- "Failed to find opening parameter '" + braces[OPENING]
- + "");
- }
-
- // find last matching brace
- int lastIndex = indexOfMatchingBrace(str, braces, firstIndex);
- if (lastIndex == -1) {
- throw new PSDictionaryFormatException(
- "Failed to find matching closing parameter '"
- + braces[CLOSING] + "'");
- }
-
- // strip brace and trim
- int braceLen = braces[OPENING].length();
- str = str.substring(firstIndex + braceLen, lastIndex).trim();
- return str;
- }
-
- /**
- * Parses a dictionary string and provides a dictionary object
- *
- * @param str a dictionary string
- * @return A postscript dictionary object
- * @throws
- * PSDictionaryFormatException thrown if a dictionary format exception occurs
- */
- public PSDictionary parseDictionary(String str) throws PSDictionaryFormatException {
- PSDictionary dictionary = new PSDictionary();
- str = stripBraces(str.trim(), BRACES[DICTIONARY]);
- // length of dictionary string
- final int len = str.length();
-
- Token keyToken;
- for (int currIndex = 0; (keyToken = nextToken(str, currIndex)) != null
- && currIndex <= len;) {
- if (keyToken.value == null) {
- throw new PSDictionaryFormatException("Failed to parse object key");
- }
- Token valueToken = nextToken(str, keyToken.endIndex + 1);
- String[] braces = null;
- for (int i = 0; i < BRACES.length; i++) {
- if (valueToken.value.startsWith(BRACES[i][OPENING])) {
- braces = BRACES[i];
- break;
- }
- }
- Object obj = null;
- if (braces != null) {
- // find closing brace
- valueToken.endIndex = indexOfMatchingBrace(str, braces,
- valueToken.startIndex)
- + braces[OPENING].length();
- if (valueToken.endIndex < 0) {
- throw new PSDictionaryFormatException("Closing value brace '"
- + braces[CLOSING] + "' not found for key '"
- + keyToken.value + "'");
- }
- valueToken.value = str.substring(valueToken.startIndex, valueToken.endIndex);
- }
- if (braces == null || braces == BRACES[PROCEDURE]) {
- obj = valueToken.value;
- } else if (BRACES[ARRAY] == braces) {
- List objList = new java.util.ArrayList();
- String objString = stripBraces(valueToken.value, braces);
- StringTokenizer tokenizer = new StringTokenizer(objString, ",");
- while (tokenizer.hasMoreTokens()) {
- objList.add(tokenizer.nextToken());
- }
- obj = objList;
- } else if (BRACES[DICTIONARY] == braces) {
- obj = parseDictionary(valueToken.value);
- }
- dictionary.put(keyToken.value, obj);
- currIndex = valueToken.endIndex + 1;
- }
- return dictionary;
- }
- }
-
- /**
- * Parses a given a dictionary string and returns an object
- *
- * @param str dictionary string
- * @return dictionary object
- * @throws PSDictionaryFormatException object format exception
- */
- public static PSDictionary valueOf(String str) throws PSDictionaryFormatException {
- return (new Maker()).parseDictionary(str);
- }
-
- /**
- * @param obj object to test equality against
- * @return whether a given object is equal to this dictionary object
- * @see java.lang.Object#equals(Object)
- */
- public boolean equals(Object obj) {
- if (!(obj instanceof PSPageDeviceDictionary)) {
- return false;
- }
- PSDictionary dictionaryObj = (PSDictionary) obj;
- if (dictionaryObj.size() != size()) {
- return false;
- }
- for (Iterator it = keySet().iterator(); it.hasNext();) {
- String key = (String) it.next();
- if (!dictionaryObj.containsKey(key)) {
- return false;
- }
- if (!dictionaryObj.get(key).equals(get(key))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * @return a hash code value for this object.
- * @see java.lang.Object#hashCode()
- */
- public int hashCode() {
- int hashCode = 7;
- for (Iterator it = values().iterator(); it.hasNext();) {
- Object value = it.next();
- hashCode += value.hashCode();
- }
- return hashCode;
- }
-
- /**
- * @return a string representation of this dictionary
- * @see java.lang.String#toString()
- */
- public String toString() {
- if (isEmpty()) {
- return "";
- }
- StringBuffer sb = new StringBuffer("<<\n");
- for (Iterator it = super.keySet().iterator(); it.hasNext();) {
- String key = (String) it.next();
- sb.append(" " + key + " ");
- Object obj = super.get(key);
- if (obj instanceof java.util.ArrayList) {
- List array = (List)obj;
- String str = "[";
- for (int i = 0; i < array.size(); i++) {
- Object element = array.get(i);
- str += element + " ";
- }
- str = str.trim();
- str += "]";
- sb.append(str + "\n");
- } else {
- sb.append(obj.toString() + "\n");
- }
- }
- sb.append(">>");
- return sb.toString();
- }
-}
+/* + * 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.ps; + +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + +/** + * This class is used to encapsulate postscript dictionary objects. + */ +public class PSDictionary extends java.util.HashMap { + + private static final long serialVersionUID = 815367222496219197L; + + /** + * This class is used to parse dictionary strings. + */ + private static class Maker { + + /** + * Simple token holding class + */ + private class Token { + /** + * start index in string + */ + private int startIndex = -1; + + /** + * end index in string + */ + private int endIndex = -1; + + /** + * token string value + */ + private String value; + } + + private static final String[][] BRACES = { + {"<<", ">>"}, + {"[", "]"}, + {"{", "}"} + }; + + private static final int OPENING = 0; + private static final int CLOSING = 1; + private static final int DICTIONARY = 0; + private static final int ARRAY = 1; + private static final int PROCEDURE = 2; + + /** + * Returns a Token containing the start, end index and value of the next token + * found in a given string + * + * @param str + * string to search + * @param fromIndex + * search from index + * @return Token containing the start, end index and value of the next token + */ + protected Token nextToken(String str, int fromIndex) { + Token t = null; + for (int i = fromIndex; i < str.length(); i++) { + boolean isWhitespace = Character.isWhitespace(str.charAt(i)); + // start index found + if (t == null && !isWhitespace) { + t = new Token(); + t.startIndex = i; + // end index found + } else if (t != null && isWhitespace) { + t.endIndex = i; + break; + } + } + // start index found + if (t != null) { + // end index not found so take end of string + if (t.endIndex == -1) { + t.endIndex = str.length(); + } + t.value = str.substring(t.startIndex, t.endIndex); + } + return t; + } + + /** + * Returns the closing brace index from a given string searches from a + * given index + * + * @param str + * string to search + * @param braces + * string array of opening and closing brace + * @param fromIndex + * searches from index + * @return matching brace index + * @throws org.apache.fop.render.ps.PSDictionaryFormatException + * thrown in the event that a parsing error occurred + */ + private int indexOfMatchingBrace(String str, String[] braces, + int fromIndex) throws PSDictionaryFormatException { + final int len = str.length(); + if (braces.length != 2) { + throw new PSDictionaryFormatException("Wrong number of braces"); + } + for (int openCnt = 0, closeCnt = 0; fromIndex < len; fromIndex++) { + if (str.startsWith(braces[OPENING], fromIndex)) { + openCnt++; + } else if (str.startsWith(braces[CLOSING], fromIndex)) { + closeCnt++; + if (openCnt > 0 && openCnt == closeCnt) { + return fromIndex; // found + } + } + } + return -1; // not found + } + + /** + * Strips braces from complex object string + * + * @param str + * String to parse + * @param braces + * String array containing opening and closing braces + * @return String with braces stripped + * @throws + * org.apache.fop.render.ps.PSDictionaryFormatException object format exception + */ + private String stripBraces(String str, String[] braces) throws PSDictionaryFormatException { + // find first opening brace + int firstIndex = str.indexOf(braces[OPENING]); + if (firstIndex == -1) { + throw new PSDictionaryFormatException( + "Failed to find opening parameter '" + braces[OPENING] + + ""); + } + + // find last matching brace + int lastIndex = indexOfMatchingBrace(str, braces, firstIndex); + if (lastIndex == -1) { + throw new PSDictionaryFormatException( + "Failed to find matching closing parameter '" + + braces[CLOSING] + "'"); + } + + // strip brace and trim + int braceLen = braces[OPENING].length(); + str = str.substring(firstIndex + braceLen, lastIndex).trim(); + return str; + } + + /** + * Parses a dictionary string and provides a dictionary object + * + * @param str a dictionary string + * @return A postscript dictionary object + * @throws + * PSDictionaryFormatException thrown if a dictionary format exception occurs + */ + public PSDictionary parseDictionary(String str) throws PSDictionaryFormatException { + PSDictionary dictionary = new PSDictionary(); + str = stripBraces(str.trim(), BRACES[DICTIONARY]); + // length of dictionary string + final int len = str.length(); + + Token keyToken; + for (int currIndex = 0; (keyToken = nextToken(str, currIndex)) != null + && currIndex <= len;) { + if (keyToken.value == null) { + throw new PSDictionaryFormatException("Failed to parse object key"); + } + Token valueToken = nextToken(str, keyToken.endIndex + 1); + String[] braces = null; + for (int i = 0; i < BRACES.length; i++) { + if (valueToken.value.startsWith(BRACES[i][OPENING])) { + braces = BRACES[i]; + break; + } + } + Object obj = null; + if (braces != null) { + // find closing brace + valueToken.endIndex = indexOfMatchingBrace(str, braces, + valueToken.startIndex) + + braces[OPENING].length(); + if (valueToken.endIndex < 0) { + throw new PSDictionaryFormatException("Closing value brace '" + + braces[CLOSING] + "' not found for key '" + + keyToken.value + "'"); + } + valueToken.value = str.substring(valueToken.startIndex, valueToken.endIndex); + } + if (braces == null || braces == BRACES[PROCEDURE]) { + obj = valueToken.value; + } else if (BRACES[ARRAY] == braces) { + List objList = new java.util.ArrayList(); + String objString = stripBraces(valueToken.value, braces); + StringTokenizer tokenizer = new StringTokenizer(objString, ","); + while (tokenizer.hasMoreTokens()) { + objList.add(tokenizer.nextToken()); + } + obj = objList; + } else if (BRACES[DICTIONARY] == braces) { + obj = parseDictionary(valueToken.value); + } + dictionary.put(keyToken.value, obj); + currIndex = valueToken.endIndex + 1; + } + return dictionary; + } + } + + /** + * Parses a given a dictionary string and returns an object + * + * @param str dictionary string + * @return dictionary object + * @throws PSDictionaryFormatException object format exception + */ + public static PSDictionary valueOf(String str) throws PSDictionaryFormatException { + return (new Maker()).parseDictionary(str); + } + + /** + * @param obj object to test equality against + * @return whether a given object is equal to this dictionary object + * @see java.lang.Object#equals(Object) + */ + public boolean equals(Object obj) { + if (!(obj instanceof PSPageDeviceDictionary)) { + return false; + } + PSDictionary dictionaryObj = (PSDictionary) obj; + if (dictionaryObj.size() != size()) { + return false; + } + for (Iterator it = keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + if (!dictionaryObj.containsKey(key)) { + return false; + } + if (!dictionaryObj.get(key).equals(get(key))) { + return false; + } + } + return true; + } + + /** + * @return a hash code value for this object. + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + int hashCode = 7; + for (Iterator it = values().iterator(); it.hasNext();) { + Object value = it.next(); + hashCode += value.hashCode(); + } + return hashCode; + } + + /** + * @return a string representation of this dictionary + * @see java.lang.String#toString() + */ + public String toString() { + if (isEmpty()) { + return ""; + } + StringBuffer sb = new StringBuffer("<<\n"); + for (Iterator it = super.keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + sb.append(" " + key + " "); + Object obj = super.get(key); + if (obj instanceof java.util.ArrayList) { + List array = (List)obj; + String str = "["; + for (int i = 0; i < array.size(); i++) { + Object element = array.get(i); + str += element + " "; + } + str = str.trim(); + str += "]"; + sb.append(str + "\n"); + } else { + sb.append(obj.toString() + "\n"); + } + } + sb.append(">>"); + return sb.toString(); + } +} diff --git a/src/java/org/apache/fop/render/ps/PSDictionaryFormatException.java b/src/java/org/apache/fop/render/ps/PSDictionaryFormatException.java index 2153e8116..1a0171d68 100644 --- a/src/java/org/apache/fop/render/ps/PSDictionaryFormatException.java +++ b/src/java/org/apache/fop/render/ps/PSDictionaryFormatException.java @@ -1,37 +1,37 @@ -/*
- * 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.ps;
-
-/**
- * Thrown to indicate that a formatting error has occured when
- * trying to parse a postscript dictionary object
- */
-public class PSDictionaryFormatException extends Exception {
-
- private static final long serialVersionUID = 6492321557297860931L;
-
- /**
- * Default constructor
- * @param string error message
- */
- public PSDictionaryFormatException(String string) {
- super(string);
- }
-}
+/* + * 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.ps; + +/** + * Thrown to indicate that a formatting error has occured when + * trying to parse a postscript dictionary object + */ +public class PSDictionaryFormatException extends Exception { + + private static final long serialVersionUID = 6492321557297860931L; + + /** + * Default constructor + * @param string error message + */ + public PSDictionaryFormatException(String string) { + super(string); + } +} diff --git a/src/java/org/apache/fop/render/ps/PSEventProducer.java b/src/java/org/apache/fop/render/ps/PSEventProducer.java new file mode 100644 index 000000000..451ed1cea --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSEventProducer.java @@ -0,0 +1,65 @@ +/* + * 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.ps; + +import org.apache.fop.events.EventBroadcaster; +import org.apache.fop.events.EventProducer; +import org.apache.fop.events.model.AbstractEventModelFactory; +import org.apache.fop.events.model.EventModel; + +/** + * Event producer interface for events generated by the PostScript renderer. + */ +public interface PSEventProducer extends EventProducer { + + /** Provider class for the event producer. */ + class Provider { + + /** + * Returns an event producer. + * @param broadcaster the event broadcaster to use + * @return the event producer + */ + public static PSEventProducer get(EventBroadcaster broadcaster) { + return (PSEventProducer)broadcaster.getEventProducerFor( + PSEventProducer.class); + } + } + + /** Event model factory for this event producer. */ + public static class EventModelFactory extends AbstractEventModelFactory { + + /** {@inheritDoc} */ + public EventModel createEventModel() { + return loadModel(getClass(), "event-model.xml"); + } + + } + + /** + * A PostScript dictionary could not be parsed. + * @param source the event source + * @param content the PostScript content + * @param e the original exception + * @event.severity ERROR + */ + void postscriptDictionaryParseError(Object source, String content, Exception e); + +} diff --git a/src/java/org/apache/fop/render/ps/PSEventProducer.xml b/src/java/org/apache/fop/render/ps/PSEventProducer.xml new file mode 100644 index 000000000..a0078223a --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSEventProducer.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<catalogue xml:lang="en"> + <message key="org.apache.fop.render.ps.PSEventProducer.postscriptDictionaryParseError">Failed to parse dictionary string. Reason: {e}, content = "{content}"</message> +</catalogue> diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index 8fb29d302..63b12c5c8 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -31,16 +31,22 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.fonts.Glyphs; +import org.apache.xmlgraphics.ps.DSCConstants; +import org.apache.xmlgraphics.ps.PSGenerator; +import org.apache.xmlgraphics.ps.PSResource; +import org.apache.xmlgraphics.ps.dsc.ResourceTracker; + +import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontType; import org.apache.fop.fonts.LazyFont; +import org.apache.fop.fonts.SingleByteEncoding; +import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; -import org.apache.xmlgraphics.ps.DSCConstants; -import org.apache.xmlgraphics.ps.PSGenerator; -import org.apache.xmlgraphics.ps.PSResource; -import org.apache.xmlgraphics.ps.dsc.ResourceTracker; /** * Utility code for font handling in PostScript. @@ -79,9 +85,21 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { while (iter.hasNext()) { String key = (String)iter.next(); Typeface tf = getTypeFace(fontInfo, fonts, key); - PSResource fontRes = new PSResource("font", tf.getFontName()); + PSResource fontRes = new PSResource(PSResource.TYPE_FONT, tf.getFontName()); fontResources.put(key, fontRes); embedFont(gen, tf, fontRes); + + if (tf instanceof SingleByteFont) { + SingleByteFont sbf = (SingleByteFont)tf; + for (int i = 0, c = sbf.getAdditionalEncodingCount(); i < c; i++) { + SingleByteEncoding encoding = sbf.getAdditionalEncoding(i); + defineEncoding(gen, encoding); + String postFix = "_" + (i + 1); + PSResource derivedFontRes = defineDerivedFont(gen, tf.getFontName(), + tf.getFontName() + postFix, encoding.getName()); + fontResources.put(key + postFix, derivedFontRes); + } + } } gen.commentln("%FOPEndFontDict"); reencodeFonts(gen, fonts); @@ -89,27 +107,35 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } private static void reencodeFonts(PSGenerator gen, Map fonts) throws IOException { + ResourceTracker tracker = gen.getResourceTracker(); + + if (!tracker.isResourceSupplied(WINANSI_ENCODING_RESOURCE)) { + defineWinAnsiEncoding(gen); + } gen.commentln("%FOPBeginFontReencode"); - defineWinAnsiEncoding(gen); //Rewrite font encodings Iterator iter = fonts.keySet().iterator(); while (iter.hasNext()) { String key = (String)iter.next(); - Typeface fm = (Typeface)fonts.get(key); - if (fm instanceof LazyFont && ((LazyFont)fm).getRealFont() == null) { - continue; - } else if (null == fm.getEncoding()) { + Typeface tf = (Typeface)fonts.get(key); + if (tf instanceof LazyFont) { + tf = ((LazyFont)tf).getRealFont(); + if (tf == null) { + continue; + } + } + if (null == tf.getEncodingName()) { //ignore (ZapfDingbats and Symbol used to run through here, kept for safety reasons) - } else if ("SymbolEncoding".equals(fm.getEncoding())) { + } else if ("SymbolEncoding".equals(tf.getEncodingName())) { //ignore (no encoding redefinition) - } else if ("ZapfDingbatsEncoding".equals(fm.getEncoding())) { + } else if ("ZapfDingbatsEncoding".equals(tf.getEncodingName())) { //ignore (no encoding redefinition) - } else if ("WinAnsiEncoding".equals(fm.getEncoding())) { - redefineFontEncoding(gen, fm.getFontName(), fm.getEncoding()); } else { - gen.commentln("%WARNING: Only WinAnsiEncoding is supported. Font '" - + fm.getFontName() + "' asks for: " + fm.getEncoding()); + if (tf instanceof Base14Font) { + //Our Base 14 fonts don't use the default encoding + redefineFontEncoding(gen, tf.getFontName(), tf.getEncodingName()); + } } } gen.commentln("%FOPEndFontReencode"); @@ -165,8 +191,7 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { } private static boolean isEmbeddable(CustomFont font) { - return font.isEmbeddable() - && (font.getEmbedFileName() != null || font.getEmbedResourceName() != null); + return font.isEmbeddable(); } private static InputStream getInputStreamOnFont(PSGenerator gen, CustomFont font) @@ -229,10 +254,88 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (isEmbeddable(cf)) { resTracker.registerSuppliedResource(fontRes); } + if (tf instanceof SingleByteFont) { + SingleByteFont sbf = (SingleByteFont)tf; + for (int i = 0, c = sbf.getAdditionalEncodingCount(); i < c; i++) { + SingleByteEncoding encoding = sbf.getAdditionalEncoding(i); + PSResource encodingRes = new PSResource( + PSResource.TYPE_ENCODING, encoding.getName()); + resTracker.registerSuppliedResource(encodingRes); + PSResource derivedFontRes = new PSResource( + PSResource.TYPE_FONT, tf.getFontName() + "_" + (i + 1)); + resTracker.registerSuppliedResource(derivedFontRes); + } + } } } } return fontResources; } + /** + * Defines the single-byte encoding for use in PostScript files. + * @param gen the PostScript generator + * @param encoding the single-byte encoding + * @return the PSResource instance that represents the encoding + * @throws IOException In case of an I/O problem + */ + public static PSResource defineEncoding(PSGenerator gen, SingleByteEncoding encoding) + throws IOException { + PSResource res = new PSResource(PSResource.TYPE_ENCODING, encoding.getName()); + gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); + gen.writeln("/" + encoding.getName() + " ["); + String[] charNames = encoding.getCharNameMap(); + for (int i = 0; i < 256; i++) { + if (i > 0) { + if ((i % 5) == 0) { + gen.newLine(); + } else { + gen.write(" "); + } + } + String glyphname = null; + if (i < charNames.length) { + glyphname = charNames[i]; + } + if (glyphname == null || "".equals(glyphname)) { + glyphname = Glyphs.NOTDEF; + } + gen.write("/"); + gen.write(glyphname); + } + gen.newLine(); + gen.writeln("] def"); + gen.writeDSCComment(DSCConstants.END_RESOURCE); + gen.getResourceTracker().registerSuppliedResource(res); + return res; + } + + /** + * Derives a new font based on an existing font with a given encoding. The encoding must + * have been registered before. + * @param gen the PostScript generator + * @param baseFontName the font name of the font to derive from + * @param fontName the font name of the new font to be define + * @param encoding the new encoding (must be predefined in the PS file) + * @return the PSResource representing the derived font + * @throws IOException In case of an I/O problem + */ + public static PSResource defineDerivedFont(PSGenerator gen, String baseFontName, String fontName, + String encoding) throws IOException { + PSResource res = new PSResource(PSResource.TYPE_FONT, fontName); + gen.writeDSCComment(DSCConstants.BEGIN_RESOURCE, res); + gen.commentln("%XGCDependencies: font " + baseFontName); + gen.commentln("%XGC+ encoding " + encoding); + gen.writeln("/" + baseFontName + " findfont"); + gen.writeln("dup length dict begin"); + gen.writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); + gen.writeln(" /Encoding " + encoding + " def"); + gen.writeln(" currentdict"); + gen.writeln("end"); + gen.writeln("/" + fontName + " exch definefont pop"); + gen.writeDSCComment(DSCConstants.END_RESOURCE); + gen.getResourceTracker().registerSuppliedResource(res); + return res; + } + } diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java b/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java index 286bbca80..a592b4f44 100644 --- a/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/ps/PSGraphics2DAdapter.java @@ -1,93 +1,105 @@ -/*
- * 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.ps;
-
-import java.awt.Dimension;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.io.IOException;
-
-import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.RendererContext;
-import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
-import org.apache.xmlgraphics.ps.PSGenerator;
-
-/**
- * Graphics2DAdapter implementation for PostScript.
- */
-public class PSGraphics2DAdapter implements Graphics2DAdapter {
-
- private PSRenderer renderer;
-
- /**
- * Main constructor
- * @param renderer the Renderer instance to which this instance belongs
- */
- public PSGraphics2DAdapter(PSRenderer renderer) {
- this.renderer = renderer;
- }
-
- /** {@inheritDoc} */
- public void paintImage(Graphics2DImagePainter painter,
- RendererContext context,
- int x, int y, int width, int height) throws IOException {
- PSGenerator gen = renderer.gen;
-
- float fwidth = width / 1000f;
- float fheight = height / 1000f;
- float fx = x / 1000f;
- float fy = y / 1000f;
-
- // get the 'width' and 'height' attributes of the SVG document
- Dimension dim = painter.getImageSize();
- float imw = (float)dim.getWidth() / 1000f;
- float imh = (float)dim.getHeight() / 1000f;
-
- float sx = fwidth / (float)imw;
- float sy = fheight / (float)imh;
-
- gen.commentln("%FOPBeginGraphics2D");
- gen.saveGraphicsState();
- // Clip to the image area.
- gen.writeln("newpath");
- gen.defineRect(fx, fy, fwidth, fheight);
- gen.writeln("clip");
-
- // transform so that the coordinates (0,0) is from the top left
- // and positive is down and to the right. (0,0) is where the
- // viewBox puts it.
- gen.concatMatrix(sx, 0, 0, sy, fx, fy);
-
- final boolean textAsShapes = false;
- PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen);
- graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
- AffineTransform transform = new AffineTransform();
- // scale to viewbox
- transform.translate(fx, fy);
- gen.getCurrentState().concatMatrix(transform);
- Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
- painter.paint(graphics, area);
-
- gen.restoreGraphicsState();
- gen.commentln("%FOPEndGraphics2D");
- }
-
-}
+/* + * 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.ps; + +import java.awt.Dimension; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.io.IOException; + +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; +import org.apache.xmlgraphics.ps.PSGenerator; + +import org.apache.fop.render.Graphics2DAdapter; +import org.apache.fop.render.RendererContext; + +/** + * Graphics2DAdapter implementation for PostScript. + */ +public class PSGraphics2DAdapter implements Graphics2DAdapter { + + private PSGenerator gen; + private boolean clip = true; + + /** + * Main constructor + * @param renderer the Renderer instance to which this instance belongs + */ + public PSGraphics2DAdapter(PSRenderer renderer) { + this(renderer.gen, true); + } + + /** + * Constructor for use without a PSRenderer instance. + * @param gen the PostScript generator + * @param clip true if the image should be clipped + */ + public PSGraphics2DAdapter(PSGenerator gen, boolean clip) { + this.gen = gen; + this.clip = clip; + } + + /** {@inheritDoc} */ + public void paintImage(Graphics2DImagePainter painter, + RendererContext context, + int x, int y, int width, int height) throws IOException { + float fwidth = width / 1000f; + float fheight = height / 1000f; + float fx = x / 1000f; + float fy = y / 1000f; + + // get the 'width' and 'height' attributes of the SVG document + Dimension dim = painter.getImageSize(); + float imw = (float)dim.getWidth() / 1000f; + float imh = (float)dim.getHeight() / 1000f; + + float sx = fwidth / (float)imw; + float sy = fheight / (float)imh; + + gen.commentln("%FOPBeginGraphics2D"); + gen.saveGraphicsState(); + if (clip) { + // Clip to the image area. + gen.writeln("newpath"); + gen.defineRect(fx, fy, fwidth, fheight); + gen.writeln("clip"); + } + + // transform so that the coordinates (0,0) is from the top left + // and positive is down and to the right. (0,0) is where the + // viewBox puts it. + gen.concatMatrix(sx, 0, 0, sy, fx, fy); + + final boolean textAsShapes = false; + PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen); + graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + AffineTransform transform = new AffineTransform(); + // scale to viewbox + transform.translate(fx, fy); + gen.getCurrentState().concatMatrix(transform); + Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh); + painter.paint(graphics, area); + + gen.restoreGraphicsState(); + gen.commentln("%FOPEndGraphics2D"); + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSImageUtils.java b/src/java/org/apache/fop/render/ps/PSImageUtils.java deleted file mode 100644 index 0ab329077..000000000 --- a/src/java/org/apache/fop/render/ps/PSImageUtils.java +++ /dev/null @@ -1,163 +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.ps; - -import java.awt.Dimension; -import java.awt.geom.Rectangle2D; -import java.io.IOException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.fop.image.EPSImage; -import org.apache.fop.image.FopImage; -import org.apache.fop.image.JpegImage; -import org.apache.xmlgraphics.ps.PSGenerator; -import org.apache.xmlgraphics.ps.PSResource; - -/** - * Utility code for rendering images in PostScript. - */ -public class PSImageUtils extends org.apache.xmlgraphics.ps.PSImageUtils { - - /** logging instance */ - protected static Log log = LogFactory.getLog(PSImageUtils.class); - - /** - * Renders a bitmap image to PostScript. - * @param img image to render - * @param x x position - * @param y y position - * @param w width - * @param h height - * @param gen PS generator - * @throws IOException In case of an I/O problem while rendering the image - */ - public static void renderBitmapImage(FopImage img, - float x, float y, float w, float h, PSGenerator gen) - throws IOException { - boolean isJPEG = (img instanceof JpegImage && (gen.getPSLevel() >= 3)); - byte[] imgmap = convertImageToRawBitmapArray(img, isJPEG); - if (imgmap == null) { - gen.commentln("%Image data is not available: " + img); - return; //Image cannot be converted - } - - String imgDescription = img.getMimeType() + " " + img.getOriginalURI(); - Dimension imgDim = new Dimension(img.getWidth(), img.getHeight()); - Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h); - writeImage(imgmap, imgDim, imgDescription, targetRect, isJPEG, - img.getColorSpace(), gen); - } - - /** - * Renders a bitmap image (as form) to PostScript. - * @param img image to render - * @param form the form resource - * @param x x position - * @param y y position - * @param w width - * @param h height - * @param gen PS generator - * @throws IOException In case of an I/O problem while rendering the image - */ - public static void renderForm(FopImage img, PSResource form, - float x, float y, float w, float h, PSGenerator gen) - throws IOException { - Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h); - paintForm(form, targetRect, gen); - } - - /** - * Generates a form resource for a FopImage in PostScript. - * @param img image to render - * @param form the form resource - * @param gen PS generator - * @throws IOException In case of an I/O problem while rendering the image - */ - public static void generateFormResourceForImage(FopImage img, PSResource form, - PSGenerator gen) throws IOException { - boolean isJPEG = (img instanceof JpegImage && (gen.getPSLevel() >= 3)); - byte[] imgmap = convertImageToRawBitmapArray(img, isJPEG); - if (imgmap == null) { - gen.commentln("%Image data is not available: " + img); - return; //Image cannot be converted - } - - String imgDescription = img.getMimeType() + " " + img.getOriginalURI(); - Dimension imgDim = new Dimension(img.getWidth(), img.getHeight()); - writeReusableImage(imgmap, imgDim, form.getName(), imgDescription, isJPEG, - img.getColorSpace(), gen); - } - - private static byte[] convertImageToRawBitmapArray(FopImage img, boolean allowUndecodedJPEG) - throws IOException { - if (img instanceof JpegImage && allowUndecodedJPEG) { - if (!img.load(FopImage.ORIGINAL_DATA)) { - return null; - } - } else { - if (!img.load(FopImage.BITMAP)) { - return null; - } - } - byte[] imgmap; - if (img.getBitmapsSize() > 0) { - imgmap = img.getBitmaps(); - } else { - imgmap = img.getRessourceBytes(); - } - return imgmap; - } - - /** - * Renders an EPS image to PostScript. - * @param img EPS image to render - * @param x x position - * @param y y position - * @param w width - * @param h height - * @param gen PS generator - */ - public static void renderEPS(EPSImage img, - float x, float y, float w, float h, - PSGenerator gen) { - try { - if (!img.load(FopImage.ORIGINAL_DATA)) { - gen.commentln("%EPS image could not be processed: " + img); - return; - } - int[] bbox = img.getBBox(); - int bboxw = bbox[2] - bbox[0]; - int bboxh = bbox[3] - bbox[1]; - String name = img.getDocName(); - if (name == null || name.length() == 0) { - name = img.getOriginalURI(); - } - renderEPS(img.getEPSImage(), name, - x, y, w, h, - bbox[0], bbox[1], bboxw, bboxh, gen); - - } catch (Exception e) { - log.error("PSRenderer.renderImageArea(): Error rendering bitmap (" - + e.getMessage() + ")", e); - } - } - -} diff --git a/src/java/org/apache/fop/render/ps/PSPageDeviceDictionary.java b/src/java/org/apache/fop/render/ps/PSPageDeviceDictionary.java index c327423ef..88667c24d 100644 --- a/src/java/org/apache/fop/render/ps/PSPageDeviceDictionary.java +++ b/src/java/org/apache/fop/render/ps/PSPageDeviceDictionary.java @@ -1,110 +1,110 @@ -/*
- * 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.ps;
-
-/**
- * Postscript page device dictionary object
- *
- * This object is used by the postscript renderer to hold postscript page device
- * values. It can also be used to minimize the number of setpagedevice calls when
- * DSC compliance is false.
- */
-public class PSPageDeviceDictionary extends PSDictionary {
-
- private static final long serialVersionUID = 845943256485806509L;
-
- /**
- * Whether or not the contents of the dictionary are flushed on retrieval
- */
- private boolean flushOnRetrieval = false;
-
- /**
- * Dictionary content that has not been output/written yet
- */
- private PSDictionary unRetrievedContentDictionary;
-
- /**
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- * @return the previous value associated with the key or null
- * @see java.util.Map#put(Object, Object)
- */
- public Object put(Object key, Object value) {
- Object previousValue = super.put(key, value);
- if (flushOnRetrieval) {
- if (previousValue == null || !previousValue.equals(value)) {
- unRetrievedContentDictionary.put(key, value);
- }
- }
- return previousValue;
- }
-
- /**
- * @see java.util.Map#clear()
- */
- public void clear() {
- super.clear();
- if (unRetrievedContentDictionary != null) {
- unRetrievedContentDictionary.clear();
- }
- }
-
- /**
- * Returns <tt>true</tt> if this map contains no key-value mappings.
- *
- * @return <tt>true</tt> if this map contains no key-value mappings.
- */
- public boolean isEmpty() {
- if (flushOnRetrieval) {
- return unRetrievedContentDictionary.isEmpty();
- }
- return super.isEmpty();
- }
-
- /**
- * The contents of the dictionary are flushed when written
- * @param flushOnRetrieval boolean value
- */
- public void setFlushOnRetrieval(boolean flushOnRetrieval) {
- this.flushOnRetrieval = flushOnRetrieval;
- if (flushOnRetrieval) {
- unRetrievedContentDictionary = new PSDictionary();
- }
- }
-
- /**
- * Returns a dictionary string with containing all unwritten content note:
- * unnecessary writes are important as there is a device specific
- * initgraphics call by the underlying postscript interpreter on every
- * setpagedevice call which can result in blank pages etc.
- *
- * @return unwritten content dictionary string
- */
- public String getContent() {
- String content;
- if (flushOnRetrieval) {
- content = unRetrievedContentDictionary.toString();
- unRetrievedContentDictionary.clear();
- } else {
- content = super.toString();
- }
- return content;
- }
-}
+/* + * 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.ps; + +/** + * Postscript page device dictionary object + * + * This object is used by the postscript renderer to hold postscript page device + * values. It can also be used to minimize the number of setpagedevice calls when + * DSC compliance is false. + */ +public class PSPageDeviceDictionary extends PSDictionary { + + private static final long serialVersionUID = 845943256485806509L; + + /** + * Whether or not the contents of the dictionary are flushed on retrieval + */ + private boolean flushOnRetrieval = false; + + /** + * Dictionary content that has not been output/written yet + */ + private PSDictionary unRetrievedContentDictionary; + + /** + * @param key key with which the specified value is to be associated. + * @param value value to be associated with the specified key. + * @return the previous value associated with the key or null + * @see java.util.Map#put(Object, Object) + */ + public Object put(Object key, Object value) { + Object previousValue = super.put(key, value); + if (flushOnRetrieval) { + if (previousValue == null || !previousValue.equals(value)) { + unRetrievedContentDictionary.put(key, value); + } + } + return previousValue; + } + + /** + * @see java.util.Map#clear() + */ + public void clear() { + super.clear(); + if (unRetrievedContentDictionary != null) { + unRetrievedContentDictionary.clear(); + } + } + + /** + * Returns <tt>true</tt> if this map contains no key-value mappings. + * + * @return <tt>true</tt> if this map contains no key-value mappings. + */ + public boolean isEmpty() { + if (flushOnRetrieval) { + return unRetrievedContentDictionary.isEmpty(); + } + return super.isEmpty(); + } + + /** + * The contents of the dictionary are flushed when written + * @param flushOnRetrieval boolean value + */ + public void setFlushOnRetrieval(boolean flushOnRetrieval) { + this.flushOnRetrieval = flushOnRetrieval; + if (flushOnRetrieval) { + unRetrievedContentDictionary = new PSDictionary(); + } + } + + /** + * Returns a dictionary string with containing all unwritten content note: + * unnecessary writes are important as there is a device specific + * initgraphics call by the underlying postscript interpreter on every + * setpagedevice call which can result in blank pages etc. + * + * @return unwritten content dictionary string + */ + public String getContent() { + String content; + if (flushOnRetrieval) { + content = unRetrievedContentDictionary.toString(); + unRetrievedContentDictionary.clear(); + } else { + content = super.toString(); + } + return content; + } +} diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 3befb0738..a94c8b0aa 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -21,9 +21,11 @@ package org.apache.fop.render.ps; // Java import java.awt.Color; +import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.RenderedImage; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.LineNumberReader; @@ -38,12 +40,38 @@ import javax.xml.transform.Source; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; +import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS; +import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.image.loader.pipeline.ImageProviderPipeline; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; +import org.apache.xmlgraphics.ps.DSCConstants; +import org.apache.xmlgraphics.ps.ImageEncoder; +import org.apache.xmlgraphics.ps.PSGenerator; +import org.apache.xmlgraphics.ps.PSImageUtils; +import org.apache.xmlgraphics.ps.PSProcSets; +import org.apache.xmlgraphics.ps.PSResource; +import org.apache.xmlgraphics.ps.PSState; +import org.apache.xmlgraphics.ps.dsc.DSCException; +import org.apache.xmlgraphics.ps.dsc.ResourceTracker; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.area.Area; import org.apache.fop.area.BlockViewport; import org.apache.fop.area.CTM; -import org.apache.fop.area.LineArea; import org.apache.fop.area.OffDocumentExtensionAttachment; import org.apache.fop.area.OffDocumentItem; import org.apache.fop.area.PageViewport; @@ -56,33 +84,25 @@ import org.apache.fop.area.inline.Leader; 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.datatypes.URISpecification; +import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.fo.Constants; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.LazyFont; +import org.apache.fop.fonts.SingleByteFont; import org.apache.fop.fonts.Typeface; -import org.apache.fop.image.EPSImage; -import org.apache.fop.image.FopImage; -import org.apache.fop.image.ImageFactory; -import org.apache.fop.image.XMLImage; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.ImageAdapter; import org.apache.fop.render.RendererContext; +import org.apache.fop.render.RendererEventProducer; import org.apache.fop.render.ps.extensions.PSCommentAfter; import org.apache.fop.render.ps.extensions.PSCommentBefore; import org.apache.fop.render.ps.extensions.PSExtensionAttachment; import org.apache.fop.render.ps.extensions.PSSetPageDevice; import org.apache.fop.render.ps.extensions.PSSetupCode; import org.apache.fop.util.CharUtilities; -import org.apache.xmlgraphics.ps.DSCConstants; -import org.apache.xmlgraphics.ps.PSGenerator; -import org.apache.xmlgraphics.ps.PSProcSets; -import org.apache.xmlgraphics.ps.PSResource; -import org.apache.xmlgraphics.ps.PSState; -import org.apache.xmlgraphics.ps.dsc.DSCException; -import org.apache.xmlgraphics.ps.dsc.ResourceTracker; -import org.w3c.dom.Document; /** * Renderer that renders to PostScript. @@ -103,7 +123,8 @@ import org.w3c.dom.Document; * @author <a href="mailto:fop-dev@xmlgraphics.apache.org">Apache FOP Development Team</a> * @version $Id$ */ -public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAdapter { +public class PSRenderer extends AbstractPathOrientedRenderer + implements ImageAdapter, PSSupportedFlavors { /** logging instance */ private static Log log = LogFactory.getLog(PSRenderer.class); @@ -149,17 +170,22 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda /** Whether or not the safe set page device macro will be used or not */ private boolean safeSetPageDevice = false; - /** Whether or not Dublin Core Standard (dsc) compliant output is enforced */ + /** + * Whether or not PostScript Document Structuring Conventions (DSC) compliant output are + * enforced. + */ private boolean dscCompliant = true; + /** Is used to determine the document's bounding box */ + private Rectangle2D documentBoundingBox; + /** This is a collection holding all document header comments */ private Collection headerComments; /** This is a collection holding all document footer comments */ private Collection footerComments; - /** - * {@inheritDoc} - */ + + /** {@inheritDoc} */ public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); Object obj; @@ -274,7 +300,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda */ protected void handleIOTrouble(IOException ioe) { if (!ioTrouble) { - log.error("Error while writing to target file", ioe); + RendererEventProducer eventProducer = RendererEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.ioError(this, ioe); ioTrouble = true; } } @@ -305,15 +333,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda writeln("clip newpath"); } - /** - * Clip an area. - * Write a clipping operation given coordinates in the current - * transform. - * @param x the x coordinate - * @param y the y coordinate - * @param width the width of the area - * @param height the height of the area - */ + /** {@inheritDoc} */ protected void clipRect(float x, float y, float width, float height) { try { gen.defineRect(x, y, width, height); @@ -369,58 +389,188 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda } } + /** + * Indicates whether an image should be inlined or added as a PostScript form. + * @param uri the URI of the image + * @return true if the image should be inlined rather than added as a form + */ + protected boolean isImageInlined(String uri) { + return !isOptimizeResources() || uri == null || "".equals(uri); + } + + /** + * Indicates whether an image should be inlined or added as a PostScript form. + * @param info the ImageInfo object of the image + * @return true if the image should be inlined rather than added as a form + */ + protected boolean isImageInlined(ImageInfo info) { + if (isImageInlined(info.getOriginalURI())) { + return true; + } + + if (!isOptimizeResources()) { + throw new IllegalStateException("Must not get here if form support is enabled"); + } + + //Investigate choice for inline mode + ImageFlavor[] inlineFlavors = getInlineFlavors(); + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageProviderPipeline[] inlineCandidates + = manager.getPipelineFactory().determineCandidatePipelines( + info, inlineFlavors); + ImageProviderPipeline inlineChoice = manager.choosePipeline(inlineCandidates); + ImageFlavor inlineFlavor = (inlineChoice != null ? inlineChoice.getTargetFlavor() : null); + + //Investigate choice for form mode + ImageFlavor[] formFlavors = getFormFlavors(); + ImageProviderPipeline[] formCandidates + = manager.getPipelineFactory().determineCandidatePipelines( + info, formFlavors); + ImageProviderPipeline formChoice = manager.choosePipeline(formCandidates); + ImageFlavor formFlavor = (formChoice != null ? formChoice.getTargetFlavor() : null); + + //Inline if form is not supported or if a better choice is available with inline mode + return formFlavor == null || !formFlavor.equals(inlineFlavor); + } + /** {@inheritDoc} */ protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { endTextObject(); - uri = ImageFactory.getURL(uri); - ImageFactory fact = userAgent.getFactory().getImageFactory(); - FopImage fopimage = fact.getImage(uri, userAgent); - if (fopimage == null) { - return; - } - if (!fopimage.load(FopImage.DIMENSIONS)) { - return; + int x = currentIPPosition + (int)Math.round(pos.getX()); + int y = currentBPPosition + (int)Math.round(pos.getY()); + uri = URISpecification.getURL(uri); + if (log.isDebugEnabled()) { + log.debug("Handling image: " + uri); } - float x = (float)pos.getX() / 1000f; - x += currentIPPosition / 1000f; - float y = (float)pos.getY() / 1000f; - y += currentBPPosition / 1000f; - float w = (float)pos.getWidth() / 1000f; - float h = (float)pos.getHeight() / 1000f; + + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageInfo info = null; try { - String mime = fopimage.getMimeType(); - if ("text/xml".equals(mime)) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; + ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); + info = manager.getImageInfo(uri, sessionContext); + int width = (int)pos.getWidth(); + int height = (int)pos.getHeight(); + + //millipoints --> points for PostScript + float ptx = x / 1000f; + float pty = y / 1000f; + float ptw = width / 1000f; + float pth = height / 1000f; + + if (isImageInlined(info)) { + if (log.isDebugEnabled()) { + log.debug("Image " + info + " is inlined"); } - Document doc = ((XMLImage) fopimage).getDocument(); - String ns = ((XMLImage) fopimage).getNameSpace(); - - renderDocument(doc, ns, pos, foreignAttributes); - } else if ("image/svg+xml".equals(mime)) { - if (!fopimage.load(FopImage.ORIGINAL_DATA)) { - return; + //Only now fully load/prepare the image + Map hints = ImageUtil.getDefaultHints(sessionContext); + org.apache.xmlgraphics.image.loader.Image img = manager.getImage( + info, getInlineFlavors(), hints, sessionContext); + + //...and embed as inline image + if (img instanceof ImageGraphics2D) { + ImageGraphics2D imageG2D = (ImageGraphics2D)img; + RendererContext context = createRendererContext( + x, y, width, height, foreignAttributes); + getGraphics2DAdapter().paintImage(imageG2D.getGraphics2DImagePainter(), + context, x, y, width, height); + } else if (img instanceof ImageRendered) { + ImageRendered imgRend = (ImageRendered)img; + RenderedImage ri = imgRend.getRenderedImage(); + PSImageUtils.renderBitmapImage(ri, ptx, pty, ptw, pth, gen); + } else if (img instanceof ImageXMLDOM) { + ImageXMLDOM imgXML = (ImageXMLDOM)img; + renderDocument(imgXML.getDocument(), imgXML.getRootNamespace(), + pos, foreignAttributes); + } else if (img instanceof ImageRawStream) { + final ImageRawStream raw = (ImageRawStream)img; + if (raw instanceof ImageRawEPS) { + ImageRawEPS eps = (ImageRawEPS)raw; + Rectangle2D bbox = eps.getBoundingBox(); + InputStream in = raw.createInputStream(); + try { + PSImageUtils.renderEPS(in, uri, + new Rectangle2D.Float(ptx, pty, ptw, pth), + bbox, + gen); + } finally { + IOUtils.closeQuietly(in); + } + } else if (raw instanceof ImageRawCCITTFax) { + final ImageRawCCITTFax ccitt = (ImageRawCCITTFax)raw; + ImageEncoder encoder = new ImageEncoderCCITTFax(ccitt); + Rectangle2D targetRect = new Rectangle2D.Float( + ptx, pty, ptw, pth); + PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(), + uri, targetRect, + ccitt.getColorSpace(), 1, false, gen); + } else if (raw instanceof ImageRawJPEG) { + ImageRawJPEG jpeg = (ImageRawJPEG)raw; + ImageEncoder encoder = new ImageEncoderJPEG(jpeg); + Rectangle2D targetRect = new Rectangle2D.Float( + ptx, pty, ptw, pth); + PSImageUtils.writeImage(encoder, info.getSize().getDimensionPx(), + uri, targetRect, + jpeg.getColorSpace(), 8, jpeg.isInverted(), gen); + } else { + throw new UnsupportedOperationException("Unsupported raw image: " + info); + } + } else { + throw new UnsupportedOperationException("Unsupported image type: " + img); } - Document doc = ((XMLImage) fopimage).getDocument(); - String ns = ((XMLImage) fopimage).getNameSpace(); - - renderDocument(doc, ns, pos, foreignAttributes); - } else if (fopimage instanceof EPSImage) { - PSImageUtils.renderEPS((EPSImage)fopimage, x, y, w, h, gen); } else { - if (isImageInlined(uri, fopimage)) { - PSImageUtils.renderBitmapImage(fopimage, x, y, w, h, gen); - } else { - PSResource form = getFormForImage(uri, fopimage); - PSImageUtils.renderForm(fopimage, form, x, y, w, h, gen); + if (log.isDebugEnabled()) { + log.debug("Image " + info + " is embedded as a form later"); } + //Don't load image at this time, just put a form placeholder in the stream + PSResource form = getFormForImage(uri); + Rectangle2D targetRect = new Rectangle2D.Double(ptx, pty, ptw, pth); + PSImageUtils.paintForm(form, info.getSize().getDimensionPt(), targetRect, gen); } + + } catch (ImageException ie) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); + } catch (FileNotFoundException fe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); } catch (IOException ioe) { - handleIOTrouble(ioe); + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); + } + } + + private ImageFlavor[] getInlineFlavors() { + ImageFlavor[] flavors; + if (gen.getPSLevel() >= 3) { + flavors = LEVEL_3_FLAVORS_INLINE; + } else { + flavors = LEVEL_2_FLAVORS_INLINE; + } + return flavors; + } + + private ImageFlavor[] getFormFlavors() { + ImageFlavor[] flavors; + if (gen.getPSLevel() >= 3) { + flavors = LEVEL_3_FLAVORS_FORM; + } else { + flavors = LEVEL_2_FLAVORS_FORM; } + return flavors; } - protected PSResource getFormForImage(String uri, FopImage fopimage) { + /** + * Returns a PSResource instance representing a image as a PostScript form. + * @param uri the image URI + * @return a PSResource instance + */ + protected PSResource getFormForImage(String uri) { + if (uri == null || "".equals(uri)) { + throw new IllegalArgumentException("uri must not be empty or null"); + } if (this.formResources == null) { this.formResources = new java.util.HashMap(); } @@ -431,11 +581,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda } return form; } - - protected boolean isImageInlined(String uri, FopImage image) { - return !isOptimizeResources(); - } - + /** {@inheritDoc} */ public void paintImage(RenderedImage image, RendererContext context, int x, int y, int width, int height) throws IOException { @@ -477,6 +623,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda /** Restores the last graphics state of the rendering engine. */ public void restoreGraphicsState() { try { + endTextObject(); //delegate gen.restoreGraphicsState(); } catch (IOException ioe) { @@ -515,7 +662,22 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda } } + /** {@inheritDoc} */ + protected void concatenateTransformationMatrix(AffineTransform at) { + try { + gen.concatMatrix(at); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + private String getPostScriptNameForFontKey(String key) { + int pos = key.indexOf('_'); + String postFix = null; + if (pos > 0) { + postFix = key.substring(pos); + key = key.substring(0, pos); + } Map fonts = fontInfo.getFonts(); Typeface tf = (Typeface)fonts.get(key); if (tf instanceof LazyFont) { @@ -524,7 +686,11 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda if (tf == null) { throw new IllegalStateException("Font not available: " + key); } - return tf.getFontName(); + if (postFix == null) { + return tf.getFontName(); + } else { + return tf.getFontName() + postFix; + } } /** @@ -554,7 +720,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda protected void useFont(String key, int size) { try { PSResource res = getPSResourceForFontKey(key); - //gen.useFont(key, size / 1000f); gen.useFont("/" + res.getName(), size / 1000f); gen.getResourceTracker().notifyResourceUsageOnPage(res); } catch (IOException ioe) { @@ -776,6 +941,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()}); gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(gen.getPSLevel())); gen.writeDSCComment(DSCConstants.PAGES, new Object[] {DSCConstants.ATEND}); + gen.writeDSCComment(DSCConstants.BBOX, DSCConstants.ATEND); + gen.writeDSCComment(DSCConstants.HIRES_BBOX, DSCConstants.ATEND); + this.documentBoundingBox = new Rectangle2D.Double(); gen.writeDSCComment(DSCConstants.DOCUMENT_SUPPLIED_RESOURCES, new Object[] {DSCConstants.ATEND}); if (headerComments != null) { @@ -804,7 +972,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda if (!isOptimizeResources()) { this.fontResources = PSFontUtils.writeFontDict(gen, fontInfo); } else { - gen.commentln("%FOPFontSetup"); + gen.commentln("%FOPFontSetup"); //Place-holder, will be replaced in the second pass } gen.writeDSCComment(DSCConstants.END_SETUP); } @@ -833,6 +1001,8 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda footerComments.clear(); } gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.currentPageNumber)); + new DSCCommentBoundingBox(this.documentBoundingBox).generate(gen); + new DSCCommentHiResBoundingBox(this.documentBoundingBox).generate(gen); gen.getResourceTracker().writeResources(false, gen); gen.writeDSCComment(DSCConstants.EOF); gen.flush(); @@ -863,7 +1033,8 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda try { try { ResourceHandler.process(this.userAgent, in, this.outputStream, - this.fontInfo, resTracker, this.formResources, this.currentPageNumber); + this.fontInfo, resTracker, this.formResources, + this.currentPageNumber, this.documentBoundingBox); this.outputStream.flush(); } catch (DSCException e) { throw new RuntimeException(e.getMessage()); @@ -910,8 +1081,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda try { this.pageDeviceDictionary.putAll(PSDictionary.valueOf(content)); } catch (PSDictionaryFormatException e) { - log.error("Failed to parse dictionary string: " - + e.getMessage() + ", content = '" + content + "'"); + PSEventProducer eventProducer = PSEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.postscriptDictionaryParseError(this, content, e); } } } else if (attachment instanceof PSCommentBefore) { @@ -931,11 +1103,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda super.processOffDocumentItem(oDI); } - /** {@inheritDoc} */ - public void startPageSequence(LineArea seqTitle) { - super.startPageSequence(seqTitle); - } - /** * Formats and writes a List of PSSetupCode instances to the output stream. * @param setupCodeList a List of PSSetupCode instances @@ -1014,8 +1181,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda try { pageDeviceDictionary.putAll(PSDictionary.valueOf(content)); } catch (PSDictionaryFormatException e) { - log.error("failed to parse dictionary string: " - + e.getMessage() + ", [" + content + "]"); + PSEventProducer eventProducer = PSEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.postscriptDictionaryParseError(this, content, e); } } } @@ -1031,7 +1199,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda log.error(e.getMessage()); } final Integer zero = new Integer(0); + Rectangle2D pageBoundingBox = new Rectangle2D.Double(); if (rotate) { + pageBoundingBox.setRect(0, 0, pageHeight, pageWidth); gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] { zero, zero, new Long(Math.round(pageHeight)), new Long(Math.round(pageWidth)) }); @@ -1040,6 +1210,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda new Double(pageWidth) }); gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape"); } else { + pageBoundingBox.setRect(0, 0, pageWidth, pageHeight); gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] { zero, zero, new Long(Math.round(pageWidth)), new Long(Math.round(pageHeight)) }); @@ -1051,6 +1222,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda "Portrait"); } } + this.documentBoundingBox.add(pageBoundingBox); gen.writeDSCComment(DSCConstants.PAGE_RESOURCES, new Object[] {DSCConstants.ATEND}); @@ -1132,9 +1304,9 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda /** Indicates the end of a text object. */ protected void endTextObject() { if (inTextMode) { + inTextMode = false; //set before restoreGraphicsState() to avoid recursion writeln("ET"); restoreGraphicsState(); - inTextMode = false; } } @@ -1143,17 +1315,16 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda */ public void renderText(TextArea area) { renderInlineAreaBackAndBorders(area); - String fontname = getInternalFontNameForArea(area); + String fontkey = getInternalFontNameForArea(area); int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE); // This assumes that *all* CIDFonts use a /ToUnicode mapping - Typeface tf = (Typeface) fontInfo.getFonts().get(fontname); + Typeface tf = (Typeface) fontInfo.getFonts().get(fontkey); //Determine position int rx = currentIPPosition + area.getBorderAndPaddingWidthStart(); int bl = currentBPPosition + area.getOffset() + area.getBaselineOffset(); - useFont(fontname, fontsize); Color ct = (Color)area.getTrait(Trait.COLOR); if (ct != null) { try { @@ -1198,30 +1369,75 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda super.renderSpace(space); } + private Typeface getTypeface(String fontName) { + Typeface tf = (Typeface)fontInfo.getFonts().get(fontName); + if (tf instanceof LazyFont) { + tf = ((LazyFont)tf).getRealFont(); + } + return tf; + } + private void renderText(AbstractTextArea area, String text, int[] letterAdjust) { + String fontkey = getInternalFontNameForArea(area); + int fontSize = area.getTraitAsInteger(Trait.FONT_SIZE); Font font = getFontFromArea(area); - Typeface tf = (Typeface) fontInfo.getFonts().get(font.getFontName()); + Typeface tf = getTypeface(font.getFontName()); + SingleByteFont singleByteFont = null; + if (tf instanceof SingleByteFont) { + singleByteFont = (SingleByteFont)tf; + } + + int textLen = text.length(); + if (singleByteFont != null && singleByteFont.hasAdditionalEncodings()) { + int start = 0; + int currentEncoding = -1; + for (int i = 0; i < textLen; i++) { + char c = text.charAt(i); + char mapped = tf.mapChar(c); + int encoding = mapped / 256; + if (currentEncoding != encoding) { + if (i > 0) { + writeText(area, text, start, i - start, letterAdjust, fontSize, tf); + } + if (encoding == 0) { + useFont(fontkey, fontSize); + } else { + useFont(fontkey + "_" + Integer.toString(encoding), fontSize); + } + currentEncoding = encoding; + start = i; + } + } + writeText(area, text, start, textLen - start, letterAdjust, fontSize, tf); + } else { + useFont(fontkey, fontSize); + writeText(area, text, 0, textLen, letterAdjust, fontSize, tf); + } + } + private void writeText(AbstractTextArea area, String text, int start, int len, + int[] letterAdjust, int fontsize, Typeface tf) { + int end = start + len; int initialSize = text.length(); initialSize += initialSize / 2; StringBuffer sb = new StringBuffer(initialSize); - int textLen = text.length(); if (letterAdjust == null && area.getTextLetterSpaceAdjust() == 0 && area.getTextWordSpaceAdjust() == 0) { sb.append("("); - for (int i = 0; i < textLen; i++) { + for (int i = start; i < end; i++) { final char c = text.charAt(i); - final char mapped = tf.mapChar(c); + final char mapped = (char)(tf.mapChar(c) % 256); PSGenerator.escapeChar(mapped, sb); } sb.append(") t"); } else { sb.append("("); - int[] offsets = new int[textLen]; - for (int i = 0; i < textLen; i++) { + int[] offsets = new int[len]; + for (int i = start; i < end; i++) { final char c = text.charAt(i); final char mapped = tf.mapChar(c); + char codepoint = (char)(mapped % 256); int wordSpace; if (CharUtilities.isAdjustableSpace(mapped)) { @@ -1229,14 +1445,14 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda } else { wordSpace = 0; } - int cw = tf.getWidth(mapped, font.getFontSize()) / 1000; - int ladj = (letterAdjust != null && i < textLen - 1 ? letterAdjust[i + 1] : 0); - int tls = (i < textLen - 1 ? area.getTextLetterSpaceAdjust() : 0); - offsets[i] = cw + ladj + tls + wordSpace; - PSGenerator.escapeChar(mapped, sb); + int cw = tf.getWidth(mapped, fontsize) / 1000; + int ladj = (letterAdjust != null && i < end - 1 ? letterAdjust[i + 1] : 0); + int tls = (i < end - 1 ? area.getTextLetterSpaceAdjust() : 0); + offsets[i - start] = cw + ladj + tls + wordSpace; + PSGenerator.escapeChar(codepoint, sb); } sb.append(")" + PSGenerator.LF + "["); - for (int i = 0; i < textLen; i++) { + for (int i = 0; i < len; i++) { if (i > 0) { if (i % 8 == 0) { sb.append(PSGenerator.LF); @@ -1249,7 +1465,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda sb.append("]" + PSGenerator.LF + "xshow"); } writeln(sb.toString()); - } /** {@inheritDoc} */ @@ -1314,7 +1529,6 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda * {@inheritDoc} */ protected void endVParea() { - endTextObject(); restoreGraphicsState(); } @@ -1491,13 +1705,14 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda } /** - * Sets whether or not Dublin Core Standard (dsc) compliance is enforced. - * - * It can cause problems (unwanted postscript subsystem initgraphics/erasepage calls) + * Sets whether or not PostScript Document Structuring Conventions (dsc) compliance are + * enforced. + * <p> + * It can cause problems (unwanted PostScript subsystem initgraphics/erasepage calls) * on some printers when the pagedevice is set. If this causes problems on a * particular implementation then use this setting with a 'false' value to try and * minimize the number of setpagedevice calls in the postscript document output. - * + * <p> * Set this value to false if you experience unwanted blank pages in your * postscript output. * @param dscCompliant boolean value (default is true) diff --git a/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java index e94d873cb..3ce9751b5 100644 --- a/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java +++ b/src/java/org/apache/fop/render/ps/PSRendererConfigurator.java @@ -15,7 +15,7 @@ * limitations under the License. */ -/* $Id: $ */ +/* $Id$ */ package org.apache.fop.render.ps; diff --git a/src/java/org/apache/fop/render/ps/PSRendererMaker.java b/src/java/org/apache/fop/render/ps/PSRendererMaker.java index d879c054c..657a65f70 100644 --- a/src/java/org/apache/fop/render/ps/PSRendererMaker.java +++ b/src/java/org/apache/fop/render/ps/PSRendererMaker.java @@ -1,54 +1,54 @@ -/*
- * 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.ps;
-
-import org.apache.fop.apps.FOUserAgent;
-import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.render.AbstractRendererMaker;
-import org.apache.fop.render.Renderer;
-import org.apache.fop.render.RendererConfigurator;
-
-/**
- * RendererMaker for the PostScript Renderer.
- */
-public class PSRendererMaker extends AbstractRendererMaker {
-
- private static final String[] MIMES = new String[] {MimeConstants.MIME_POSTSCRIPT};
-
- /** {@inheritDoc} */
- public Renderer makeRenderer(FOUserAgent userAgent) {
- return new PSRenderer();
- }
-
- /** {@inheritDoc} */
- public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
- return new PSRendererConfigurator(userAgent);
- }
-
- /** {@inheritDoc} */
- public boolean needsOutputStream() {
- return true;
- }
-
- /** {@inheritDoc} */
- public String[] getSupportedMimeTypes() {
- return MIMES;
- }
-}
+/* + * 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.ps; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; +import org.apache.fop.render.AbstractRendererMaker; +import org.apache.fop.render.Renderer; +import org.apache.fop.render.RendererConfigurator; + +/** + * RendererMaker for the PostScript Renderer. + */ +public class PSRendererMaker extends AbstractRendererMaker { + + private static final String[] MIMES = new String[] {MimeConstants.MIME_POSTSCRIPT}; + + /** {@inheritDoc} */ + public Renderer makeRenderer(FOUserAgent userAgent) { + return new PSRenderer(); + } + + /** {@inheritDoc} */ + public RendererConfigurator getConfigurator(FOUserAgent userAgent) { + return new PSRendererConfigurator(userAgent); + } + + /** {@inheritDoc} */ + public boolean needsOutputStream() { + return true; + } + + /** {@inheritDoc} */ + public String[] getSupportedMimeTypes() { + return MIMES; + } +} diff --git a/src/java/org/apache/fop/render/ps/PSSVGHandler.java b/src/java/org/apache/fop/render/ps/PSSVGHandler.java index 5cfe617c8..ebe098282 100644 --- a/src/java/org/apache/fop/render/ps/PSSVGHandler.java +++ b/src/java/org/apache/fop/render/ps/PSSVGHandler.java @@ -23,31 +23,24 @@ package org.apache.fop.render.ps; import java.awt.geom.AffineTransform; import java.io.IOException; -// DOM import org.w3c.dom.Document; -import org.w3c.dom.svg.SVGDocument; -import org.w3c.dom.svg.SVGSVGElement; -// Batik import org.apache.avalon.framework.configuration.Configuration; -import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.BridgeContext; -import org.apache.batik.bridge.ViewBox; -import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.gvt.GraphicsNode; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; +import org.apache.xmlgraphics.ps.PSGenerator; -// FOP import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.AbstractGenericSVGHandler; import org.apache.fop.render.Renderer; -import org.apache.fop.render.XMLHandler; import org.apache.fop.render.RendererContext; +import org.apache.fop.svg.SVGEventProducer; import org.apache.fop.svg.SVGUserAgent; -import org.apache.xmlgraphics.java2d.ps.PSGraphics2D; -import org.apache.xmlgraphics.ps.PSGenerator; - -// Commons-Logging -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * PostScript XML handler for SVG. Uses Apache Batik for SVG processing. @@ -57,7 +50,8 @@ import org.apache.commons.logging.LogFactory; * * @version $Id$ */ -public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { +public class PSSVGHandler extends AbstractGenericSVGHandler + implements PSRendererContextConstants { /** logging instance */ private static Log log = LogFactory.getLog(PSSVGHandler.class); @@ -68,16 +62,6 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { public PSSVGHandler() { } - /** {@inheritDoc} */ - public void handleXML(RendererContext context, - Document doc, String ns) throws Exception { - PSInfo psi = getPSInfo(context); - - if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) { - renderSVGDocument(context, doc, psi); - } - } - /** * Get the pdf information from the render context. * @@ -234,10 +218,10 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { * Render the svg document. * @param context the renderer context * @param doc the svg document - * @param psInfo the pdf information of the current context */ protected void renderSVGDocument(RendererContext context, - Document doc, PSInfo psInfo) { + Document doc) { + PSInfo psInfo = getPSInfo(context); int xOffset = psInfo.currentXPosition; int yOffset = psInfo.currentYPosition; PSGenerator gen = psInfo.psGenerator; @@ -250,9 +234,7 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { } SVGUserAgent ua - = new SVGUserAgent( - context.getUserAgent().getSourcePixelUnitToMillimeter(), - new AffineTransform()); + = new SVGUserAgent(context.getUserAgent(), new AffineTransform()); PSGraphics2D graphics = new PSGraphics2D(strokeText, gen); graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); @@ -273,8 +255,9 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { try { root = builder.build(ctx, doc); } catch (Exception e) { - log.error("SVG graphic could not be built: " - + e.getMessage(), e); + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + context.getUserAgent().getEventBroadcaster()); + eventProducer.svgNotBuilt(this, e, getDocumentURI(doc)); return; } // get the 'width' and 'height' attributes of the SVG document @@ -305,10 +288,10 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { // viewBox puts it. gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f); + /* SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, - psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f); - /* + psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f, ctx); if (!at.isIdentity()) { double[] vals = new double[6]; at.getMatrix(vals); @@ -322,15 +305,17 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { try { root.paint(graphics); } catch (Exception e) { - log.error("SVG graphic could not be rendered: " - + e.getMessage(), e); + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + context.getUserAgent().getEventBroadcaster()); + eventProducer.svgRenderingError(this, e, getDocumentURI(doc)); } gen.restoreGraphicsState(); gen.commentln("%FOPEndSVG"); } catch (IOException ioe) { - log.error("SVG graphic could not be rendered: " - + ioe.getMessage(), ioe); + SVGEventProducer eventProducer = SVGEventProducer.Provider.get( + context.getUserAgent().getEventBroadcaster()); + eventProducer.svgRenderingError(this, ioe, getDocumentURI(doc)); } } @@ -339,10 +324,5 @@ public class PSSVGHandler implements XMLHandler, PSRendererContextConstants { return (renderer instanceof PSRenderer); } - /** {@inheritDoc} */ - public String getNamespace() { - return SVGDOMImplementation.SVG_NAMESPACE_URI; - } - } diff --git a/src/java/org/apache/fop/render/ps/PSSupportedFlavors.java b/src/java/org/apache/fop/render/ps/PSSupportedFlavors.java new file mode 100644 index 000000000..8ccfa8e26 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSSupportedFlavors.java @@ -0,0 +1,67 @@ +/* + * 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.ps; + +import org.apache.xmlgraphics.image.loader.ImageFlavor; + +/** + * Defines the set of supported ImageFlavors for the PostScript renderer. + */ +public interface PSSupportedFlavors { + + /** The flavors supported inline with PostScript level 2. */ + ImageFlavor[] LEVEL_2_FLAVORS_INLINE = new ImageFlavor[] + {ImageFlavor.RAW_EPS, + ImageFlavor.RAW_CCITTFAX, + ImageFlavor.GRAPHICS2D, + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE, + ImageFlavor.XML_DOM}; + + /** The flavors supported inline with PostScript level 3 and higher. */ + ImageFlavor[] LEVEL_3_FLAVORS_INLINE = new ImageFlavor[] + {ImageFlavor.RAW_EPS, + ImageFlavor.RAW_JPEG, + ImageFlavor.RAW_CCITTFAX, + ImageFlavor.GRAPHICS2D, + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE, + ImageFlavor.XML_DOM}; + + /** The flavors supported as forms with PostScript level 2. */ + ImageFlavor[] LEVEL_2_FLAVORS_FORM = new ImageFlavor[] + {//ImageFlavor.RAW_EPS, + ImageFlavor.RAW_CCITTFAX, + ImageFlavor.GRAPHICS2D, + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE/*, + ImageFlavor.XML_DOM*/}; + + /** The flavors supported as forms with PostScript level 3 or higher. */ + ImageFlavor[] LEVEL_3_FLAVORS_FORM = new ImageFlavor[] + {//ImageFlavor.RAW_EPS, + ImageFlavor.RAW_JPEG, + ImageFlavor.RAW_CCITTFAX, + ImageFlavor.GRAPHICS2D, + ImageFlavor.BUFFERED_IMAGE, + ImageFlavor.RENDERED_IMAGE/*, + ImageFlavor.XML_DOM*/}; + +} diff --git a/src/java/org/apache/fop/render/ps/ResourceHandler.java b/src/java/org/apache/fop/render/ps/ResourceHandler.java index f187e619a..1a363c90e 100644 --- a/src/java/org/apache/fop/render/ps/ResourceHandler.java +++ b/src/java/org/apache/fop/render/ps/ResourceHandler.java @@ -19,6 +19,9 @@ package org.apache.fop.render.ps; +import java.awt.geom.Dimension2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -26,12 +29,25 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; -import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.image.FopImage; -import org.apache.fop.image.ImageFactory; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax; +import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS; +import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.xmlgraphics.ps.DSCConstants; +import org.apache.xmlgraphics.ps.FormGenerator; +import org.apache.xmlgraphics.ps.ImageEncoder; +import org.apache.xmlgraphics.ps.ImageFormGenerator; import org.apache.xmlgraphics.ps.PSGenerator; +import org.apache.xmlgraphics.ps.PSProcSets; import org.apache.xmlgraphics.ps.dsc.DSCException; import org.apache.xmlgraphics.ps.dsc.DSCFilter; import org.apache.xmlgraphics.ps.dsc.DSCParser; @@ -39,8 +55,10 @@ import org.apache.xmlgraphics.ps.dsc.DSCParserConstants; import org.apache.xmlgraphics.ps.dsc.DefaultNestedDocumentHandler; import org.apache.xmlgraphics.ps.dsc.ResourceTracker; import org.apache.xmlgraphics.ps.dsc.events.DSCComment; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentNeededResources; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentDocumentSuppliedResources; +import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentLanguageLevel; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPage; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentPages; @@ -49,13 +67,17 @@ import org.apache.xmlgraphics.ps.dsc.events.DSCHeaderComment; import org.apache.xmlgraphics.ps.dsc.events.PostScriptComment; import org.apache.xmlgraphics.ps.dsc.tools.DSCTools; +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.events.ResourceEventProducer; +import org.apache.fop.fonts.FontInfo; + /** * This class is used when two-pass production is used to generate the PostScript file (setting * "optimize-resources"). It uses the DSC parser from XML Graphics Commons to go over the * temporary file generated by the PSRenderer and adds all used fonts and images as resources * to the PostScript file. */ -public class ResourceHandler implements DSCParserConstants { +public class ResourceHandler implements DSCParserConstants, PSSupportedFlavors { /** * Rewrites the temporary PostScript file generated by PSRenderer adding all needed resources @@ -67,11 +89,14 @@ public class ResourceHandler implements DSCParserConstants { * @param resTracker the resource tracker to use * @param formResources Contains all forms used by this document (maintained by PSRenderer) * @param pageCount the number of pages (given here because PSRenderer writes an "(atend)") + * @param documentBoundingBox the document's bounding box + * (given here because PSRenderer writes an "(atend)") * @throws DSCException If there's an error in the DSC structure of the PS file * @throws IOException In case of an I/O error */ public static void process(FOUserAgent userAgent, InputStream in, OutputStream out, - FontInfo fontInfo, ResourceTracker resTracker, Map formResources, int pageCount) + FontInfo fontInfo, ResourceTracker resTracker, Map formResources, + int pageCount, Rectangle2D documentBoundingBox) throws DSCException, IOException { DSCParser parser = new DSCParser(in); PSGenerator gen = new PSGenerator(out); @@ -86,6 +111,8 @@ public class ResourceHandler implements DSCParserConstants { { //We rewrite those as part of the processing filtered.add(DSCConstants.PAGES); + filtered.add(DSCConstants.BBOX); + filtered.add(DSCConstants.HIRES_BBOX); filtered.add(DSCConstants.DOCUMENT_NEEDED_RESOURCES); filtered.add(DSCConstants.DOCUMENT_SUPPLIED_RESOURCES); } @@ -109,6 +136,8 @@ public class ResourceHandler implements DSCParserConstants { //Set number of pages DSCCommentPages pages = new DSCCommentPages(pageCount); pages.generate(gen); + new DSCCommentBoundingBox(documentBoundingBox).generate(gen); + new DSCCommentHiResBoundingBox(documentBoundingBox).generate(gen); PSFontUtils.determineSuppliedFonts(resTracker, fontInfo, fontInfo.getUsedFonts()); registerSuppliedForms(resTracker, formResources); @@ -197,13 +226,132 @@ public class ResourceHandler implements DSCParserConstants { Iterator iter = formResources.values().iterator(); while (iter.hasNext()) { PSImageFormResource form = (PSImageFormResource)iter.next(); - ImageFactory fact = userAgent.getFactory().getImageFactory(); - FopImage image = fact.getImage(form.getImageURI(), userAgent); - if (image == null) { - throw new NullPointerException("Image not found: " + form.getImageURI()); + final String uri = form.getImageURI(); + + ImageManager manager = userAgent.getFactory().getImageManager(); + ImageInfo info = null; + try { + ImageSessionContext sessionContext = userAgent.getImageSessionContext(); + info = manager.getImageInfo(uri, sessionContext); + + ImageFlavor[] flavors; + if (gen.getPSLevel() >= 3) { + flavors = LEVEL_3_FLAVORS_FORM; + } else { + flavors = LEVEL_2_FLAVORS_FORM; + } + Map hints = ImageUtil.getDefaultHints(sessionContext); + org.apache.xmlgraphics.image.loader.Image img = manager.getImage( + info, flavors, hints, sessionContext); + + String imageDescription = info.getMimeType() + " " + info.getOriginalURI(); + final Dimension2D dimensionsPt = info.getSize().getDimensionPt(); + final Dimension2D dimensionsMpt = info.getSize().getDimensionMpt(); + + if (img instanceof ImageGraphics2D) { + final ImageGraphics2D imageG2D = (ImageGraphics2D)img; + FormGenerator formGen = new FormGenerator( + form.getName(), imageDescription, dimensionsPt) { + + protected void generatePaintProc(PSGenerator gen) + throws IOException { + gen.getResourceTracker().notifyResourceUsageOnPage( + PSProcSets.EPS_PROCSET); + gen.writeln("BeginEPSF"); + PSGraphics2DAdapter adapter = new PSGraphics2DAdapter(gen, false); + adapter.paintImage(imageG2D.getGraphics2DImagePainter(), + null, + 0, 0, + (int)Math.round(dimensionsMpt.getWidth()), + (int)Math.round(dimensionsMpt.getHeight())); + gen.writeln("EndEPSF"); + } + + }; + formGen.generate(gen); + } else if (img instanceof ImageRendered) { + ImageRendered imgRend = (ImageRendered)img; + RenderedImage ri = imgRend.getRenderedImage(); + FormGenerator formGen = new ImageFormGenerator( + form.getName(), imageDescription, + info.getSize().getDimensionPt(), + ri, false); + formGen.generate(gen); + } else if (img instanceof ImageXMLDOM) { + throw new UnsupportedOperationException( + "Embedding an ImageXMLDOM as a form isn't supported, yet"); + } else if (img instanceof ImageRawStream) { + final ImageRawStream raw = (ImageRawStream)img; + if (raw instanceof ImageRawEPS) { + final ImageRawEPS eps = (ImageRawEPS)raw; + throw new UnsupportedOperationException( + "Embedding EPS as forms isn't supported, yet"); + /* + InputStream in = eps.createInputStream(); + try { + FormGenerator formGen = new EPSFormGenerator(form.getName(), + imageDescription, dimensions, in); + formGen.generate(gen); + } finally { + IOUtils.closeQuietly(in); + }*/ + } else if (raw instanceof ImageRawCCITTFax) { + ImageRawCCITTFax jpeg = (ImageRawCCITTFax)raw; + ImageEncoder encoder = new ImageEncoderCCITTFax(jpeg); + FormGenerator formGen = new ImageFormGenerator( + form.getName(), imageDescription, + info.getSize().getDimensionPt(), + info.getSize().getDimensionPx(), + encoder, + jpeg.getColorSpace(), 1, false); + formGen.generate(gen); + } else if (raw instanceof ImageRawJPEG) { + ImageRawJPEG jpeg = (ImageRawJPEG)raw; + ImageEncoder encoder = new ImageEncoderJPEG(jpeg); + FormGenerator formGen = new ImageFormGenerator( + form.getName(), imageDescription, + info.getSize().getDimensionPt(), + info.getSize().getDimensionPx(), + encoder, + jpeg.getColorSpace(), jpeg.isInverted()); + formGen.generate(gen); + } else { + throw new UnsupportedOperationException("Unsupported raw image: " + info); + } + } else { + throw new UnsupportedOperationException("Unsupported image type: " + img); + } + } catch (ImageException ie) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + userAgent.getEventBroadcaster()); + eventProducer.imageError(resTracker, (info != null ? info.toString() : uri), + ie, null); } - PSImageUtils.generateFormResourceForImage(image, form, gen); } } + private static FormGenerator createMissingForm(String formName, final Dimension2D dimensions) { + FormGenerator formGen = new FormGenerator(formName, null, dimensions) { + + protected void generatePaintProc(PSGenerator gen) throws IOException { + gen.writeln("0 setgray"); + gen.writeln("0 setlinewidth"); + String w = gen.formatDouble(dimensions.getWidth()); + String h = gen.formatDouble(dimensions.getHeight()); + gen.writeln(w + " " + h + " scale"); + gen.writeln("0 0 1 1 rectstroke"); + gen.writeln("newpath"); + gen.writeln("0 0 moveto"); + gen.writeln("1 1 lineto"); + gen.writeln("stroke"); + gen.writeln("newpath"); + gen.writeln("0 1 moveto"); + gen.writeln("1 0 lineto"); + gen.writeln("stroke"); + } + + }; + return formGen; + } + } diff --git a/src/java/org/apache/fop/render/ps/extensions/AbstractPSCommentElement.java b/src/java/org/apache/fop/render/ps/extensions/AbstractPSCommentElement.java index a6e77fb13..1eb1d9d13 100644 --- a/src/java/org/apache/fop/render/ps/extensions/AbstractPSCommentElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/AbstractPSCommentElement.java @@ -22,7 +22,6 @@ package org.apache.fop.render.ps.extensions; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.ValidationException; /** * Base postscript commment element class @@ -46,8 +45,8 @@ public abstract class AbstractPSCommentElement extends AbstractPSExtensionElemen protected void startOfNode() throws FOPException { if (parent.getNameId() != Constants.FO_DECLARATIONS && parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) { - throw new ValidationException(getName() - + " must be a child of fo:declarations or fo:simple-page-master."); + invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), + "rule.childOfSPMorDeclarations"); } } diff --git a/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionElement.java b/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionElement.java index f2a9c56d9..31e44d2d2 100644 --- a/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionElement.java @@ -1,133 +1,133 @@ -/*
- * 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: AbstractPSExtensionObject.java 426576 2006-07-28 15:44:37Z jeremias $ */
-
-package org.apache.fop.render.ps.extensions;
-
-// FOP
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.PropertyList;
-import org.apache.fop.fo.ValidationException;
-import org.apache.fop.fo.extensions.ExtensionAttachment;
-
-import org.xml.sax.Locator;
-
-/**
- * Base class for the PostScript-specific extension elements.
- */
-public abstract class AbstractPSExtensionElement extends FONode {
-
- /**
- * extension attachment
- */
- protected PSExtensionAttachment attachment;
-
- /**
- * Default constructor
- *
- * @param parent parent of this node
- * @see org.apache.fop.fo.FONode#FONode(FONode)
- */
- public AbstractPSExtensionElement(FONode parent) {
- super(parent);
- }
-
- /**
- * Blocks XSL FO's from having non-FO parents.
- *
- * @param loc location in the FO source file
- * @param nsURI namespace of incoming node
- * @param localName (e.g. "table" for "fo:table")
- * @throws ValidationException if incoming node not valid for parent
- * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
- */
- protected void validateChildNode(Locator loc, String nsURI, String localName)
- throws ValidationException {
- if (FO_URI.equals(nsURI)) {
- invalidChildError(loc, nsURI, localName);
- }
- }
-
- /**
- * Adds characters (does nothing here)
- * @param data array of characters containing text to be added
- * @param start starting array element to add
- * @param length of data array to add
- * @param pList currently applicable PropertyList
- * @param locator location in fo source file.
- * @see org.apache.fop.fo.FONode#addCharacters(char[], int, int, PropertyList, Locator)
- */
- protected void addCharacters(char[] data, int start, int length,
- PropertyList pList, Locator locator) {
- PSExtensionAttachment a = (PSExtensionAttachment)getExtensionAttachment();
- if (a.getContent() != null) {
- StringBuffer sb = new StringBuffer(a.getContent());
- sb.append(data, start, length - start);
- a.setContent(sb.toString());
- } else {
- a.setContent(new String(data, start, length - start));
- }
- }
-
- /**
- * @return a String representation of this object
- * @see org.apache.fop.fo.FONode#getNamespaceURI()
- */
- public String getNamespaceURI() {
- return PSExtensionElementMapping.NAMESPACE;
- }
-
- /**
- * @return a String representation of this object
- * @see org.apache.fop.fo.FONode#getNormalNamespacePrefix()
- */
- public String getNormalNamespacePrefix() {
- return "fox";
- }
-
- /**
- * @see org.apache.fop.fo.FONode#endOfNode()
- * @throws FOPException if there's a problem during processing
- */
- protected void endOfNode() throws FOPException {
- super.endOfNode();
- String s = ((PSExtensionAttachment)getExtensionAttachment()).getContent();
- if (s == null || s.length() == 0) {
- missingChildElementError("#PCDATA");
- }
- }
-
- /**
- * @return the extension attachment if one is created by the extension element, null otherwise.
- * @see org.apache.fop.fo.FONode#getExtensionAttachment()
- */
- public ExtensionAttachment getExtensionAttachment() {
- if (attachment == null) {
- this.attachment = (PSExtensionAttachment)instantiateExtensionAttachment();
- }
- return this.attachment;
- }
-
- /**
- * Instantiates extension attachment object
- * @return extension attachment
- */
- protected abstract ExtensionAttachment instantiateExtensionAttachment();
-}
-
+/* + * 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.ps.extensions; + +// FOP +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.extensions.ExtensionAttachment; + +/** + * Base class for the PostScript-specific extension elements. + */ +public abstract class AbstractPSExtensionElement extends FONode { + + /** + * extension attachment + */ + protected PSExtensionAttachment attachment; + + /** + * Default constructor + * + * @param parent parent of this node + * @see org.apache.fop.fo.FONode#FONode(FONode) + */ + public AbstractPSExtensionElement(FONode parent) { + super(parent); + } + + /** + * Blocks XSL FO's from having non-FO parents. + * + * @param loc location in the FO source file + * @param nsURI namespace of incoming node + * @param localName (e.g. "table" for "fo:table") + * @throws ValidationException if incoming node not valid for parent + * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) + */ + protected void validateChildNode(Locator loc, String nsURI, String localName) + throws ValidationException { + if (FO_URI.equals(nsURI)) { + invalidChildError(loc, nsURI, localName); + } + } + + /** + * Adds characters (does nothing here) + * @param data array of characters containing text to be added + * @param start starting array element to add + * @param length of data array to add + * @param pList currently applicable PropertyList + * @param locator location in fo source file. + * @see org.apache.fop.fo.FONode#addCharacters(char[], int, int, PropertyList, Locator) + */ + protected void addCharacters(char[] data, int start, int length, + PropertyList pList, Locator locator) { + PSExtensionAttachment a = (PSExtensionAttachment)getExtensionAttachment(); + if (a.getContent() != null) { + StringBuffer sb = new StringBuffer(a.getContent()); + sb.append(data, start, length - start); + a.setContent(sb.toString()); + } else { + a.setContent(new String(data, start, length - start)); + } + } + + /** + * @return a String representation of this object + * @see org.apache.fop.fo.FONode#getNamespaceURI() + */ + public String getNamespaceURI() { + return PSExtensionElementMapping.NAMESPACE; + } + + /** + * @return a String representation of this object + * @see org.apache.fop.fo.FONode#getNormalNamespacePrefix() + */ + public String getNormalNamespacePrefix() { + return "ps"; + } + + /** + * @see org.apache.fop.fo.FONode#endOfNode() + * @throws FOPException if there's a problem during processing + */ + protected void endOfNode() throws FOPException { + super.endOfNode(); + String s = ((PSExtensionAttachment)getExtensionAttachment()).getContent(); + if (s == null || s.length() == 0) { + missingChildElementError("#PCDATA"); + } + } + + /** + * @return the extension attachment if one is created by the extension element, null otherwise. + * @see org.apache.fop.fo.FONode#getExtensionAttachment() + */ + public ExtensionAttachment getExtensionAttachment() { + if (attachment == null) { + this.attachment = (PSExtensionAttachment)instantiateExtensionAttachment(); + } + return this.attachment; + } + + /** + * Instantiates extension attachment object + * @return extension attachment + */ + protected abstract ExtensionAttachment instantiateExtensionAttachment(); +} + diff --git a/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionObject.java b/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionObject.java index 6823d75d9..78b2f91eb 100644 --- a/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionObject.java +++ b/src/java/org/apache/fop/render/ps/extensions/AbstractPSExtensionObject.java @@ -20,13 +20,14 @@ package org.apache.fop.render.ps.extensions; // FOP +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FONode; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.extensions.ExtensionAttachment; -import org.xml.sax.Attributes; -import org.xml.sax.Locator; /** * Base class for the PostScript-specific extension elements. @@ -36,15 +37,15 @@ public abstract class AbstractPSExtensionObject extends FONode { private PSSetupCode setupCode = new PSSetupCode(); /** + * Main constructor. + * @param parent the parent node * @see org.apache.fop.fo.FONode#FONode(FONode) */ public AbstractPSExtensionObject(FONode parent) { super(parent); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void validateChildNode(Locator loc, String nsURI, String localName) throws ValidationException { if (FO_URI.equals(nsURI)) { @@ -71,7 +72,7 @@ public abstract class AbstractPSExtensionObject extends FONode { /**{@inheritDoc} */ public String getNormalNamespacePrefix() { - return "fox"; + return "ps"; } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java b/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java index 306cd7bda..1dd0f4be6 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSCommentAfterElement.java @@ -27,6 +27,7 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; */ public class PSCommentAfterElement extends AbstractPSCommentElement { + /** the element name */ protected static final String ELEMENT = "ps-comment-after"; /** diff --git a/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java b/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java index 6058f355b..5d3c863f5 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSCommentBeforeElement.java @@ -27,6 +27,7 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; */ public class PSCommentBeforeElement extends AbstractPSCommentElement { + /** the element name */ protected static final String ELEMENT = "ps-comment-before"; /** diff --git a/src/java/org/apache/fop/render/ps/extensions/PSExtensionAttachment.java b/src/java/org/apache/fop/render/ps/extensions/PSExtensionAttachment.java index 0fb623bdc..3fccf4f67 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSExtensionAttachment.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSExtensionAttachment.java @@ -1,108 +1,110 @@ -/*
- * 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.ps.extensions;
-
-import org.apache.fop.fo.extensions.ExtensionAttachment;
-import org.apache.fop.util.XMLizable;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * This is the pass-through value object for the PostScript extension.
- */
-public abstract class PSExtensionAttachment implements ExtensionAttachment, XMLizable {
-
- /** extension node content */
- protected String content;
-
- /** The category URI for this extension attachment. */
- public static final String CATEGORY = "apache:fop:extensions:postscript";
-
- /**
- * Default constructor.
- * @param content the content of the setup code object
- */
- public PSExtensionAttachment(String content) {
- this.content = content;
- }
-
- /**
- * No-argument contructor.
- */
- public PSExtensionAttachment() {
- }
-
- /**
- * @return the category URI
- * @see org.apache.fop.fo.extensions.ExtensionAttachment#getCategory()
- */
- public String getCategory() {
- return CATEGORY;
- }
-
- /** @return the content */
- public String getContent() {
- return content;
- }
-
- /**
- * Sets the content for the setup code object.
- * @param content The content to set.
- */
- public void setContent(String content) {
- this.content = content;
- }
-
- /**
- * Generates SAX events representing the object's state.
- *
- * @param handler ContentHandler instance to send the SAX events to
- * @throws SAXException if there's a problem generating the SAX events
- * @see org.apache.fop.util.XMLizable#toSAX(org.xml.sax.ContentHandler)
- */
- public void toSAX(ContentHandler handler) throws SAXException {
- AttributesImpl atts = new AttributesImpl();
- String element = getElement();
- handler.startElement(CATEGORY, element, element, atts);
- if (content != null && content.length() > 0) {
- char[] chars = content.toCharArray();
- handler.characters(chars, 0, chars.length);
- }
- handler.endElement(CATEGORY, element, element);
- }
-
- /** @return type name */
- public String getType() {
- String className = getClass().getName();
- return className.substring(className.lastIndexOf('.') + 3);
- }
-
- /**
- * @return a string representation of this object
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return getType() + ": content=" + content;
- }
-
- /** @return element */
- protected abstract String getElement();
-}
+/* + * 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.ps.extensions; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import org.apache.xmlgraphics.util.XMLizable; + +import org.apache.fop.fo.extensions.ExtensionAttachment; + +/** + * This is the pass-through value object for the PostScript extension. + */ +public abstract class PSExtensionAttachment implements ExtensionAttachment, XMLizable { + + /** extension node content */ + protected String content; + + /** The category URI for this extension attachment. */ + public static final String CATEGORY = "apache:fop:extensions:postscript"; + + /** + * Default constructor. + * @param content the content of the setup code object + */ + public PSExtensionAttachment(String content) { + this.content = content; + } + + /** + * No-argument contructor. + */ + public PSExtensionAttachment() { + } + + /** + * @return the category URI + * @see org.apache.fop.fo.extensions.ExtensionAttachment#getCategory() + */ + public String getCategory() { + return CATEGORY; + } + + /** @return the content */ + public String getContent() { + return content; + } + + /** + * Sets the content for the setup code object. + * @param content The content to set. + */ + public void setContent(String content) { + this.content = content; + } + + /** + * Generates SAX events representing the object's state. + * + * @param handler ContentHandler instance to send the SAX events to + * @throws SAXException if there's a problem generating the SAX events + * @see org.apache.fop.util.XMLizable#toSAX(org.xml.sax.ContentHandler) + */ + public void toSAX(ContentHandler handler) throws SAXException { + AttributesImpl atts = new AttributesImpl(); + String element = getElement(); + handler.startElement(CATEGORY, element, element, atts); + if (content != null && content.length() > 0) { + char[] chars = content.toCharArray(); + handler.characters(chars, 0, chars.length); + } + handler.endElement(CATEGORY, element, element); + } + + /** @return type name */ + public String getType() { + String className = getClass().getName(); + return className.substring(className.lastIndexOf('.') + 3); + } + + /** + * @return a string representation of this object + * @see java.lang.Object#toString() + */ + public String toString() { + return getType() + ": content=" + content; + } + + /** @return element */ + protected abstract String getElement(); +} diff --git a/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java b/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java index 72f665a0f..e69500736 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSExtensionHandler.java @@ -15,17 +15,19 @@ * limitations under the License. */ -/* $Id: $ */ +/* $Id$ */ package org.apache.fop.render.ps.extensions; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.util.ContentHandlerFactory; import org.apache.fop.util.ContentHandlerFactory.ObjectBuiltListener; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; /** * ContentHandler (parser) for restoring PSExtension objects from XML. @@ -91,25 +93,19 @@ public class PSExtensionHandler extends DefaultHandler content.append(ch, start, length); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void endDocument() throws SAXException { if (listener != null) { listener.notifyObjectBuilt(getObject()); } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public Object getObject() { return returnedObject; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void setObjectBuiltListener(ObjectBuiltListener listener) { this.listener = listener; } diff --git a/src/java/org/apache/fop/render/ps/extensions/PSPageSetupCodeElement.java b/src/java/org/apache/fop/render/ps/extensions/PSPageSetupCodeElement.java index ad46b9364..207c11e76 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSPageSetupCodeElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSPageSetupCodeElement.java @@ -22,13 +22,13 @@ package org.apache.fop.render.ps.extensions; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.ValidationException; /** * Extension element for fox:ps-page-setup-code. */ public class PSPageSetupCodeElement extends AbstractPSExtensionObject { + /** The element name */ protected static final String ELEMENT = "ps-page-setup-code"; /** @@ -43,7 +43,8 @@ public class PSPageSetupCodeElement extends AbstractPSExtensionObject { protected void startOfNode() throws FOPException { super.startOfNode(); if (parent.getNameId() != Constants.FO_SIMPLE_PAGE_MASTER) { - throw new ValidationException(getName() + " must be a child of fo:simple-page-master."); + invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), + "rule.childOfSPM"); } } diff --git a/src/java/org/apache/fop/render/ps/extensions/PSSetPageDevice.java b/src/java/org/apache/fop/render/ps/extensions/PSSetPageDevice.java index 5684ba6a3..28ea3c24c 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSSetPageDevice.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSSetPageDevice.java @@ -1,114 +1,114 @@ -/*
- * 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.ps.extensions;
-
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-/**
- * Element for postscript setpagedevice instruction
- * This is a an extension which provides a pass-through value
- * dictionary object for the postscript setpagedevice instruction.
- */
-public class PSSetPageDevice extends PSExtensionAttachment {
- /** element name */
- protected static final String ELEMENT = "ps-setpagedevice";
-
- private static final String ATT_NAME = "name";
-
- /**
- * name attribute
- */
- protected String name = null;
-
- /**
- * default constructor
- * @param content set page device dictionary
- */
- public PSSetPageDevice(String content) {
- super(content);
- }
-
- /**
- * constructor
- * @param name name attribute of this setpagedevice content
- * @param content set page device dictionary
- */
- public PSSetPageDevice(String name, String content) {
- this(content);
- this.name = name;
- }
-
- /**
- * constructor
- */
- public PSSetPageDevice() {
- }
-
- /** @return the name */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the name of the setup code object.
- * @param name The name to set.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * @return a string representation of this object
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return "PSSetPageDevice(name=" + getName() + ", content='" + getContent() + "')";
- }
-
- /**
- * @return a string representation of this object
- * @see org.apache.fop.render.ps.extensions.PSExtensionAttachment#getElement()
- */
- protected String getElement() {
- return ELEMENT;
- }
-
- /**
- * Generates SAX events representing the object's state.
- * @param handler ContentHandler instance to send the SAX events to
- * @throws SAXException if there's a problem generating the SAX events
- * @see org.apache.fop.util.XMLizable#toSAX(org.xml.sax.ContentHandler)
- */
- public void toSAX(ContentHandler handler) throws SAXException {
- AttributesImpl atts = new AttributesImpl();
- if (name != null && name.length() > 0) {
- atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name);
- }
- String element = getElement();
- handler.startElement(CATEGORY, element, element, atts);
- if (content != null && content.length() > 0) {
- char[] chars = content.toCharArray();
- handler.characters(chars, 0, chars.length);
- }
- handler.endElement(CATEGORY, element, element);
- }
-}
+/* + * 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.ps.extensions; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * Element for postscript setpagedevice instruction + * This is a an extension which provides a pass-through value + * dictionary object for the postscript setpagedevice instruction. + */ +public class PSSetPageDevice extends PSExtensionAttachment { + /** element name */ + protected static final String ELEMENT = "ps-setpagedevice"; + + private static final String ATT_NAME = "name"; + + /** + * name attribute + */ + protected String name = null; + + /** + * default constructor + * @param content set page device dictionary + */ + public PSSetPageDevice(String content) { + super(content); + } + + /** + * constructor + * @param name name attribute of this setpagedevice content + * @param content set page device dictionary + */ + public PSSetPageDevice(String name, String content) { + this(content); + this.name = name; + } + + /** + * constructor + */ + public PSSetPageDevice() { + } + + /** @return the name */ + public String getName() { + return name; + } + + /** + * Sets the name of the setup code object. + * @param name The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return a string representation of this object + * @see java.lang.Object#toString() + */ + public String toString() { + return "PSSetPageDevice(name=" + getName() + ", content='" + getContent() + "')"; + } + + /** + * @return a string representation of this object + * @see org.apache.fop.render.ps.extensions.PSExtensionAttachment#getElement() + */ + protected String getElement() { + return ELEMENT; + } + + /** + * Generates SAX events representing the object's state. + * @param handler ContentHandler instance to send the SAX events to + * @throws SAXException if there's a problem generating the SAX events + * @see org.apache.xmlgraphics.util.XMLizable#toSAX(org.xml.sax.ContentHandler) + */ + public void toSAX(ContentHandler handler) throws SAXException { + AttributesImpl atts = new AttributesImpl(); + if (name != null && name.length() > 0) { + atts.addAttribute(null, ATT_NAME, ATT_NAME, "CDATA", name); + } + String element = getElement(); + handler.startElement(CATEGORY, element, element, atts); + if (content != null && content.length() > 0) { + char[] chars = content.toCharArray(); + handler.characters(chars, 0, chars.length); + } + handler.endElement(CATEGORY, element, element); + } +} diff --git a/src/java/org/apache/fop/render/ps/extensions/PSSetPageDeviceElement.java b/src/java/org/apache/fop/render/ps/extensions/PSSetPageDeviceElement.java index ff7e8f792..21acc8001 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSSetPageDeviceElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSSetPageDeviceElement.java @@ -1,95 +1,96 @@ -/*
- * 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.ps.extensions;
-
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.PropertyList;
-import org.apache.fop.fo.ValidationException;
-import org.apache.fop.fo.extensions.ExtensionAttachment;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-
-/**
- * Extension element for ps:ps-setpagedevice.
- */
-public class PSSetPageDeviceElement extends AbstractPSExtensionElement {
-
- protected static final String ELEMENT = "ps-setpagedevice";
-
- /**
- * Main constructor
- * @param parent parent FO node
- */
- protected PSSetPageDeviceElement(FONode parent) {
- super(parent);
- }
-
- /**
- * Called after processNode() is called. Subclasses can do additional processing.
- * @throws FOPException if there's a problem during processing
- * @see org.apache.fop.fo.FONode#startOfNode()
- */
- protected void startOfNode() throws FOPException {
- super.startOfNode();
- if ( !((parent.getNameId() == Constants.FO_DECLARATIONS)
- || (parent.getNameId() == Constants.FO_SIMPLE_PAGE_MASTER)) ) {
- throw new ValidationException( getName()
- + " must be a child of fo:declarations or fo:simple-page-master.");
- }
- }
-
- /**
- * Initialize the node with its name, location information, and attributes
- * The attributes must be used immediately as the sax attributes
- * will be altered for the next element.
- * @param elementName element name (e.g., "fo:block")
- * @param locator Locator object (ignored by default)
- * @param attlist Collection of attributes passed to us from the parser.
- * @param propertyList property list
- * @throws FOPException if there's a problem during processing
- * @see org.apache.fop.fo.FONode#processNode
- */
- public void processNode(String elementName, Locator locator,
- Attributes attlist, PropertyList propertyList)
- throws FOPException {
- String name = attlist.getValue("name");
- if (name != null && name.length() > 0) {
- ((PSSetPageDevice)getExtensionAttachment()).setName(name);
- }
- }
-
- /**
- * @return local name
- * @see org.apache.fop.fo.FONode#getLocalName() */
- public String getLocalName() {
- return ELEMENT;
- }
-
- /**
- * @return a new PSSetPageDevice object
- * @see org.apache.fop.render.ps.extensions.AbstractPSExtensionElement
- * #instantiateExtensionAttachment()
- */
- protected ExtensionAttachment instantiateExtensionAttachment() {
- return new PSSetPageDevice();
- }
-}
+/* + * 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.ps.extensions; + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.extensions.ExtensionAttachment; + +/** + * Extension element for ps:ps-setpagedevice. + */ +public class PSSetPageDeviceElement extends AbstractPSExtensionElement { + + /** The element name */ + protected static final String ELEMENT = "ps-setpagedevice"; + + /** + * Main constructor + * @param parent parent FO node + */ + protected PSSetPageDeviceElement(FONode parent) { + super(parent); + } + + /** + * Called after processNode() is called. Subclasses can do additional processing. + * @throws FOPException if there's a problem during processing + * @see org.apache.fop.fo.FONode#startOfNode() + */ + protected void startOfNode() throws FOPException { + super.startOfNode(); + if ( !((parent.getNameId() == Constants.FO_DECLARATIONS) + || (parent.getNameId() == Constants.FO_SIMPLE_PAGE_MASTER)) ) { + invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), + "rule.childOfSPMorDeclarations"); + } + } + + /** + * Initialize the node with its name, location information, and attributes + * The attributes must be used immediately as the sax attributes + * will be altered for the next element. + * @param elementName element name (e.g., "fo:block") + * @param locator Locator object (ignored by default) + * @param attlist Collection of attributes passed to us from the parser. + * @param propertyList property list + * @throws FOPException if there's a problem during processing + * @see org.apache.fop.fo.FONode#processNode + */ + public void processNode(String elementName, Locator locator, + Attributes attlist, PropertyList propertyList) + throws FOPException { + String name = attlist.getValue("name"); + if (name != null && name.length() > 0) { + ((PSSetPageDevice)getExtensionAttachment()).setName(name); + } + } + + /** + * @return local name + * @see org.apache.fop.fo.FONode#getLocalName() */ + public String getLocalName() { + return ELEMENT; + } + + /** + * @return a new PSSetPageDevice object + * @see org.apache.fop.render.ps.extensions.AbstractPSExtensionElement + * #instantiateExtensionAttachment() + */ + protected ExtensionAttachment instantiateExtensionAttachment() { + return new PSSetPageDevice(); + } +} diff --git a/src/java/org/apache/fop/render/ps/extensions/PSSetupCodeElement.java b/src/java/org/apache/fop/render/ps/extensions/PSSetupCodeElement.java index ec7216c44..e76dfeb64 100644 --- a/src/java/org/apache/fop/render/ps/extensions/PSSetupCodeElement.java +++ b/src/java/org/apache/fop/render/ps/extensions/PSSetupCodeElement.java @@ -22,13 +22,13 @@ package org.apache.fop.render.ps.extensions; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.ValidationException; /** * Extension element for fox:ps-setup-code. */ public class PSSetupCodeElement extends AbstractPSExtensionObject { + /** The element name */ protected static final String ELEMENT = "ps-setup-code"; /** @@ -43,7 +43,8 @@ public class PSSetupCodeElement extends AbstractPSExtensionObject { protected void startOfNode() throws FOPException { super.startOfNode(); if (parent.getNameId() != Constants.FO_DECLARATIONS) { - throw new ValidationException(getName() + " must be a child of fo:declarations."); + invalidChildError(getLocator(), parent.getName(), getNamespaceURI(), getName(), + "rule.childOfDeclarations"); } } |