aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/render/ps
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2003-03-11 13:05:43 +0000
committerJeremias Maerki <jeremias@apache.org>2003-03-11 13:05:43 +0000
commit1e5d512c216d329effa693b91ef64652945def6a (patch)
tree5bd3521ee8121eade7bf1909ceaf29cfc0263fd1 /src/java/org/apache/fop/render/ps
parent73c824d39411bf11ad0c2f4e1c57cd9c484665f9 (diff)
downloadxmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.tar.gz
xmlgraphics-fop-1e5d512c216d329effa693b91ef64652945def6a.zip
Moved sources from src/org/** to src/java/org/**
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196061 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/render/ps')
-rw-r--r--src/java/org/apache/fop/render/ps/ASCII85OutputStream.java254
-rw-r--r--src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java134
-rw-r--r--src/java/org/apache/fop/render/ps/DSCConstants.java202
-rw-r--r--src/java/org/apache/fop/render/ps/Finalizable.java74
-rw-r--r--src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java85
-rw-r--r--src/java/org/apache/fop/render/ps/PSGenerator.java371
-rw-r--r--src/java/org/apache/fop/render/ps/PSGraphics2D.java1134
-rw-r--r--src/java/org/apache/fop/render/ps/PSProcSets.java200
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderer.java901
-rw-r--r--src/java/org/apache/fop/render/ps/PSState.java97
-rw-r--r--src/java/org/apache/fop/render/ps/PSTextElementBridge.java159
-rw-r--r--src/java/org/apache/fop/render/ps/PSTextPainter.java435
-rw-r--r--src/java/org/apache/fop/render/ps/PSXMLHandler.java379
-rw-r--r--src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java217
14 files changed, 4642 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/render/ps/ASCII85OutputStream.java b/src/java/org/apache/fop/render/ps/ASCII85OutputStream.java
new file mode 100644
index 000000000..7a0c2aeef
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/ASCII85OutputStream.java
@@ -0,0 +1,254 @@
+/*
+ * $Id: ASCII85OutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.OutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+
+/**
+ * This class applies a ASCII85 encoding to the stream.
+ *
+ * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a>
+ * @version $Id: ASCII85OutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class ASCII85OutputStream extends FilterOutputStream
+ implements Finalizable {
+
+ private static final int ZERO = 0x7A; //"z"
+ private static final byte[] ZERO_ARRAY = {(byte)ZERO};
+ private static final int START = 0x21; //"!"
+ private static final int EOL = 0x0A; //"\n"
+ private static final byte[] EOD = {0x7E, 0x3E}; //"~>"
+
+ private static final long BASE85_4 = 85;
+ private static final long BASE85_3 = BASE85_4 * BASE85_4;
+ private static final long BASE85_2 = BASE85_3 * BASE85_4;
+ private static final long BASE85_1 = BASE85_2 * BASE85_4;
+
+ private static final boolean DEBUG = false;
+
+ private int pos = 0;
+ private long buffer = 0;
+ private int posinline = 0;
+ private int bw = 0;
+
+
+ /** @see java.io.FilterOutputStream **/
+ public ASCII85OutputStream(OutputStream out) {
+ super(out);
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void write(int b) throws IOException {
+ if (pos == 0) {
+ buffer += (b << 24) & 0xff000000L;
+ } else if (pos == 1) {
+ buffer += (b << 16) & 0xff0000L;
+ } else if (pos == 2) {
+ buffer += (b << 8) & 0xff00L;
+ } else {
+ buffer += b & 0xffL;
+ }
+ pos++;
+
+ if (pos > 3) {
+ checkedWrite(convertWord(buffer));
+ buffer = 0;
+ pos = 0;
+ }
+ }
+
+
+ private void checkedWrite(int b) throws IOException {
+ if (posinline == 80) {
+ out.write(EOL); bw++;
+ posinline = 0;
+ }
+ checkedWrite(b);
+ posinline++;
+ bw++;
+ }
+
+
+ private void checkedWrite(byte[] buf) throws IOException {
+ checkedWrite(buf, buf.length);
+ }
+
+
+ private void checkedWrite(byte[] buf , int len) throws IOException {
+ if (posinline + len > 80) {
+ int firstpart = len - (posinline + len - 80);
+ if (firstpart > 0) {
+ out.write(buf, 0, firstpart);
+ }
+ out.write(EOL); bw++;
+ int rest = len - firstpart;
+ if (rest > 0) {
+ out.write(buf, firstpart, rest);
+ }
+ posinline = rest;
+ } else {
+ out.write(buf, 0, len);
+ posinline += len;
+ }
+ bw += len;
+ }
+
+
+ /**
+ * This converts a 32 bit value (4 bytes) into 5 bytes using base 85.
+ * each byte in the result starts with zero at the '!' character so
+ * the resulting base85 number fits into printable ascii chars
+ *
+ * @param word the 32 bit unsigned (hence the long datatype) word
+ * @return 5 bytes (or a single byte of the 'z' character for word
+ * values of 0)
+ */
+ private byte[] convertWord(long word) {
+ word = word & 0xffffffff;
+
+ if (word == 0) {
+ return ZERO_ARRAY;
+ } else {
+ if (word < 0) {
+ word = -word;
+ }
+ byte c1 = (byte)((word / BASE85_1) & 0xFF);
+ byte c2 = (byte)(((word - (c1 * BASE85_1)) / BASE85_2) & 0xFF);
+ byte c3 =
+ (byte)(((word - (c1 * BASE85_1) - (c2 * BASE85_2))
+ / BASE85_3) & 0xFF);
+ byte c4 =
+ (byte)(((word - (c1 * BASE85_1) - (c2 * BASE85_2) - (c3 * BASE85_3))
+ / BASE85_4) & 0xFF);
+ byte c5 =
+ (byte)(((word - (c1 * BASE85_1) - (c2 * BASE85_2) - (c3 * BASE85_3)
+ - (c4 * BASE85_4)))
+ & 0xFF);
+
+ byte[] ret = {
+ (byte)(c1 + START), (byte)(c2 + START),
+ (byte)(c3 + START), (byte)(c4 + START),
+ (byte)(c5 + START)
+ };
+
+ if (DEBUG) {
+ for (int i = 0; i < ret.length; i++) {
+ if (ret[i] < 33 || ret[i] > 117) {
+ System.out.println("Illegal char value "
+ + new Integer(ret[i]));
+ }
+ }
+ }
+ return ret;
+ }
+ }
+
+
+ /** @see org.apache.fop.render.ps.Finalizable **/
+ public void finalizeStream() throws IOException {
+ // now take care of the trailing few bytes.
+ // with n leftover bytes, we append 0 bytes to make a full group of 4
+ // then convert like normal (except not applying the special zero rule)
+ // and write out the first n+1 bytes from the result
+ if (pos > 0) {
+ int rest = pos;
+ /*
+ byte[] lastdata = new byte[4];
+ int i = 0;
+ for (int j = 0; j < 4; j++) {
+ if (j < rest) {
+ lastdata[j] = data[i++];
+ } else {
+ lastdata[j] = 0;
+ }
+ }
+
+ long val = ((lastdata[0] << 24) & 0xff000000L)
+ + ((lastdata[1] << 16) & 0xff0000L)
+ + ((lastdata[2] << 8) & 0xff00L)
+ + (lastdata[3] & 0xffL);
+ */
+
+ byte[] conv;
+ // special rule for handling zeros at the end
+ if (buffer != 0) {
+ conv = convertWord(buffer);
+ } else {
+ conv = new byte[5];
+ for (int j = 0; j < 5; j++) {
+ conv[j] = (byte)'!';
+ }
+ }
+ // assert rest+1 <= 5
+ checkedWrite(conv, rest + 1);
+ }
+ // finally write the two character end of data marker
+ checkedWrite(EOD);
+
+ flush();
+ if (out instanceof Finalizable) {
+ ((Finalizable)out).finalizeStream();
+ }
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void close() throws IOException {
+ finalizeStream();
+ super.close();
+ }
+
+}
+
+
diff --git a/src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java b/src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java
new file mode 100644
index 000000000..1be3766b0
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/ASCIIHexOutputStream.java
@@ -0,0 +1,134 @@
+/*
+ * $Id: ASCIIHexOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.OutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+
+/**
+ * This class applies a ASCII Hex encoding to the stream.
+ *
+ * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a>
+ * @version $Id: ASCIIHexOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class ASCIIHexOutputStream extends FilterOutputStream
+ implements Finalizable {
+
+ private static final int EOL = 0x0A; //"\n"
+ private static final int EOD = 0x3E; //">"
+ private static final int ZERO = 0x30; //"0"
+ private static final int NINE = 0x39; //"9"
+ private static final int A = 0x41; //"A"
+ private static final int ADIFF = A - NINE - 1;
+
+ private int posinline = 0;
+
+
+ /** @see java.io.FilterOutputStream **/
+ public ASCIIHexOutputStream(OutputStream out) {
+ super(out);
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void write(int b) throws IOException {
+ b &= 0xFF;
+
+ int digit1 = ((b & 0xF0) >> 4) + ZERO;
+ if (digit1 > NINE) {
+ digit1 += ADIFF;
+ }
+ out.write(digit1);
+
+ int digit2 = (b & 0x0F) + ZERO;
+ if (digit2 > NINE) {
+ digit2 += ADIFF;
+ }
+ out.write(digit2);
+
+ posinline++;
+ checkLineWrap();
+ }
+
+
+ private void checkLineWrap() throws IOException {
+ //Maximum line length is 80 characters
+ if (posinline >= 40) {
+ out.write(EOL);
+ posinline = 0;
+ }
+ }
+
+
+ /** @see org.apache.fop.render.ps.Finalizable **/
+ public void finalizeStream() throws IOException {
+ checkLineWrap();
+ //Write closing character ">"
+ super.write(EOD);
+
+ flush();
+ if (out instanceof Finalizable) {
+ ((Finalizable) out).finalizeStream();
+ }
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void close() throws IOException {
+ finalizeStream();
+ super.close();
+ }
+
+
+}
+
+
diff --git a/src/java/org/apache/fop/render/ps/DSCConstants.java b/src/java/org/apache/fop/render/ps/DSCConstants.java
new file mode 100644
index 000000000..fcaee2ac9
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/DSCConstants.java
@@ -0,0 +1,202 @@
+/*
+ * $Id: DSCConstants.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+/**
+ * This class defines constants with Strings for the DSC specification.
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id: DSCConstants.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class DSCConstants {
+
+ // ----==== General Header Comments ====----
+
+ /** Lead-in for a DSC-conformant PostScript file */
+ public static final String PS_ADOBE_30 = "%!PS-Adobe-3.0";
+
+ /** Bounding box for the document */
+ public static final String BBOX = "BoundingBox";
+ /** Copyright information associated with the document or resource */
+ public static final String COPYRIGHT = "Copyright";
+ /** Creator of the document */
+ public static final String CREATOR = "Creator";
+ /** Date and time when the document was created */
+ public static final String CREATION_DATE = "CreationDate";
+ /** Type of data */
+ public static final String DOCUMENT_DATA = "BoundingBox";
+ /** Use for inidicating an emulator being invoked in the document */
+ public static final String EMULATION = "Emulation";
+ /** Explicit end of comments */
+ public static final String END_COMMENTS = "EndComments";
+ /** Required PostScript Level 1 extension for this document */
+ public static final String EXTENSIONS = "Extensions";
+ /** Indicates who is this document printed for */
+ public static final String FOR = "For";
+ /** Indicates the PostScript language level used in the document */
+ public static final String LANGUAGE_LEVEL = "LanguageLevel";
+ /** Indicates the orientation of the document */
+ public static final String ORIENTATION = "Orientation";
+ /** Number of pages in the document */
+ public static final String PAGES = "Pages";
+ /** Indicates the order of the pages */
+ public static final String PAGE_ORDER = "PageOrder";
+ /** Indicates how the document should be routed back to its owner */
+ public static final String ROUTING = "Routing";
+ /** Title of the document */
+ public static final String TITLE = "Title";
+ /** Version of the document */
+ public static final String VERSION = "Version";
+
+ // ----==== General Body Comments ====----
+
+ /** Indicates a continued line */
+ public static final String NEXT_LINE = "+ ";
+
+ //Skipping BeginBinary/EndBinary. They are deprecated.
+
+ /** Indicates the start of a data section*/
+ public static final String BEGIN_DATA = "BeginData";
+ /** Indicates the end of a data section*/
+ public static final String END_DATA = "EndData";
+
+ /** Indicates the start of the defaults section */
+ public static final String BEGIN_DEFAULTS = "BeginDefaults";
+ /** Indicates the end of the defaults section */
+ public static final String END_DEFAULTS = "EndDefaults";
+
+ /** Indicates the start of a non-PostScript section */
+ public static final String BEGIN_EMULATION = "BeginEmulation";
+ /** Indicates the end of a non-PostScript section */
+ public static final String END_EMULATION = "EndEmulation";
+
+ /** Indicates the start of a preview section (EPS only)*/
+ public static final String BEGIN_PREVIEW = "BeginPreview";
+ /** Indicates the end of a preview section (EPS only)*/
+ public static final String END_PREVIEW = "EndPreview";
+
+ /** Indicates the start of the prolog */
+ public static final String BEGIN_PROLOG = "BeginProlog";
+ /** Indicates the end of the prolog */
+ public static final String END_PROLOG = "EndProlog";
+
+ /** Indicates the start of the document setup */
+ public static final String BEGIN_SETUP = "BeginSetup";
+ /** Indicates the end of the document setup */
+ public static final String END_SETUP = "EndSetup";
+
+
+ // ----==== General Page Comments ====----
+
+ /** Indicates the start of a graphic object */
+ public static final String BEGIN_OBJECT = "BeginObject";
+ /** Indicates the end of a graphic object */
+ public static final String END_OBJECT = "EndObject";
+
+ /** Indicates the start of the page setup section */
+ public static final String BEGIN_PAGE_SETUP = "BeginPageSetup";
+ /** Indicates the end of the page setup section */
+ public static final String END_PAGE_SETUP = "EndPageSetup";
+
+ /** Indicates a page number */
+ public static final String PAGE = "Page";
+ /** Bounding box for a page */
+ public static final String PAGE_BBOX = "PageBoundingBox";
+ /** Bounding box for a page */
+ public static final String PAGE_ORIENTATION = "PageOrientation";
+
+
+ // ----==== General Trailer Comments ====----
+
+ /** Indicates the start of the page trailer */
+ public static final String PAGE_TRAILER = "PageTrailer";
+ /** Indicates the start of the document trailer */
+ public static final String TRAILER = "Trailer";
+ /** Indicates the end of a page (NON-STANDARD!) */
+ public static final String END_PAGE = "EndPage";
+ /** Indicates the end of the document */
+ public static final String EOF = "EOF";
+
+
+ // ----==== Requirements Conventions ====----
+
+ /**@todo Add the missing comments */
+
+ // ----==== Requirement Body Comments ====----
+
+ /** Indicates the start of an embedded document */
+ public static final String BEGIN_DOCUMENT = "BeginDocument";
+ /** Indicates the end of an embedded document */
+ public static final String END_DOCUMENT = "EndDocument";
+ /** Indicates a referenced embedded document */
+ public static final String INCLUDE_DOCUMENT = "IncludeDocument";
+
+ /** Indicates the start of a PPD feature */
+ public static final String BEGIN_FEATURE = "BeginFeature";
+ /** Indicates the end of a PPD feature */
+ public static final String END_FEATURE = "EndFeature";
+ /** Indicates a referenced a PPD feature */
+ public static final String INCLUDE_FEATURE = "IncludeFeature";
+
+ //Skipping BeginFile/EndFile/IncludeFile. They are deprecated.
+ //Skipping BeginFont/EndFont/IncludeFont. They are deprecated.
+ //Skipping BeginProcSet/EndProcSet/IncludeProcSet. They are deprecated.
+
+ /** Indicates the start of a resource (font, file, procset) */
+ public static final String BEGIN_RESOURCE = "BeginResource";
+ /** Indicates the end of a resource (font, file, procset) */
+ public static final String END_RESOURCE = "EndResource";
+ /** Indicates a referenced a resource (font, file, procset) */
+ public static final String INCLUDE_RESOURCE = "IncludeResource";
+
+
+}
diff --git a/src/java/org/apache/fop/render/ps/Finalizable.java b/src/java/org/apache/fop/render/ps/Finalizable.java
new file mode 100644
index 000000000..af07bdfd6
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/Finalizable.java
@@ -0,0 +1,74 @@
+/*
+ * $Id: Finalizable.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+/**
+ * This interface is used for special FilteredOutputStream classes that won't
+ * be closed (since this causes the target OutputStream to be closed, too) but
+ * where flush() is not enough, for example because a final marker has to be
+ * written to the target stream.
+ *
+ * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a>
+ * @version $Id: Finalizable.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ */
+public interface Finalizable {
+
+ /**
+ * This method can be called instead of close() on a subclass of
+ * FilteredOutputStream when a final marker has to be written to the target
+ * stream, but close() cannot be called.
+ *
+ * @exception java.io.IOException In case of an IO problem
+ */
+ void finalizeStream()
+ throws java.io.IOException;
+
+}
diff --git a/src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java b/src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java
new file mode 100644
index 000000000..3ebb7726c
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/FlateEncodeOutputStream.java
@@ -0,0 +1,85 @@
+/*
+ * $Id: FlateEncodeOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class applies a FlateEncode filter to the stream. It is basically the
+ * normal DeflaterOutputStream except now also implementing the Finalizable
+ * interface.
+ *
+ * @author <a href="mailto:jeremias.maerki@outline.ch">Jeremias Maerki</a>
+ * @version $Id: FlateEncodeOutputStream.java,v 1.4 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class FlateEncodeOutputStream extends java.util.zip.DeflaterOutputStream
+ implements Finalizable {
+
+
+ /** @see java.util.zip.DeflaterOutputStream **/
+ public FlateEncodeOutputStream(OutputStream out) {
+ super(out);
+ }
+
+
+ /** @see org.apache.fop.render.ps.Finalizable **/
+ public void finalizeStream() throws IOException {
+ finish();
+ flush();
+ if (out instanceof Finalizable) {
+ ((Finalizable)out).finalizeStream();
+ }
+ }
+
+}
+
+
diff --git a/src/java/org/apache/fop/render/ps/PSGenerator.java b/src/java/org/apache/fop/render/ps/PSGenerator.java
new file mode 100644
index 000000000..2b0622d96
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSGenerator.java
@@ -0,0 +1,371 @@
+/*
+ * $Id: PSGenerator.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.NumberFormat;
+import java.util.Date;
+import java.util.Stack;
+
+/**
+ * This class is used to output PostScript code to an OutputStream.
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id: PSGenerator.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class PSGenerator {
+
+ /**
+ * Indicator for the PostScript interpreter that the value is provided
+ * later in the document (mostly in the %%Trailer section).
+ */
+ public static final AtendIndicator ATEND = new AtendIndicator() {};
+
+ private OutputStream out;
+
+ private Stack graphicsStateStack = new Stack();
+ private PSState currentState;
+
+ private StringBuffer tempBuffer = new StringBuffer(256);
+
+ /** @see java.io.FilterOutputStream **/
+ public PSGenerator(OutputStream out) {
+ this.out = out;
+ this.currentState = new PSState();
+ this.graphicsStateStack.push(this.currentState);
+ }
+
+ /**
+ * Writes a newline character to the OutputStream.
+ *
+ * @throws IOException In case of an I/O problem
+ */
+ public final void newLine() throws IOException {
+ out.write('\n');
+ }
+
+ /**
+ * Formats a double value for PostScript output.
+ *
+ * @param value value to format
+ * @return the formatted value
+ */
+ public String formatDouble(double value) {
+ NumberFormat nf = new java.text.DecimalFormat("0.#");
+ return nf.format(value);
+ }
+
+ /**
+ * Writes a PostScript command to the stream.
+ *
+ * @param cmd The PostScript code to be written.
+ * @exception IOException In case of an I/O problem
+ */
+ public void write(String cmd) throws IOException {
+ if (cmd.length() > 255) {
+ throw new RuntimeException("PostScript command exceeded limit of 255 characters");
+ }
+ out.write(cmd.getBytes("US-ASCII"));
+ }
+
+ /**
+ * Writes a PostScript command to the stream and ends the line.
+ *
+ * @param cmd The PostScript code to be written.
+ * @exception IOException In case of an I/O problem
+ */
+ public void writeln(String cmd) throws IOException {
+ write(cmd);
+ newLine();
+ }
+
+ /**
+ * Writes encoded data to the PostScript stream.
+ *
+ * @param cmd The encoded PostScript code to be written.
+ * @exception IOException In case of an I/O problem
+ */
+ public void writeByteArr(byte[] cmd) throws IOException {
+ out.write(cmd);
+ newLine();
+ }
+
+
+ /**
+ * Flushes the OutputStream.
+ *
+ * @exception IOException In case of an I/O problem
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+
+ /**
+ * Escapes a character conforming to the rules established in the PostScript
+ * Language Reference (Search for "Literal Text Strings").
+ * @param c character to escape
+ * @param target target StringBuffer to write the escaped character to
+ */
+ public static final void escapeChar(char c, StringBuffer target) {
+ if (c > 127) {
+ target.append("\\");
+ target.append(Integer.toOctalString(c));
+ } else {
+ switch (c) {
+ case '\n':
+ target.append("\\n");
+ break;
+ case '\r':
+ target.append("\\r");
+ break;
+ case '\t':
+ target.append("\\t");
+ break;
+ case '\b':
+ target.append("\\b");
+ break;
+ case '\f':
+ target.append("\\f");
+ break;
+ case '\\':
+ target.append("\\\\");
+ break;
+ case '(':
+ target.append("\\(");
+ break;
+ case ')':
+ target.append("\\)");
+ break;
+ default:
+ target.append(c);
+ }
+ }
+ }
+
+
+ /**
+ * Converts text by applying escaping rules established in the DSC specs.
+ * @param text Text to convert
+ * @return String The resulting String
+ */
+ public static final String convertStringToDSC(String text) {
+ return convertStringToDSC(text, false);
+ }
+
+
+ /**
+ * Converts text by applying escaping rules established in the DSC specs.
+ * @param text Text to convert
+ * @param forceParentheses Force the use of parentheses
+ * @return String The resulting String
+ */
+ public static final String convertStringToDSC(String text,
+ boolean forceParentheses) {
+ if ((text == null) || (text.length() == 0)) {
+ return "()";
+ } else {
+ int initialSize = text.length();
+ initialSize += initialSize / 2;
+ StringBuffer sb = new StringBuffer(initialSize);
+ if ((Long.getLong(text) != null)
+ || (text.indexOf(" ") >= 0)
+ || forceParentheses) {
+
+ sb.append("(");
+ for (int i = 0; i < text.length(); i++) {
+ final char c = text.charAt(i);
+ escapeChar(c, sb);
+ }
+ sb.append(")");
+ return sb.toString();
+ } else {
+ return text;
+ }
+ }
+ }
+
+
+ /**
+ * Writes a DSC comment to the output stream.
+ * @param name Name of the DSC comment
+ * @exception IOException In case of an I/O problem
+ * @see org.apache.fop.render.ps.DSCConstants
+ */
+ public void writeDSCComment(String name) throws IOException {
+ writeln("%%" + name);
+ }
+
+
+ /**
+ * Writes a DSC comment to the output stream. The parameter to the DSC
+ * comment can be any object. The object is converted to a String as
+ * necessary.
+ * @param name Name of the DSC comment
+ * @param param Single parameter to the DSC comment
+ * @exception IOException In case of an I/O problem
+ * @see org.apache.fop.render.ps.DSCConstants
+ */
+ public void writeDSCComment(String name, Object param) throws IOException {
+ writeDSCComment(name, new Object[] {param});
+ }
+
+
+ /**
+ * Writes a DSC comment to the output stream. The parameters to the DSC
+ * comment can be any object. The objects are converted to Strings as
+ * necessary. Please see the source code to find out what parameters are
+ * currently supported.
+ * @param name Name of the DSC comment
+ * @param params Array of parameters to the DSC comment
+ * @exception IOException In case of an I/O problem
+ * @see org.apache.fop.render.ps.DSCConstants
+ */
+ public void writeDSCComment(String name, Object[] params) throws IOException {
+ tempBuffer.setLength(0);
+ tempBuffer.append("%%");
+ tempBuffer.append(name);
+ if ((params != null) && (params.length > 0)) {
+ tempBuffer.append(": ");
+ for (int i = 0; i < params.length; i++) {
+ if (i > 0) {
+ tempBuffer.append(" ");
+ }
+
+ if (params[i] instanceof String) {
+ tempBuffer.append(convertStringToDSC((String)params[i]));
+ } else if (params[i] instanceof AtendIndicator) {
+ tempBuffer.append("(atend)");
+ } else if (params[i] instanceof Number) {
+ tempBuffer.append(params[i].toString());
+ } else if (params[i] instanceof Date) {
+ DateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ tempBuffer.append(convertStringToDSC(df.format((Date)params[i])));
+ } else {
+ throw new IllegalArgumentException("Unsupported parameter type: "
+ + params[i].getClass().getName());
+ }
+ }
+ }
+ writeln(tempBuffer.toString());
+ }
+
+
+ /**
+ * Saves the graphics state of the rendering engine.
+ * @exception IOException In case of an I/O problem
+ */
+ public void saveGraphicsState() throws IOException {
+ writeln("gsave");
+
+ PSState state = (PSState)this.currentState.clone();
+ this.graphicsStateStack.push(this.currentState);
+ this.currentState = state;
+ }
+
+ /**
+ * Restores the last graphics state of the rendering engine.
+ * @exception IOException In case of an I/O problem
+ */
+ public void restoreGraphicsState() throws IOException {
+ writeln("grestore");
+ this.currentState = (PSState)this.graphicsStateStack.pop();
+ }
+
+ /**
+ * Concats the transformation matrix.
+ * @param a A part
+ * @param b B part
+ * @param c C part
+ * @param d D part
+ * @param e E part
+ * @param f F part
+ * @exception IOException In case of an I/O problem
+ */
+ public void concatMatrix(double a, double b,
+ double c, double d,
+ double e, double f) throws IOException {
+ writeln("[" + formatDouble(a) + " "
+ + formatDouble(b) + " "
+ + formatDouble(c) + " "
+ + formatDouble(d) + " "
+ + formatDouble(e) + " "
+ + formatDouble(f) + "] concat");
+ }
+
+ /**
+ * Concats the transformations matrix.
+ * @param matrix Matrix to use
+ * @exception IOException In case of an I/O problem
+ */
+ public void concatMatrix(double[] matrix) throws IOException {
+ concatMatrix(matrix[0], matrix[1],
+ matrix[2], matrix[3],
+ matrix[4], matrix[5]);
+ }
+
+ /**
+ * Returns the current graphics state.
+ * @return the current graphics state
+ */
+ public PSState getCurrentState() {
+ return this.currentState;
+ }
+
+
+ /** Used for the ATEND constant. See there. */
+ private static interface AtendIndicator {
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java
new file mode 100644
index 000000000..9a2908422
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java
@@ -0,0 +1,1134 @@
+/*
+ * $Id: PSGraphics2D.java,v 1.11 2003/03/11 08:42:24 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+//Java
+import java.util.List;
+import java.text.AttributedCharacterIterator;
+import java.text.CharacterIterator;
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.TexturePaint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferInt;
+import java.awt.image.ImageObserver;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.io.IOException;
+
+// FOP
+import org.apache.fop.layout.FontInfo;
+import org.apache.fop.layout.FontState;
+
+// Batik
+import org.apache.batik.ext.awt.g2d.AbstractGraphics2D;
+import org.apache.batik.ext.awt.g2d.GraphicContext;
+
+
+/**
+ * This concrete implementation of <tt>AbstractGraphics2D</tt> is a
+ * simple help to programmers to get started with their own
+ * implementation of <tt>Graphics2D</tt>.
+ * <tt>DefaultGraphics2D</tt> implements all the abstract methods
+ * is <tt>AbstractGraphics2D</tt> and makes it easy to start
+ * implementing a <tt>Graphic2D</tt> piece-meal.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @version $Id: PSGraphics2D.java,v 1.11 2003/03/11 08:42:24 jeremias Exp $
+ * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D
+ */
+public class PSGraphics2D extends AbstractGraphics2D {
+
+ private boolean standalone = false;
+
+ /**
+ * the PostScript genertaor being created
+ */
+ protected PSGenerator gen;
+
+ /** Currently valid FontState */
+ protected FontState fontState;
+
+ /** Overriding FontState */
+ protected FontState overrideFontState = null;
+
+ /**
+ * the current (internal) font name
+ */
+ protected String currentFontName;
+
+ /**
+ * the current font size in millipoints
+ */
+ protected int currentFontSize;
+
+ /**
+ * the current vertical position in millipoints from bottom
+ */
+ protected int currentYPosition = 0;
+
+ /**
+ * the current horizontal position in millipoints from left
+ */
+ protected int currentXPosition = 0;
+
+ /**
+ * the current colour for use in svg
+ */
+ protected Color currentColour = new Color(0, 0, 0);
+
+ /** FontInfo containing all available fonts */
+ protected FontInfo fontInfo;
+
+ /**
+ * Create a new Graphics2D that generates PostScript code.
+ * @param textAsShapes True if text should be rendered as graphics
+ * @param gen PostScript generator to use for output
+ * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean)
+ */
+ public PSGraphics2D(boolean textAsShapes, PSGenerator gen) {
+ super(textAsShapes);
+ this.gen = gen;
+ }
+
+ /**
+ * Constructor for creating copies
+ * @param g parent PostScript Graphics2D
+ */
+ public PSGraphics2D(PSGraphics2D g) {
+ super(g);
+ }
+
+ /**
+ * Sets the GraphicContext
+ * @param c GraphicContext to use
+ */
+ public void setGraphicContext(GraphicContext c) {
+ gc = c;
+ }
+
+ /**
+ * Creates a new <code>Graphics</code> object that is
+ * a copy of this <code>Graphics</code> object.
+ * @return a new graphics context that is a copy of
+ * this graphics context.
+ */
+ public Graphics create() {
+ return new PSGraphics2D(this);
+ }
+
+ /**
+ * Central handler for IOExceptions for this class.
+ * @param ioe IOException to handle
+ */
+ protected void handleIOException(IOException ioe) {
+ ioe.printStackTrace();
+ }
+
+ /**
+ * Draws as much of the specified image as is currently available.
+ * The image is drawn with its top-left corner at
+ * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
+ * space. Transparent pixels in the image do not affect whatever
+ * pixels are already there.
+ * <p>
+ * This method returns immediately in all cases, even if the
+ * complete image has not yet been loaded, and it has not been dithered
+ * and converted for the current output device.
+ * <p>
+ * If the image has not yet been completely loaded, then
+ * <code>drawImage</code> returns <code>false</code>. As more of
+ * the image becomes available, the process that draws the image notifies
+ * the specified image observer.
+ * @param img the specified image to be drawn.
+ * @param x the <i>x</i> coordinate.
+ * @param y the <i>y</i> coordinate.
+ * @param observer object to be notified as more of
+ * the image is converted.
+ * @return True if the image has been fully drawn/loaded
+ * @see java.awt.Image
+ * @see java.awt.image.ImageObserver
+ * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+ */
+ public boolean drawImage(Image img, int x, int y,
+ ImageObserver observer) {
+ // System.err.println("drawImage:x, y");
+
+ final int width = img.getWidth(observer);
+ final int height = img.getHeight(observer);
+ if (width == -1 || height == -1) {
+ return false;
+ }
+
+ Dimension size = new Dimension(width, height);
+ BufferedImage buf = buildBufferedImage(size);
+
+ java.awt.Graphics2D g = buf.createGraphics();
+ g.setComposite(AlphaComposite.SrcOver);
+ g.setBackground(new Color(1, 1, 1, 0));
+ g.setPaint(new Color(1, 1, 1, 0));
+ g.fillRect(0, 0, width, height);
+ g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
+
+ if (!g.drawImage(img, 0, 0, observer)) {
+ return false;
+ }
+ g.dispose();
+
+ final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3];
+ //final byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
+
+ Raster raster = buf.getData();
+ DataBuffer bd = raster.getDataBuffer();
+
+ int count = 0;
+ //int maskpos = 0;
+ switch (bd.getDataType()) {
+ case DataBuffer.TYPE_INT:
+ int[][] idata = ((DataBufferInt)bd).getBankData();
+ for (int i = 0; i < idata.length; i++) {
+ for (int j = 0; j < idata[i].length; j++) {
+ // mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF);
+ if (((idata[i][j] >> 24) & 0xFF) != 255) {
+ result[count++] = (byte)0xFF;
+ result[count++] = (byte)0xFF;
+ result[count++] = (byte)0xFF;
+ } else {
+ result[count++] = (byte)((idata[i][j] >> 16) & 0xFF);
+ result[count++] = (byte)((idata[i][j] >> 8) & 0xFF);
+ result[count++] = (byte)((idata[i][j]) & 0xFF);
+ }
+ }
+ }
+ break;
+ default:
+ // error
+ break;
+ }
+
+ /*try {
+ FopImage fopimg = new TempImage(width, height, result, mask);
+ AffineTransform at = getTransform();
+ double[] matrix = new double[6];
+ at.getMatrix(matrix);
+ psRenderer.write("gsave");
+ Shape imclip = getClip();
+ writeClip(imclip);
+ // psRenderer.write("" + matrix[0] + " " + matrix[1] +
+ // " " + matrix[2] + " " + matrix[3] + " " +
+ // matrix[4] + " " + matrix[5] + " cm\n");
+ //psRenderer.renderBitmap(fopimg, x, y, width, height);
+ psRenderer.write("grestore");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }*/
+ return true;
+ }
+
+ /**
+ * Creates a buffered image.
+ * @param size dimensions of the image to be created
+ * @return the buffered image
+ */
+ public BufferedImage buildBufferedImage(Dimension size) {
+ return new BufferedImage(size.width, size.height,
+ BufferedImage.TYPE_INT_ARGB);
+ }
+
+ /*class TempImage implements FopImage {
+ int m_height;
+ int m_width;
+ int m_bitsPerPixel;
+ PDFColorSpace m_colorSpace;
+ int m_bitmapSiye;
+ byte[] m_bitmaps;
+ byte[] m_mask;
+ PDFColor transparent = new PDFColor(255, 255, 255);
+
+ TempImage(int width, int height, byte[] result,
+ byte[] mask) {
+ this.m_height = height;
+ this.m_width = width;
+ this.m_bitsPerPixel = 8;
+ this.m_colorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
+ // this.m_isTransparent = false;
+ // this.m_bitmapsSize = this.m_width * this.m_height * 3;
+ this.m_bitmaps = result;
+ this.m_mask = mask;
+ }
+
+ public boolean load(int type, FOUserAgent ua) {
+ return true;
+ }
+
+ public String getMimeType() {
+ return "";
+ }
+
+ public String getURL() {
+ return "" + m_bitmaps;
+ }
+
+ // image size
+ public int getWidth() {
+ return m_width;
+ }
+
+ public int getHeight() {
+ return m_height;
+ }
+
+ // DeviceGray, DeviceRGB, or DeviceCMYK
+ public PDFColorSpace getColorSpace() {
+ return m_colorSpace;
+ }
+
+ // bits per pixel
+ public int getBitsPerPixel() {
+ return m_bitsPerPixel;
+ }
+
+ // For transparent images
+ public boolean isTransparent() {
+ return transparent != null;
+ }
+
+ public PDFColor getTransparentColor() {
+ return transparent;
+ }
+
+ public boolean hasSoftMask() {
+ return m_mask != null;
+ }
+
+ public byte[] getSoftMask() {
+ return m_mask;
+ }
+
+ // get the image bytes, and bytes properties
+
+ // get uncompressed image bytes
+ public byte[] getBitmaps() {
+ return m_bitmaps;
+ }
+
+ // width * (bitsPerPixel / 8) * height, no ?
+ public int getBitmapsSize() {
+ return m_width * m_height * 3;
+ }
+
+ // get compressed image bytes
+ // I don't know if we really need it, nor if it
+ // should be changed...
+ public byte[] getRessourceBytes() {
+ return null;
+ }
+
+ public int getRessourceBytesSize() {
+ return 0;
+ }
+
+ // return null if no corresponding PDFFilter
+ public PDFFilter getPDFFilter() {
+ return null;
+ }
+
+ // release memory
+ public void close() {}
+
+ }*/
+
+
+ /**
+ * Draws as much of the specified image as has already been scaled
+ * to fit inside the specified rectangle.
+ * <p>
+ * The image is drawn inside the specified rectangle of this
+ * graphics context's coordinate space, and is scaled if
+ * necessary. Transparent pixels do not affect whatever pixels
+ * are already there.
+ * <p>
+ * This method returns immediately in all cases, even if the
+ * entire image has not yet been scaled, dithered, and converted
+ * for the current output device.
+ * If the current output representation is not yet complete, then
+ * <code>drawImage</code> returns <code>false</code>. As more of
+ * the image becomes available, the process that draws the image notifies
+ * the image observer by calling its <code>imageUpdate</code> method.
+ * <p>
+ * A scaled version of an image will not necessarily be
+ * available immediately just because an unscaled version of the
+ * image has been constructed for this output device. Each size of
+ * the image may be cached separately and generated from the original
+ * data in a separate image production sequence.
+ * @param img the specified image to be drawn.
+ * @param x the <i>x</i> coordinate.
+ * @param y the <i>y</i> coordinate.
+ * @param width the width of the rectangle.
+ * @param height the height of the rectangle.
+ * @param observer object to be notified as more of
+ * the image is converted.
+ * @return True if the image has been fully loaded/drawn
+ * @see java.awt.Image
+ * @see java.awt.image.ImageObserver
+ * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
+ */
+ public boolean drawImage(Image img, int x, int y, int width, int height,
+ ImageObserver observer) {
+ System.out.println("drawImage");
+ return true;
+ }
+
+ /**
+ * Disposes of this graphics context and releases
+ * any system resources that it is using.
+ * A <code>Graphics</code> object cannot be used after
+ * <code>dispose</code>has been called.
+ * <p>
+ * When a Java program runs, a large number of <code>Graphics</code>
+ * objects can be created within a short time frame.
+ * Although the finalization process of the garbage collector
+ * also disposes of the same system resources, it is preferable
+ * to manually free the associated resources by calling this
+ * method rather than to rely on a finalization process which
+ * may not run to completion for a long period of time.
+ * <p>
+ * Graphics objects which are provided as arguments to the
+ * <code>paint</code> and <code>update</code> methods
+ * of components are automatically released by the system when
+ * those methods return. For efficiency, programmers should
+ * call <code>dispose</code> when finished using
+ * a <code>Graphics</code> object only if it was created
+ * directly from a component or another <code>Graphics</code> object.
+ * @see java.awt.Graphics#finalize
+ * @see java.awt.Component#paint
+ * @see java.awt.Component#update
+ * @see java.awt.Component#getGraphics
+ * @see java.awt.Graphics#create
+ */
+ public void dispose() {
+ // System.out.println("dispose");
+ this.gen = null;
+ fontState = null;
+ currentFontName = null;
+ currentColour = null;
+ fontInfo = null;
+ }
+
+ /**
+ * Strokes the outline of a <code>Shape</code> using the settings of the
+ * current <code>Graphics2D</code> context. The rendering attributes
+ * applied include the <code>Clip</code>, <code>Transform</code>,
+ * <code>Paint</code>, <code>Composite</code> and
+ * <code>Stroke</code> attributes.
+ * @param s the <code>Shape</code> to be rendered
+ * @see #setStroke
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see #transform
+ * @see #setTransform
+ * @see #clip
+ * @see #setClip
+ * @see #setComposite
+ */
+ public void draw(Shape s) {
+ try {
+ // System.out.println("draw(Shape)");
+ gen.saveGraphicsState();
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " "
+ + gen.formatDouble(c.getGreen() / 255.0) + " "
+ + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor");
+
+ applyPaint(getPaint(), false);
+ applyStroke(getStroke());
+
+ gen.writeln("newpath");
+ PathIterator iter = s.getPathIterator(getTransform());
+ while (!iter.isDone()) {
+ double vals[] = new double[6];
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " "
+ + gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5])
+ + " curveto");
+ break;
+ case PathIterator.SEG_LINETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " lineto");
+ break;
+ case PathIterator.SEG_MOVETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " M");
+ break;
+ case PathIterator.SEG_QUADTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
+ break;
+ case PathIterator.SEG_CLOSE:
+ gen.writeln("closepath");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ doDrawing(false, true, false);
+ gen.restoreGraphicsState();
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Establishes a clipping region
+ * @param s Shape defining the clipping region
+ */
+ protected void writeClip(Shape s) {
+ try {
+ PathIterator iter = s.getPathIterator(getTransform());
+ gen.writeln("newpath");
+ while (!iter.isDone()) {
+ double vals[] = new double[6];
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " "
+ + gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5])
+ + " curveto");
+ break;
+ case PathIterator.SEG_LINETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " lineto");
+ break;
+ case PathIterator.SEG_MOVETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " M");
+ break;
+ case PathIterator.SEG_QUADTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
+ break;
+ case PathIterator.SEG_CLOSE:
+ gen.writeln("closepath");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ // clip area
+ gen.writeln("clippath");
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Applies a new Paint object.
+ * @param paint Paint object to use
+ * @param fill True if to be applied for filling
+ */
+ protected void applyPaint(Paint paint, boolean fill) {
+ if (paint instanceof GradientPaint) {
+ GradientPaint gp = (GradientPaint)paint;
+ Color c1 = gp.getColor1();
+ Color c2 = gp.getColor2();
+ Point2D p1 = gp.getPoint1();
+ Point2D p2 = gp.getPoint2();
+ //boolean cyclic = gp.isCyclic();
+
+ List theCoords = new java.util.ArrayList();
+ theCoords.add(new Double(p1.getX()));
+ theCoords.add(new Double(p1.getY()));
+ theCoords.add(new Double(p2.getX()));
+ theCoords.add(new Double(p2.getY()));
+
+ List theExtend = new java.util.ArrayList();
+ theExtend.add(new Boolean(true));
+ theExtend.add(new Boolean(true));
+
+ List theDomain = new java.util.ArrayList();
+ theDomain.add(new Double(0));
+ theDomain.add(new Double(1));
+
+ List theEncode = new java.util.ArrayList();
+ theEncode.add(new Double(0));
+ theEncode.add(new Double(1));
+ theEncode.add(new Double(0));
+ theEncode.add(new Double(1));
+
+ List theBounds = new java.util.ArrayList();
+ theBounds.add(new Double(0));
+ theBounds.add(new Double(1));
+
+ //List theFunctions = new java.util.ArrayList();
+
+ List someColors = new java.util.ArrayList();
+
+ Color color1 = new Color(c1.getRed(), c1.getGreen(),
+ c1.getBlue());
+ someColors.add(color1);
+ Color color2 = new Color(c2.getRed(), c2.getGreen(),
+ c2.getBlue());
+ someColors.add(color2);
+
+ //PDFColorSpace aColorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
+ } else if (paint instanceof TexturePaint) {
+ //nop
+ }
+ }
+
+ /**
+ * Applies a new Stroke object.
+ * @param stroke Stroke object to use
+ */
+ protected void applyStroke(Stroke stroke) {
+ try {
+ if (stroke instanceof BasicStroke) {
+ BasicStroke bs = (BasicStroke)stroke;
+
+ float[] da = bs.getDashArray();
+ if (da != null) {
+ gen.writeln("[");
+ for (int count = 0; count < da.length; count++) {
+ gen.writeln("" + (1000 * (int)da[count]));
+ if (count < da.length - 1) {
+ gen.writeln(" ");
+ }
+ }
+ gen.writeln("] ");
+ float offset = bs.getDashPhase();
+ gen.writeln((1000 * (int)offset) + " setdash");
+ }
+ int ec = bs.getEndCap();
+ switch (ec) {
+ case BasicStroke.CAP_BUTT:
+ gen.writeln(0 + " setlinecap");
+ break;
+ case BasicStroke.CAP_ROUND:
+ gen.writeln(1 + " setlinecap");
+ break;
+ case BasicStroke.CAP_SQUARE:
+ gen.writeln(2 + " setlinecap");
+ break;
+ }
+
+ int lj = bs.getLineJoin();
+ switch (lj) {
+ case BasicStroke.JOIN_MITER:
+ gen.writeln("0 setlinejoin");
+ break;
+ case BasicStroke.JOIN_ROUND:
+ gen.writeln("1 setlinejoin");
+ break;
+ case BasicStroke.JOIN_BEVEL:
+ gen.writeln("2 setlinejoin");
+ break;
+ }
+ float lw = bs.getLineWidth();
+ gen.writeln(gen.formatDouble(1000 * lw) + " setlinewidth");
+
+ float ml = bs.getMiterLimit();
+ gen.writeln(gen.formatDouble(1000 * ml) + " setmiterlimit");
+ }
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Renders a {@link RenderedImage},
+ * applying a transform from image
+ * space into user space before drawing.
+ * The transformation from user space into device space is done with
+ * the current <code>Transform</code> in the <code>Graphics2D</code>.
+ * The specified transformation is applied to the image before the
+ * transform attribute in the <code>Graphics2D</code> context is applied.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, and <code>Composite</code> attributes. Note
+ * that no rendering is done if the specified transform is
+ * noninvertible.
+ * @param img the image to be rendered
+ * @param xform the transformation from image space into user space
+ * @see #transform
+ * @see #setTransform
+ * @see #setComposite
+ * @see #clip
+ * @see #setClip
+ */
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ System.out.println("drawRenderedImage");
+ }
+
+
+ /**
+ * Renders a
+ * {@link RenderableImage},
+ * applying a transform from image space into user space before drawing.
+ * The transformation from user space into device space is done with
+ * the current <code>Transform</code> in the <code>Graphics2D</code>.
+ * The specified transformation is applied to the image before the
+ * transform attribute in the <code>Graphics2D</code> context is applied.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, and <code>Composite</code> attributes. Note
+ * that no rendering is done if the specified transform is
+ * noninvertible.
+ * <p>
+ * Rendering hints set on the <code>Graphics2D</code> object might
+ * be used in rendering the <code>RenderableImage</code>.
+ * If explicit control is required over specific hints recognized by a
+ * specific <code>RenderableImage</code>, or if knowledge of which hints
+ * are used is required, then a <code>RenderedImage</code> should be
+ * obtained directly from the <code>RenderableImage</code>
+ * and rendered using
+ * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.
+ * @param img the image to be rendered
+ * @param xform the transformation from image space into user space
+ * @see #transform
+ * @see #setTransform
+ * @see #setComposite
+ * @see #clip
+ * @see #setClip
+ * @see #drawRenderedImage
+ */
+ public void drawRenderableImage(RenderableImage img,
+ AffineTransform xform) {
+ System.out.println("drawRenderableImage");
+ }
+
+ /**
+ * Renders the text specified by the specified <code>String</code>,
+ * using the current <code>Font</code> and <code>Paint</code> attributes
+ * in the <code>Graphics2D</code> context.
+ * The baseline of the first character is at position
+ * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
+ * <code>Composite</code> attributes. For characters in script systems
+ * such as Hebrew and Arabic, the glyphs can be rendered from right to
+ * left, in which case the coordinate supplied is the location of the
+ * leftmost character on the baseline.
+ * @param s the <code>String</code> to be rendered
+ * @param x the x-coordinate where the <code>String</code>
+ * should be rendered
+ * @param y the y-coordinate where the <code>String</code>
+ * should be rendered
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see java.awt.Graphics#setFont
+ * @see #setTransform
+ * @see #setComposite
+ * @see #setClip
+ */
+ public void drawString(String s, float x, float y) {
+ try {
+ if (overrideFontState == null) {
+ Font gFont = getFont();
+ String n = gFont.getFamily();
+ if (n.equals("sanserif")) {
+ n = "sans-serif";
+ }
+ int siz = gFont.getSize();
+ String style = gFont.isItalic() ? "italic" : "normal";
+ String weight = gFont.isBold() ? "bold" : "normal";
+
+ //try {
+ //fontState = new FontState(n, fontState.getFontMetrics(),siz);
+ //} catch (org.apache.fop.apps.FOPException fope) {
+ //fope.printStackTrace();
+ //}
+ } else {
+ fontState = overrideFontState;
+ overrideFontState = null;
+ }
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ gen.writeln(c.getRed() / 255.0 + " "
+ + c.getGreen() / 255.0 + " "
+ + c.getBlue() / 255.0 + " setrgbcolor");
+
+ AffineTransform trans = getTransform();
+ trans.translate(x, y);
+ double[] vals = new double[6];
+ trans.getMatrix(vals);
+ gen.writeln(gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5]) + " moveto ");
+ //String fontWeight = fontState.getFontWeight();
+ StringBuffer sb = new StringBuffer();
+
+ int l = s.length();
+
+ if ((currentFontName != fontState.getFontName())
+ || (currentFontSize != fontState.getFontSize())) {
+ gen.writeln(fontState.getFontName() + " " + fontState.getFontSize() + " F");
+ currentFontName = fontState.getFontName();
+ currentFontSize = fontState.getFontSize();
+ }
+ for (int i = 0; i < l; i++) {
+ char ch = s.charAt(i);
+ char mch = fontState.mapChar(ch);
+ if (mch > 127) {
+ sb = sb.append("\\" + Integer.toOctalString(mch));
+ } else {
+ String escape = "\\()[]{}";
+ if (escape.indexOf(mch) >= 0) {
+ sb.append("\\");
+ }
+ sb = sb.append(mch);
+ }
+ }
+
+ String psString = null;
+ psString = " (" + sb.toString() + ") " + " t ";
+
+ gen.writeln(" 1.0 -1.0 scale");
+ gen.writeln(psString);
+ gen.writeln(" 1.0 -1.0 scale");
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Renders the text of the specified iterator, using the
+ * <code>Graphics2D</code> context's current <code>Paint</code>. The
+ * iterator must specify a font
+ * for each character. The baseline of the
+ * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the
+ * User Space.
+ * The rendering attributes applied include the <code>Clip</code>,
+ * <code>Transform</code>, <code>Paint</code>, and
+ * <code>Composite</code> attributes.
+ * For characters in script systems such as Hebrew and Arabic,
+ * the glyphs can be rendered from right to left, in which case the
+ * coordinate supplied is the location of the leftmost character
+ * on the baseline.
+ * @param iterator the iterator whose text is to be rendered
+ * @param x the x-coordinate where the iterator's text is to be
+ * rendered
+ * @param y the y-coordinate where the iterator's text is to be
+ * rendered
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see #setTransform
+ * @see #setComposite
+ * @see #setClip
+ */
+ public void drawString(AttributedCharacterIterator iterator, float x,
+ float y) {
+ try {
+ System.err.println("drawString(AttributedCharacterIterator)");
+
+ gen.writeln("BT");
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ currentColour = new Color(c.getRed(), c.getGreen(), c.getBlue());
+ //gen.writeln(currentColour.getColorSpaceOut(true));
+ c = getBackground();
+ Color col = new Color(c.getRed(), c.getGreen(), c.getBlue());
+ //gen.writeln(col.getColorSpaceOut(false));
+
+ AffineTransform trans = getTransform();
+ trans.translate(x, y);
+ double[] vals = new double[6];
+ trans.getMatrix(vals);
+
+ for (char ch = iterator.first(); ch != CharacterIterator.DONE;
+ ch = iterator.next()) {
+ //Map attr = iterator.getAttributes();
+
+ gen.writeln(gen.formatDouble(vals[0]) + " "
+ + gen.formatDouble(vals[1]) + " "
+ + gen.formatDouble(vals[2]) + " "
+ + gen.formatDouble(vals[3]) + " "
+ + gen.formatDouble(vals[4]) + " "
+ + gen.formatDouble(vals[5]) + " "
+ + gen.formatDouble(vals[6]) + " Tm [" + ch
+ + "]");
+ }
+
+ gen.writeln("ET");
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Fills the interior of a <code>Shape</code> using the settings of the
+ * <code>Graphics2D</code> context. The rendering attributes applied
+ * include the <code>Clip</code>, <code>Transform</code>,
+ * <code>Paint</code>, and <code>Composite</code>.
+ * @param s the <code>Shape</code> to be filled
+ * @see #setPaint
+ * @see java.awt.Graphics#setColor
+ * @see #transform
+ * @see #setTransform
+ * @see #setComposite
+ * @see #clip
+ * @see #setClip
+ */
+ public void fill(Shape s) {
+ try {
+ // System.err.println("fill");
+ gen.writeln("gsave");
+ Shape imclip = getClip();
+ writeClip(imclip);
+ Color c = getColor();
+ gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " "
+ + gen.formatDouble(c.getGreen() / 255.0) + " "
+ + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor");
+
+ applyPaint(getPaint(), true);
+
+ gen.writeln("newpath");
+ PathIterator iter = s.getPathIterator(getTransform());
+ while (!iter.isDone()) {
+ double vals[] = new double[6];
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " "
+ + gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5])
+ + " curveto");
+ break;
+ case PathIterator.SEG_LINETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " lineto");
+ break;
+ case PathIterator.SEG_MOVETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " M");
+ break;
+ case PathIterator.SEG_QUADTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
+ break;
+ case PathIterator.SEG_CLOSE:
+ gen.writeln("closepath");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
+ doDrawing(true, false,
+ iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
+ gen.writeln("grestore");
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ /**
+ * Commits a painting operation.
+ * @param fill filling
+ * @param stroke stroking
+ * @param nonzero ???
+ * @exception IOException In case of an I/O problem
+ */
+ protected void doDrawing(boolean fill, boolean stroke, boolean nonzero)
+ throws IOException {
+ if (fill) {
+ if (stroke) {
+ if (!nonzero) {
+ gen.writeln("stroke");
+ } else {
+ gen.writeln("stroke");
+ }
+ } else {
+ if (!nonzero) {
+ gen.writeln("fill");
+ } else {
+ gen.writeln("fill");
+ }
+ }
+ } else {
+ // if(stroke)
+ gen.writeln("stroke");
+ }
+ }
+
+ /**
+ * Returns the device configuration associated with this
+ * <code>Graphics2D</code>.
+ * @return the device configuration
+ */
+ public GraphicsConfiguration getDeviceConfiguration() {
+ // System.out.println("getDeviceConviguration");
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().
+ getDefaultScreenDevice().getDefaultConfiguration();
+ }
+
+ /**
+ * Used to create proper font metrics
+ */
+ private Graphics2D fmg;
+
+ {
+ BufferedImage bi = new BufferedImage(1, 1,
+ BufferedImage.TYPE_INT_ARGB);
+
+ fmg = bi.createGraphics();
+ }
+
+ /**
+ * Sets the overrideing font state.
+ * @param infont FontState to set
+ */
+ public void setOverrideFontState(FontState infont) {
+ overrideFontState = infont;
+ }
+
+ /**
+ * Gets the font metrics for the specified font.
+ * @return the font metrics for the specified font.
+ * @param f the specified font
+ * @see java.awt.Graphics#getFont
+ * @see java.awt.FontMetrics
+ * @see java.awt.Graphics#getFontMetrics()
+ */
+ public java.awt.FontMetrics getFontMetrics(Font f) {
+ return fmg.getFontMetrics(f);
+ }
+
+ /**
+ * Sets the paint mode of this graphics context to alternate between
+ * this graphics context's current color and the new specified color.
+ * This specifies that logical pixel operations are performed in the
+ * XOR mode, which alternates pixels between the current color and
+ * a specified XOR color.
+ * <p>
+ * When drawing operations are performed, pixels which are the
+ * current color are changed to the specified color, and vice versa.
+ * <p>
+ * Pixels that are of colors other than those two colors are changed
+ * in an unpredictable but reversible manner; if the same figure is
+ * drawn twice, then all pixels are restored to their original values.
+ * @param c1 the XOR alternation color
+ */
+ public void setXORMode(Color c1) {
+ System.out.println("setXORMode");
+ }
+
+
+ /**
+ * Copies an area of the component by a distance specified by
+ * <code>dx</code> and <code>dy</code>. From the point specified
+ * by <code>x</code> and <code>y</code>, this method
+ * copies downwards and to the right. To copy an area of the
+ * component to the left or upwards, specify a negative value for
+ * <code>dx</code> or <code>dy</code>.
+ * If a portion of the source rectangle lies outside the bounds
+ * of the component, or is obscured by another window or component,
+ * <code>copyArea</code> will be unable to copy the associated
+ * pixels. The area that is omitted can be refreshed by calling
+ * the component's <code>paint</code> method.
+ * @param x the <i>x</i> coordinate of the source rectangle.
+ * @param y the <i>y</i> coordinate of the source rectangle.
+ * @param width the width of the source rectangle.
+ * @param height the height of the source rectangle.
+ * @param dx the horizontal distance to copy the pixels.
+ * @param dy the vertical distance to copy the pixels.
+ */
+ public void copyArea(int x, int y, int width, int height, int dx,
+ int dy) {
+ System.out.println("copyArea");
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSProcSets.java b/src/java/org/apache/fop/render/ps/PSProcSets.java
new file mode 100644
index 000000000..566328733
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSProcSets.java
@@ -0,0 +1,200 @@
+/*
+ * $Id: PSProcSets.java,v 1.3 2003/03/11 08:42:24 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.IOException;
+
+/**
+ * This class defines the basic resources (procsets) used by FOP's PostScript
+ * renderer and SVG transcoder.
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id: PSProcSets.java,v 1.3 2003/03/11 08:42:24 jeremias Exp $
+ */
+public final class PSProcSets {
+
+ /**
+ * Generates a resource defining standard procset for FOP.
+ * @param gen PSGenerator to use for output
+ * @throws IOException In case of an I/O problem
+ */
+ public static final void writeFOPStdProcSet(PSGenerator gen) throws IOException {
+ gen.writeln("%%BeginResource: procset (Apache FOP Std ProcSet) 1.0 0");
+ gen.writeln("%%Version: 1.0 0");
+ gen.writeln("%%Copyright: Copyright (C) 2001-2003 "
+ + "The Apache Software Foundation. All rights reserved.");
+ gen.writeln("%%Title: Basic set of procedures used by FOP");
+
+ gen.writeln("/bd{bind def}bind def");
+ gen.writeln("/ld{load def}bd");
+ gen.writeln("/M/moveto ld");
+ gen.writeln("/RM/rmoveto ld");
+ gen.writeln("/t/show ld");
+
+ gen.writeln("/_ctm matrix def"); //Holds the current matrix
+ gen.writeln("/_tm matrix def");
+ //BT: save currentmatrix, set _tm to identitymatrix and move to 0/0
+ gen.writeln("/BT { _ctm currentmatrix pop matrix _tm copy pop 0 0 moveto } bd");
+ //ET: restore last currentmatrix
+ gen.writeln("/ET { _ctm setmatrix } bd");
+ gen.writeln("/iTm { _ctm setmatrix _tm concat } bd");
+ gen.writeln("/Tm { _tm astore pop iTm 0 0 moveto } bd");
+
+ gen.writeln("/ux 0.0 def");
+ gen.writeln("/uy 0.0 def");
+
+ // <font> <size> F
+ gen.writeln("/F {");
+ gen.writeln(" /Tp exch def");
+ // gen.writeln(" currentdict exch get");
+ gen.writeln(" /Tf exch def");
+ gen.writeln(" Tf findfont Tp scalefont setfont");
+ gen.writeln(" /cf Tf def /cs Tp def /cw ( ) stringwidth pop def");
+ gen.writeln("} bd");
+
+ gen.writeln("/ULS {currentpoint /uy exch def /ux exch def} bd");
+ gen.writeln("/ULE {");
+ gen.writeln(" /Tcx currentpoint pop def");
+ gen.writeln(" gsave");
+ gen.writeln(" newpath");
+ gen.writeln(" cf findfont cs scalefont dup");
+ gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup");
+ gen.writeln(" /UnderlinePosition get Ts mul /To exch def");
+ gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def");
+ gen.writeln(" ux uy To add moveto Tcx uy To add lineto");
+ gen.writeln(" Tt setlinewidth stroke");
+ gen.writeln(" grestore");
+ gen.writeln("} bd");
+
+ gen.writeln("/OLE {");
+ gen.writeln(" /Tcx currentpoint pop def");
+ gen.writeln(" gsave");
+ gen.writeln(" newpath");
+ gen.writeln(" cf findfont cs scalefont dup");
+ gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup");
+ gen.writeln(" /UnderlinePosition get Ts mul /To exch def");
+ gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def");
+ gen.writeln(" ux uy To add cs add moveto Tcx uy To add cs add lineto");
+ gen.writeln(" Tt setlinewidth stroke");
+ gen.writeln(" grestore");
+ gen.writeln("} bd");
+
+ gen.writeln("/SOE {");
+ gen.writeln(" /Tcx currentpoint pop def");
+ gen.writeln(" gsave");
+ gen.writeln(" newpath");
+ gen.writeln(" cf findfont cs scalefont dup");
+ gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup");
+ gen.writeln(" /UnderlinePosition get Ts mul /To exch def");
+ gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def");
+ gen.writeln(" ux uy To add cs 10 mul 26 idiv add moveto "
+ + "Tcx uy To add cs 10 mul 26 idiv add lineto");
+ gen.writeln(" Tt setlinewidth stroke");
+ gen.writeln(" grestore");
+ gen.writeln("} bd");
+
+ gen.writeln("/QUADTO {");
+ gen.writeln("/Y22 exch store");
+ gen.writeln("/X22 exch store");
+ gen.writeln("/Y21 exch store");
+ gen.writeln("/X21 exch store");
+ gen.writeln("currentpoint");
+ gen.writeln("/Y21 load 2 mul add 3 div exch");
+ gen.writeln("/X21 load 2 mul add 3 div exch");
+ gen.writeln("/X21 load 2 mul /X22 load add 3 div");
+ gen.writeln("/Y21 load 2 mul /Y22 load add 3 div");
+ gen.writeln("/X22 load /Y22 load curveto");
+ gen.writeln("} bd");
+
+ gen.writeln("%%EndResource");
+ }
+
+
+ /**
+ * Generates a resource defining a procset for including EPS graphics.
+ * @param gen PSGenerator to use for output
+ * @throws IOException In case of an I/O problem
+ */
+ public static final void writeFOPEPSProcSet(PSGenerator gen) throws IOException {
+ gen.writeln("%%BeginResource: procset (Apache FOP EPS ProcSet) 1.0 0");
+ gen.writeln("%%Version: 1.0 0");
+ gen.writeln("%%Copyright: Copyright (C) 2002-2003 "
+ + "The Apache Software Foundation. All rights reserved.");
+ gen.writeln("%%Title: EPS procedures used by FOP");
+
+ gen.writeln("/BeginEPSF { %def");
+ gen.writeln("/b4_Inc_state save def % Save state for cleanup");
+ gen.writeln("/dict_count countdictstack def % Count objects on dict stack");
+ gen.writeln("/op_count count 1 sub def % Count objects on operand stack");
+ gen.writeln("userdict begin % Push userdict on dict stack");
+ gen.writeln("/showpage { } def % Redefine showpage, { } = null proc");
+ gen.writeln("0 setgray 0 setlinecap % Prepare graphics state");
+ gen.writeln("1 setlinewidth 0 setlinejoin");
+ gen.writeln("10 setmiterlimit [ ] 0 setdash newpath");
+ gen.writeln("/languagelevel where % If level not equal to 1 then");
+ gen.writeln("{pop languagelevel % set strokeadjust and");
+ gen.writeln("1 ne % overprint to their defaults.");
+ gen.writeln("{false setstrokeadjust false setoverprint");
+ gen.writeln("} if");
+ gen.writeln("} if");
+ gen.writeln("} bd");
+
+ gen.writeln("/EndEPSF { %def");
+ gen.writeln("count op_count sub {pop} repeat % Clean up stacks");
+ gen.writeln("countdictstack dict_count sub {end} repeat");
+ gen.writeln("b4_Inc_state restore");
+ gen.writeln("} bd");
+
+ gen.writeln("%%EndResource");
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java
new file mode 100644
index 000000000..9e22812ed
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSRenderer.java
@@ -0,0 +1,901 @@
+/*
+ * $Id: PSRenderer.java,v 1.31 2003/03/11 08:42:24 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+// Java
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+// FOP
+import org.apache.fop.fo.properties.BackgroundRepeat;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.RegionViewport;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.area.Block;
+import org.apache.fop.area.BlockViewport;
+import org.apache.fop.area.CTM;
+import org.apache.fop.area.PageViewport;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.ForeignObject;
+import org.apache.fop.area.inline.Word;
+import org.apache.fop.datatypes.ColorType;
+import org.apache.fop.fo.FOUserAgent;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.layout.FontInfo;
+import org.apache.fop.render.AbstractRenderer;
+import org.apache.fop.render.RendererContext;
+
+import org.apache.fop.image.FopImage;
+import org.apache.fop.image.ImageFactory;
+import org.apache.fop.traits.BorderProps;
+
+import org.w3c.dom.Document;
+/**
+ * Renderer that renders to PostScript.
+ * <br>
+ * This class currently generates PostScript Level 2 code. The only exception
+ * is the FlateEncode filter which is a Level 3 feature. The filters in use
+ * are hardcoded at the moment.
+ * <br>
+ * This class follows the Document Structuring Conventions (DSC) version 3.0.
+ * If anyone modifies this renderer please make
+ * sure to also follow the DSC to make it simpler to programmatically modify
+ * the generated Postscript files (ex. extract pages etc.).
+ * <br>
+ * The PS renderer operates in millipoints as the layout engine. Since PostScript
+ * initially uses points, scaling is applied as needed.
+ * @todo Rebuild the PostScript renderer
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id: PSRenderer.java,v 1.31 2003/03/11 08:42:24 jeremias Exp $
+ */
+public class PSRenderer extends AbstractRenderer {
+
+ /** The MIME type for PostScript */
+ public static final String MIME_TYPE = "application/postscript";
+
+ /** The application producing the PostScript */
+ protected String producer;
+ private int currentPageNumber = 0;
+
+ private boolean enableComments = true;
+
+ /** The PostScript generator used to output the PostScript */
+ protected PSGenerator gen;
+ private boolean ioTrouble = false;
+
+ private String currentFontName;
+ private int currentFontSize;
+ private int pageHeight;
+ private int pageWidth;
+ private float currRed;
+ private float currGreen;
+ private float currBlue;
+
+ private FontInfo fontInfo;
+
+ /**
+ * Set the document's producer
+ *
+ * @param producer string indicating application producing the PostScript
+ */
+ public void setProducer(String producer) {
+ this.producer = producer;
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
+ */
+ public void setUserAgent(FOUserAgent agent) {
+ super.setUserAgent(agent);
+ PSXMLHandler xmlHandler = new PSXMLHandler();
+ //userAgent.setDefaultXMLHandler(MIME_TYPE, xmlHandler);
+ String svg = "http://www.w3.org/2000/svg";
+ userAgent.addXMLHandler(MIME_TYPE, svg, xmlHandler);
+ }
+
+ /**
+ * Write out a command
+ * @param cmd PostScript command
+ */
+ protected void writeln(String cmd) {
+ try {
+ gen.writeln(cmd);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * Central exception handler for I/O exceptions.
+ * @param ioe IOException to handle
+ */
+ protected void handleIOTrouble(IOException ioe) {
+ if (!ioTrouble) {
+ getLogger().error("Error while writing to target file", ioe);
+ ioTrouble = true;
+ }
+ }
+
+ /**
+ * Write out a comment
+ * @param comment Comment to write
+ */
+ protected void comment(String comment) {
+ if (this.enableComments) {
+ writeln(comment);
+ }
+ }
+
+ /**
+ * Generates the PostScript code for the font dictionary.
+ * @param fontInfo available fonts
+ */
+ protected void writeFontDict(FontInfo fontInfo) {
+ writeln("%%BeginResource: procset FOPFonts");
+ writeln("%%Title: Font setup (shortcuts) for this file");
+ writeln("/FOPFonts 100 dict dup begin");
+
+ // write("/gfF1{/Helvetica findfont} bd");
+ // write("/gfF3{/Helvetica-Bold findfont} bd");
+ Map fonts = fontInfo.getFonts();
+ Iterator enum = fonts.keySet().iterator();
+ while (enum.hasNext()) {
+ String key = (String)enum.next();
+ Font fm = (Font)fonts.get(key);
+ writeln("/" + key + " /" + fm.getFontName() + " def");
+ }
+ writeln("end def");
+ writeln("%%EndResource");
+ enum = fonts.keySet().iterator();
+ while (enum.hasNext()) {
+ String key = (String)enum.next();
+ Font fm = (Font)fonts.get(key);
+ writeln("/" + fm.getFontName() + " findfont");
+ writeln("dup length dict begin");
+ writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall");
+ writeln(" /Encoding ISOLatin1Encoding def");
+ writeln(" currentdict");
+ writeln("end");
+ writeln("/" + fm.getFontName() + " exch definefont pop");
+ }
+ }
+
+ /**
+ * Make sure the cursor is in the right place.
+ */
+ protected void movetoCurrPosition() {
+ moveTo(this.currentIPPosition, this.currentBPPosition);
+ }
+
+ /**
+ * Moves the cursor.
+ * @param x X coordinate
+ * @param y Y coordinate
+ */
+ protected void moveTo(int x, int y) {
+ writeln(x + " " + y + " M");
+ }
+
+ /** Saves the graphics state of the rendering engine. */
+ public void saveGraphicsState() {
+ try {
+ //delegate
+ gen.saveGraphicsState();
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /** Restores the last graphics state of the rendering engine. */
+ public void restoreGraphicsState() {
+ try {
+ //delegate
+ gen.restoreGraphicsState();
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /** Indicates the beginning of a text object. */
+ protected void beginTextObject() {
+ writeln("BT");
+ }
+
+ /** Indicates the end of a text object. */
+ protected void endTextObject() {
+ writeln("ET");
+ }
+
+ /**
+ * Concats the transformation matrix.
+ * @param a A part
+ * @param b B part
+ * @param c C part
+ * @param d D part
+ * @param e E part
+ * @param f F part
+ */
+ protected void concatMatrix(double a, double b,
+ double c, double d,
+ double e, double f) {
+ try {
+ gen.concatMatrix(a, b, c, d, e, f);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * Concats the transformations matrix.
+ * @param matrix Matrix to use
+ */
+ protected void concatMatrix(double[] matrix) {
+ try {
+ gen.concatMatrix(matrix);
+ } catch (IOException ioe) {
+ handleIOTrouble(ioe);
+ }
+ }
+
+ /**
+ * Set up the font info
+ *
+ * @param fontInfo the font info object to set up
+ */
+ public void setupFontInfo(FontInfo fontInfo) {
+ /* use PDF's font setup to get PDF metrics */
+ org.apache.fop.render.pdf.FontSetup.setup(fontInfo, null);
+ this.fontInfo = fontInfo;
+ }
+
+ /**
+ * Draws a filled rectangle.
+ * @param x x-coordinate
+ * @param y y-coordinate
+ * @param w width
+ * @param h height
+ * @param col color to fill with
+ */
+ protected void fillRect(int x, int y, int w, int h,
+ ColorType col) {
+ useColor(col);
+ writeln(x + " " + y + " " + w + " " + h + " rectfill");
+ }
+
+ /**
+ * Draws a stroked rectangle with the current stroke settings.
+ * @param x x-coordinate
+ * @param y y-coordinate
+ * @param w width
+ * @param h height
+ */
+ protected void drawRect(int x, int y, int w, int h) {
+ writeln(x + " " + y + " " + w + " " + h + " rectstroke");
+ }
+
+ /**
+ * 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
+ */
+ protected void clip(float x, float y, float width, float height) {
+ writeln(x + " " + y + " " + width + " " + height + " rectclip");
+ }
+
+ /**
+ * Changes the currently used font.
+ * @param name name of the font
+ * @param size font size
+ */
+ public void useFont(String name, int size) {
+ if ((currentFontName != name) || (currentFontSize != size)) {
+ writeln(name + " " + size + " F");
+ currentFontName = name;
+ currentFontSize = size;
+ }
+ }
+
+ private void useColor(ColorType col) {
+ useColor(col.getRed(), col.getGreen(), col.getBlue());
+ }
+
+ private void useColor(float red, float green, float blue) {
+ if ((red != currRed) || (green != currGreen) || (blue != currBlue)) {
+ writeln(red + " " + green + " " + blue + " setrgbcolor");
+ currRed = red;
+ currGreen = green;
+ currBlue = blue;
+ }
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#startRenderer(OutputStream)
+ */
+ public void startRenderer(OutputStream outputStream)
+ throws IOException {
+ getLogger().debug("rendering areas to PostScript");
+
+ //Setup for PostScript generation
+ this.gen = new PSGenerator(outputStream);
+ this.currentPageNumber = 0;
+
+ //PostScript Header
+ writeln(DSCConstants.PS_ADOBE_30);
+ gen.writeDSCComment(DSCConstants.CREATOR, new String[] {"FOP " + this.producer});
+ gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()});
+ gen.writeDSCComment(DSCConstants.PAGES, new Object[] {PSGenerator.ATEND});
+ gen.writeDSCComment(DSCConstants.END_COMMENTS);
+
+ //Defaults
+ gen.writeDSCComment(DSCConstants.BEGIN_DEFAULTS);
+ gen.writeDSCComment(DSCConstants.END_DEFAULTS);
+
+ //Prolog
+ gen.writeDSCComment(DSCConstants.BEGIN_PROLOG);
+ gen.writeDSCComment(DSCConstants.END_PROLOG);
+
+ //Setup
+ gen.writeDSCComment(DSCConstants.BEGIN_SETUP);
+ PSProcSets.writeFOPStdProcSet(gen);
+ PSProcSets.writeFOPEPSProcSet(gen);
+ writeFontDict(fontInfo);
+ gen.writeDSCComment(DSCConstants.END_SETUP);
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#stopRenderer()
+ */
+ public void stopRenderer() throws IOException {
+ gen.writeDSCComment(DSCConstants.TRAILER);
+ gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.currentPageNumber));
+ gen.writeDSCComment(DSCConstants.EOF);
+ gen.flush();
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#renderPage(PageViewport)
+ */
+ public void renderPage(PageViewport page)
+ throws IOException, FOPException {
+ getLogger().debug("renderPage(): " + page);
+
+ this.currentPageNumber++;
+ gen.writeDSCComment(DSCConstants.PAGE, new Object[]
+ {page.getPageNumber(),
+ new Integer(this.currentPageNumber)});
+ final Integer zero = new Integer(0);
+ final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth()));
+ final Long pageheight = new Long(Math.round(page.getViewArea().getHeight()));
+ gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[]
+ {zero, zero, pagewidth, pageheight});
+ gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP);
+ gen.writeln("FOPFonts begin");
+ gen.writeln("0.001 0.001 scale");
+ concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue());
+
+ gen.writeDSCComment(DSCConstants.END_PAGE_SETUP);
+
+ //Process page
+ super.renderPage(page);
+
+ writeln("showpage");
+ gen.writeDSCComment(DSCConstants.PAGE_TRAILER);
+ gen.writeDSCComment(DSCConstants.END_PAGE);
+ }
+
+ /**
+ * Paints text.
+ * @param rx X coordinate
+ * @param bl Y coordinate
+ * @param text Text to paint
+ * @param font Font to use
+ */
+ protected void paintText(int rx, int bl, String text, Font font) {
+ saveGraphicsState();
+ writeln("1 0 0 -1 " + rx + " " + bl + " Tm");
+
+ int initialSize = text.length();
+ initialSize += initialSize / 2;
+ StringBuffer sb = new StringBuffer(initialSize);
+ sb.append("(");
+ for (int i = 0; i < text.length(); i++) {
+ final char c = text.charAt(i);
+ final char mapped = font.mapChar(c);
+ gen.escapeChar(mapped, sb);
+ }
+ sb.append(") t");
+ writeln(sb.toString());
+ restoreGraphicsState();
+ }
+
+ /**
+ * @see org.apache.fop.render.Renderer#renderWord(Word)
+ */
+ public void renderWord(Word area) {
+ String fontname = (String)area.getTrait(Trait.FONT_NAME);
+ int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE);
+
+ // This assumes that *all* CIDFonts use a /ToUnicode mapping
+ Font f = (Font)fontInfo.getFonts().get(fontname);
+
+ //Determine position
+ int rx = currentBlockIPPosition;
+ int bl = currentBPPosition + area.getOffset();
+
+ useFont(fontname, fontsize);
+
+ paintText(rx, bl, area.getWord(), f);
+
+/*
+ String psString = null;
+ if (area.getFontState().getLetterSpacing() > 0) {
+ //float f = area.getFontState().getLetterSpacing()
+ // * 1000 / this.currentFontSize;
+ float f = area.getFontState().getLetterSpacing();
+ psString = (new StringBuffer().append(f).append(" 0.0 (")
+ .append(sb.toString()).append(") A")).toString();
+ } else {
+ psString = (new StringBuffer("(").append(sb.toString())
+ .append(") t")).toString();
+ }
+
+
+ // System.out.println("["+s+"] --> ["+sb.toString()+"]");
+
+ // comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString());
+ useFont(fs.getFontName(), fs.getFontSize());
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ if (area.getUnderlined() || area.getLineThrough()
+ || area.getOverlined())
+ write("ULS");
+ write(psString);
+ if (area.getUnderlined())
+ write("ULE");
+ if (area.getLineThrough())
+ write("SOE");
+ if (area.getOverlined())
+ write("OLE");
+ this.currentXPosition += area.getContentWidth();
+ */
+ super.renderWord(area); //Updates IPD
+ }
+
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
+ */
+ protected void renderBlockViewport(BlockViewport bv, List children) {
+ // clip and position viewport if necessary
+
+ // save positions
+ int saveIP = currentIPPosition;
+ int saveBP = currentBPPosition;
+ String saveFontName = currentFontName;
+
+ CTM ctm = bv.getCTM();
+
+ if (bv.getPositioning() == Block.ABSOLUTE) {
+
+ currentIPPosition = 0;
+ currentBPPosition = 0;
+
+ //closeText();
+ endTextObject();
+
+ if (bv.getClip()) {
+ saveGraphicsState();
+ int x = bv.getXOffset() + containingIPPosition;
+ int y = bv.getYOffset() + containingBPPosition;
+ int width = bv.getWidth();
+ int height = bv.getHeight();
+ clip(x, y, width, height);
+ }
+
+ CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
+ ctm = tempctm.multiply(ctm);
+
+ startVParea(ctm);
+ handleBlockTraits(bv);
+ renderBlocks(children);
+ endVParea();
+
+ if (bv.getClip()) {
+ restoreGraphicsState();
+ }
+ beginTextObject();
+
+ // clip if necessary
+
+ currentIPPosition = saveIP;
+ currentBPPosition = saveBP;
+ } else {
+
+ if (ctm != null) {
+ currentIPPosition = 0;
+ currentBPPosition = 0;
+
+ //closeText();
+ endTextObject();
+
+ double[] vals = ctm.toArray();
+ //boolean aclock = vals[2] == 1.0;
+ if (vals[2] == 1.0) {
+ ctm = ctm.translate(-saveBP - bv.getHeight(), -saveIP);
+ } else if (vals[0] == -1.0) {
+ ctm = ctm.translate(-saveIP - bv.getWidth(), -saveBP - bv.getHeight());
+ } else {
+ ctm = ctm.translate(saveBP, saveIP - bv.getWidth());
+ }
+ }
+
+ // clip if necessary
+ if (bv.getClip()) {
+ if (ctm == null) {
+ //closeText();
+ endTextObject();
+ }
+ saveGraphicsState();
+ int x = bv.getXOffset();
+ int y = bv.getYOffset();
+ int width = bv.getWidth();
+ int height = bv.getHeight();
+ clip(x, y, width, height);
+ }
+
+ if (ctm != null) {
+ startVParea(ctm);
+ }
+ handleBlockTraits(bv);
+ renderBlocks(children);
+ if (ctm != null) {
+ endVParea();
+ }
+
+ if (bv.getClip()) {
+ restoreGraphicsState();
+ if (ctm == null) {
+ beginTextObject();
+ }
+ }
+ if (ctm != null) {
+ beginTextObject();
+ }
+
+ currentIPPosition = saveIP;
+ currentBPPosition = saveBP;
+ currentBPPosition += (int)(bv.getHeight());
+ }
+ currentFontName = saveFontName;
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM)
+ */
+ protected void startVParea(CTM ctm) {
+ // Set the given CTM in the graphics state
+ //currentState.push();
+ //currentState.setTransform(new AffineTransform(CTMHelper.toPDFArray(ctm)));
+
+ saveGraphicsState();
+ // multiply with current CTM
+ //writeln(CTMHelper.toPDFString(ctm) + " cm\n");
+ final double matrix[] = ctm.toArray();
+ concatMatrix(matrix);
+
+ // Set clip?
+ beginTextObject();
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#endVParea()
+ */
+ protected void endVParea() {
+ endTextObject();
+ restoreGraphicsState();
+ //currentState.pop();
+ }
+
+ /**
+ * Handle the viewport traits.
+ * This is used to draw the traits for a viewport.
+ *
+ * @param region the viewport region to handle
+ */
+ protected void handleViewportTraits(RegionViewport region) {
+ currentFontName = "";
+ float startx = 0;
+ float starty = 0;
+ Rectangle2D viewArea = region.getViewArea();
+ float width = (float)(viewArea.getWidth());
+ float height = (float)(viewArea.getHeight());
+ /*
+ Trait.Background back;
+ back = (Trait.Background)region.getTrait(Trait.BACKGROUND);
+ */
+ drawBackAndBorders(region, startx, starty, width, height);
+ }
+
+ /**
+ * Handle block traits.
+ * The block could be any sort of block with any positioning
+ * so this should render the traits such as border and background
+ * in its position.
+ *
+ * @param block the block to render the traits
+ */
+ protected void handleBlockTraits(Block block) {
+ float startx = currentIPPosition;
+ float starty = currentBPPosition;
+ drawBackAndBorders(block, startx, starty,
+ block.getWidth(), block.getHeight());
+ }
+
+ /**
+ * Draw the background and borders.
+ * This draws the background and border traits for an area given
+ * the position.
+ *
+ * @param block the area to get the traits from
+ * @param startx the start x position
+ * @param starty the start y position
+ * @param width the width of the area
+ * @param height the height of the area
+ */
+ protected void drawBackAndBorders(Area block,
+ float startx, float starty,
+ float width, float height) {
+ // draw background then border
+
+ boolean started = false;
+ Trait.Background back;
+ back = (Trait.Background)block.getTrait(Trait.BACKGROUND);
+ if (back != null) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+
+ if (back.getColor() != null) {
+ updateColor(back.getColor(), true, null);
+ writeln(startx + " " + starty + " "
+ + width + " " + height + " rectfill");
+ }
+ if (back.getURL() != null) {
+ ImageFactory fact = ImageFactory.getInstance();
+ FopImage fopimage = fact.getImage(back.getURL(), userAgent);
+ if (fopimage != null && fopimage.load(FopImage.DIMENSIONS, userAgent)) {
+ if (back.getRepeat() == BackgroundRepeat.REPEAT) {
+ // create a pattern for the image
+ } else {
+ // place once
+ Rectangle2D pos;
+ pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000,
+ (starty + back.getVertical()) * 1000,
+ fopimage.getWidth() * 1000,
+ fopimage.getHeight() * 1000);
+ // putImage(back.url, pos);
+ }
+ }
+ }
+ }
+
+ BorderProps bps = (BorderProps)block.getTrait(Trait.BORDER_BEFORE);
+ if (bps != null) {
+ float endx = startx + width;
+
+ if (!started) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+
+ drawLine(startx, starty + bwidth / 2, endx, starty + bwidth / 2);
+ }
+ bps = (BorderProps)block.getTrait(Trait.BORDER_START);
+ if (bps != null) {
+ float endy = starty + height;
+
+ if (!started) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+
+ drawLine(startx + bwidth / 2, starty, startx + bwidth / 2, endy);
+ }
+ bps = (BorderProps)block.getTrait(Trait.BORDER_AFTER);
+ if (bps != null) {
+ float sy = starty + height;
+ float endx = startx + width;
+
+ if (!started) {
+ started = true;
+// closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+
+ drawLine(startx, sy - bwidth / 2, endx, sy - bwidth / 2);
+ }
+ bps = (BorderProps)block.getTrait(Trait.BORDER_END);
+ if (bps != null) {
+ float sx = startx + width;
+ float endy = starty + height;
+
+ if (!started) {
+ started = true;
+ // closeText();
+ endTextObject();
+ //saveGraphicsState();
+ }
+
+ float bwidth = bps.width ;
+ updateColor(bps.color, false, null);
+ writeln(bwidth + " setlinewidth");
+ drawLine(sx - bwidth / 2, starty, sx - bwidth / 2, endy);
+ }
+ if (started) {
+ //restoreGraphicsState();
+ beginTextObject();
+ // font last set out of scope in text section
+ currentFontName = "";
+ }
+ }
+
+ /**
+ * Draw a line.
+ *
+ * @param startx the start x position
+ * @param starty the start y position
+ * @param endx the x end position
+ * @param endy the y end position
+ */
+ private void drawLine(float startx, float starty, float endx, float endy) {
+ writeln(startx + " " + starty + " M ");
+ writeln(endx + " " + endy + " lineto");
+ }
+
+ private void updateColor(ColorType col, boolean fill, StringBuffer pdf) {
+ writeln(gen.formatDouble(col.getRed()) + " "
+ + gen.formatDouble(col.getGreen()) + " "
+ + gen.formatDouble(col.getBlue()) + " setrgbcolor");
+ }
+
+ private void updateFont(String name, int size, StringBuffer pdf) {
+
+ }
+
+ /**
+ * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
+ */
+ public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
+ Document doc = fo.getDocument();
+ String ns = fo.getNameSpace();
+ renderDocument(doc, ns, pos);
+ }
+
+ /**
+ * Renders an XML document (SVG for example).
+ * @param doc DOM Document containing the XML document to be rendered
+ * @param ns Namespace for the XML document
+ * @param pos Position for the generated graphic/image
+ */
+ public void renderDocument(Document doc, String ns, Rectangle2D pos) {
+ RendererContext context;
+ context = new RendererContext(MIME_TYPE);
+ context.setUserAgent(userAgent);
+
+ context.setProperty(PSXMLHandler.PS_GENERATOR, this.gen);
+ context.setProperty(PSXMLHandler.PS_FONT_INFO, fontInfo);
+ context.setProperty(PSXMLHandler.PS_WIDTH,
+ new Integer((int) pos.getWidth()));
+ context.setProperty(PSXMLHandler.PS_HEIGHT,
+ new Integer((int) pos.getHeight()));
+ context.setProperty(PSXMLHandler.PS_XPOS,
+ new Integer(currentBlockIPPosition + (int) pos.getX()));
+ context.setProperty(PSXMLHandler.PS_YPOS,
+ new Integer(currentBPPosition + (int) pos.getY()));
+ //context.setProperty("strokeSVGText", options.get("strokeSVGText"));
+
+ /*
+ context.setProperty(PDFXMLHandler.PDF_DOCUMENT, pdfDoc);
+ context.setProperty(PDFXMLHandler.OUTPUT_STREAM, ostream);
+ context.setProperty(PDFXMLHandler.PDF_STATE, currentState);
+ context.setProperty(PDFXMLHandler.PDF_PAGE, currentPage);
+ context.setProperty(PDFXMLHandler.PDF_CONTEXT,
+ currentContext == null ? currentPage: currentContext);
+ context.setProperty(PDFXMLHandler.PDF_CONTEXT, currentContext);
+ context.setProperty(PDFXMLHandler.PDF_STREAM, currentStream);
+ context.setProperty(PDFXMLHandler.PDF_XPOS,
+ new Integer(currentBlockIPPosition + (int) pos.getX()));
+ context.setProperty(PDFXMLHandler.PDF_YPOS,
+ new Integer(currentBPPosition + (int) pos.getY()));
+ context.setProperty(PDFXMLHandler.PDF_FONT_INFO, fontInfo);
+ context.setProperty(PDFXMLHandler.PDF_FONT_NAME, currentFontName);
+ context.setProperty(PDFXMLHandler.PDF_FONT_SIZE,
+ new Integer(currentFontSize));
+ context.setProperty(PDFXMLHandler.PDF_WIDTH,
+ new Integer((int) pos.getWidth()));
+ context.setProperty(PDFXMLHandler.PDF_HEIGHT,
+ new Integer((int) pos.getHeight()));
+ */
+ userAgent.renderXML(context, doc, ns);
+
+ }
+
+
+
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSState.java b/src/java/org/apache/fop/render/ps/PSState.java
new file mode 100644
index 000000000..32daaee53
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSState.java
@@ -0,0 +1,97 @@
+/*
+ * $Id: PSState.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.Serializable;
+import java.awt.geom.AffineTransform;
+
+/**
+ * This class holds the current state of the PostScript interpreter.
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id: PSState.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class PSState implements Serializable, Cloneable {
+
+ private AffineTransform transform = new AffineTransform();
+
+
+
+ /**
+ * Returns the transform.
+ * @return the current transformation matrix
+ */
+ public AffineTransform getTransform() {
+ return this.transform;
+ }
+
+ /**
+ * Concats the given transformation matrix with the current one.
+ * @param transform The new transformation matrix
+ */
+ public void concatMatrix(AffineTransform transform) {
+ this.transform.concatenate(transform);
+ }
+
+ /**
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError();
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSTextElementBridge.java b/src/java/org/apache/fop/render/ps/PSTextElementBridge.java
new file mode 100644
index 000000000..e7bc31fe8
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSTextElementBridge.java
@@ -0,0 +1,159 @@
+/*
+ * $Id: PSTextElementBridge.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+//import org.apache.batik.gvt.TextNode;
+import org.apache.batik.bridge.SVGTextElementBridge;
+import org.apache.batik.bridge.BridgeContext;
+//import org.apache.batik.bridge.TextUtilities;
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.apache.fop.layout.FontInfo;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Bridge class for the &lt;text> element.
+ * This bridge will use the direct text painter if the text
+ * for the element is simple.
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @version $Id: PSTextElementBridge.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class PSTextElementBridge extends SVGTextElementBridge {
+
+ //private PSTextPainter textPainter;
+
+ /**
+ * Constructs a new bridge for the &lt;text> element.
+ * @param fi the font infomration
+ */
+ public PSTextElementBridge(FontInfo fi) {
+ //textPainter = new PSTextPainter(fi);
+ }
+
+ /**
+ * Create a text element bridge.
+ * This set the text painter on the node if the text is simple.
+ * @param ctx the bridge context
+ * @param e the svg element
+ * @return the text graphics node created by the super class
+ */
+ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
+ GraphicsNode node = super.createGraphicsNode(ctx, e);
+ /*
+ if (node != null && isSimple(ctx, e, node)) {
+ ((TextNode)node).setTextPainter(getTextPainter());
+ }*/
+ return node;
+ }
+
+ /*
+ private PSTextPainter getTextPainter() {
+ return textPainter;
+ }
+ */
+
+ /**
+ * Check if text element contains simple text.
+ * This checks the children of the text element to determine
+ * if the text is simple. The text is simple if it can be rendered
+ * with basic text drawing algorithms. This means there are no
+ * alternate characters, the font is known and there are no effects
+ * applied to the text.
+ *
+ * @param ctx the bridge context
+ * @param element the svg text element
+ * @param node the graphics node
+ * @return true if this text is simple of false if it cannot be
+ * easily rendered using normal drawString on the PDFGraphics2D
+ */
+ private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) {
+ /*
+ // Font size, in user space units.
+ float fs = TextUtilities.convertFontSize(element).floatValue();
+ // PDF cannot display fonts over 36pt
+ if (fs > 36) {
+ return false;
+ }
+ */
+
+
+ for (Node n = element.getFirstChild();
+ n != null;
+ n = n.getNextSibling()) {
+
+ switch (n.getNodeType()) {
+ case Node.ELEMENT_NODE:
+
+ if (n.getLocalName().equals(SVG_TSPAN_TAG)
+ || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) {
+ return false;
+ } else if (n.getLocalName().equals(SVG_TEXT_PATH_TAG)) {
+ return false;
+ } else if (n.getLocalName().equals(SVG_TREF_TAG)) {
+ return false;
+ }
+ break;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ }
+ }
+
+ /*if (CSSUtilities.convertFilter(element, node, ctx) != null) {
+ return false;
+ }*/
+
+ return true;
+ }
+}
+
diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java
new file mode 100644
index 000000000..6f2aab65a
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java
@@ -0,0 +1,435 @@
+/*
+ * $Id$
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.Font;
+
+import java.text.AttributedCharacterIterator;
+import java.awt.font.TextAttribute;
+import java.awt.Shape;
+import java.awt.Paint;
+import java.awt.Stroke;
+import java.awt.Color;
+import java.util.List;
+import java.util.Iterator;
+
+import org.apache.batik.gvt.text.Mark;
+import org.apache.batik.gvt.TextPainter;
+import org.apache.batik.gvt.TextNode;
+import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+import org.apache.batik.gvt.font.GVTFontFamily;
+import org.apache.batik.bridge.SVGFontFamily;
+import org.apache.batik.gvt.renderer.StrokingTextPainter;
+
+import org.apache.fop.fonts.FontMetrics;
+import org.apache.fop.layout.FontState;
+import org.apache.fop.layout.FontInfo;
+
+/**
+ * Renders the attributed character iterator of a <tt>TextNode</tt>.
+ * This class draws the text directly into the PSGraphics2D so that
+ * the text is not drawn using shapes which makes the PS files larger.
+ * If the text is simple enough to draw then it sets the font and calls
+ * drawString. If the text is complex or the cannot be translated
+ * into a simple drawString the StrokingTextPainter is used instead.
+ *
+ * @todo handle underline, overline and strikethrough
+ * @todo use drawString(AttributedCharacterIterator iterator...) for some
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @version $Id: PSTextPainter.java,v 1.15 2003/01/08 14:03:55 jeremias Exp $
+ */
+public class PSTextPainter implements TextPainter {
+ private FontInfo fontInfo;
+
+ /**
+ * Use the stroking text painter to get the bounds and shape.
+ * Also used as a fallback to draw the string with strokes.
+ */
+ protected static final TextPainter PROXY_PAINTER =
+ StrokingTextPainter.getInstance();
+
+ /**
+ * Create a new PS text painter with the given font information.
+ * @param fi the fint info
+ */
+ public PSTextPainter(FontInfo fi) {
+ fontInfo = fi;
+ }
+
+ /**
+ * Paints the specified attributed character iterator using the
+ * specified Graphics2D and context and font context.
+ * @param node the TextNode to paint
+ * @param g2d the Graphics2D to use
+ */
+ public void paint(TextNode node, Graphics2D g2d) {
+ // System.out.println("PSText paint");
+ String txt = node.getText();
+ Point2D loc = node.getLocation();
+
+ AttributedCharacterIterator aci =
+ node.getAttributedCharacterIterator();
+ // reset position to start of char iterator
+ if (aci.getBeginIndex() == aci.getEndIndex()) {
+ return;
+ }
+ char ch = aci.first();
+ if (ch == AttributedCharacterIterator.DONE) {
+ return;
+ }
+ TextNode.Anchor anchor;
+ anchor = (TextNode.Anchor) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+
+ List gvtFonts;
+ gvtFonts = (List) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
+ Paint forg = (Paint) aci.getAttribute(TextAttribute.FOREGROUND);
+ Paint strokePaint;
+ strokePaint = (Paint) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT);
+ Float size = (Float) aci.getAttribute(TextAttribute.SIZE);
+ if (size == null) {
+ return;
+ }
+ Stroke stroke = (Stroke) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.STROKE);
+ /*
+ Float xpos = (Float) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.X);
+ Float ypos = (Float) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.Y);
+ */
+
+ Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
+ Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
+
+ boolean useStrokePainter = false;
+
+ if (forg instanceof Color) {
+ Color col = (Color) forg;
+ if (col.getAlpha() != 255) {
+ useStrokePainter = true;
+ }
+ g2d.setColor(col);
+ }
+ g2d.setPaint(forg);
+ g2d.setStroke(stroke);
+
+ if (strokePaint != null) {
+ // need to draw using AttributedCharacterIterator
+ useStrokePainter = true;
+ }
+
+ if (hasUnsupportedAttributes(aci)) {
+ useStrokePainter = true;
+ }
+
+ // text contains unsupported information
+ if (useStrokePainter) {
+ PROXY_PAINTER.paint(node, g2d);
+ return;
+ }
+
+ String style = ((posture != null) && (posture.floatValue() > 0.0))
+ ? "italic" : "normal";
+ int weight = ((taWeight != null)
+ && (taWeight.floatValue() > 1.0)) ? FontInfo.BOLD
+ : FontInfo.NORMAL;
+
+ FontState fontState = null;
+ FontInfo fi = fontInfo;
+ boolean found = false;
+ String fontFamily = null;
+ if (gvtFonts != null) {
+ Iterator i = gvtFonts.iterator();
+ while (i.hasNext()) {
+ GVTFontFamily fam = (GVTFontFamily) i.next();
+ if (fam instanceof SVGFontFamily) {
+ PROXY_PAINTER.paint(node, g2d);
+ return;
+ }
+ fontFamily = fam.getFamilyName();
+ if (fi.hasFont(fontFamily, style, weight)) {
+ String fname = fontInfo.fontLookup(fontFamily, style,
+ weight);
+ FontMetrics metrics = fontInfo.getMetricsFor(fname);
+ int fsize = (int)(size.floatValue() * 1000);
+ fontState = new FontState(fname, metrics, fsize);
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ String fname =
+ fontInfo.fontLookup("any", style, FontInfo.NORMAL);
+ FontMetrics metrics = fontInfo.getMetricsFor(fname);
+ int fsize = (int)(size.floatValue() * 1000);
+ fontState = new FontState(fname, metrics, fsize);
+ } else {
+ if (g2d instanceof PSGraphics2D) {
+ ((PSGraphics2D) g2d).setOverrideFontState(fontState);
+ }
+ }
+ int fStyle = Font.PLAIN;
+ if (weight == FontInfo.BOLD) {
+ if (style.equals("italic")) {
+ fStyle = Font.BOLD | Font.ITALIC;
+ } else {
+ fStyle = Font.BOLD;
+ }
+ } else {
+ if (style.equals("italic")) {
+ fStyle = Font.ITALIC;
+ } else {
+ fStyle = Font.PLAIN;
+ }
+ }
+ Font font = new Font(fontFamily, fStyle,
+ (int)(fontState.getFontSize() / 1000));
+
+ g2d.setFont(font);
+
+ float advance = getStringWidth(txt, fontState);
+ float tx = 0;
+ if (anchor != null) {
+ switch (anchor.getType()) {
+ case TextNode.Anchor.ANCHOR_MIDDLE:
+ tx = -advance / 2;
+ break;
+ case TextNode.Anchor.ANCHOR_END:
+ tx = -advance;
+ }
+ }
+ g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
+ }
+
+ private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
+ boolean hasunsupported = false;
+ Object letSpace = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
+ if (letSpace != null) {
+ hasunsupported = true;
+ }
+
+ Object wordSpace = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
+ if (wordSpace != null) {
+ hasunsupported = true;
+ }
+
+ AttributedCharacterIterator.Attribute key;
+ key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE;
+ Object writeMod = aci.getAttribute(key);
+ if (!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
+ writeMod)) {
+ hasunsupported = true;
+ }
+
+ Object vertOr = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
+ if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
+ vertOr)) {
+ hasunsupported = true;
+ }
+ return hasunsupported;
+ }
+
+ private float getStringWidth(String str, FontState fontState) {
+ float wordWidth = 0;
+ float whitespaceWidth = fontState.getWidth(fontState.mapChar(' '));
+
+ for (int i = 0; i < str.length(); i++) {
+ float charWidth;
+ char c = str.charAt(i);
+ if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) {
+ charWidth = fontState.getWidth(fontState.mapChar(c));
+ if (charWidth <= 0) {
+ charWidth = whitespaceWidth;
+ }
+ } else {
+ charWidth = whitespaceWidth;
+ }
+ wordWidth += charWidth;
+ }
+ return wordWidth / 1000f;
+ }
+
+ /**
+ * Get the outline shape of the text characters.
+ * This uses the StrokingTextPainter to get the outline
+ * shape since in theory it should be the same.
+ *
+ * @param node the text node
+ * @return the outline shape of the text characters
+ */
+ public Shape getOutline(TextNode node) {
+ return PROXY_PAINTER.getOutline(node);
+ }
+
+ /**
+ * Get the bounds.
+ * This uses the StrokingTextPainter to get the bounds
+ * since in theory it should be the same.
+ *
+ * @param node the text node
+ * @return the bounds of the text
+ */
+ public Rectangle2D getBounds2D(TextNode node) {
+ return PROXY_PAINTER.getBounds2D(node);
+ }
+
+ /**
+ * Get the geometry bounds.
+ * This uses the StrokingTextPainter to get the bounds
+ * since in theory it should be the same.
+ * @param node the text node
+ * @return the bounds of the text
+ */
+ public Rectangle2D getGeometryBounds(TextNode node) {
+ return PROXY_PAINTER.getGeometryBounds(node);
+ }
+
+ // Methods that have no purpose for PS
+
+ /**
+ * Get the mark.
+ * This does nothing since the output is pdf and not interactive.
+ * @param node the text node
+ * @param pos the position
+ * @param all select all
+ * @return null
+ */
+ public Mark getMark(TextNode node, int pos, boolean all) {
+ System.out.println("PSText getMark");
+ return null;
+ }
+
+ /**
+ * Select at.
+ * This does nothing since the output is pdf and not interactive.
+ * @param x the x position
+ * @param y the y position
+ * @param node the text node
+ * @return null
+ */
+ public Mark selectAt(double x, double y, TextNode node) {
+ System.out.println("PSText selectAt");
+ return null;
+ }
+
+ /**
+ * Select to.
+ * This does nothing since the output is pdf and not interactive.
+ * @param x the x position
+ * @param y the y position
+ * @param beginMark the start mark
+ * @return null
+ */
+ public Mark selectTo(double x, double y, Mark beginMark) {
+ System.out.println("PSText selectTo");
+ return null;
+ }
+
+ /**
+ * Selec first.
+ * This does nothing since the output is pdf and not interactive.
+ * @param node the text node
+ * @return null
+ */
+ public Mark selectFirst(TextNode node) {
+ System.out.println("PSText selectFirst");
+ return null;
+ }
+
+ /**
+ * Select last.
+ * This does nothing since the output is pdf and not interactive.
+ * @param node the text node
+ * @return null
+ */
+ public Mark selectLast(TextNode node) {
+ System.out.println("PSText selectLast");
+ return null;
+ }
+
+ /**
+ * Get selected.
+ * This does nothing since the output is pdf and not interactive.
+ * @param start the start mark
+ * @param finish the finish mark
+ * @return null
+ */
+ public int[] getSelected(Mark start, Mark finish) {
+ System.out.println("PSText getSelected");
+ return null;
+ }
+
+ /**
+ * Get the highlighted shape.
+ * This does nothing since the output is pdf and not interactive.
+ * @param beginMark the start mark
+ * @param endMark the end mark
+ * @return null
+ */
+ public Shape getHighlightShape(Mark beginMark, Mark endMark) {
+ System.out.println("PSText getHighlightShape");
+ return null;
+ }
+
+}
+
+
diff --git a/src/java/org/apache/fop/render/ps/PSXMLHandler.java b/src/java/org/apache/fop/render/ps/PSXMLHandler.java
new file mode 100644
index 000000000..3b4ddcdd1
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/PSXMLHandler.java
@@ -0,0 +1,379 @@
+/*
+ * $Id: PSXMLHandler.java,v 1.4 2003/03/11 08:42:24 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+// Java
+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.batik.bridge.GVTBuilder;
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.ViewBox;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.TextPainter;
+
+// FOP
+import org.apache.fop.render.XMLHandler;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.svg.SVGUserAgent;
+import org.apache.fop.layout.FontInfo;
+
+/**
+ * PostScript XML handler.
+ * This handler handles XML for foreign objects when rendering to PostScript.
+ * It renders SVG to the PostScript document using the PSGraphics2D.
+ * The properties from the PostScript renderer are subject to change.
+ *
+ * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
+ * @version $Id: PSXMLHandler.java,v 1.4 2003/03/11 08:42:24 jeremias Exp $
+ */
+public class PSXMLHandler implements XMLHandler {
+
+ /**
+ * The PostScript generator that is being used to drawn into.
+ */
+ public static final String PS_GENERATOR = "psGenerator";
+
+ /**
+ * The font information for the PostScript renderer.
+ */
+ public static final String PS_FONT_INFO = "psFontInfo";
+
+ /**
+ * The width of the SVG graphic.
+ */
+ public static final String PS_WIDTH = "width";
+
+ /**
+ * The height of the SVG graphic.
+ */
+ public static final String PS_HEIGHT = "height";
+
+ /**
+ * The x position that this is being drawn at.
+ */
+ public static final String PS_XPOS = "xpos";
+
+ /**
+ * The y position that this is being drawn at.
+ */
+ public static final String PS_YPOS = "ypos";
+
+ /**
+ * Create a new PostScript XML handler for use by the PostScript renderer.
+ */
+ public PSXMLHandler() {
+ }
+
+ /**
+ * Handle the XML.
+ * This checks the type of XML and handles appropraitely.
+ *
+ * @param context the renderer context
+ * @param doc the XML document to render
+ * @param ns the namespace of the XML document
+ * @throws Exception any sort of exception could be thrown and shuld be handled
+ */
+ public void handleXML(RendererContext context, Document doc,
+ String ns) throws Exception {
+ PSInfo psi = getPSInfo(context);
+
+ String svg = "http://www.w3.org/2000/svg";
+ if (svg.equals(ns)) {
+ SVGHandler svghandler = new SVGHandler();
+ svghandler.renderSVGDocument(context, doc, psi);
+ } else {
+ }
+ }
+
+ /**
+ * Get the pdf information from the render context.
+ *
+ * @param context the renderer context
+ * @return the pdf information retrieved from the context
+ */
+ public static PSInfo getPSInfo(RendererContext context) {
+ PSInfo psi = new PSInfo();
+ psi.psGenerator = (PSGenerator)context.getProperty(PS_GENERATOR);
+ psi.fontInfo = (FontInfo)context.getProperty(PS_FONT_INFO);
+ psi.width = ((Integer)context.getProperty(PS_WIDTH)).intValue();
+ psi.height = ((Integer)context.getProperty(PS_HEIGHT)).intValue();
+ psi.currentXPosition = ((Integer)context.getProperty(PS_XPOS)).intValue();
+ psi.currentYPosition = ((Integer)context.getProperty(PS_YPOS)).intValue();
+ return psi;
+ }
+
+ /**
+ * PostScript information structure for drawing the XML document.
+ */
+ public static class PSInfo {
+
+ /** see PS_GENERATOR */
+ private PSGenerator psGenerator;
+ /** see PS_FONT_INFO */
+ private FontInfo fontInfo;
+ /** see PS_PAGE_WIDTH */
+ private int width;
+ /** see PS_PAGE_HEIGHT */
+ private int height;
+ /** see PS_XPOS */
+ private int currentXPosition;
+ /** see PS_YPOS */
+ private int currentYPosition;
+ /**
+ * Returns the PSGenerator.
+ * @return PSGenerator
+ */
+ public PSGenerator getPSGenerator() {
+ return psGenerator;
+ }
+
+ /**
+ * Sets the PSGenerator.
+ * @param psGenerator The PSGenerator to set
+ */
+ public void setPsGenerator(PSGenerator psGenerator) {
+ this.psGenerator = psGenerator;
+ }
+
+ /**
+ * Returns the fontInfo.
+ * @return FontInfo
+ */
+ public FontInfo getFontInfo() {
+ return fontInfo;
+ }
+
+ /**
+ * Sets the fontInfo.
+ * @param fontInfo The fontInfo to set
+ */
+ public void setFontInfo(FontInfo fontInfo) {
+ this.fontInfo = fontInfo;
+ }
+
+ /**
+ * Returns the currentXPosition.
+ * @return int
+ */
+ public int getCurrentXPosition() {
+ return currentXPosition;
+ }
+
+ /**
+ * Sets the currentXPosition.
+ * @param currentXPosition The currentXPosition to set
+ */
+ public void setCurrentXPosition(int currentXPosition) {
+ this.currentXPosition = currentXPosition;
+ }
+
+ /**
+ * Returns the currentYPosition.
+ * @return int
+ */
+ public int getCurrentYPosition() {
+ return currentYPosition;
+ }
+
+ /**
+ * Sets the currentYPosition.
+ * @param currentYPosition The currentYPosition to set
+ */
+ public void setCurrentYPosition(int currentYPosition) {
+ this.currentYPosition = currentYPosition;
+ }
+
+ /**
+ * Returns the width.
+ * @return int
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Sets the width.
+ * @param width The pageWidth to set
+ */
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ /**
+ * Returns the height.
+ * @return int
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Sets the height.
+ * @param height The height to set
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ }
+
+ /**
+ * This method is placed in an inner class so that we don't get class
+ * loading errors if batik is not present.
+ */
+ protected class SVGHandler {
+ /**
+ * 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) {
+ int xOffset = psInfo.currentXPosition;
+ int yOffset = psInfo.currentYPosition;
+ PSGenerator gen = psInfo.psGenerator;
+
+ SVGUserAgent ua
+ = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
+
+
+ GVTBuilder builder = new GVTBuilder();
+ BridgeContext ctx = new BridgeContext(ua);
+ PSTextElementBridge tBridge = new PSTextElementBridge(psInfo.getFontInfo());
+ ctx.putBridge(tBridge);
+
+ //PSAElementBridge aBridge = new PSAElementBridge();
+ // to get the correct transform we need to use the PDFState
+ AffineTransform transform = gen.getCurrentState().getTransform();
+ transform.translate(xOffset / 1000f, yOffset / 1000f);
+ //aBridge.setCurrentTransform(transform);
+ //ctx.putBridge(aBridge);
+
+ TextPainter textPainter = new PSTextPainter(psInfo.getFontInfo());
+ ctx.setTextPainter(textPainter);
+ GraphicsNode root;
+ try {
+ root = builder.build(ctx, doc);
+ } catch (Exception e) {
+ context.getUserAgent().getLogger().error("SVG graphic could not be built: "
+ + e.getMessage(), e);
+ return;
+ }
+ // get the 'width' and 'height' attributes of the SVG document
+ float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
+ float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
+
+ float sx = psInfo.getWidth() / (float)w;
+ float sy = psInfo.getHeight() / (float)h;
+
+ ctx = null;
+ builder = null;
+
+ try {
+ gen.writeln("%SVG graphic start ---");
+ /*
+ * Clip to the svg area.
+ * Note: To have the svg overlay (under) a text area then use
+ * an fo:block-container
+ */
+ gen.saveGraphicsState();
+ // 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, xOffset, yOffset);
+
+ SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
+ AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg,
+ w / 1000f, h / 1000f);
+ if (!at.isIdentity()) {
+ double[] vals = new double[6];
+ at.getMatrix(vals);
+ gen.concatMatrix(vals);
+ }
+
+ /*
+ if (psInfo.pdfContext == null) {
+ psInfo.pdfContext = psInfo.pdfPage;
+ }*/
+ PSGraphics2D graphics = new PSGraphics2D(true, gen);
+ graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
+ //psInfo.pdfState.push();
+ transform = new AffineTransform();
+ // scale to viewbox
+ transform.translate(xOffset, yOffset);
+ gen.getCurrentState().concatMatrix(transform);
+ //graphics.setPDFState(psInfo.pdfState);
+ try {
+ root.paint(graphics);
+ //psInfo.currentStream.add(graphics.getString());
+ } catch (Exception e) {
+ context.getUserAgent().getLogger().error("SVG graphic could not be rendered: "
+ + e.getMessage(), e);
+ }
+
+ psInfo.psGenerator.restoreGraphicsState();
+ //psInfo.pdfState.pop();
+ gen.writeln("%SVG graphic end ---");
+ } catch (IOException ioe) {
+ context.getUserAgent().getLogger().error("SVG graphic could not be rendered: "
+ + ioe.getMessage(), ioe);
+ }
+ }
+ }
+}
+
diff --git a/src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java b/src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java
new file mode 100644
index 000000000..bdad9c0f0
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java
@@ -0,0 +1,217 @@
+/*
+ * $Id: RunLengthEncodeOutputStream.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class applies a RunLengthEncode filter to the stream.
+ *
+ * @author <a href="mailto:smwolke@geistig.com">Stephen Wolke</a>
+ * @version $Id: RunLengthEncodeOutputStream.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $
+ */
+public class RunLengthEncodeOutputStream extends FilterOutputStream
+ implements Finalizable {
+
+ private static final int MAX_SEQUENCE_COUNT = 127;
+ private static final int END_OF_DATA = 128;
+ private static final int BYTE_MAX = 256;
+
+ private static final int NOT_IDENTIFY_SEQUENCE = 0;
+ private static final int START_SEQUENCE = 1;
+ private static final int IN_SEQUENCE = 2;
+ private static final int NOT_IN_SEQUENCE = 3;
+
+ private int runCount = 0;
+ private int isSequence = NOT_IDENTIFY_SEQUENCE;
+ private byte[] runBuffer = new byte[MAX_SEQUENCE_COUNT + 1];
+
+
+ /** @see java.io.FilterOutputStream **/
+ public RunLengthEncodeOutputStream(OutputStream out) {
+ super(out);
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void write(byte b)
+ throws java.io.IOException {
+ runBuffer[runCount] = b;
+
+ switch (runCount) {
+ case 0:
+ runCount = 0;
+ isSequence = NOT_IDENTIFY_SEQUENCE;
+ runCount++;
+ break;
+ case 1:
+ if (runBuffer[runCount] != runBuffer[runCount - 1]) {
+ isSequence = NOT_IN_SEQUENCE;
+ }
+ runCount++;
+ break;
+ case 2:
+ if (runBuffer[runCount] != runBuffer[runCount - 1]) {
+ isSequence = NOT_IN_SEQUENCE;
+ } else {
+ if (isSequence == NOT_IN_SEQUENCE) {
+ isSequence = START_SEQUENCE;
+ } else {
+ isSequence = IN_SEQUENCE;
+ }
+ }
+ runCount++;
+ break;
+ case MAX_SEQUENCE_COUNT:
+ if (isSequence == IN_SEQUENCE) {
+ out.write(BYTE_MAX - (MAX_SEQUENCE_COUNT - 1));
+ out.write(runBuffer[runCount - 1]);
+ runBuffer[0] = runBuffer[runCount];
+ runCount = 1;
+ } else {
+ out.write(MAX_SEQUENCE_COUNT);
+ out.write(runBuffer, 0, runCount + 1);
+ runCount = 0;
+ }
+ isSequence = NOT_IDENTIFY_SEQUENCE;
+ break;
+ default:
+ switch (isSequence) {
+ case IN_SEQUENCE:
+ if (runBuffer[runCount] != runBuffer[runCount - 1]) {
+ out.write(BYTE_MAX - (runCount - 1));
+ out.write(runBuffer[runCount - 1]);
+ runBuffer[0] = runBuffer[runCount];
+ runCount = 1;
+ isSequence = NOT_IDENTIFY_SEQUENCE;
+ break;
+ }
+ runCount++;
+ break;
+ case NOT_IN_SEQUENCE:
+ if (runBuffer[runCount] == runBuffer[runCount - 1]) {
+ isSequence = START_SEQUENCE;
+ }
+ runCount++;
+ break;
+ case START_SEQUENCE:
+ if (runBuffer[runCount] == runBuffer[runCount - 1]) {
+ out.write(runCount - 3);
+ out.write(runBuffer, 0, runCount - 2);
+ runBuffer[0] = runBuffer[runCount];
+ runBuffer[1] = runBuffer[runCount];
+ runBuffer[2] = runBuffer[runCount];
+ runCount = 3;
+ isSequence = IN_SEQUENCE;
+ break;
+ } else {
+ isSequence = NOT_IN_SEQUENCE;
+ runCount++;
+ break;
+ }
+ }
+ }
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void write(byte[] b)
+ throws IOException {
+
+ for (int i = 0; i < b.length; i++) {
+ this.write(b[i]);
+ }
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void write(byte[] b, int off, int len)
+ throws IOException {
+
+ for (int i = 0; i < len; i++) {
+ this.write(b[off + i]);
+ }
+ }
+
+
+ /** @see org.apache.fop.render.ps.Finalizable **/
+ public void finalizeStream()
+ throws IOException {
+ switch (isSequence) {
+ case IN_SEQUENCE:
+ out.write(BYTE_MAX - (runCount - 1));
+ out.write(runBuffer[runCount - 1]);
+ break;
+ default:
+ out.write(runCount - 1);
+ out.write(runBuffer, 0, runCount);
+ }
+
+ out.write(END_OF_DATA);
+
+ flush();
+ if (out instanceof Finalizable) {
+ ((Finalizable) out).finalizeStream();
+ }
+ }
+
+
+ /** @see java.io.FilterOutputStream **/
+ public void close()
+ throws IOException {
+ finalizeStream();
+ super.close();
+ }
+
+}
+