jeremias    2005/01/19 13:48:12

  Modified:    src/java/org/apache/fop/pdf PDFState.java
               src/java/org/apache/fop/render/pdf PDFRenderer.java
  Log:
  "fixed" block-containers implemented.
  PDFState was cleaned up, simplified and refactored to support a "break-out" 
mechanism that allows to temporarily break out of the current viewport context.
  
  Support for sending comments to the PDF stream for debugging purposes.
  
  Revision  Changes    Path
  1.5       +141 -109  xml-fop/src/java/org/apache/fop/pdf/PDFState.java
  
  Index: PDFState.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/pdf/PDFState.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- PDFState.java     12 Jan 2005 12:03:00 -0000      1.4
  +++ PDFState.java     19 Jan 2005 21:48:12 -0000      1.5
  @@ -18,16 +18,16 @@
    
   package org.apache.fop.pdf;
   
  -import java.awt.Shape;
  -import java.util.ArrayList;
  -import java.util.HashMap;
  +import java.io.Serializable;
  +import java.util.List;
   import java.util.Iterator;
  -import java.awt.geom.GeneralPath;
  -import java.awt.geom.Area;
   
   import java.awt.Color;
   import java.awt.Paint;
  +import java.awt.Shape;
   import java.awt.geom.AffineTransform;
  +import java.awt.geom.Area;
  +import java.awt.geom.GeneralPath;
   
   /**
    * This keeps information about the current state when writing to pdf.
  @@ -47,41 +47,10 @@
    * the possible combinations after completing.
    */
   public class PDFState {
  -    private static final String COLOR = "color";
  -    private static final String BACKCOLOR = "backcolor";
  -    private static final String PAINT = "paint";
  -    private static final String BACKPAINT = "backpaint";
  -    private static final String LINECAP = "lineCap";
  -    private static final String LINEJOIN = "lineJoin";
  -    private static final String LINEWIDTH = "lineWidth";
  -    private static final String MITERLIMIT = "miterLimit";
  -    private static final String TEXT = "text";
  -    private static final String DASHOFFSET = "dashOffset";
  -    private static final String DASHARRAY = "dashArray";
  -    private static final String TRANSFORM = "transform";
  -    private static final String FONTSIZE = "fontSize";
  -    private static final String FONTNAME = "fontName";
  -    private static final String CLIP = "clip";
  -    private static final String GSTATE = "gstate";
  -
  -    private Color color = Color.black;
  -    private Color backcolor = Color.white;
  -    private Paint paint = null;
  -    private Paint backPaint = null;
  -    private int lineCap = 0;
  -    private int lineJoin = 0;
  -    private float lineWidth = 1;
  -    private float miterLimit = 0;
  -    private boolean text = false;
  -    private int dashOffset = 0;
  -    private int[] dashArray = new int[0];
  -    private AffineTransform transform = new AffineTransform();
  -    private float fontSize = 0;
  -    private String fontName = "";
  -    private Shape clip = null;
  -    private PDFGState gstate = null;
   
  -    private ArrayList stateStack = new ArrayList();
  +    private Data data = new Data();
  +    
  +    private List stateStack = new java.util.ArrayList();
   
       /**
        * PDF State for storing graphics state.
  @@ -96,54 +65,37 @@
        * so that the state is known when popped.
        */
       public void push() {
  -        HashMap saveMap = new HashMap();
  -        saveMap.put(COLOR, color);
  -        saveMap.put(BACKCOLOR, backcolor);
  -        saveMap.put(PAINT, paint);
  -        saveMap.put(BACKPAINT, backPaint);
  -        saveMap.put(LINECAP, new Integer(lineCap));
  -        saveMap.put(LINEJOIN, new Integer(lineJoin));
  -        saveMap.put(LINEWIDTH, new Float(lineWidth));
  -        saveMap.put(MITERLIMIT, new Float(miterLimit));
  -        saveMap.put(TEXT, new Boolean(text));
  -        saveMap.put(DASHOFFSET, new Integer(dashOffset));
  -        saveMap.put(DASHARRAY, dashArray);
  -        saveMap.put(TRANSFORM, transform);
  -        saveMap.put(FONTSIZE, new Float(fontSize));
  -        saveMap.put(FONTNAME, fontName);
  -        saveMap.put(CLIP, clip);
  -        saveMap.put(GSTATE, gstate);
  -
  -        stateStack.add(saveMap);
  -
  -        transform = new AffineTransform();
  +        Data copy;
  +        try {
  +            copy = (Data)getData().clone();
  +        } catch (CloneNotSupportedException e) {
  +            throw new RuntimeException(e.getMessage());
  +        }
  +        stateStack.add(copy);
  +        data.resetConcatenations();
       }
   
       /**
  +     * @return the currently valid state
  +     */
  +    public Data getData() {
  +        return data;
  +    }
  +    
  +    /**
        * Pop the state from the stack and set current values to popped state.
        * This should be called when a Q operator is used so
        * the state is restored to the correct values.
  +     * @return the restored state, null if the stack is empty
        */
  -    public void pop() {
  +    public Data pop() {
           if (getStackLevel() > 0) {
  -            HashMap saveMap = (HashMap)stateStack.get(stateStack.size() - 1);
  -            stateStack.remove(stateStack.size() - 1);
  -            color = (Color)saveMap.get(COLOR);
  -            backcolor = (Color)saveMap.get(BACKCOLOR);
  -            paint = (Paint)saveMap.get(PAINT);
  -            backPaint = (Paint)saveMap.get(BACKPAINT);
  -            lineCap = ((Integer)saveMap.get(LINECAP)).intValue();
  -            lineJoin = ((Integer)saveMap.get(LINEJOIN)).intValue();
  -            lineWidth = ((Float)saveMap.get(LINEWIDTH)).floatValue();
  -            miterLimit = ((Float)saveMap.get(MITERLIMIT)).floatValue();
  -            text = ((Boolean)saveMap.get(TEXT)).booleanValue();
  -            dashOffset = ((Integer)saveMap.get(DASHOFFSET)).intValue();
  -            dashArray = (int[])saveMap.get(DASHARRAY);
  -            transform = (AffineTransform)saveMap.get(TRANSFORM);
  -            fontSize = ((Float)saveMap.get(FONTSIZE)).floatValue();
  -            fontName = (String)saveMap.get(FONTNAME);
  -            clip = (Shape)saveMap.get(CLIP);
  -            gstate = (PDFGState)saveMap.get(GSTATE);
  +            Data popped = (Data)stateStack.remove(stateStack.size() - 1);
  +
  +            data = popped;
  +            return popped;
  +        } else {
  +            return null;
           }
       }
   
  @@ -163,6 +115,7 @@
        *
        * @param stack the level to restore to
        */
  +    /*
       public void restoreLevel(int stack) {
           int pos = stack;
           while (stateStack.size() > pos + 1) {
  @@ -171,7 +124,7 @@
           if (stateStack.size() > pos) {
               pop();
           }
  -    }
  +    }*/
   
       /**
        * Set the current line dash.
  @@ -182,9 +135,10 @@
        * @param offset the line dash start offset
        * @return true if the line dash has changed
        */
  +    /*
       public boolean setLineDash(int[] array, int offset) {
           return false;
  -    }
  +    }*/
   
       /**
        * Set the current line width.
  @@ -192,8 +146,8 @@
        * @return true if the line width has changed
        */
       public boolean setLineWidth(float width) {
  -        if (lineWidth != width) {
  -            lineWidth = width;
  +        if (getData().lineWidth != width) {
  +            getData().lineWidth = width;
               return true;
           } else {
               return false;
  @@ -208,11 +162,13 @@
        * @return true if the color has changed
        */
       public boolean setColor(Color col) {
  -        if (!col.equals(color)) {
  -            color = col;
  +        if (!col.equals(getData().color)) {
  +            //System.out.println("old: " + getData().color + ", new: " + 
col);
  +            getData().color = col;
               return true;
  +        } else {
  +            return false;
           }
  -        return false;
       }
   
       /**
  @@ -223,11 +179,12 @@
        * @return true if the background color has changed
        */
       public boolean setBackColor(Color col) {
  -        if (!col.equals(backcolor)) {
  -            backcolor = col;
  +        if (!col.equals(getData().backcolor)) {
  +            getData().backcolor = col;
               return true;
  +        } else {
  +            return false;
           }
  -        return false;
       }
   
       /**
  @@ -238,13 +195,13 @@
        * @return true if the new paint changes the current paint
        */
       public boolean setPaint(Paint p) {
  -        if (paint == null) {
  +        if (getData().paint == null) {
               if (p != null) {
  -                paint = p;
  +                getData().paint = p;
                   return true;
               }
  -        } else if (!paint.equals(p)) {
  -            paint = p;
  +        } else if (!data.paint.equals(p)) {
  +            getData().paint = p;
               return true;
           }
           return false;
  @@ -263,14 +220,14 @@
        * @return true if the clip will change the current clip.
        */
       public boolean checkClip(Shape cl) {
  -        if (clip == null) {
  +        if (getData().clip == null) {
               if (cl != null) {
                   return true;
               }
  -        } else if (!new Area(clip).equals(new Area(cl))) {
  +        } else if (!new Area(getData().clip).equals(new Area(cl))) {
               return true;
           }
  -        // todo check for clips that are larger than the current
  +        //TODO check for clips that are larger than the current
           return false;
       }
   
  @@ -282,12 +239,12 @@
        * @param cl the new clip in the current state
        */
       public void setClip(Shape cl) {
  -        if (clip != null) {
  -            Area newClip = new Area(clip);
  +        if (getData().clip != null) {
  +            Area newClip = new Area(getData().clip);
               newClip.intersect(new Area(cl));
  -            clip = new GeneralPath(newClip);
  +            getData().clip = new GeneralPath(newClip);
           } else {
  -            clip = cl;
  +            getData().clip = cl;
           }
       }
   
  @@ -301,7 +258,7 @@
        * @return true if the new transform is different then the current 
transform
        */
       public boolean checkTransform(AffineTransform tf) {
  -        return !tf.equals(transform);
  +        return !tf.equals(getData().transform);
       }
   
       /**
  @@ -312,7 +269,7 @@
        * @param tf the transform to concatonate to the current level transform
        */
       public void setTransform(AffineTransform tf) {
  -        transform.concatenate(tf);
  +        getData().concatenate(tf);
       }
   
       /**
  @@ -326,11 +283,11 @@
           AffineTransform tf;
           AffineTransform at = new AffineTransform();
           for (Iterator iter = stateStack.iterator(); iter.hasNext();) {
  -            HashMap map = (HashMap)iter.next();
  -            tf = (AffineTransform)map.get(TRANSFORM);
  +            Data d = (Data)iter.next();
  +            tf = d.transform;
               at.concatenate(tf);
           }
  -        at.concatenate(transform);
  +        at.concatenate(getData().transform);
   
           return at;
       }
  @@ -351,17 +308,92 @@
           PDFGState newstate = new PDFGState();
           newstate.addValues(defaultState);
           for (Iterator iter = stateStack.iterator(); iter.hasNext();) {
  -            HashMap map = (HashMap)iter.next();
  -            state = (PDFGState)map.get(GSTATE);
  +            Data d = (Data)iter.next();
  +            state = d.gstate;
               if (state != null) {
                   newstate.addValues(state);
               }
           }
  -        if (gstate != null) {
  -            newstate.addValues(gstate);
  +        if (getData().gstate != null) {
  +            newstate.addValues(getData().gstate);
           }
   
           return newstate;
  +    }
  +    
  +    public class Data implements Cloneable, Serializable {
  +        
  +        public Color color = Color.black;
  +        public Color backcolor = Color.white;
  +        public Paint paint = null;
  +        public Paint backPaint = null;
  +        public int lineCap = 0;
  +        public int lineJoin = 0;
  +        public float lineWidth = 1;
  +        public float miterLimit = 0;
  +        public boolean text = false;
  +        public int dashOffset = 0;
  +        public int[] dashArray = new int[0];
  +        public AffineTransform transform = new AffineTransform();
  +        public float fontSize = 0;
  +        public String fontName = "";
  +        public Shape clip = null;
  +        public PDFGState gstate = null;
  +        /** Log of all concatenation operations */
  +        public List concatenations = null;
  +
  +        
  +        /** @see java.lang.Object#clone() */
  +        public Object clone() throws CloneNotSupportedException {
  +            Data obj = new Data();
  +            obj.color = this.color;
  +            obj.backcolor = this.backcolor;
  +            obj.paint = this.paint;
  +            obj.backPaint = this.paint;
  +            obj.lineCap = this.lineCap;
  +            obj.lineJoin = this.lineJoin;
  +            obj.lineWidth = this.lineWidth;
  +            obj.miterLimit = this.miterLimit;
  +            obj.text = this.text;
  +            obj.dashOffset = this.dashOffset;
  +            obj.dashArray = this.dashArray;
  +            obj.transform = new AffineTransform(this.transform);
  +            obj.fontSize = this.fontSize;
  +            obj.fontName = this.fontName;
  +            obj.clip = this.clip;
  +            obj.gstate = this.gstate;
  +            if (this.concatenations != null) {
  +                obj.concatenations = new 
java.util.ArrayList(this.concatenations);
  +            }
  +            return obj;
  +        }
  +        
  +        /**
  +         * Forgets the previously made AffineTransform concatenations.
  +         */
  +        public void resetConcatenations() {
  +            this.concatenations = null;
  +        }
  +        
  +        /**
  +         * Concatenate the given AffineTransform with the current thus 
creating
  +         * a new viewport. Note that all concatenation operations are logged
  +         * so they can be replayed if necessary (ex. for block-containers 
with
  +         * "fixed" positioning.
  +         * @param at Transformation to perform
  +         */
  +        public void concatenate(AffineTransform at) {
  +            if (this.concatenations == null) {
  +                this.concatenations = new java.util.ArrayList();
  +            }
  +            concatenations.add(at);
  +            transform.concatenate(at);
  +        }
  +        
  +        /** @see java.lang.Object#toString() */
  +        public String toString() {
  +            return super.toString() + ", " + this.transform + " | " + 
this.concatenations;
  +        }
       }
   }
   
  
  
  
  1.71      +71 -2     
xml-fop/src/java/org/apache/fop/render/pdf/PDFRenderer.java
  
  Index: PDFRenderer.java
  ===================================================================
  RCS file: 
/home/cvs/xml-fop/src/java/org/apache/fop/render/pdf/PDFRenderer.java,v
  retrieving revision 1.70
  retrieving revision 1.71
  diff -u -r1.70 -r1.71
  --- PDFRenderer.java  18 Jan 2005 09:40:01 -0000      1.70
  +++ PDFRenderer.java  19 Jan 2005 21:48:12 -0000      1.71
  @@ -24,6 +24,7 @@
   import java.awt.Color;
   import java.awt.geom.Rectangle2D;
   import java.awt.geom.AffineTransform;
  +import java.util.Iterator;
   import java.util.Map;
   import java.util.List;
   
  @@ -101,11 +102,15 @@
    *
    */
   public class PDFRenderer extends PrintRenderer {
  +    
       /**
        * The mime type for pdf
        */
       public static final String MIME_TYPE = "application/pdf";
   
  +    /** Controls whether comments are written to the PDF stream. */
  +    protected static final boolean WRITE_COMMENTS = true;
  +    
       /**
        * the PDF Document being created
        */
  @@ -330,6 +335,16 @@
               renderBookmarkItem(bookmarkItem.getSubData(i), pdfOutline);
           }
       }
  +    
  +    /** 
  +     * writes out a comment.
  +     * @param text text for the comment
  +     */
  +    protected void comment(String text) {
  +        if (WRITE_COMMENTS) {
  +            currentStream.add("% " + text + "\n");
  +        }
  +    }
   
       /** Saves the graphics state of the rendering engine. */
       protected void saveGraphicsState() {
  @@ -432,11 +447,17 @@
               .makeStream(PDFFilterList.CONTENT_FILTER, false);
   
           currentState = new PDFState();
  +        /* This transform shouldn't affect PDFState as it only sets the basic
  +         * coordinate system for the rendering process.
  +         *
           currentState.setTransform(new AffineTransform(1, 0, 0, -1, 0,
                                      (int) Math.round(pageHeight / 1000)));
  +        */
           // Transform origin at top left to origin at bottom left
           currentStream.add("1 0 0 -1 0 "
                              + (int) Math.round(pageHeight / 1000) + " cm\n");
  +        
  +        
           currentFontName = "";
   
           Page p = page.getPage();
  @@ -459,7 +480,7 @@
           // Set the given CTM in the graphics state
           currentState.push();
           currentState.setTransform(
  -          new AffineTransform(CTMHelper.toPDFArray(ctm)));
  +                new AffineTransform(CTMHelper.toPDFArray(ctm)));
   
           saveGraphicsState();
           // multiply with current CTM
  @@ -682,7 +703,27 @@
           if (bv.getPositioning() == Block.ABSOLUTE
                   || bv.getPositioning() == Block.FIXED) {
   
  -            //TODO Handle positioning=FIXED
  +            //For FIXED, we need to break out of the current viewports to the
  +            //one established by the page. We save the state stack for 
restoration
  +            //after the block-container has been painted. See below.
  +            List breakOutList = null;
  +            if (bv.getPositioning() == Block.FIXED) {
  +                //break out
  +                breakOutList = new java.util.ArrayList();
  +                PDFState.Data data;
  +                while (true) {
  +                    data = currentState.getData();
  +                    if (currentState.pop() == null) {
  +                        break;
  +                    }
  +                    if (breakOutList.size() == 0) {
  +                        comment("------ break out!");
  +                    }
  +                    breakOutList.add(0, data); //Insert because of 
stack-popping
  +                    //getLogger().debug("Adding to break out list: " + data);
  +                    restoreGraphicsState();
  +                }
  +            }
               
               CTM tempctm = new CTM(containingIPPosition, 
containingBPPosition);
               ctm = tempctm.multiply(ctm);
  @@ -729,6 +770,34 @@
   
               // clip if necessary
   
  +            if (breakOutList != null) {
  +                comment("------ restoring context after break-out...");
  +                PDFState.Data data;
  +                Iterator i = breakOutList.iterator();
  +                while (i.hasNext()) {
  +                    data = (PDFState.Data)i.next();
  +                    //getLogger().debug("Restoring: " + data);
  +                    currentState.push();
  +                    saveGraphicsState();
  +                    if (data.concatenations != null) {
  +                        Iterator tr = data.concatenations.iterator();
  +                        while (tr.hasNext()) {
  +                            AffineTransform at = (AffineTransform)tr.next();
  +                            currentState.setTransform(at);
  +                            double[] matrix = new double[6];
  +                            at.getMatrix(matrix);
  +                            tempctm = new CTM(matrix[0], matrix[1], 
matrix[2], matrix[3], 
  +                                    matrix[4] * 1000, matrix[5] * 1000);
  +                            currentStream.add(CTMHelper.toPDFString(tempctm) 
+ " cm\n");
  +                        }
  +                    }
  +                    //TODO Break-out: Also restore items such as line width 
and color
  +                    //Left out for now because all this painting stuff is 
very
  +                    //inconsistent. Some values go over PDFState, some don't.
  +                }
  +                comment("------ done.");
  +            }
  +            
               currentIPPosition = saveIP;
               currentBPPosition = saveBP;
           } else {
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to