Package org.apache.fop.render.txt

Source Code of org.apache.fop.render.txt.TXTRenderer

/* $Id: TXTRenderer.java,v 1.4 2001/03/22 22:28:36 klease Exp $
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources."
*/

//package com.eastpoint.chrysalis;
package org.apache.fop.render.txt;

// FOP
import org.apache.fop.render.PrintRenderer;
import org.apache.fop.render.pcl.*;
import org.apache.fop.messaging.MessageHandler;
import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.properties.*;
import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.*;
import org.apache.fop.datatypes.*;
import org.apache.fop.svg.PathPoint;
import org.apache.fop.pdf.PDFPathPaint;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.image.*;

import org.apache.fop.dom.svg.SVGArea;
import org.w3c.dom.svg.SVGSVGElement;

// Java
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;

/**
* Renderer that renders areas to plain text
*/
public class TXTRenderer extends PrintRenderer
{
    /** the current stream to add Text commands to */
    PCLStream currentStream;

  private int pageHeight = 7920;

  // These variables control the virtual paggination functionality.
  public int  curdiv = 0;
  private int  divisions = -1;
  private int  paperheight = -1// Paper height in decipoints?
  public int  orientation = -1// -1=default/unknown, 0=portrait, 1=landscape.
  public int  topmargin = -1// Top margin in decipoints?
  public int  leftmargin = -1// Left margin in decipoints?
  private int fullmargin = 0;
  final boolean debug = false;

  // Variables for rendering text.
  StringBuffer  charData[];
  StringBuffer  decoData[];
  public float  textCPI = 16.67f;
  public float  textLPI = 8;
  int  maxX = (int)(8.5f * textCPI + 1);
  int  maxY = (int)(11f * textLPI + 1);
  float  xFactor;
  float  yFactor;
   public String lineEnding = "\r\n"; // Every line except the last line on a page (which will end with pageEnding) will be terminated with this string.
   public String pageEnding = "\f"; // Every page except the last one will end with this string.
   public boolean suppressGraphics = false; // If true then graphics/decorations will not be rendered - text only.

    /**
     * create the TXT renderer
     */
    public TXTRenderer()
    {
    }

    /**
     * set the TXT document's producer
     *
     * @param producer string indicating application producing PDF
     */
    public void setProducer(String producer)
    {
    }

    /**
     * render the areas into text
     *
     * @param areaTree the laid-out area tree
     * @param writer the PrintWriter to write the PDF with
     */
    public void render(AreaTree areaTree, OutputStream stream) throws IOException, FOPException
    {
    MessageHandler.logln("rendering areas to TEXT");
    idReferences=areaTree.getIDReferences();
    Enumeration e = areaTree.getPages().elements();
    currentStream = new PCLStream(stream);

    boolean first = true;

    while (e.hasMoreElements())
    {
      if ( first )
        first = false;
      else
        currentStream.add(pageEnding);
        this.renderPage((Page) e.nextElement());
    }
    currentStream.add(lineEnding);
        if ( !idReferences.isEveryIdValid() )
        {
            //throw new FOPException("The following id's were referenced but not found: "+idReferences.getInvalidIds()+"\n");
            MessageHandler.errorln("Warning: The following id's were referenced but not found: "+idReferences.getInvalidIds()+"\n");
        }

        MessageHandler.logln("writing out TEXT");
    stream.flush();
    }

  void addStr(int row, int col, String str, boolean ischar)
  {
if ( debug )
System.out.println("TXTRenderer.addStr(" + row + ", " + col + ", \"" + str + "\", " + ischar + ")");
     if ( suppressGraphics && ! ischar )
       return;
    StringBuffer sb;
    if ( row < 0 )
      row = 0;
    if ( ischar )
      sb = charData[row];
    else
      sb = decoData[row];
    if ( sb == null )
      sb = new StringBuffer();
    if ( (col + str.length()) > maxX )
      col = maxX - str.length();
    if ( col < 0 )
    {
      col = 0;
      if ( str.length() > maxX )
        str = str.substring(0, maxX);
    }
    // Pad to col
    for ( int countr = sb.length() ; countr < col ; countr++ )
      sb.append(' ');
if ( debug )
System.out.println("TXTRenderer.addStr() sb.length()=" + sb.length());
    for ( int countr = col ; countr < (col + str.length()) ; countr++ )
    {
      if ( countr >= sb.length() )
        sb.append(str.charAt(countr - col));
      else
      {
if ( debug )
System.out.println("TXTRenderer.addStr() sb.length()=" + sb.length() + " countr=" + countr);
        sb.setCharAt(countr, str.charAt(countr - col));
      }
    }

    if ( ischar )
      charData[row] = sb;
    else
      decoData[row] = sb;
  }

    /**
     * add a line to the current stream
     *
     * @param x1 the start x location in millipoints
     * @param y1 the start y location in millipoints
     * @param x2 the end x location in millipoints
     * @param y2 the end y location in millipoints
     * @param th the thickness in millipoints
     * @param stroke the line color
     */
    protected void addLine(int x1, int y1, int x2, int y2, int th, PDFPathPaint stroke)
  {
    if ( x1 == x2 )
    {
      addRect(x1, y1, th, y2 - y1 + 1, stroke, stroke);
    }
    else if ( y1 == y2 )
    {
      addRect(x1, y1, x2 - x1 + 1, th, stroke, stroke);
    }
    }

    /**
     * add a line to the current stream
     *
     * @param x1 the start x location in millipoints
     * @param y1 the start y location in millipoints
     * @param x2 the end x location in millipoints
     * @param y2 the end y location in millipoints
     * @param th the thickness in millipoints
     * @param rs the rule style
     * @param stroke the line color
     */
    protected void addLine(int x1, int y1, int x2, int y2, int th, int rs, PDFPathPaint stroke)
  {
    PDFColor lstroke = null;
    if ( rs == org.apache.fop.fo.properties.RuleStyle.DOTTED )
      lstroke = new PDFColor(0.7f, 0.7f, 0.7f);
    else
      lstroke = (PDFColor)stroke;
    if ( x1 == x2 )
    {
      addRect(x1, y1, th, y2 - y1 + 1, lstroke, lstroke);
    }
    else if ( y1 == y2 )
    {
      addRect(x1, y1, x2 - x1 + 1, th, lstroke, lstroke);
    }
    }

    protected void addLine(float x1, float y1, float x2, float y2, PDFColor sc, float sw)
  {
/* SVG - Not yet implemented
if ( debug )
System.out.println("TXTRenderer.addLine(" + x1 + ", " + y1 + ", " + x2 + ", " + y2 + ", " + sc + ", " + sw + ")");
    if ( x1 == x2 )
    {
      addRect(x1 - sw/2, y1, sw, y2 - y1 + 1, 0, 0, sc, null, 0);
    }
    else if ( y1 == y2 || (Math.abs(y1 - y2) <= 0.24) )  // 72/300=0.24
    {
      addRect(x1, y1 - sw/2, x2 - x1 + 1, sw, 0, 0, sc, null, 0);
    }
    else if ( sc != null )
    {
      // Convert dimensions to characters.
      //float cfact = 300f / 72f;  // 300 dpi, 1pt=1/72in
      int  ix1 = (int)(x1 * xFactor);
      int  iy1 = (int)(y1 * yFactor);
      int  ix2 = (int)(x2 * xFactor);
      int  iy2 = (int)(y2 * yFactor);
      int  isw = (int)(sw * xFactor);
      int origix;

      // Normalize
      if ( iy1 > iy2 )
      {
        int tmp = ix1;
        ix1 = ix2;
        ix2 = tmp;
        tmp = iy1;
        iy1 = iy2;
        iy2 = tmp;
      }
      if ( ix1 > ix2 )
      {
        origix = ix2;
        ix1 -=ix2;
        ix2 = 0;
      }
      else
      {
        origix = ix1;
        ix2 -= ix1;
        ix1 = 0;
      }

      // Convert line width to a pixel run length.
//System.out.println("TXTRenderer.addLine(" + ix1 + ", " + iy1 + ", " + ix2 + ", " + iy2 + ", " + isw + ")");
      int  runlen = (int)Math.sqrt(Math.pow(isw, 2) * (1 + Math.pow((ix1 - ix2) / (iy1 - iy2), 2)));
      if ( runlen < 1 )
        runlen = 1;
      StringBuffer rlbuff = new StringBuffer();
      for ( int countr = 0 ; countr < runlen ; countr++ )
        rlbuff.append('*');
      String rlstr = rlbuff.toString();
//System.out.println("TXTRenderer.addLine: runlen = " + runlen);

      // Draw the line.
      int  d, dx, dy;
      int  Aincr, Bincr;
      int  xincr = 1;
      int  x, y;


      dx = Math.abs(ix2 - ix1);
      dy = iy2 - iy1;

      if ( dx > dy )
      {
        xincr = dx / dy;

        // Move to starting position.
        //currentStream.add("\033*p" + origix + "x" + iy1 + "Y");
        x = ix1 - runlen / 2;
        iy2 += (isw / 2);
        // Start raster graphics
        //currentStream.add("\033*t300R\033*r" + dx + "s1A\033*b1M");
      }
      else
      {
        // Move to starting position.
        //currentStream.add("\033*p" + (origix - runlen / 2) + "x" + iy1 + "Y");
        x = ix1;
        // Start raster graphics
        //currentStream.add("\033*t300R\033*r1A\033*b1M");
      }

      if ( ix1 > ix2 )
        xincr *= -1;
      d = 2 * dx - dy;
      Aincr = 2 * (dx - dy);
      Bincr = 2 * dx;

      y = iy1;

      xferLineBytes(x, runlen, null, -1);
     
      for ( y = iy1 + 1 ; y <= iy2 ; y++ )
      {
        if ( d >= 0 )
        {
          x += xincr;
          d += Aincr;
        }
        else
          d += Bincr;
        xferLineBytes(x, runlen, null, -1);
      }

      // End raster graphics
      //currentStream.add("\033*rB");
      // Return to regular print mode.
      //currentStream.add("\033*v0t0n0O");
    }
*/
    }

  private void xferLineBytes(int  startpos, int bitcount, Vector save, int start2)
  {
/* Not yet implemented
//System.out.println("TXTRenderer.xferLineBytes(" + startpos + ", " + bitcount + ")");
    int  curbitpos = 0;
    if ( start2 > 0 && start2 <= (startpos + bitcount) )
    {
      bitcount += (start2 - startpos);
      start2 = 0;
    }

    char bytes[] = new char[((start2>startpos?start2:startpos) + bitcount) / 4 + 2];
    int  dlen = 0;
    byte dbyte = 0;
    int  bytepos = 0;

    do
    {
      int bits2set;
      if ( startpos < 0 )
      {
        bits2set = bitcount + startpos;
        startpos = 0;
      }
      else
        bits2set = bitcount;

      byte bittype = 0;
      do
      {
        if ( bytepos > 0 )
        {
          int inc = startpos - curbitpos;
          if ( (inc) >=  (8 - bytepos) )
          {
            curbitpos += (8 - bytepos);
            bytepos = 0;
            bytes[dlen++] = (char)0;
            bytes[dlen++] = (char)dbyte;
            dbyte = 0;
          }
          else
          {
            bytepos += inc;
            dbyte = (byte)(dbyte ^ (byte)(Math.pow(2, 8 - bytepos) - 1));
            curbitpos += inc;
          }
        }

        // Set runs of whole bytes.
        int  setbytes = (startpos - curbitpos) / 8;
        if ( setbytes > 0 )
        {
          curbitpos += setbytes * 8;
          while ( setbytes > 0 )
          {
            if ( setbytes > 256 )
            {
              bytes[dlen++] = 0xFF;
              setbytes -= 256;
            }
            else
            {
              bytes[dlen++] = (char)((setbytes - 1) & 0xFF);
              setbytes = 0;
            }
            bytes[dlen++] = (char)bittype;
          }
        }
        // move to position in the first byte.
        if ( curbitpos < startpos )
        {
          if ( bytepos == 0 )
            dbyte = bittype;
          bytepos += startpos - curbitpos;
          dbyte = (byte)(dbyte ^ (byte)(Math.pow(2, 8 - bytepos) - 1));
          curbitpos += bytepos;
          startpos += bits2set;
        }
        else
        {
          startpos += bits2set;
        }

        if ( bittype == 0 )
          bittype = (byte)0xFF;
        else
          bittype = 7;
      } while ( bittype != 7 );

      if ( start2 > 0 )
      {
        startpos = start2;
        start2 = -1;
      }
      else
        startpos = -1;
    } while ( startpos >= 0 );
    if ( bytepos > 0 )
    {
      bytes[dlen++] = (char)0;
      bytes[dlen++] = (char)dbyte;
    }
    if ( save == null )
    {
      //currentStream.add("\033*b" + dlen + "W");
      //currentStream.add(new String(bytes, 0, dlen));
    }
    else
    {
      String line = "\033*b" + dlen + "W" + new String(bytes, 0, dlen);
      //currentStream.add(line);
      save.addElement(line);
    }
*/
  }

    /**
     * add a rectangle to the current stream
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param stroke the stroke color/gradient
     */
    protected void addRect(int x, int y, int w, int h, PDFPathPaint stroke)
    {
    if ( h < 0 )
      h *= -1;

    if (h < 720 || w < 720)
    {
      if ( w < 720 )
        w = 720;
      if ( h < 720 )
        h = 720;
        addRect(x, y, w, h, stroke, stroke);
    }
    else
    {
        addRect(x, y, w, 720, stroke, stroke);
        addRect(x, y, 720, h, stroke, stroke);
        addRect(x + w - 720, y, 720, h, stroke, stroke);
        addRect(x, y - h + 720, w, 720, stroke, stroke);
    }
    }

    /**
     * add a filled rectangle to the current stream
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param fill the fill color/gradient
     * @param stroke the stroke color/gradient
     */
    protected void addRect(int x, int y, int w, int h, PDFPathPaint stroke, PDFPathPaint fill)
  {
//System.out.println("TXTRenderer.addRect(" + x + ", " + y + ", " + w + ", " + h + ", " + r + ", " + g + ", " + b + ", " + fr + ", " + fg + ", " + fb + ")");
    if ((w == 0) || (h == 0))
        return;
    if ( h < 0 )
      h *= -1;

    int  row = (int)((pageHeight - (y / 100))* 100 * yFactor);
    int  col = (int)(x * xFactor);

    PDFColor sc = (PDFColor)stroke;
    PDFColor fc = (PDFColor)fill;

    sc.setColorSpace(ColorSpace.DEVICE_RGB);
    fc.setColorSpace(ColorSpace.DEVICE_RGB);

    int  lineshade = (int)(100 - ((0.3f * sc.red() + 0.59f * sc.green() + 0.11f * sc.blue()) * 100f));
    int  fillshade = (int)(100 - ((0.3f * fc.red() + 0.59f * fc.green() + 0.11f * fc.blue()) * 100f));
if ( debug )
System.out.println("TXTRenderer.addRect(" + x + ", " + y + ", " + w + ", " + h + ", " + stroke + ", " + fill + ") fillshade=" + fillshade);
    char  fillchar = ' ';
    if ( fillshade >= 75 )
      fillchar = '#';
    else if ( fillshade >= 50 )
      fillchar = '*';
    else if ( fillshade >= 25 )
      fillchar = ':';


    if ( fillchar != ' ' )
    {
      StringBuffer linefill = new StringBuffer();
      int  sw = (int)(w * xFactor);
      int sh = (int)(h * yFactor);
      if ( sw == 0 || sh == 0 )
      {
        if ( fillshade >= 50 )
        {
          if ( h > w )
            fillchar = '|';
          else
            fillchar = '-';
        }
        else
        {
          if ( h > w )
            fillchar = ':';
          else
            fillchar = '.';
        }
      }
      if ( sw == 0 )
        linefill.append(fillchar);
      else
        for ( int countr = 0 ; countr < sw ; countr++ )
          linefill.append(fillchar);
      if ( sh == 0 )
        addStr(row, col, linefill.toString(), false);
      else
        for ( int countr = 0 ; countr < sh ; countr++ )
          addStr(row + countr, col, linefill.toString(), false);
    }

    if ( lineshade >= 25 )
    {
      char vlinechar = '|';
      char hlinechar = '-';
      if ( lineshade < 50 )
      {
        vlinechar = ':';
        hlinechar = '.';
      }
      StringBuffer linefill = new StringBuffer();
      int  sw = (int)(w * xFactor);
      for ( int countr = 0 ; countr < sw ; countr++ )
        linefill.append(hlinechar);
      int sh = (int)(h * yFactor);

      if ( w > h )
      {
        for ( int countr = 1 ; countr < (sh - 1); countr++ )
        {
          addStr(row + countr, col, String.valueOf(vlinechar), false);
          addStr(row + countr, col + sw, String.valueOf(vlinechar), false);
        }
        addStr(row, col, linefill.toString(), false);
        addStr(row + sh, col, linefill.toString(), false);

      }
      else
      {
        addStr(row, col, linefill.toString(), false);
        addStr(row + sh, col, linefill.toString(), false);
        for ( int countr = 1 ; countr < (sh - 1); countr++ )
        {
          addStr(row + countr, col, String.valueOf(vlinechar), false);
          addStr(row + countr, col + sw, String.valueOf(vlinechar), false);
        }

      }
    }
    }


    /**
     * add a filled rectangle to the current stream
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param r the red component of edges
     * @param g the green component of edges
     * @param b the blue component of edges
     * @param fr the red component of the fill
     * @param fg the green component of the fill
     * @param fb the blue component of the fill
     */
    protected void addRect(float x, float y, float w, float h, float rx, float ry,
         PDFColor fc, PDFColor sc, float sw)
  {
/* SVG - Not yet implemented
if ( debug )
System.out.println("TXTRenderer.addRect(" + x + ", " + y + ", " + w + ", " + h + ", " + rx + ", " + ry + ", " + fc + ", " + sc + ", " + sw + ")");

    float sr = 1;
    float sg = 1;
    float sb = 1;
    float fr = 1;
    float fg = 1;
    float fb = 1;
    if ( sc != null && sw > 0 )
    {
      sr = (float)sc.red();
      sg = (float)sc.green();
      sb = (float)sc.blue();
    }
    if ( fc != null )
    {
      fr = (float)fc.red();
      fg = (float)fc.green();
      fb = (float)fc.blue();
    }
    addRect((int)(x * 1000), (int)(pageHeight * 100 - y * 1000), (int)(w * 1000), (int)(h * 1000), sr, sg, sb, fr, fg, fb);

    fc = null;
    sc = null;

    if ( rx == 0 || ry == 0 )
    {
      if ( fc != null )
      {
        int fillshade = (int)(100 - ((0.3f * fc.red() + 0.59f * fc.green() + 0.11f * fc.blue()) * 100f));
        currentStream.add("\033*v0n1O\033&a" + (x * 10) + "h" + ((y * 10)) + "V"
                  + "\033*c" + (w * 10) + "h" + (h * 10) + "v" + fillshade + "g2P\033*v0n0O");
      }
      if ( sc != null && sw > 0 )
      {
        String lend = "v" + String.valueOf((int)(100 - ((0.3f * sc.red() + 0.59f * sc.green() + 0.11f * sc.blue()) * 100f))) + "g2P";
        currentStream.add("\033*v0n1O");
        currentStream.add("\033&a" + ((x - sw/2) * 10) + "h" + (((y - sw/2)) * 10) + "V"
                  + "\033*c" + ((w + sw) * 10) + "h" + ((sw) * 10) + lend);
        currentStream.add("\033&a" + ((x - sw/2) * 10) + "h" + (((y - sw/2)) * 10) + "V"
                  + "\033*c" + ((sw) * 10) + "h" + ((h + sw) * 10) + lend);
        currentStream.add("\033&a" + ((x + w - sw/2) * 10) + "h" + (((y - sw/2)) * 10) + "V"
                  + "\033*c" + ((sw) * 10) + "h" + ((h + sw) * 10) + lend);
        currentStream.add("\033&a" + ((x - sw/2) * 10) + "h" + (((y + h - sw/2)) * 10) + "V"
                  + "\033*c" + ((w + sw) * 10) + "h" + ((sw) * 10) + lend);
        currentStream.add("\033*v0n0O");
      }
    }
    else
    {
      // Convert dimensions to pixels.
      float cfact = 300f / 72f;  // 300 dpi, 1pt=1/72in
      int  ix = (int)(x * cfact);
      int  iy = (int)(y * cfact);
      int  iw = (int)(w * cfact);
      int  ih = (int)(h * cfact);
      int  irx = (int)(rx * cfact);
      int  iry = (int)(ry * cfact);
      int  isw = (int)(sw * cfact);
      int  longwidth = 0;
      int  pass = 0;
      PDFColor thecolor = null;

      do
      {
        if ( pass == 0 && fc != null )
        {
          thecolor = fc;
        }
        else if ( pass == 1 && sc != null )
        {
          int  iswdiv2 = isw / 2;
          thecolor = sc;
          ix -= iswdiv2;
          iy -= iswdiv2;
          irx += iswdiv2;
          iry += iswdiv2;
          iw += isw;
          ih += isw;
          longwidth = (int)(isw * 1.414);
        }
        else
          thecolor = null;


        if ( thecolor != null )
        {
          int    tx = 0;
          int    ty = iry;
          long  a = irx;
          long  b = iry;
          long  Asquared = (long)Math.pow(a, 2);
          long  TwoAsquared = 2 * Asquared;
          long  Bsquared = (long)Math.pow(b, 2);
          long  TwoBsquared = 2 * Bsquared;
          long  d = Bsquared - Asquared * b + Asquared / 4;
          long  dx = 0;
          long  dy = TwoAsquared * b;
          int    rectlen = iw - 2 * irx;
          Vector  bottomlines = new Vector();

          int x0 = tx;

          // Set Transparency modes and select shading.
          currentStream.add("\033*v0n1O\033*c" + (int)(100 - ((0.3f * thecolor.red() + 0.59f * thecolor.green() + 0.11f * thecolor.blue()) * 100f)) + "G\033*v2T");
          // Move to starting position.
          currentStream.add("\033*p" + ix + "x" + iy + "Y");
          // Start raster graphics
          currentStream.add("\033*t300R\033*r" + iw + "s1A\033*b1M");

          while ( dx < dy )
          {
            if ( d > 0 )
            {
              if ( pass == 0 || ty > (iry - isw) )
                xferLineBytes(irx - x0, rectlen + 2 * x0, bottomlines, -1);
              else
                xferLineBytes(irx - x0, longwidth, bottomlines, iw - irx + x0 - longwidth);
              x0 = tx + 1;
              ty--;
              dy -= TwoAsquared;
              d -= dy;
            }
            tx++;
            dx += TwoBsquared;
            d += Bsquared + dx;
          }

          d += (3 * (Asquared - Bsquared) / 2 - (dx + dy)) / 2;

          while ( ty > 0 )
          {
            if ( pass == 0 || ty >= (iry - isw) )
              xferLineBytes(irx - tx, rectlen + 2 * tx, bottomlines, -1);
            else
              xferLineBytes(irx - tx, isw, bottomlines, iw - irx + tx - isw);
           
            if ( d < 0 )
            {
              tx++;
              dx += TwoBsquared;
              d += dx;
            }
            ty--;
            dy -= TwoAsquared;
            d += Asquared - dy;
          }

          // Draw the middle part of the rectangle
          int  midlen = ih - 2 * iry;
          if ( midlen > 0 )
          {
            if ( pass == 0 )
              xferLineBytes(0, iw, null, -1);
            else
              xferLineBytes(0, isw, null, iw - isw);
            currentStream.add("\033*b3M");
            for ( int countr = midlen - 1 ; countr > 0 ; countr-- )
              currentStream.add("\033*b0W");
            currentStream.add("\033*b1M");
          }

          // Draw the bottom.
          for ( int countr = bottomlines.size() - 1 ; countr >= 0 ; countr-- )
            currentStream.add((String)bottomlines.elementAt(countr));

          // End raster graphics
          currentStream.add("\033*rB");
          // Return to regular print mode.
          currentStream.add("\033*v0t0n0O");
        }
        pass++;
      } while ( pass < 2 );
    }
*/
    }

  // Add a polyline or polygon. Does not support fills yet!!!
    protected void addPolyline(Vector points, int posx, int posy, PDFColor fc, PDFColor sc, float sw, boolean close)
    {
    PathPoint pc;
      float lastx = 0;
      float lasty = 0;
      float curx = 0;
      float cury = 0;
      float startx = 0;
      float starty = 0;
      Enumeration e = points.elements();
      if(e.hasMoreElements())
      {
        pc = (PathPoint)e.nextElement();
      lastx = pc.x + posx / 1000;
      lasty = ((pageHeight / 10) - posy/1000) + pc.y;
      startx = lastx;
      starty = lasty;
      }
      while(e.hasMoreElements())
      {
        pc = (PathPoint)e.nextElement();
      curx = pc.x + posx / 1000;
      cury = ((pageHeight / 10) - posy/1000) + pc.y;
        addLine(lastx, lasty, curx, cury, sc, sw);
      lastx = curx;
      lasty = cury;
      }
      if(close)
    {
        addLine(lastx, lasty, startx, starty, sc, sw);
    }
    }

  boolean printBMP(FopImage img, int x, int y, int w, int h) throws FopImageException
  {
    if ( debug )
      System.out.println("TXTRenderer.printBMP(" + img + ", " + x + ", "
      + y + ", " + w + ", " + h + ")");
    addRect(x, y, w, h, new PDFColor(1f, 1f, 1f), new PDFColor(0f, 0f, 0f));
    int  nameh = (int)(h * yFactor / 2);
    if ( nameh > 0 )
    {
      int  namew = (int)(w * xFactor);

      if ( namew > 4 )
      {
        String iname = img.getURL();
        if ( iname.length() >= namew )
           addStr((int)((pageHeight - (y / 100))* 100 * yFactor) + nameh, (int)(x * xFactor), iname.substring(iname.length() - namew), true);
        else
          addStr((int)((pageHeight - (y / 100))* 100 * yFactor) + nameh, (int)(x * xFactor + (namew - iname.length()) / 2), iname, true);

      }
    }
    return(true);
  }

    /**
     * render image area to PCL
     *
     * @param area the image area to render
     */
    public void renderImageArea(ImageArea area)
    {
    int x = this.currentAreaContainerXPosition + area.getXOffset();
    int y = this.currentYPosition;
    int w = area.getContentWidth();
    int h = area.getHeight();

    this.currentYPosition -= h;

    FopImage img = area.getImage();

    try
    {
      printBMP(img, x, y, w, h);
    }
    catch ( FopImageException e )
    {
      //e.printStackTrace(System.out);
      MessageHandler.errorln("TXTRenderer.renderImageArea() Error printing BMP (" + e.toString() + ").");
    }
    }

  public void renderImage(FontState fontState, String href, float x, float y, float width, float height)
  {
    try
    {
      if ( href.indexOf(":") == -1 )
        href = "file:" + href;
      FopImage img = FopImageFactory.Make(href);
      if(img != null)
      {
        if ( img instanceof SVGImage )
        {
          SVGSVGElement svg = ((SVGImage)img).getSVGDocument().getRootElement();
          renderSVG(fontState, svg, (int)x * 1000, (int)y * 1000);
        }
        else
        {
          printBMP(img, (int)x, (int)y, (int)width, (int)height);
        }
      }
    }
    catch(Exception e)
    {
      MessageHandler.errorln("could not add image to SVG: " + href);
    }
  }

    /** render a foreign object area */
    public void renderForeignObjectArea(ForeignObjectArea area)
    {
        // if necessary need to scale and align the content
        this.currentXPosition = this.currentXPosition + area.getXOffset();
        this.currentYPosition = this.currentYPosition;
        switch (area.getAlign())
        {
            case TextAlign.START:
                break;
            case TextAlign.END:
                break;
            case TextAlign.CENTER:
            case TextAlign.JUSTIFY:
                break;
        }
        switch (area.getVerticalAlign())
        {
            case VerticalAlign.BASELINE:
                break;
            case VerticalAlign.MIDDLE:
                break;
            case VerticalAlign.SUB:
                break;
            case VerticalAlign.SUPER:
                break;
            case VerticalAlign.TEXT_TOP:
                break;
            case VerticalAlign.TEXT_BOTTOM:
                break;
            case VerticalAlign.TOP:
                break;
            case VerticalAlign.BOTTOM:
                break;
        }
        // in general the content will not be text

        // align and scale

        switch (area.scalingMethod())
        {
            case Scaling.UNIFORM:
                break;
            case Scaling.NON_UNIFORM:
                break;
        }
        // if the overflow is auto (default), scroll or visible
        // then the contents should not be clipped, since this
        // is considered a printing medium.
        switch (area.getOverflow())
        {
            case Overflow.VISIBLE:
            case Overflow.SCROLL:
            case Overflow.AUTO:
                break;
            case Overflow.HIDDEN:
                break;
        }
        area.getObject().render(this);

        this.currentXPosition += area.getEffectiveWidth();
    //    this.currentYPosition -= area.getEffectiveHeight();
    }

  void renderSVG(FontState fontState, SVGSVGElement svg, int x, int y)
  {
/* SVG - Not yet implemented
    NodeList nl = svg.getChildNodes();
    for(int count = 0; count < nl.getLength(); count++) {
      Node n = nl.item(count);
      if(n instanceof SVGElement) {
        renderElement(fontState, (SVGElement)n, x, y);
      }
    }
*/
  }

    /**
     * render SVG area to Text
     *
     * @param area the SVG area to render
     */
  public void renderSVGArea(SVGArea area)
  {
if ( debug )
System.out.println("TXTRenderer.renderSVGArea(" + area + ")");
    int x = this.currentAreaContainerXPosition;
    int y = this.currentYPosition;
    SVGSVGElement svg = area.getSVGDocument().getRootElement();
    int w = (int)(svg.getWidth().getBaseVal().getValue() * 1000);
    int h = (int)(svg.getHeight().getBaseVal().getValue() * 1000);

    //currentStream.add("ET\n");
    /*
     * Clip to the svg area.
     * Note: To have the svg overlay (under) a text area then use
     * an fo:block-container
     */
    //currentStream.add("q\n");
    //currentStream.add(x / 1000f + " " + y / 1000f + " m\n");
    //currentStream.add((x + w) / 1000f + " " + y / 1000f + " l\n");
    //currentStream.add((x + w) / 1000f + " " + (y - h) / 1000f + " l\n");
    //currentStream.add(x / 1000f + " " + (y - h) / 1000f + " l\n");
    //currentStream.add("h\n");
    //currentStream.add("W\n");
    //currentStream.add("n\n");
    // transform so that the coordinates (0,0) is from the top left
    // and positive is down and to the right
    //currentStream.add(1 + " " + 0 + " " + 0 + " " + (-1) + " " + x / 1000f + " " + y / 1000f + " cm\n");

    // TODO - translate and clip to viewbox

    renderSVG(area.getFontState(), svg, x, y);

    //Enumeration e = area.getChildren().elements();
    //while (e.hasMoreElements()) {
    //  Object o = e.nextElement();
    //  if(o instanceof GraphicImpl) {
    //    renderElement(area, (GraphicImpl)o, x, y);
    //  }
    //}

    //currentStream.add("Q\n");
    //currentStream.add("BT\n");
    //this.currentYPosition -= h;
  }

/* SVG - Not yet implemented
  public void renderElement(FontState fontState, SVGElement area, int posx, int posy)
  {
if ( debug )
System.out.println("TXTRenderer.renderElement(" + fontState + ", " + area + ", " + posx + ", " + posy + ")");
    int x = posx;
    int y = posy;
    CSSStyleDeclaration style = null;
    if ( area instanceof SVGStylable )
      style = ((SVGStylable)area).getStyle();
    PDFColor fillColour = null;
    PDFColor strokeColour = null;
    float strokeWidth = 0;

    //currentStream.add("q\n");
    //if( area instanceof SVGTransformable )
    //{
    //  SVGTransformable tf = (SVGTransformable)area;
    //  SVGAnimatedTransformList trans = tf.getTransform();
    //  SVGRect bbox = tf.getBBox();
    //  if(trans != null) {
    //    applyTransform(trans, bbox);
    //  }
    //}

    if(style != null)
    {
      CSSValue sp = style.getPropertyCSSValue("fill");
      if(sp != null)
      {
        if( sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE )
        {
          if( ((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_RGBCOLOR )
          {
            RGBColor col = ((CSSPrimitiveValue)sp).getRGBColorValue();
            CSSPrimitiveValue val;
            val = col.getRed();
            float red = val.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
            val = col.getGreen();
            float green = val.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
            val = col.getBlue();
            float blue = val.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
            fillColour = new PDFColor(red, green, blue);
          }
        }
        //if(sp instanceof ColorType)
        //{
        //  ColorType ct = (ColorType)sp;
        //  fillColour = new PDFColor(ct.red(), ct.green(), ct.blue());
        //}
      }
      else
        fillColour = new PDFColor(0, 0, 0);
      sp = style.getPropertyCSSValue("stroke");
      if(sp != null)
      {
        if( sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE )
        {
          if( ((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_RGBCOLOR )
          {
            RGBColor col = ((CSSPrimitiveValue)sp).getRGBColorValue();
            CSSPrimitiveValue val;
            val = col.getRed();
            float red = val.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
            val = col.getGreen();
            float green = val.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
            val = col.getBlue();
            float blue = val.getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
            strokeColour = new PDFColor(red, green, blue);
          }
        }
        //if(sp instanceof ColorType)
        //{
        //  ColorType ct = (ColorType)sp;
        //  strokeColour = new PDFColor(ct.red(), ct.green(), ct.blue());
        //}
      }
      sp = style.getPropertyCSSValue("stroke-width");
      if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE)
      {
            strokeWidth = ((CSSPrimitiveValue)sp).getFloatValue(CSSPrimitiveValue.CSS_PT);
        //PDFNumber pdfNumber = new PDFNumber();
        //currentStream.add(pdfNumber.doubleOut(width) + " w\n");
        //strokeWidth = ((SVGLengthImpl)sp).getValue();
      }
      else
        strokeWidth = 1;
    }

    if (area instanceof SVGRectElement)
    {
      SVGRectElement rg = (SVGRectElement)area;
      float rectx = rg.getX().getBaseVal().getValue() + posx / 1000;
      float recty = ((pageHeight / 10) - posy/1000) + rg.getY().getBaseVal().getValue();
      float rx = rg.getRx().getBaseVal().getValue();
      float ry = rg.getRy().getBaseVal().getValue();
      float rw = rg.getWidth().getBaseVal().getValue();
      float rh = rg.getHeight().getBaseVal().getValue();
      addRect(rectx, recty, rw, rh, rx, ry, fillColour, strokeColour, strokeWidth);
    }
    else if (area instanceof SVGLineElement)
    {
      SVGLineElement lg = (SVGLineElement)area;
      float x1 = lg.getX1().getBaseVal().getValue() + posx / 1000;
      float y1 = ((pageHeight / 10) - posy/1000) + lg.getY1().getBaseVal().getValue();
      float x2 = lg.getX2().getBaseVal().getValue() + posx / 1000;
      float y2 = ((pageHeight / 10) - posy/1000) + lg.getY2().getBaseVal().getValue();
      addLine(x1,y1,x2,y2, strokeColour, strokeWidth);
    }
    else if (area instanceof SVGTextElementImpl)
    {
      //currentStream.add("BT\n");
      renderText(fontState, (SVGTextElementImpl)area, posx / 1000f, ((float)(pageHeight / 10) - posy/1000f));
      //currentStream.add("ET\n");
    }
    else if (area instanceof SVGCircleElement)
    {
      SVGCircleElement cg = (SVGCircleElement)area;
      float cx = cg.getCx().getBaseVal().getValue() + posx / 1000;
      float cy = ((pageHeight / 10) - posy/1000) + cg.getCy().getBaseVal().getValue();
      float r = cg.getR().getBaseVal().getValue();
      //addCircle(cx,cy,r, di);
      addRect(cx - r, cy - r, 2 * r, 2 * r, r, r, fillColour, strokeColour, strokeWidth);
    }
    else if (area instanceof SVGEllipseElement)
    {
      SVGEllipseElement cg = (SVGEllipseElement)area;
      float cx = cg.getCx().getBaseVal().getValue() + posx / 1000;
      float cy = ((pageHeight / 10) - posy/1000) + cg.getCy().getBaseVal().getValue();
      float rx = cg.getRx().getBaseVal().getValue();
      float ry = cg.getRy().getBaseVal().getValue();
      //addEllipse(cx,cy,rx,ry, di);
      addRect(cx - rx, cy - ry, 2 * rx, 2 * ry, rx, ry, fillColour, strokeColour, strokeWidth);
    }
    else if (area instanceof SVGPathElementImpl)
    {
      //addPath(((SVGPathElementImpl)area).pathElements, posx, posy, di);
    }
    else if (area instanceof SVGPolylineElementImpl)
    {
      addPolyline(((SVGPolylineElementImpl)area).points, posx, posy, fillColour, strokeColour, strokeWidth, false);
    }
    else if (area instanceof SVGPolygonElementImpl)
    {
      addPolyline(((SVGPolylineElementImpl)area).points, posx, posy, fillColour, strokeColour, strokeWidth, true);
    }
    else if (area instanceof SVGGElementImpl)
    {
      renderGArea(fontState, (SVGGElementImpl)area, x, y);
    }
    else if(area instanceof SVGUseElementImpl)
    {
      SVGUseElementImpl ug = (SVGUseElementImpl)area;
      String ref = ug.link;
      ref = ref.substring(1, ref.length());
      SVGElement graph = null;
      //GraphicImpl graph = null;
      //graph = area.locateDef(ref);
      if(graph != null) {
        // probably not the best way to do this, should be able
        // to render without the style being set.
        //GraphicImpl parent = graph.getGraphicParent();
        //graph.setParent(area);
        // need to clip (if necessary) to the use area
        // the style of the linked element is as if is was
        // a direct descendant of the use element.
        renderElement(fontState, graph, posx, posy);
        //graph.setParent(parent);
      }
    }
    else if (area instanceof SVGImageElementImpl)
    {
      SVGImageElementImpl ig = (SVGImageElementImpl)area;
      renderImage(fontState, ig.link, ig.x, ig.y, ig.width, ig.height);
    }
    else if (area instanceof SVGSVGElement)
    {
      // the x and y pos will be wrong!
      renderSVG(fontState, (SVGSVGElement)area, x, y);
    }
    else if (area instanceof SVGAElement)
    {
      SVGAElement ael = (SVGAElement)area;
      org.w3c.dom.NodeList nl = ael.getChildNodes();
      for ( int count = 0 ; count < nl.getLength() ; count++ )
      {
        org.w3c.dom.Node n = nl.item(count);
        if ( n instanceof SVGElement )
        {
          if ( n instanceof GraphicElement )
          {
            SVGRect rect = ((GraphicElement)n).getBBox();
            if ( rect != null )
            {
//              currentAnnotList = this.pdfDoc.makeAnnotList();
//              currentPage.setAnnotList(currentAnnotList);
//              String dest = linkSet.getDest();
//              int linkType = linkSet.getLinkType();
//              currentAnnotList.addLink(
//                this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType));
//              currentAnnotList = null;
//            }
          }
          renderElement(fontState, (SVGElement)n, posx, posy);
        }
      }
    }
    else if ( area instanceof SVGSwitchElement )
    {
      handleSwitchElement(fontState, posx, posy, (SVGSwitchElement)area);
    }
    // should be done with some cleanup code, so only
    // required values are reset.
    //currentStream.add("Q\n");
  }
*/

  private void setFont(String name, float size)
  {
    return;
  }

/* SVG - Not implemented yet.
  public void renderText(FontState fontState, SVGTextElementImpl tg, float x, float y)
  {
    PDFNumber pdfNumber = new PDFNumber();

    CSSStyleDeclaration styles;
    styles = tg.getStyle();
    //applyStyle(tg, styles);
    // apply transform
    // text has a Tm and need to handle each element
    SVGTransformList trans = tg.getTransform().getBaseVal();
    SVGMatrix matrix = trans.consolidate().getMatrix();
    String transstr = (pdfNumber.doubleOut(matrix.getA())
              + " " + pdfNumber.doubleOut(matrix.getB())
              + " " + pdfNumber.doubleOut(matrix.getC())
              + " " + pdfNumber.doubleOut(-matrix.getD()) + " ");

    String fontFamily = null;
    CSSValue sp = styles.getPropertyCSSValue("font-family");
      if ( sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE )
      {
        if ( ((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING )
        fontFamily = sp.getCssText();
      }
    if ( fontFamily == null )
      fontFamily = fontState.getFontFamily();
    String fontStyle = null;
    sp = styles.getPropertyCSSValue("font-style");
      if ( sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE )
      {
        if ( ((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING )
        fontStyle = sp.getCssText();
      }
    if ( fontStyle == null )
      fontStyle = fontState.getFontStyle();
    String fontWeight = null;
    sp = styles.getPropertyCSSValue("font-weight");
      if( sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE )
      {
        if ( ((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING )
        fontWeight = sp.getCssText();
      }
    if( fontWeight == null )
      fontWeight = fontState.getFontWeight();
    float fontSize;
    sp = styles.getPropertyCSSValue("font-size");
      if( sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE )
      {
//        if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_NUMBER) {
        fontSize = ((CSSPrimitiveValue)sp).getFloatValue(CSSPrimitiveValue.CSS_PT);
//        }
      }
      else
      {
      fontSize = fontState.getFontSize() / 1000f;
    }
    FontState fs = fontState;
    try
    {
      fs = new FontState(fontState.getFontInfo(), fontFamily, fontStyle,
                  fontWeight, (int)(fontSize * 1000));
    }
    catch( Exception fope )
    {
//      fope.printStackTrace();
    }

    //currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n");
    setFont(fs.getFontName(), fontSize * 1000);

    float tx = tg.x;
    float ty = tg.y;
    float currentX = x + tx;
    float currentY = y + ty;
    Vector list = tg.textList;
    for ( Enumeration e = list.elements() ; e.hasMoreElements() ; )
    {
      Object o = e.nextElement();
      styles = tg.getStyle();
      //applyStyle(tg, styles);
      if( o instanceof String )
      {
        String str = (String)o;
        //currentStream.add(transstr
        //  + (currentX + matrix.getE()) + " "
        //  + (y+ty + matrix.getF()) + " Tm "
        //  + "(");
        boolean spacing = "preserve".equals(tg.getXMLspace());
        //currentX = addSVGStr(fs, currentX, str, spacing);
        //currentStream.add(") Tj\n");
//        for(int count = 0; count < str.length(); count++) {
//        }
//        currentX += fs.width(' ') / 1000f;
        currentStream.add("\033&a" + (currentX + matrix.getE())*10 + "h" + (y+ty + matrix.getF())*10 + "V" + str);
        for ( int count = 0; count < str.length(); count++ )
        {
          currentX += fs.width(str.charAt(count)) / 1000f;
        }
        currentX += fs.width(' ') / 1000f;
      } else if(o instanceof SVGTextPathElementImpl) {
        SVGTextPathElementImpl tpg = (SVGTextPathElementImpl)o;
        String ref = tpg.str;
        SVGElement graph = null;
//        graph = tpg.locateDef(ref);
        if(graph != null && graph instanceof SVGPathElementImpl) {
          // probably not the best way to do this, should be able
          // to render without the style being set.
//          GraphicImpl parent = graph.getGraphicParent();
//          graph.setParent(tpg);
          // set text path??
          // how should this work
//          graph.setParent(parent);
        }
      } else if(o instanceof SVGTRefElementImpl) {
        SVGTRefElementImpl trg = (SVGTRefElementImpl)o;
        String ref = trg.ref;
        ref = ref.substring(1, ref.length());
        SVGElement graph = null;
//        graph = trg.locateDef(ref);
        if(graph != null && graph instanceof SVGTextElementImpl) {
//          GraphicImpl parent = graph.getGraphicParent();
//          graph.setParent(trg);
          SVGTextElementImpl te = (SVGTextElementImpl)graph;
          renderText(fs, te, (int)(x + tx), (int)(y + ty));
//          graph.setParent(parent);
        }
      } else if(o instanceof SVGTSpanElementImpl) {
        SVGTSpanElementImpl tsg = (SVGTSpanElementImpl)o;
        styles = tsg.getStyle();
        //applyStyle(tsg, styles);
        boolean changed = false;

        String newprop = null;
        sp = styles.getPropertyCSSValue("font-family");
          if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
            if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) {
            newprop = sp.getCssText();
            }
          }
        if(newprop != null && !newprop.equals(fontFamily)) {
          fontFamily = newprop;
          changed = true;
        }
        sp = styles.getPropertyCSSValue("font-style");
          if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
            if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) {
            newprop = sp.getCssText();
            }
          }
        if(newprop != null && !newprop.equals(fontStyle)) {
          fontStyle = newprop;
          changed = true;
        }
        sp = styles.getPropertyCSSValue("font-weight");
          if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
            if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_STRING) {
            newprop = sp.getCssText();
            }
          }
        if(newprop != null && !newprop.equals(fontWeight)) {
          fontWeight = newprop;
          changed = true;
        }
        float newSize = fontSize;
        sp = styles.getPropertyCSSValue("font-size");
          if(sp != null && sp.getValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
//            if(((CSSPrimitiveValue)sp).getPrimitiveType() == CSSPrimitiveValue.CSS_NUMBER) {
            newSize = ((CSSPrimitiveValue)sp).getFloatValue(CSSPrimitiveValue.CSS_PT);
//            }
          }
        if ( fontSize != newSize )
        {
          fontSize = newSize;
          changed = true;
        }
        FontState oldfs = null;
        if ( changed )
        {
          oldfs = fs;
          try
          {
            fs = new FontState(fontState.getFontInfo(), fontFamily, fontStyle,
                      fontWeight, (int)(fontSize * 1000));
          }
          catch(Exception fope)
          {
          }

          setFont(fs.getFontName(), fontSize * 1000);
          //currentStream.add("/" + fs.getFontName() + " " + fontSize + " Tf\n");
        }

        float baseX;
        float baseY;

        StringBuffer pdf = new StringBuffer();
        boolean spacing = "preserve".equals(tsg.getXMLspace());
        boolean inbetween = false;
        boolean addedspace = false;
        int charPos = 0;
        float xpos = currentX;
        float ypos = currentY;
        for ( int i=0 ; i < tsg.str.length() ; i++ )
        {
          char ch = tsg.str.charAt(i);
          xpos = currentX;
          ypos = currentY;
          if ( tsg.ylist.size() > charPos )
            ypos = y + ty + ((Float)tsg.ylist.elementAt(charPos)).floatValue();
          if ( tsg.dylist.size() > charPos )
            ypos = ypos + ((Float)tsg.dylist.elementAt(charPos)).floatValue();
          if ( tsg.xlist.size() > charPos )
            xpos = x + tx + ((Float)tsg.xlist.elementAt(charPos)).floatValue();
          if ( tsg.dxlist.size() > charPos )
            xpos = xpos + ((Float)tsg.dxlist.elementAt(charPos)).floatValue();
          switch (ch)
          {
            case '  ':
            case ' ':
                if ( spacing )
                {
                currentX = xpos + fs.width(' ') / 1000f;
                currentY = ypos;
                charPos++;
                }
                else
                {
                    if ( inbetween && !addedspace)
                    {
                      addedspace = true;
                  currentX = xpos + fs.width(' ') / 1000f;
                  currentY = ypos;
                  charPos++;
                    }
                }
            break;
            case '\n':
            case '\r':
                if ( spacing )
                {
                currentX = xpos + fs.width(' ') / 1000f;
                currentY = ypos;
                charPos++;
                }
            break;
            default:
                  addedspace = false;
              pdf = pdf.append(transstr
                + (xpos + matrix.getE()) + " "
                + (ypos + matrix.getF()) + " Tm "
                + "(" + ch + ") Tj\n");
              pdf = pdf.append("\033&a" + (xpos + matrix.getE())*10 + "h" + (ypos + matrix.getF())*10 + "V" + ch);
              currentX = xpos + fs.width(ch) / 1000f;
              currentY = ypos;
              charPos++;
              inbetween = true;
            break;
        }
        //currentStream.add(pdf.toString());
        }
//        currentX += fs.width(' ') / 1000f;
        if ( changed )
        {
          fs = oldfs;
          setFont(fs.getFontName(), fs.getFontSize() * 1000);
          //currentStream.add("/" + fs.getFontName() + " " + fs.getFontSize() / 1000f + " Tf\n");
        }
      }
      else
      {
        System.err.println("Error: unknown text element " + o);
      }
    }
  }
*/

/* SVG - Not yet implemented
  public void renderGArea(FontState fontState, SVGGElement area, int posx, int posy)
  {
    NodeList nl = area.getChildNodes();
    for ( int count = 0 ; count < nl.getLength() ; count++ )
    {
      Node n = nl.item(count);
      if ( n instanceof SVGElement )
        renderElement(fontState, (SVGElement)n, posx, posy);
    }
  }
*/

/* SVG - Not yet implemented
  void handleSwitchElement(FontState fontState, int posx, int posy, SVGSwitchElement ael)
  {
    SVGList relist = ael.getRequiredExtensions();
    SVGList rflist = ael.getRequiredFeatures();
    SVGList sllist = ael.getSystemLanguage();
    org.w3c.dom.NodeList nl = ael.getChildNodes();
    for(int count = 0; count < nl.getLength(); count++) {
      org.w3c.dom.Node n = nl.item(count);
      // only render the first child that has a valid
      // test data
      if(n instanceof GraphicElement) {
        GraphicElement graphic = (GraphicElement)n;
        SVGList grelist = graphic.getRequiredExtensions();
        // if null it evaluates to true
        if(grelist != null) {
          for(int i = 0; i < grelist.getNumberOfItems(); i++) {
            String str = (String)grelist.getItem(i);
            if(relist == null) {
              // use default extension set
              // currently no extensions are supported
//              if(!(str.equals("http:// ??"))) {
                continue;
//              }
            } else {
            }
          }
        }
        SVGList grflist = graphic.getRequiredFeatures();
        if(grflist != null) {
          for(int i = 0; i < grflist.getNumberOfItems(); i++) {
            String str = (String)grflist.getItem(i);
            if(rflist == null) {
              // use default feature set
              if(!(str.equals("org.w3c.svg.static")
                || str.equals("org.w3c.dom.svg.all"))) {
                continue;
              }
            } else {
              boolean found = false;
              for(int j = 0; j < rflist.getNumberOfItems(); j++) {
                if(rflist.getItem(j).equals(str)) {
                  found = true;
                  break;
                }
              }
              if(!found)
                continue;
            }
          }
        }
        SVGList gsllist = graphic.getSystemLanguage();
        if(gsllist != null) {
          for(int i = 0; i < gsllist.getNumberOfItems(); i++) {
            String str = (String)gsllist.getItem(i);
            if(sllist == null) {
              // use default feature set
              if(!(str.equals("en"))) {
                continue;
              }
            } else {
              boolean found = false;
              for(int j = 0; j < sllist.getNumberOfItems(); j++) {
                if(sllist.getItem(j).equals(str)) {
                  found = true;
                  break;
                }
              }
              if(!found)
                continue;
            }
          }
        }
        renderElement(fontState, (SVGElement)n, posx, posy);
        // only render the first valid one
        break;
      }
    }
  }
*/

    /**
     * render inline area to Text
     *
     * @param area inline area to render
     */
    public void renderWordArea(WordArea area)
    {
//System.out.println("TXTRenderer.renderInlineArea: currentXPosition=" + this.currentXPosition + " currentYPosition=" + this.currentYPosition + " text=" + area.getText());
    int rx = this.currentXPosition;
    int bl = this.currentYPosition;

    String s;
    if ( area.getPageNumberID()!=null )
    {
      // this text is a page number, so resolve it
        s = idReferences.getPageNumber(area.getPageNumberID());           
        if(s==null)
            s="";
    }
    else
    {
        s = area.getText();
    }

if ( debug )
System.out.println("TXTRenderer.renderInlineArea: rx=" + rx + " bl=" + bl + " pageHeight=" + pageHeight);
    addStr((int)((pageHeight - (bl / 100))* 100 * yFactor) - 1, (int)(rx * xFactor), s, true);

    this.currentXPosition += area.getContentWidth();
    }

    /**
     * render inline space to Text
     *
     * @param space space to render
     */
    public void renderInlineSpace(InlineSpace space)
    {
    this.currentXPosition += space.getSize();
    }

    /**
     * render page into Text
     *
     * @param page page to render
     */
    public void renderPage(Page page)
    {
if ( debug )
System.out.println("TXTRenderer.renderPage() page.getHeight() = " + page.getHeight());
    BodyAreaContainer body;
    AreaContainer before, after, start, end;

    maxX = (int)(textCPI * page.getWidth() / 72000 + 1);
    maxY = (int)(textLPI * page.getHeight() / 72000 + 1);
    xFactor = (float)(maxX - 1) / (float)page.getWidth();
    yFactor = (float)(maxY - 1) / (float)page.getHeight();
    charData = new StringBuffer[maxY + 1];
    decoData = new StringBuffer[maxY + 1];

    if ( paperheight > 0 )
      pageHeight = paperheight;
    else
      pageHeight = page.getHeight() / 100;

if ( debug )
System.out.println("TXTRenderer.renderPage() maxX=" + maxX + " maxY=" + maxY + " xFactor=" + xFactor + " yFactor=" + yFactor + " paperHeight=" + pageHeight);
       
    body = page.getBody();
    before = page.getBefore();
    after = page.getAfter();
    start = page.getStart();
    end = page.getEnd();

    this.currentFontName = "";
    this.currentFontSize = 0;

    //currentStream.add("BT\n");
    renderBodyAreaContainer(body);

    if (before != null)
        renderAreaContainer(before);

    if (after != null)
        renderAreaContainer(after);
   
    if (start != null)
        renderAreaContainer(start);
   
    if (end != null)
        renderAreaContainer(end);
   
    // Write out the buffers.
    for ( int row = 0 ; row <= maxY ; row++ )
    {
      StringBuffer cr = charData[row];
      StringBuffer dr = decoData[row];
      StringBuffer outr = null;

      if ( cr != null && dr == null )
        outr = cr;
      else if ( dr != null && cr == null )
        outr = dr;
      else if ( cr != null && dr != null )
      {
        int  len = dr.length();
        if ( cr.length() > len )
          len = cr.length();
        outr = new StringBuffer();
        for ( int countr = 0 ; countr < len ; countr++ )
        {
          if ( countr < cr.length() && cr.charAt(countr) != ' ' )
            outr.append(cr.charAt(countr));
          else if ( countr < dr.length() )
            outr.append(dr.charAt(countr));
          else
            outr.append(' ');
        }
      }

      if ( outr != null )
        currentStream.add(outr.toString());
       if ( row < maxY )
        currentStream.add(lineEnding);
    }

    // End page.
    //if ( ++curdiv == divisions || divisions == -1 )
    //{
    //  curdiv = 0;
    //  currentStream.add("\f");
    //}

    // Links, etc not implemented...
    /*
    currentPage = this.pdfDoc.makePage(this.pdfResources, currentStream,
           page.getWidth()/1000,
           page.getHeight()/1000, page);

    if (page.hasLinks()) {
      currentAnnotList = this.pdfDoc.makeAnnotList();
      currentPage.setAnnotList(currentAnnotList);

      Enumeration e = page.getLinkSets().elements();
      while (e.hasMoreElements()) {
      LinkSet linkSet = (LinkSet) e.nextElement();

      linkSet.align();
      String dest = linkSet.getDest();
                  int linkType = linkSet.getLinkType();
      Enumeration f = linkSet.getRects().elements();
      while (f.hasMoreElements()) {
        LinkedRectangle lrect = (LinkedRectangle) f.nextElement();
        currentAnnotList.addLink(
          this.pdfDoc.makeLink(lrect.getRectangle(), dest, linkType));
      }
      }
    } else {
      // just to be on the safe side
      currentAnnotList = null;
    }
    */
    }
}
TOP

Related Classes of org.apache.fop.render.txt.TXTRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.