aboutsummaryrefslogtreecommitdiffstats
path: root/src/org/apache/fop/pdf/PDFState.java
blob: d9500c1b273b2422d2c16d346e2d4aac0f58ee66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
 * $Id$
 * 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 org.apache.fop.pdf;

import java.awt.Shape;
import java.util.ArrayList;
import java.util.HashMap;
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.geom.AffineTransform;

/**
 * This keeps information about the current state when writing to pdf.
 * It allows for creating new graphics states with the q operator.
 *
 * When setting the state for pdf there are three possible ways of
 * handling the situation.
 * The values can be set to override previous or default values.
 * A new state can be added and then the values set.
 * The current state can be popped and values will return to a
 * previous state then the necessary values can be overridden.
 * The current transform behaves differently to other values as the
 * matrix is combined with the current resolved value.
 * It is impossible to optimise the result without analysing the all
 * the possible combinations after completing.
 */
public class PDFState {
    private final static String COLOR = "color";
    private final static String BACKCOLOR = "backcolor";
    private final static String PAINT = "paint";
    private final static String BACKPAINT = "backpaint";
    private final static String LINECAP = "lineCap";
    private final static String LINEJOIN = "lineJoin";
    private final static String LINEWIDTH = "lineWidth";
    private final static String MITERLIMIT = "miterLimit";
    private final static String TEXT = "text";
    private final static String DASHOFFSET = "dashOffset";
    private final static String DASHARRAY = "dashArray";
    private final static String TRANSFORM = "transform";
    private final static String FONTSIZE = "fontSize";
    private final static String FONTNAME = "fontName";
    private final static String CLIP = "clip";
    private final static String GSTATE = "gstate";

    Color color = Color.black;
    Color backcolor = Color.white;
    Paint paint = null;
    Paint backPaint = null;
    int lineCap = 0;
    int lineJoin = 0;
    float lineWidth = 1;
    float miterLimit = 0;
    boolean text = false;
    int dashOffset = 0;
    int[] dashArray = new int[0];
    AffineTransform transform = new AffineTransform();
    float fontSize = 0;
    String fontName = "";
    Shape clip = null;
    PDFGState gstate = null;

    ArrayList stateStack = new ArrayList();

    public PDFState() {

    }

    // this call should be used when the q operator is used
    // 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();
    }

    public void 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);
        }
    }

    public int getStackLevel() {
        return stateStack.size();
    }

    public void restoreLevel(int stack) {
        int pos = stack;
        while(stateStack.size() > pos + 1) {
            stateStack.remove(stateStack.size() - 1);
        }
        if(stateStack.size() > pos) {
            pop();
        }
    }

    public boolean setLineDash(int[] array, int offset) {
        return false;
    }

    public boolean setColor(Color col) {
        if(!col.equals(color)) {
            color = col;
            return true;
        }
        return false;
    }

    public boolean setBackColor(Color col) {
        if(!col.equals(backcolor)) {
            backcolor = col;
            return true;
        }
        return false;
    }

    public boolean setPaint(Paint p) {
        if(paint == null) {
            if(p != null) {
                paint = p;
                return true;
            }
        } else if(!paint.equals(p)) {
            paint = p;
            return true;
        }
        return false;
    }

    /**
     * For clips it can start a new state
     */
    public boolean checkClip(Shape cl) {
        if(clip == null) {
            if(cl != null) {
                return true;
            }
        } else if(!new Area(clip).equals(new Area(cl))) {
            return true;
        }
        return false;
    }

    public void setClip(Shape cl) {
        if (clip != null) {
            Area newClip = new Area(clip);
            newClip.intersect(new Area(cl));
            clip = new GeneralPath(newClip);
        } else {
            clip = cl;
        }
    }

    public boolean checkTransform(AffineTransform tf) {
        return !tf.equals(transform);
    }

    /**
     * Set a new transform.
     * This transform is appended to the transform of
     * the current graphic state.
     */
    public void setTransform(AffineTransform tf) {
        transform.concatenate(tf);
    }

    /**
     * Get the current transform.
     * This gets the combination of all transforms in the
     * current state.
     */
    public AffineTransform getTransform() {
        AffineTransform tf;
        AffineTransform at = new AffineTransform();
        for(Iterator iter = stateStack.iterator(); iter.hasNext(); ) {
            HashMap map = (HashMap)iter.next();
            tf = (AffineTransform)map.get(TRANSFORM);
            at.concatenate(tf);
        }
        at.concatenate(transform);

        return at;
    }

    /**
     * Get the grapics state.
     * This gets the combination of all graphic states for
     * the current context.
     * This is the graphic state set with the gs operator not
     * the other graphic state changes.
     */
    public PDFGState getGState() {
        PDFGState defaultState = PDFGState.DEFAULT;

        PDFGState state;
        PDFGState newstate = new PDFGState(0);
        newstate.addValues(defaultState);
        for(Iterator iter = stateStack.iterator(); iter.hasNext(); ) {
            HashMap map = (HashMap)iter.next();
            state = (PDFGState)map.get(GSTATE);
            if(state != null) {
                newstate.addValues(state);
            }
        }
        if(gstate != null) {
            newstate.addValues(gstate);
        }

        return newstate;
    }
}