View | Details | Raw Unified | Return to bug 37253
Collapse All | Expand All

(-)src/java/org/apache/fop/fo/flow/TableColumn.java (+9 lines)
Lines 30-35 Link Here
30
import org.apache.fop.fo.ValidationException;
30
import org.apache.fop.fo.ValidationException;
31
import org.apache.fop.fo.expr.PropertyException;
31
import org.apache.fop.fo.expr.PropertyException;
32
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
32
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
33
import org.apache.fop.fo.properties.FixedLength;
33
34
34
/**
35
/**
35
 * Class modelling the fo:table-column object.
36
 * Class modelling the fo:table-column object.
Lines 176-180 Link Here
176
        sb.append(" column-width=").append(getColumnWidth());
177
        sb.append(" column-width=").append(getColumnWidth());
177
        return sb.toString();
178
        return sb.toString();
178
    }
179
    }
180
181
    /**
182
     * Sets a column width.
183
     * @param length
184
     */
185
	public void setColumnWidth(Length columnWidth) {
186
		this.columnWidth = columnWidth;
187
	}
179
}
188
}
180
189
(-)src/java/org/apache/fop/render/RendererFactory.java (+3 lines)
Lines 33-38 Link Here
33
import org.apache.fop.fo.FOEventHandler;
33
import org.apache.fop.fo.FOEventHandler;
34
import org.apache.fop.render.mif.MIFHandler;
34
import org.apache.fop.render.mif.MIFHandler;
35
import org.apache.fop.render.rtf.RTFHandler;
35
import org.apache.fop.render.rtf.RTFHandler;
36
import org.apache.fop.render.txt.TXTHandler;
36
37
37
/**
38
/**
38
 * Factory for FOEventHandlers and Renderers.
39
 * Factory for FOEventHandlers and Renderers.
Lines 132-137 Link Here
132
                return new MIFHandler(userAgent, out);
133
                return new MIFHandler(userAgent, out);
133
            } else if (renderType == Constants.RENDER_RTF) {
134
            } else if (renderType == Constants.RENDER_RTF) {
134
                return new RTFHandler(userAgent, out);
135
                return new RTFHandler(userAgent, out);
136
			} else if (renderType == Constants.RENDER_TXT) {
137
				 return new TXTHandler(userAgent, out);
135
            } else {
138
            } else {
136
                if (renderType < Constants.RENDER_MIN_CONST 
139
                if (renderType < Constants.RENDER_MIN_CONST 
137
                    || renderType > Constants.RENDER_MAX_CONST) {
140
                    || renderType > Constants.RENDER_MAX_CONST) {
(-)src/java/org/apache/fop/render/txt/border/DashedBorderElement.java (+105 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt.border;
18
19
import java.util.Arrays;
20
21
/**
22
 * This class is responsible for managing of dashed border elements.
23
 */
24
public class DashedBorderElement extends AbstractBorderElement {
25
	
26
	public static final char DASH_HORIZONTAL = '-';
27
28
	public static final char DASH_VERTICAL = '|';
29
	
30
	public static final char UNDEFINED = '?';
31
	
32
	private static final int UP2 = 1;
33
	
34
	private static final int RIGHT2 = 2;
35
	
36
	private static final int DOWN2 = 4;
37
	
38
	private static final int LEFT2 = 8;
39
	
40
	private static char[] map = new char[20];
41
	
42
	static {
43
		Arrays.fill(map, UNDEFINED);
44
		map[0] = ' ';
45
		map[UP2] = DASH_VERTICAL;
46
		map[DOWN2] = DASH_VERTICAL;
47
		map[UP2 + DOWN2] = DASH_VERTICAL;
48
		
49
		map[LEFT2] = DASH_HORIZONTAL;
50
		map[RIGHT2] = DASH_HORIZONTAL;
51
		map[LEFT2 + RIGHT2] = DASH_HORIZONTAL;
52
	}
53
	
54
	public DashedBorderElement(int type) {
55
		super(type);
56
	}
57
	
58
	private AbstractBorderElement mergeSolid(SolidAndDoubleBorderElement sdb) {
59
		AbstractBorderElement e = new SolidAndDoubleBorderElement(EN_SOLID, 0);
60
		for (int i = 0; i < 4; i++) {
61
			e.setData(i, Math.max(data[i], sdb.getData(i)));
62
		}
63
		return e;		
64
	}
65
	
66
	private AbstractBorderElement toSolidAndDouble() {
67
		AbstractBorderElement e = new SolidAndDoubleBorderElement(EN_SOLID, 0);
68
		for (int i = 0; i < 4; i++) {
69
			e.setData(i, data[i]);
70
		}
71
		return e;		
72
	}
73
	
74
	private AbstractBorderElement mergeDashed(DashedBorderElement dbe) {
75
		for (int i = 0; i < 4; i++) {
76
			data[i] = Math.max(data[i], dbe.getData(i));
77
		}
78
		return this;
79
	}
80
	
81
	public AbstractBorderElement merge(AbstractBorderElement e) {
82
		AbstractBorderElement abe = this;
83
		if (e instanceof SolidAndDoubleBorderElement) {
84
			abe = mergeSolid((SolidAndDoubleBorderElement) e);
85
		} else if (e instanceof DashedBorderElement) {
86
			abe = mergeDashed((DashedBorderElement) e);
87
		} else {
88
			abe = e;
89
		}
90
		return abe;
91
	}
92
93
	public char convert2Char() {
94
		int key = 0;
95
		key += data[UP] * UP2;
96
		key += data[DOWN] * DOWN2;
97
		key += data[LEFT] * LEFT2;
98
		key += data[RIGHT] * RIGHT2;
99
		char ch = map[key];
100
		if (ch == UNDEFINED) {
101
			ch = toSolidAndDouble().convert2Char();
102
		}
103
		return ch;
104
	}
105
}
(-)src/java/org/apache/fop/render/txt/border/SolidAndDoubleBorderElement.java (+257 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt.border;
18
19
import java.util.Arrays;
20
21
/**
22
 * This class is responsible for managing of solid and double border elements.
23
 */
24
public class SolidAndDoubleBorderElement extends AbstractBorderElement {
25
26
	public static final char LIGHT_HORIZONTAL = '\u2500';
27
28
	public static final char LIGHT_VERTICAL = '\u2502';
29
30
	public static final char LIGHT_DOWN_AND_RIGHT = '\u250C';
31
32
	public static final char LIGHT_DOWN_AND_LEFT = '\u2510';
33
34
	public static final char LIGHT_UP_AND_RIGHT = '\u2514';
35
36
	public static final char LIGHT_UP_AND_LEFT = '\u2518';
37
38
	public static final char LIGHT_VERTICAL_AND_RIGHT = '\u251C';
39
40
	public static final char LIGHT_VERTICAL_AND_LEFT = '\u2524';
41
42
	public static final char LIGHT_DOWN_AND_HORIZONTAL = '\u252C';
43
44
	public static final char LIGHT_UP_AND_HORIZONTAL = '\u2534';
45
46
	public static final char LIGHT_VERTICAL_AND_HORIZONTAL = '\u253C';
47
	
48
	public static final char DOUBLE_HORIZONTAL = '\u2550';
49
50
	public static final char DOUBLE_VERTICAL = '\u2551';
51
	
52
	public static final char DOUBLE_DOWN_AND_RIGHT = '\u2554';	
53
54
	public static final char DOUBLE_DOWN_AND_LEFT = '\u2557';
55
56
	public static final char DOUBLE_UP_AND_RIGHT = '\u255A';
57
58
	public static final char DOUBLE_UP_AND_LEFT = '\u255D';
59
	
60
	public static final char DOUBLE_VERTICAL_AND_RIGHT = '\u2560';
61
	
62
	public static final char DOUBLE_VERTICAL_AND_LEFT = '\u2563';
63
	
64
	public static final char DOUBLE_DOWN_AND_HORIZONTAL = '\u2566';
65
	
66
	public static final char DOUBLE_UP_AND_HORIZONTAL = '\u2569';
67
	
68
	public static final char DOUBLE_VERTICAL_AND_HORIZONTAL = '\u256C';
69
	
70
	public static final char DOWN_SINGLE_AND_RIGHT_DOUBLE = '\u2552';
71
	
72
	public static final char DOWN_DOUBLE_AND_RIGHT_SINGLE = '\u2553';
73
74
	public static final char DOWN_SINGLE_AND_LEFT_DOUBLE = '\u2555';
75
76
	public static final char DOWN_DOUBLE_AND_LEFT_SINGLE = '\u2556';
77
	
78
	public static final char UP_SINGLE_AND_RIGHT_DOUBLE = '\u2558';
79
	
80
	public static final char UP_DOUBLE_AND_RIGHT_SINGLE = '\u2559';
81
	
82
	public static final char UP_SINGLE_AND_LEFT_DOUBLE = '\u255B';
83
	
84
	public static final char UP_DOUBLE_AND_LEFT_SINGLE = '\u255C';
85
	
86
	public static final char VERTICAL_SINGLE_AND_RIGHT_DOUBLE = '\u255E';
87
	
88
	public static final char VERTICAL_DOUBLE_AND_RIGHT_SINGLE = '\u255F';
89
	
90
	public static final char VERTICAL_SINGLE_AND_LEFT_DOUBLE = '\u2561';
91
	
92
	public static final char VERTICAL_DOUBLE_AND_LEFT_SINGLE = '\u2562';
93
	
94
	public static final char DOWN_SINGLE_AND_HORIZONTAL_DOUBLE = '\u2564';
95
	
96
	public static final char DOWN_DOUBLE_AND_HORIZONTAL_SINGLE = '\u2565';
97
	
98
	public static final char UP_SINGLE_AND_HORIZONTAL_DOUBLE = '\u2567';
99
	
100
	public static final char UP_DOUBLE_AND_HORIZONTAL_SINGLE = '\u2568';
101
	
102
	public static final char VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE = '\u256A';
103
	
104
	public static final char VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE = '\u256B';
105
	
106
	private static final char UNDEFINED = '?';
107
	
108
	private static final int UP3 = 1;
109
110
	private static final int DOWN3 = 3;
111
112
	private static final int LEFT3 = 9;
113
114
	private static final int RIGHT3 = 27;
115
116
	private static final char[] map = new char[100];
117
118
	static {
119
		Arrays.fill(map, UNDEFINED);
120
		map[0] = ' ';
121
		map[UP3] = LIGHT_VERTICAL;
122
		map[DOWN3] = LIGHT_VERTICAL;
123
		map[RIGHT3] = LIGHT_HORIZONTAL;
124
		map[LEFT3] = LIGHT_HORIZONTAL;
125
		map[UP3 + DOWN3] = LIGHT_VERTICAL;
126
		map[LEFT3 + RIGHT3] = LIGHT_HORIZONTAL;
127
		map[UP3 + LEFT3] = LIGHT_UP_AND_LEFT;
128
		map[LEFT3 + DOWN3] = LIGHT_DOWN_AND_LEFT;
129
		map[DOWN3 + RIGHT3] = LIGHT_DOWN_AND_RIGHT;
130
		map[UP3 + RIGHT3] = LIGHT_UP_AND_RIGHT;
131
		map[UP3 + DOWN3 + RIGHT3] = LIGHT_VERTICAL_AND_RIGHT;
132
		map[UP3 + LEFT3 + DOWN3] = LIGHT_VERTICAL_AND_LEFT;
133
		map[LEFT3 + DOWN3 + RIGHT3] = LIGHT_DOWN_AND_HORIZONTAL;
134
		map[UP3 + LEFT3 + RIGHT3] = LIGHT_UP_AND_HORIZONTAL;
135
		map[UP3 + LEFT3 + DOWN3 + RIGHT3] = LIGHT_VERTICAL_AND_HORIZONTAL;
136
		//DOUBLE
137
		map[2*UP3] = DOUBLE_VERTICAL;
138
		map[2*DOWN3] = DOUBLE_VERTICAL;
139
		map[2*RIGHT3] = DOUBLE_HORIZONTAL;
140
		map[2*LEFT3] = DOUBLE_HORIZONTAL;
141
		map[2*UP3 + 2*DOWN3] = DOUBLE_VERTICAL;
142
		map[2*LEFT3 + 2*RIGHT3] = DOUBLE_HORIZONTAL;
143
		map[2*UP3 + 2*LEFT3] = DOUBLE_UP_AND_LEFT;
144
		map[2*LEFT3 + 2*DOWN3] = DOUBLE_DOWN_AND_LEFT;
145
		map[2*DOWN3 + 2*RIGHT3] = DOUBLE_DOWN_AND_RIGHT;
146
		map[2*UP3 + 2*RIGHT3] = DOUBLE_UP_AND_RIGHT;
147
		map[2*UP3 + 2*DOWN3 + 2*RIGHT3] = DOUBLE_VERTICAL_AND_RIGHT;
148
		map[2*UP3 + 2*DOWN3 + 2*LEFT3] = DOUBLE_VERTICAL_AND_LEFT;
149
		map[2*DOWN3 + 2*RIGHT3 + 2*LEFT3] = DOUBLE_DOWN_AND_HORIZONTAL;
150
		map[2*UP3 + 2*RIGHT3 + 2*LEFT3] = DOUBLE_UP_AND_HORIZONTAL;
151
		map[2*UP3 + 2*DOWN3 + 2*RIGHT3 + 2*LEFT3] = DOUBLE_VERTICAL_AND_HORIZONTAL;
152
		//DOUBLE&SINGLE
153
		map[DOWN3 + 2*RIGHT3] = DOWN_SINGLE_AND_RIGHT_DOUBLE;
154
		map[2*DOWN3 + RIGHT3] = DOWN_DOUBLE_AND_RIGHT_SINGLE;
155
		map[DOWN3 + 2*LEFT3] = DOWN_SINGLE_AND_LEFT_DOUBLE;
156
		map[2*DOWN3 + LEFT3] = DOWN_DOUBLE_AND_LEFT_SINGLE;
157
		map[UP3 + 2*RIGHT3] = UP_SINGLE_AND_RIGHT_DOUBLE;
158
		map[2*UP3 + RIGHT3] = UP_DOUBLE_AND_RIGHT_SINGLE;
159
		map[UP3 + 2*LEFT3] = UP_SINGLE_AND_LEFT_DOUBLE;
160
		map[2*UP3 + LEFT3] = UP_DOUBLE_AND_LEFT_SINGLE;
161
		map[UP3 + DOWN3 + 2*RIGHT3] = VERTICAL_SINGLE_AND_RIGHT_DOUBLE;
162
		map[2*UP3 + 2*DOWN3 + RIGHT3] = VERTICAL_DOUBLE_AND_RIGHT_SINGLE;
163
		map[UP3 + DOWN3 + 2*LEFT3] = VERTICAL_SINGLE_AND_LEFT_DOUBLE;
164
		map[2*UP3 + 2*DOWN3 + LEFT3] = VERTICAL_DOUBLE_AND_LEFT_SINGLE;
165
		map[DOWN3 + 2*LEFT3 + 2*RIGHT3] = DOWN_SINGLE_AND_HORIZONTAL_DOUBLE;
166
		map[2*DOWN3 + LEFT3 + RIGHT3] = DOWN_DOUBLE_AND_HORIZONTAL_SINGLE;
167
		map[UP3 + 2*LEFT3 + 2*RIGHT3] = UP_SINGLE_AND_HORIZONTAL_DOUBLE;
168
		map[2*UP3 + LEFT3 + RIGHT3] = UP_DOUBLE_AND_HORIZONTAL_SINGLE;
169
		map[UP3 + DOWN3 + 2*LEFT3 + 2*RIGHT3] = VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE;
170
		map[2*UP3 + 2*DOWN3 + LEFT3 + RIGHT3] = VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE;
171
	}
172
173
	public SolidAndDoubleBorderElement() {
174
	}
175
176
	public SolidAndDoubleBorderElement(int style, int type) {
177
		super(type);
178
		if (style == EN_DOUBLE) {
179
			for (int i = 0; i < 4; i++) {
180
				data[i] *= 2;
181
			}
182
		}
183
	}
184
	
185
	/**
186
	 * Merges with <code>sde</code>.
187
	 * @param sde instance of SolidAndDoubleBorderElement
188
	 * @return instance of AbstractBorderElement
189
	 */
190
	private AbstractBorderElement mergeSolid(SolidAndDoubleBorderElement sde) {
191
		AbstractBorderElement e = new SolidAndDoubleBorderElement(EN_SOLID, 0);
192
		for (int i = 0; i < 4; i++) {
193
			if (sde.getData(i) != 0) {
194
				e.setData(i, sde.getData(i));
195
			} else {
196
				e.setData(i, data[i]);
197
			}
198
		}
199
		return e;
200
	}
201
202
	/**
203
	 * Merges with e.
204
	 * @param e instance of AbstractBorderElement
205
	 * @return instance of AbstractBorderElement
206
	 */
207
	public AbstractBorderElement merge(AbstractBorderElement e) {
208
		AbstractBorderElement abe = this;
209
		if (e instanceof SolidAndDoubleBorderElement) {
210
			abe = mergeSolid((SolidAndDoubleBorderElement) e);
211
		} else if (e instanceof DottedBorderElement) {
212
			abe = e;
213
		} else if (e instanceof DashedBorderElement) {
214
			abe = e.merge(this);
215
		}
216
		return abe;
217
	}
218
	
219
	/**
220
	 * Maps to char.
221
	 * @return resulting mapping char 
222
	 */
223
	private char map2Char() {
224
		int key = 0;
225
		key += data[UP] * UP3;
226
		key += data[LEFT] * LEFT3;
227
		key += data[DOWN] * DOWN3;
228
		key += data[RIGHT] * RIGHT3;
229
		return map[key];
230
	}
231
232
	/**
233
	 * Modifies data to nearest normal internal representation.
234
	 */
235
	private void modifyData() {
236
		int c1 = 0;
237
		int c2 = 0;
238
		for (int i = 0; i < 4; i++) {
239
			c1 += (data[i] == 1) ? 1: 0;
240
			c2 += (data[i] == 2) ? 1: 0;
241
		}
242
		int m = c1 > c2 ? 1 : 0;
243
		int[] p = {0, m, 2*(1 - m)};
244
		for (int i = 0; i < 4; i++) {
245
			data[i] = p[data[i]];
246
		}
247
	}
248
249
	public char convert2Char() {
250
		char ch = map2Char();
251
		if (ch == UNDEFINED) {
252
			modifyData();
253
			ch = map2Char();
254
		}
255
		return ch;
256
	}
257
}
(-)src/java/org/apache/fop/render/txt/border/BorderManager.java (+162 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt.border;
18
19
import org.apache.fop.fo.Constants;
20
import org.apache.fop.render.txt.TXTState;
21
22
/**
23
 * This keeps all information about borders for current processed page.
24
 */
25
public class BorderManager {
26
27
	/** Matrix for storing information about one border element. */
28
	private AbstractBorderElement[][] borderInfo;
29
30
	/** Width of current processed border. */
31
	private int width;
32
	
33
	/** Height of current processed border. */
34
	private int height;
35
36
	/** x-coordinate of upper left point of current processed border. */
37
	private int startX;
38
39
	/** y-coordinate of upper left point of current processed border. */
40
	private int startY;
41
42
	/** Stores TXTState for transforming border elements. */
43
	private TXTState state;
44
45
	/**
46
	 * Constructs BorderManger, using <code>pageWidth</code> and 
47
	 * <code>pageHeight</code> for creating <code>borderInfo</code>.
48
	 *  
49
	 * @param pageWidth page width
50
	 * @param pageHeight page height
51
	 * @param state TXTState
52
	 */
53
	public BorderManager(int pageWidth, int pageHeight, TXTState state) {
54
		this.state = state;
55
		borderInfo = new AbstractBorderElement[pageHeight][pageWidth];
56
	}
57
58
	/**
59
	 * Adds border element to <code>borderInfo</code>.
60
	 * 
61
	 * @param x x-coordinate
62
	 * @param y y-coordinate
63
	 * @param style border-style
64
	 * @param type border element type, binary representation of wich gives 
65
	 * 		information about availability or absence of corresponding side. 
66
	 */
67
	public void addBorderElement(int x, int y, int style, int type) {
68
		AbstractBorderElement be = null;
69
70
		if (style == Constants.EN_SOLID || style == Constants.EN_DOUBLE) {
71
			be = new SolidAndDoubleBorderElement(style, type);
72
		} else if (style == Constants.EN_DOTTED) {
73
			be = new DottedBorderElement();
74
		} else if (style == Constants.EN_DASHED) {
75
			be = new DashedBorderElement(type);
76
		} else {
77
			return;
78
		}
79
		be.transformElement(state);
80
81
		if (borderInfo[y][x] != null) {
82
			borderInfo[y][x] = borderInfo[y][x].merge(be);
83
		} else {
84
			borderInfo[y][x] = be;
85
		}
86
	}
87
88
	/**
89
	 * @param x x-coordinate
90
	 * @param y y-coordinate
91
	 * @return if border element at point (x,y) is available, returns instance 
92
	 * of Character, created on char, given by corresponding border element, 
93
	 * otherwise returns null. 
94
	 */
95
	public Character getCharacter(int x, int y) {
96
		Character c = null;
97
		if (borderInfo[y][x] != null) {
98
			c = new Character(borderInfo[y][x].convert2Char());
99
		}
100
		return c;
101
	}
102
103
	/**
104
	 * @return width of current processed border.
105
	 */
106
	public int getWidth() {
107
		return width;
108
	}
109
	
110
	/**
111
	 * Sets width of current processed border.
112
	 * @param width width of border
113
	 */
114
	public void setWidth(int width) {
115
		this.width = width;
116
	}
117
	
118
	/**
119
	 * @return height of current processed border.
120
	 */
121
	public int getHeight() {
122
		return height;
123
	}
124
125
	/**
126
	 * Sets height of current processed border.
127
	 * @param height height of border
128
	 */
129
	public void setHeight(int height) {
130
		this.height = height;
131
	}
132
133
	/**
134
	 * @return x-coordinate of upper left point of current processed border.
135
	 */
136
	public int getStartX() {
137
		return startX;
138
	}
139
140
	/**
141
	 * Sets x-coordinate of upper left point of current processed border.
142
	 * @param startX x-coordinate of upper left border's point.
143
	 */
144
	public void setStartX(int startX) {
145
		this.startX = startX;
146
	}
147
148
	/**
149
	 * @return y-coordinate of upper left point of current processed border.
150
	 */
151
	public int getStartY() {
152
		return startY;
153
	}
154
155
	/**
156
	 * Sets y-coordinate of upper left point of current processed border.
157
	 * @param startY y-coordinate of upper left border's point.
158
	 */
159
	public void setStartY(int startY) {
160
		this.startY = startY;
161
	}
162
}
(-)src/java/org/apache/fop/render/txt/border/AbstractBorderElement.java (+119 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt.border;
18
19
import java.awt.Point;
20
import java.util.Arrays;
21
22
import org.apache.fop.area.CTM;
23
import org.apache.fop.fo.Constants;
24
import org.apache.fop.render.txt.TXTState;
25
26
/**
27
 * This class keeps information about abstract border element, i. e. specifies
28
 * border element for one text position.
29
 */
30
public abstract class AbstractBorderElement implements Constants {
31
32
	public static final int UP = 0;
33
34
	public static final int RIGHT = 1;
35
36
	public static final int DOWN = 2;
37
38
	public static final int LEFT = 3;
39
40
	/**
41
	 * I-th element of this array specify, if there line from center of symbol
42
	 * to corresponding side (UP, RIGHT, DOWN, LEFT).
43
	 */
44
	protected int[] data = { 0, 0, 0, 0 };
45
46
	public AbstractBorderElement() {
47
	}
48
49
	/**
50
	 * Constructs a newly allocated <code>AbstractBorderElement</code> object.
51
	 * Fills <code>data</code> using binary representation of <code>type<code>.
52
	 * 
53
	 * @param type binary representation of type gives <code>data</code>
54
	 */
55
	public AbstractBorderElement(int type) {
56
		for (int i = 0; i < 4; i++) {
57
			data[i] = (type >> i) & 1;
58
		}
59
	}
60
61
	/**
62
	 * @return value of side's element of <code>data</code>
63
	 */
64
	public int getData(int side) {
65
		return data[side];
66
	}
67
68
	/**
69
	 * Sets value for <code>data[side]</code>.
70
	 */
71
	public void setData(int side, int value) {
72
		data[side] = value;
73
	}
74
75
	/**
76
	 * Transform border element in according with <code>state</code>
77
	 * @param state instance of TXTState
78
	 */
79
	public void transformElement(TXTState state) {
80
		// here we'll get CTM^-1 without shift
81
		double da[] = state.getResultCTM().toArray();
82
		CTM ctm = new CTM(da[0], -da[1], -da[2], da[3], 0, 0);
83
84
		Point[] pa = new Point[4];
85
		pa[0] = new Point(0, data[UP]);
86
		pa[1] = new Point(data[RIGHT], 0);
87
		pa[2] = new Point(0, -data[DOWN]);
88
		pa[3] = new Point(-data[LEFT], 0);
89
90
		Arrays.fill(data, 0);
91
		for (int i = 0; i < 4; i++) {
92
			Point p = state.transformPoint(pa[i], ctm);
93
94
			int length = (int) p.distance(0, 0);
95
			if (p.x == 0 && p.y > 0) {
96
				data[UP] = length;
97
			} else if (p.x == 0 && p.y < 0) {
98
				data[DOWN] = length;
99
			} else if (p.x > 0 && p.y == 0) {
100
				data[RIGHT] = length;
101
			} else if (p.x < 0 && p.y == 0) {
102
				data[LEFT] = length;
103
			}
104
		}
105
	}
106
107
	/**
108
	 * Merges with <code>e</code>.
109
	 * @param e instance of AbstractBorderElement
110
	 * @return instance of AbstractBorderElement
111
	 */
112
	public abstract AbstractBorderElement merge(AbstractBorderElement e);
113
114
	/**
115
	 * Convert internal representation of border element to char.
116
	 * @return corresponding char
117
	 */
118
	public abstract char convert2Char();
119
}
(-)src/java/org/apache/fop/render/txt/border/DottedBorderElement.java (+33 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt.border;
18
19
/**
20
 * This class is responsible for managing of dotted border elements.
21
 */
22
public class DottedBorderElement extends AbstractBorderElement {
23
	
24
	public static final char MIDDLE_DOT = '\u00B7';
25
26
	public AbstractBorderElement merge(AbstractBorderElement e) {
27
		return this;
28
	}
29
30
	public char convert2Char() {
31
		return MIDDLE_DOT;
32
	}
33
}
(-)src/java/org/apache/fop/render/txt/Helper.java (+60 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt;
18
19
public class Helper {
20
21
	/**
22
	 * @return nearest integer to <code>x</code>, divisible by
23
	 *         <code>quantum</code>.
24
	 */
25
	public static int round(int x, int quantum) {
26
		int ceil = ceil(x, quantum);
27
		int floor = floor(x, quantum);
28
		return (ceil - x < x - floor) ? ceil : floor;
29
	}
30
31
	/**
32
	 * @return minimal possible integer, greater or equal than <code>x</code>,
33
	 *         divisible by <code>quantum</code>
34
	 */
35
	public static int ceil(int x, int quantum) {
36
		int dx = (x < 0) || (x % quantum == 0) ? 0 : 1;
37
		return (x / quantum + dx) * quantum;
38
	}
39
40
	/**
41
	 * @return maximum possible integer, less or equal than
42
	 *         <code>oldValue</code>, divisible by <code>quantum</code>
43
	 */
44
	public static int floor(int x, int quantum) {
45
		int dx = (x > 0) || (x % quantum == 0) ? 0 : -1;
46
		return (x / quantum + dx) * quantum;
47
	}
48
49
	public static int roundPosition(int x, int quantum) {
50
		return round(x, quantum) / quantum;
51
	}
52
53
	public static int ceilPosition(int x, int quantum) {
54
		return ceil(x, quantum) / quantum;
55
	}
56
57
	public static int floorPosition(int x, int quantum) {
58
		return floor(x, quantum) / quantum;
59
	}
60
}
(-)src/java/org/apache/fop/render/txt/TXTHandler.java (+550 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt;
18
19
import java.io.OutputStream;
20
import java.util.Arrays;
21
import java.util.Iterator;
22
import java.util.List;
23
24
import org.apache.fop.apps.FOPException;
25
import org.apache.fop.apps.FOUserAgent;
26
import org.apache.fop.area.AreaTreeHandler;
27
import org.apache.fop.datatypes.CompoundDatatype;
28
import org.apache.fop.datatypes.Length;
29
import org.apache.fop.datatypes.PercentBaseContext;
30
import org.apache.fop.fo.Constants;
31
import org.apache.fop.fo.FONode;
32
import org.apache.fop.fo.FOText;
33
import org.apache.fop.fo.expr.NumericProperty;
34
import org.apache.fop.fo.flow.Block;
35
import org.apache.fop.fo.flow.BlockContainer;
36
import org.apache.fop.fo.flow.ExternalGraphic;
37
import org.apache.fop.fo.flow.Inline;
38
import org.apache.fop.fo.flow.ListBlock;
39
import org.apache.fop.fo.flow.ListItem;
40
import org.apache.fop.fo.flow.Table;
41
import org.apache.fop.fo.flow.TableCell;
42
import org.apache.fop.fo.flow.TableColumn;
43
import org.apache.fop.fo.pagination.PageSequence;
44
import org.apache.fop.fo.properties.CommonAbsolutePosition;
45
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
46
import org.apache.fop.fo.properties.CommonFont;
47
import org.apache.fop.fo.properties.CommonMarginBlock;
48
import org.apache.fop.fo.properties.FixedLength;
49
import org.apache.fop.fo.properties.Property;
50
import org.apache.fop.fo.properties.SpaceProperty;
51
import org.apache.fop.layoutmgr.BlockLayoutManager;
52
53
/**
54
 * Handler for formatting objects in case of rendering to txt.
55
 * 
56
 * This handler gets page-sequence, modifies formatting objects and return them
57
 * to superclass. So areas are generated from modified FO. Idea of modifying is
58
 * to quantize FO properties, making them divisible by width of char or height 
59
 * of char.
60
 */
61
public class TXTHandler extends AreaTreeHandler {
62
63
	/** Percent base context. Needed for line-height. */
64
	private static final PercentBaseContext CONTEXT = 
65
		new BlockLayoutManager(new Block(null));
66
67
	/** Modified font size in millipoints. */
68
	private static final int MODIFIED_FONT_SIZE = 10000;
69
70
	/** Quantum for each side (BEFORE, AFTER, START, END). */
71
	private final int[] quantum = { TXTRenderer.CHAR_HEIGHT,
72
			TXTRenderer.CHAR_HEIGHT, TXTRenderer.CHAR_WIDTH,
73
			TXTRenderer.CHAR_WIDTH };
74
75
	/** Keeps overpatching for each side. */
76
	private int[] overPatching = new int[4];
77
78
	/**
79
	 * Keeps last overpatching for each side. Needed for selective modifying of
80
	 * start-indent and end-indent.
81
	 */
82
	private int[] lastOverPatching = new int[4];
83
84
	public TXTHandler(FOUserAgent userAgent, OutputStream stream)
85
			throws FOPException {
86
		super(userAgent, Constants.RENDER_TXT, stream);
87
	}
88
89
	/**
90
	 * Sets a component <code>CP_LENGTH</code> of <code>cd</code> to
91
	 * <code>value</code>.
92
	 */
93
	private static void setLength(CompoundDatatype cd, int value) {
94
		cd.setComponent(Constants.CP_LENGTH, new FixedLength(value), true);
95
	}
96
97
	/**
98
	 * Sets components <code>CP_MINIMUM, CP_OPTIMUM, CP_MAXIMUM</code> of
99
	 * <code>cd</code> to <code>p</code>.
100
	 * 
101
	 * @param cd instance of CompoundDatatype for modifying.
102
	 * @param p  property for setting.
103
	 */
104
	private static void setMinOptMax(CompoundDatatype cd, Property p) {
105
		cd.setComponent(Constants.CP_MINIMUM, p, true);
106
		cd.setComponent(Constants.CP_OPTIMUM, p, true);
107
		cd.setComponent(Constants.CP_MAXIMUM, p, true);
108
	}
109
110
	/**
111
	 * Modifies border of side. If there is no border of given side, does
112
	 * nothing, otherwise sets border-width to half of char width or char height
113
	 * depending on side. <p> 
114
	 * Difference between values of new border-width and old border-width is 
115
	 * saved in <code>lastOverPatching</code>.
116
	 * 
117
	 * @param side side to modify.
118
	 * @param bpb instance of CommonBorderPaddingBackground for modifying.
119
	 */
120
	private void modifyBorder(int side, CommonBorderPaddingBackground bpb) {
121
		CommonBorderPaddingBackground.BorderInfo bi = bpb.getBorderInfo(side);
122
123
		if (bi != null) {
124
			int width = bpb.getBorderWidth(side, false);
125
			setLength(bi.getWidth(), quantum[side] / 2);
126
			lastOverPatching[side] += bpb.getBorderWidth(side, false) - width;
127
		}
128
	}
129
130
	/**
131
	 * Modifies padding of side. First rounds padding to nearest integer,
132
	 * divisible by char width or char height depending on side. If border of
133
	 * given side is available, modifies padding in such a way, so sum of border
134
	 * width and padding will be divisible by char width or char height,
135
	 * depending on side. <p>
136
	 * Difference between values of new padding and old padding is saved 
137
	 * in <code>lastOverPatching</code>.
138
	 * 
139
	 * @param side side to modify.
140
	 * @param bpb instance of CommonBorderPaddingBackground for modifying.
141
	 */
142
	private void modifyPadding(int side, CommonBorderPaddingBackground bpb) {
143
		int oldPadding = bpb.getPadding(side, false, null);
144
		int newPadding = Helper.round(oldPadding, quantum[side]);
145
		if (bpb.getBorderInfo(side) != null) {
146
			newPadding = Math.max(newPadding, quantum[side])
147
					- bpb.getBorderWidth(side, false);
148
		}
149
150
		setLength(bpb.getPaddingLengthProperty(side), newPadding);
151
		lastOverPatching[side] += newPadding - oldPadding;
152
	}
153
154
	/**
155
	 * Modifies borders and paddings of <code>bpb</code>.
156
	 * 
157
	 * @param bpb instance of CommonBorderPaddingBackground for modifying.
158
	 */
159
	private void modifyBPB(CommonBorderPaddingBackground bpb) {
160
		modifyBorder(CommonBorderPaddingBackground.BEFORE, bpb);
161
		modifyBorder(CommonBorderPaddingBackground.AFTER, bpb);
162
		modifyBorder(CommonBorderPaddingBackground.START, bpb);
163
		modifyBorder(CommonBorderPaddingBackground.END, bpb);
164
165
		modifyPadding(CommonBorderPaddingBackground.BEFORE, bpb);
166
		modifyPadding(CommonBorderPaddingBackground.AFTER, bpb);
167
		modifyPadding(CommonBorderPaddingBackground.START, bpb);
168
		modifyPadding(CommonBorderPaddingBackground.END, bpb);
169
	}
170
171
	/**
172
	 * Rounds optimum value of <code>space</code> to nearest integer,
173
	 * divisible by <code>quantum</code>.
174
	 * 
175
	 * @param space instance of SpaceProperty.
176
	 * @param quantum integer.
177
	 */
178
	private void modifySpace(SpaceProperty space, int quantum) {
179
		int value = space.getOptimum(null).getLength().getValue();
180
		setMinOptMax(space, new FixedLength(Helper.round(value, quantum)));
181
	}
182
183
	/**
184
	 * @param length instance of Length.
185
	 * @param quantum integer.
186
	 * @return instance of Length, having value nearest to value of
187
	 *         <code>length</code>, and divisible by <code>quantum</code>.
188
	 */
189
	private Length roundLength(Length length, int quantum) {
190
		int x = Helper.round(length.getValue(), quantum);
191
		return new FixedLength(x);
192
	}
193
194
	/**
195
	 * @param length instance of Length.
196
	 * @param quantum integer.
197
	 * @return instance of Length, having minimal value, greater value of
198
	 *         <code>length</code>, and divisible by <code>quantum</code>.
199
	 */
200
	private Length ceilLength(Length length, int quantum) {
201
		int x = Helper.ceil(length.getValue(), quantum);
202
		return new FixedLength(x);
203
	}
204
205
	/**
206
	 * Modifies indent for given side. Summarizes value of indent and modifing
207
	 * error (i.e. overPatching). Rounds result to nearest integer, divisible by
208
	 * quantum.
209
	 * 
210
	 * @param indent Length to modify.
211
	 * @param side an integer, representing side.
212
	 * @return modified Length.
213
	 */
214
	private Length modifyIndent(Length indent, int side) {
215
		if (indent instanceof NumericProperty) {
216
			overPatching[side] += lastOverPatching[side];
217
		}
218
		int newValue = indent.getValue() + overPatching[side];
219
		newValue = Helper.round(newValue, quantum[side]);
220
		return new FixedLength(newValue);
221
	}
222
223
	/**
224
	 * Modifies Common Margin Properties-Block:
225
	 * <ul>
226
	 * <li>margin-top, margin-left, margin-bottom, margin-right
227
	 * <li>start-indent, end-indent
228
	 * <li>space-before, space-after.
229
	 * </ul>
230
	 * 
231
	 * @param cmb instance of CommonMarginBlock to modify.
232
	 */
233
	private void modifyCommonMarginBlock(CommonMarginBlock cmb) {
234
		cmb.marginTop = roundLength(cmb.marginTop, TXTRenderer.CHAR_HEIGHT);
235
		cmb.marginBottom = roundLength(cmb.marginBottom,
236
				TXTRenderer.CHAR_HEIGHT);
237
		cmb.marginLeft = roundLength(cmb.marginLeft, TXTRenderer.CHAR_WIDTH);
238
		cmb.marginRight = roundLength(cmb.marginRight, TXTRenderer.CHAR_WIDTH);
239
240
		modifySpace(cmb.spaceBefore, TXTRenderer.CHAR_HEIGHT);
241
		modifySpace(cmb.spaceAfter, TXTRenderer.CHAR_HEIGHT);
242
243
		cmb.startIndent = modifyIndent(cmb.startIndent,
244
				CommonBorderPaddingBackground.START);
245
		cmb.endIndent = modifyIndent(cmb.endIndent,
246
				CommonBorderPaddingBackground.END);
247
	}
248
249
	/**
250
	 * Modifies fo:table attributes:
251
	 * <ul>
252
	 * <li>Common Margin Properties Block
253
	 * <li>Common Border, Padding, and Background Properties
254
	 * <li>columns.
255
	 * </ul>
256
	 * 
257
	 * @param table Table to modify.
258
	 */
259
	private void modifyTable(Table table) {
260
		CommonMarginBlock cmb = table.getCommonMarginBlock();
261
		if (table.getBorderCollapse() == Constants.EN_COLLAPSE) {
262
			// If border-collapse == "collapse", add space-after in order to
263
			// impove interaction with other FO.
264
			int value = cmb.spaceAfter.getOptimum(null).getLength().getValue();
265
			value += TXTRenderer.CHAR_HEIGHT;
266
			setMinOptMax(cmb.spaceAfter, new FixedLength(value));
267
		}
268
		modifyCommonMarginBlock(cmb);
269
270
		modifyBPB(table.getCommonBorderPaddingBackground());
271
272
		// modify all table-columns
273
		List columnList = table.getColumns();
274
		Iterator iter = columnList.iterator();
275
		while (iter.hasNext()) {
276
			modifyTableColumn((TableColumn) iter.next());
277
		}
278
	}
279
280
	/**
281
	 * Modifies fo:table-column attributes:
282
	 * <ul>
283
	 * <li>width.
284
	 * </ul>
285
	 * 
286
	 * @param column TableColumn to modify.
287
	 */
288
	private void modifyTableColumn(TableColumn column) {
289
		column.setColumnWidth(ceilLength(column.getColumnWidth(), 
290
				TXTRenderer.CHAR_WIDTH));
291
	}
292
293
	/**
294
	 * Modifies padding of fo:table-cell.
295
	 * 
296
	 * @param side side.
297
	 * @param bpb instance of CommonBorderPaddingBackground to modify.
298
	 */
299
	private void modifyCellPadding(int side, CommonBorderPaddingBackground bpb) {
300
		if (bpb.getBorderInfo(side) == null) {
301
			int oldPadding = bpb.getPadding(side, false, null);
302
			int newPadding = oldPadding + quantum[side] / 2;
303
			setLength(bpb.getPaddingLengthProperty(side), newPadding);
304
		}
305
	}
306
307
	/**
308
	 * Modifies table-cell properties:
309
	 * <ul>
310
	 * <li>Common Border, Padding, and Background Properties.
311
	 * </ul>
312
	 * 
313
	 * @param c TableCell to modify.
314
	 */
315
	private void modifyTableCell(TableCell c) {
316
		CommonBorderPaddingBackground bpb = c
317
				.getCommonBorderPaddingBackground();
318
		modifyBPB(bpb);
319
		modifyCellPadding(CommonBorderPaddingBackground.BEFORE, bpb);
320
		modifyCellPadding(CommonBorderPaddingBackground.AFTER, bpb);
321
		modifyCellPadding(CommonBorderPaddingBackground.START, bpb);
322
		modifyCellPadding(CommonBorderPaddingBackground.END, bpb);
323
	}
324
325
	/**
326
	 * Modifies Common Absolute Position Properties:
327
	 * <ul>
328
	 * <li>left
329
	 * <li>top.
330
	 * </ul>
331
	 * 
332
	 * @param cap CommonAbsolutePosition to modify.
333
	 */
334
	private void modifyCommonAbsolutePosition(CommonAbsolutePosition cap) {
335
		if (cap.absolutePosition == Constants.EN_ABSOLUTE) {
336
			cap.left = roundLength(cap.left, TXTRenderer.CHAR_WIDTH);
337
			cap.top = roundLength(cap.top, TXTRenderer.CHAR_HEIGHT);
338
		}
339
	}
340
341
	/**
342
	 * Modifies line-height property. Sets a value of line-height to max(char
343
	 * height; lowest integer, divisible by char height).
344
	 * 
345
	 * @param lineHeight SpaceProperty to modify.
346
	 */
347
	private void modifyLineHeight(SpaceProperty lineHeight) {
348
		Property p = lineHeight.getOptimum(null);
349
		int value = p.getLength().getValue(CONTEXT);
350
351
		int height = TXTRenderer.CHAR_HEIGHT;
352
		int newValue = Math.max(Helper.floor(value, height), height);
353
		setMinOptMax(lineHeight, new FixedLength(newValue));
354
	}
355
356
	/**
357
	 * Modifies Common Font Properties:
358
	 * <ul>
359
	 * <li>font-family = Courier;
360
	 * <li>font-size = MODIFIED_FONT_SIZE;
361
	 * <li>font-stretch = EN_NORMAL;
362
	 * <li>font-weight = EN_NORMAL.
363
	 * </ul>
364
	 * 
365
	 * @param cf the font to modify.
366
	 */
367
	private void modifyCommonFont(CommonFont cf) {
368
		if (cf != null) {
369
			cf.fontFamily = "Courier";
370
			cf.fontSize = new FixedLength(MODIFIED_FONT_SIZE);
371
			cf.fontStretch = Constants.EN_NORMAL;
372
			cf.fontWeight = Constants.EN_NORMAL;
373
		}
374
	}
375
376
	/**
377
	 * Modifies fo:block:
378
	 * <ul>
379
	 * <li>Common Border, Padding, and Background Properties
380
	 * <li>Common Margin Properties-Block
381
	 * <li>Common Font Properties
382
	 * <li>line-height.
383
	 * </ul>
384
	 * 
385
	 * @param block Block to modify.
386
	 */
387
	private void modifyBlock(Block block) {
388
		modifyBPB(block.getCommonBorderPaddingBackground());
389
		modifyCommonMarginBlock(block.getCommonMarginBlock());
390
		modifyCommonFont(block.getCommonFont());
391
		modifyLineHeight(block.getLineHeight());
392
	}
393
394
	/**
395
	 * Modifies fo:block-container:
396
	 * <ul>
397
	 * <li>Common Border, Padding, and Background Properties
398
	 * <li>Common Margin Properties-Block
399
	 * <li>Common Absolute Position Properties.
400
	 * </ul>
401
	 * 
402
	 * @param bc BlockContainer to modify.
403
	 */
404
	private void modifyBlockContainer(BlockContainer bc) {
405
		modifyBPB(bc.getCommonBorderPaddingBackground());
406
		modifyCommonMarginBlock(bc.getCommonMarginBlock());
407
		modifyCommonAbsolutePosition(bc.getCommonAbsolutePosition());
408
	}
409
410
	/**
411
	 * Modifies fo:inline:
412
	 * <ul>
413
	 * <li>Common Font Properties
414
	 * </ul>
415
	 * 
416
	 * @param inline Inline to modify.
417
	 */
418
	private void modifyInline(Inline inline) {
419
		modifyCommonFont(inline.getCommonFont());
420
	}
421
422
	/**
423
	 * Modifies FOText:
424
	 * <ul>
425
	 * <li>Common Font Properties
426
	 * </ul>
427
	 * 
428
	 * @param text FOText to modify.
429
	 */
430
	private void modifyFOText(FOText text) {
431
		modifyCommonFont(text.getCommonFont());
432
	}
433
434
	/**
435
	 * Modifies fo:external-graphic:
436
	 * <ul>
437
	 * <li>Common Border, Padding, and Background Properties
438
	 * <li>line-height.
439
	 * </ul>
440
	 * 
441
	 * @param eg ExternalGraphic to modify.
442
	 */
443
	private void modifyExternalGraphic(ExternalGraphic eg) {
444
		modifyBPB(eg.getCommonBorderPaddingBackground());
445
		modifyLineHeight(eg.getLineHeight());
446
	}
447
448
	/**
449
	 * Modifies fo:list-block:
450
	 * <ul>
451
	 * <li>Common Border, Padding, and Background Properties
452
	 * <li>Common Margin Properties-Block.
453
	 * </ul>
454
	 * 
455
	 * @param lb ListBlock to modify.
456
	 */
457
	private void modifyListBlock(ListBlock lb) {
458
		modifyBPB(lb.getCommonBorderPaddingBackground());
459
		modifyCommonMarginBlock(lb.getCommonMarginBlock());
460
	}
461
462
	/**
463
	 * Modifies fo:list-item:
464
	 * <ul>
465
	 * <li>Common Border, Padding, and Background Properties
466
	 * <li>Common Margin Properties-Block.
467
	 * </ul>
468
	 * <p>
469
	 * Make refinement for fo:list-item-label and fo:list-item-body.
470
	 * 
471
	 * @param li ListItem to modify.
472
	 */
473
	private void modifyListItem(ListItem li) {
474
		modifyBPB(li.getCommonBorderPaddingBackground());
475
		modifyCommonMarginBlock(li.getCommonMarginBlock());
476
		refinement(li.getLabel());
477
		refinement(li.getBody());
478
	}
479
	
480
	/**
481
	 * Does refinement for particular node. Modifies node's properties and
482
	 * refines its children recursively.
483
	 * 
484
	 * @param node the node to refine.
485
	 */
486
	private void refinement(FONode node) {
487
		int[] saveOverPatching = (int[]) overPatching.clone();
488
		Arrays.fill(lastOverPatching, 0);
489
490
		if (node instanceof Block) {
491
			modifyBlock((Block) node);
492
		} else if (node instanceof BlockContainer) {
493
			modifyBlockContainer((BlockContainer) node);
494
		} else if (node instanceof Inline) {
495
			modifyInline((Inline) node);
496
		} else if (node instanceof FOText) {
497
			modifyFOText((FOText) node);
498
		} else if (node instanceof Table) {
499
			modifyTable((Table) node);
500
			Arrays.fill(overPatching, 0);
501
		} else if (node instanceof TableCell) {
502
			modifyTableCell((TableCell) node);
503
		} else if (node instanceof ExternalGraphic) {
504
			modifyExternalGraphic((ExternalGraphic) node);
505
		} else if (node instanceof ListBlock) {
506
			modifyListBlock((ListBlock) node);
507
		} else if (node instanceof ListItem) {
508
			modifyListItem((ListItem) node);
509
		}
510
511
		Iterator it = node.getChildNodes();
512
		if (it != null) {
513
			while (it.hasNext()) {
514
				refinement((FONode) it.next());
515
			}
516
		}
517
		overPatching = saveOverPatching;
518
	}
519
520
	/**
521
	 * Run refinement for:
522
	 * <ul>
523
	 * <li>mainflow (xsl-region-body)
524
	 * <li>staticflow (xsl-region-before, xsl-region-after, xsl-region-start,
525
	 * xsl-region-end).
526
	 * </ul>
527
	 * 
528
	 * @param pageSequence PageSequence to refine.
529
	 */
530
	public void endPageSequence(PageSequence pageSequence) {
531
		Arrays.fill(overPatching, 0);
532
533
		refinement(pageSequence.getMainFlow());
534
535
		if (pageSequence.getStaticContent("xsl-region-before") != null) {
536
			refinement(pageSequence.getStaticContent("xsl-region-before"));
537
		}
538
		if (pageSequence.getStaticContent("xsl-region-after") != null) {
539
			refinement(pageSequence.getStaticContent("xsl-region-after"));
540
		}
541
		if (pageSequence.getStaticContent("xsl-region-start") != null) {
542
			refinement(pageSequence.getStaticContent("xsl-region-start"));
543
		}
544
		if (pageSequence.getStaticContent("xsl-region-end") != null) {
545
			refinement(pageSequence.getStaticContent("xsl-region-end"));
546
		}
547
548
		super.endPageSequence(pageSequence);
549
	}
550
}
(-)src/java/org/apache/fop/render/txt/TXTRenderer.java (-99 / +426 lines)
Lines 18-139 Link Here
18
 
18
 
19
package org.apache.fop.render.txt;
19
package org.apache.fop.render.txt;
20
20
21
// FOP
21
import java.awt.Point;
22
import org.apache.fop.render.PrintRenderer;
22
import java.awt.geom.Rectangle2D;
23
import org.apache.fop.render.pcl.PCLStream;
23
import java.io.IOException;
24
import java.io.OutputStream;
25
import java.util.List;
24
26
27
import org.apache.fop.apps.FOPException;
28
import org.apache.fop.area.Area;
29
import org.apache.fop.area.CTM;
30
import org.apache.fop.area.PageViewport;
31
import org.apache.fop.area.inline.Image;
32
import org.apache.fop.area.inline.TextArea;
33
import org.apache.fop.datatypes.ColorType;
34
import org.apache.fop.render.AbstractPathOrientedRenderer;
35
import org.apache.fop.render.txt.border.AbstractBorderElement;
36
import org.apache.fop.render.txt.border.BorderManager;
37
25
/**
38
/**
26
 * Renderer that renders areas to plain text
39
 * Renderer that renders areas to plain text.
27
 *
40
 * 
28
 * Created by Arthur E Welch III while at M&I EastPoint Technology
41
 * @author Art Welch
29
 * Modified by Mark Lillywhite mark-fop@inomial.com to use the new
42
 * @author <a href="mailto:mark-fop@inomial.com">Mark Lillywhite</a> (to use
30
 * Renderer interface.
43
 *         the new Renderer interface)
31
 */
44
 */
32
public class TXTRenderer extends PrintRenderer {
45
public class TXTRenderer extends AbstractPathOrientedRenderer {
46
	
47
	private static final char LIGHT_SHADE = '\u2591';
48
	
49
	private static final char MEDIUM_SHADE = '\u2592';
50
	
51
	private static final char DARK_SHADE = '\u2593';
33
52
34
    /** The MIME type for PostScript */
53
	private static final char FULL_BLOCK = '\u2588';
35
    public static final String MIME_TYPE = "text/plain";
36
54
55
	public static final char IMAGE_CHAR = '#';
56
57
    /**The stream for output */
58
	private OutputStream outputStream;
59
60
	/** The current stream to add Text commands to. */
61
	private TXTStream currentStream;
62
63
    /** Buffer for text. */
64
	private StringBuffer charData[];
65
66
    /** Buffer for background and images. */
67
	private StringBuffer decoData[];
68
69
    /** Height of one symbol in Courier font size of 10pt. */
70
	public static final int CHAR_HEIGHT = 7860;
71
72
    /** Width of one symbol in Courier font size of 10pt. */
73
	public static final int CHAR_WIDTH = 6000;
74
75
    /** Current processing page width. */
76
	private int pageWidth;
77
78
    /** Current processing page height. */
79
	private int pageHeight;
80
81
	/**
82
	 * Every line except the last line on a page (which will end with
83
	 * pageEnding) will be terminated with this string.
84
	 */
85
	public String lineEnding = "\r\n";
86
87
	/** Every page except the last one will end with this string. */
88
	public String pageEnding = "\f";
89
90
	/** Equals true, if current page is first. */
91
	private boolean firstPage = false;
92
93
	/** Manager for storing border's information. */
94
	private BorderManager bm;
95
	
96
	/** Char for current filling. */
97
	private char fillChar;
98
99
	/** Saves current coordinate transformation. */
100
	private TXTState currentState = new TXTState();
101
102
	public TXTRenderer() {
103
	}
104
37
    /**
105
    /**
38
     * the current stream to add Text commands to
106
     * Indicates if point (x, y) lay inside currentPage.
107
     * 
108
     * @param x x coordinate
109
     * @param y y coordinate
110
     * @return <b>true</b> if point lay inside page
39
     */
111
     */
40
    private PCLStream currentStream;
112
	public boolean isLayInside(int x, int y) {
113
		return (x >= 0) && (x < pageWidth) && (y >= 0) && (y < pageHeight);
114
	}
41
115
42
    private int pageHeight = 7920;
116
    /**
117
     * Add char to text buffer.
118
     * 
119
     * @param x x coordinate
120
     * @param y y coordinate
121
     * @param ch char to add
122
     */
123
	protected void addChar(int x, int y, char ch, boolean ischar) {
124
		Point point = currentState.transformPoint(x, y);
125
		putChar(point.x, point.y, ch, ischar);
126
	}
43
127
44
    // These variables control the virtual paggination functionality.
128
    /**
45
    private int curdiv = 0;
129
     * Add char to text or background buffer.
46
    private int divisions = -1;
130
     * 
47
    private int paperheight = -1;    // Paper height in decipoints?
131
     * @param x x coordinate
48
    private int orientation = -1;    // -1=default/unknown, 0=portrait, 1=landscape.
132
     * @param y x coordinate
49
    private int topmargin = -1;      // Top margin in decipoints?
133
     * @param ch char to add
50
    private int leftmargin = -1;     // Left margin in decipoints?
134
     * @param ischar indicates if it char or background
51
    private int fullmargin = 0;
135
     */
52
    private final boolean debug = false;
136
	protected void putChar(int x, int y, char ch, boolean ischar) {
137
		if (isLayInside(x, y)) {
138
			StringBuffer sb = ischar ? charData[y] : decoData[y];
139
			while (sb.length() <= x) {
140
				sb.append(' ');
141
			}
142
			sb.setCharAt(x, ch);
143
		}
144
	}
53
145
54
    // Variables for rendering text.
146
    /**
55
    private StringBuffer charData[];
147
     * Adds string to text buffer (<code>charData</code>). <p>
56
    private StringBuffer decoData[];
148
     * Chars of string map in turn.
57
    private float textCPI = 16.67f;
149
     * 
58
    private float textLPI = 8;
150
     * @param row x coordinate
59
    private int maxX = (int)(8.5f * textCPI + 1);
151
     * @param col y coordinate
60
    private int maxY = (int)(11f * textLPI + 1);
152
     * @param s string to add
61
    private float xFactor;
62
    private float yFactor;
63
    /** 
64
     * Every line except the last line on a page (which will end with 
65
     * pageEnding) will be terminated with this string.
66
     */
153
     */
67
    private String lineEnding = "\r\n";
154
	protected void addString(int row, int col, String s) {
68
    /** 
155
		for (int l = 0; l < s.length(); l++) {
69
     * Every page except the last one will end with this string.
156
			addChar(col + l, row, s.charAt(l), true);
157
		}
158
	}
159
160
	/**
161
	 * Render TextArea to Text.
162
	 * 
163
	 * @param area inline area to render
164
	 */
165
	protected void renderText(TextArea area) {
166
		int col = Helper.ceilPosition(this.currentIPPosition, CHAR_WIDTH);
167
		int row = Helper.ceilPosition(this.currentBPPosition, CHAR_HEIGHT);
168
169
		String s = area.getTextArea();
170
171
		addString(row, col, s);
172
173
		super.renderText(area);
174
	}
175
176
	/**
177
	 * Render page into Text.
178
	 * 
179
	 * @param page - page to render
180
	 */
181
	public void renderPage(PageViewport page) throws IOException, FOPException {
182
		if (firstPage) {
183
			firstPage = false;
184
		} else {
185
			currentStream.add(pageEnding);
186
		}
187
188
		Rectangle2D bounds = page.getViewArea();
189
		double width = bounds.getWidth();
190
		double height = bounds.getHeight();
191
192
		pageWidth = Helper.ceilPosition((int) width, CHAR_WIDTH);
193
		pageHeight = Helper.ceilPosition((int) height, CHAR_HEIGHT);
194
		
195
		// init buffers
196
		charData = new StringBuffer[pageHeight];
197
		decoData = new StringBuffer[pageHeight];
198
		for (int i = 0; i < pageHeight; i++) {
199
			charData[i] = new StringBuffer();
200
			decoData[i] = new StringBuffer();
201
		}
202
203
		bm = new BorderManager(pageWidth, pageHeight, currentState);
204
205
		super.renderPage(page);
206
207
		flushBorderToBuffer();
208
		flushBuffer();
209
	}
210
211
    /**
212
     * Projects current page borders (i.e.<code>bm</code>) to buffer for 
213
     * background and images (i.e.<code>decoData</code>). 
70
     */
214
     */
71
    private String pageEnding = "\f";
215
	private void flushBorderToBuffer() {
216
		for (int x = 0; x < pageWidth; x++) {
217
			for (int y = 0; y < pageHeight; y++) {
218
				Character c = bm.getCharacter(x, y);
219
				if (c != null) {
220
					putChar(x, y, c.charValue(), false);
221
				}
222
			}
223
		}
224
	}
225
72
    /**
226
    /**
73
     * If true then graphics/decorations will not be rendered - text only.
227
     * Write out the buffer to output stream.
74
     */
228
     */
75
    private boolean suppressGraphics = false;
229
	private void flushBuffer() {
76
    private boolean firstPage = false;
230
		for (int row = 0; row < pageHeight; row++) {
231
			StringBuffer cr = charData[row];
232
			StringBuffer dr = decoData[row];
233
			StringBuffer outr = null;
77
234
78
    private void addStr(int row, int col, String str, boolean ischar) {
235
			if (cr != null && dr == null)
79
        if (debug) {
236
				outr = cr;
80
            log.debug("TXTRenderer.addStr(" + row + ", " + col
237
			else if (dr != null && cr == null)
81
                               + ", \"" + str + "\", " + ischar + ")");
238
				outr = dr;
82
        }
239
			else if (cr != null && dr != null) {
83
        if (suppressGraphics && !ischar) {
240
				int len = dr.length();
84
            return;
241
				if (cr.length() > len)
85
        }
242
					len = cr.length();
86
        StringBuffer sb;
243
				outr = new StringBuffer();
87
        if (row < 0) {
244
				for (int countr = 0; countr < len; countr++) {
88
            row = 0;
245
					if (countr < cr.length() && cr.charAt(countr) != ' ')
89
        }
246
						outr.append(cr.charAt(countr));
90
        if (ischar) {
247
					else if (countr < dr.length())
91
            sb = charData[row];
248
						outr.append(dr.charAt(countr));
92
        } else {
249
					else
93
            sb = decoData[row];
250
						outr.append(' ');
94
        }
251
				}
95
        if (sb == null) {
252
			}
96
            sb = new StringBuffer();
97
        }
98
        if ((col + str.length()) > maxX) {
99
            col = maxX - str.length();
100
        }
101
        if (col < 0) {
102
            col = 0;
103
            if (str.length() > maxX) {
104
                str = str.substring(0, maxX);
105
            }
106
        }
107
        // Pad to col
108
        for (int countr = sb.length(); countr < col; countr++) {
109
            sb.append(' ');
110
        }
111
        if (debug) {
112
            log.debug("TXTRenderer.addStr() sb.length()="
113
                               + sb.length());
114
        }
115
        for (int countr = col; countr < (col + str.length()); countr++) {
116
            if (countr >= sb.length()) {
117
                sb.append(str.charAt(countr - col));
118
            } else {
119
                if (debug) {
120
                    log.debug("TXTRenderer.addStr() sb.length()="
121
                                       + sb.length() + " countr=" + countr);
122
                }
123
                sb.setCharAt(countr, str.charAt(countr - col));
124
            }
125
        }
126
253
127
        if (ischar) {
254
			if (outr != null) {
128
            charData[row] = sb;
255
				currentStream.add(outr.toString());
129
        } else {
256
			}
130
            decoData[row] = sb;
257
			if (row < pageHeight) {
131
        }
258
				currentStream.add(lineEnding);
132
    }
259
			}
260
		}
261
	}
133
262
134
    /** @see org.apache.fop.render.AbstractRenderer */
263
	public void startRenderer(OutputStream outputStream) throws IOException {
135
    public String getMimeType() {
264
		log.info("Rendering areas to TEXT.");
136
        return MIME_TYPE;
265
		this.outputStream = outputStream;
266
		currentStream = new TXTStream(outputStream);
267
		firstPage = true;
268
	}
269
270
	public void stopRenderer() throws IOException {
271
		log.info("writing out TEXT");
272
		outputStream.flush();
273
		super.stopRenderer();
274
	}
275
276
	/** Does nothing. */
277
	protected void restoreStateStackAfterBreakOut(List breakOutList) {
278
	}
279
280
	/** Does nothing. */
281
	protected List breakOutOfStateStack() {
282
		return null;
283
	}
284
285
	/** Does nothing. */
286
	protected void saveGraphicsState() {
287
	}
288
289
	/** Does nothing. */
290
	protected void restoreGraphicsState() {
291
	}
292
293
	/** Does nothing. */
294
	protected void beginTextObject() {
295
	}
296
297
	/** Does nothing. */
298
	protected void endTextObject() {
299
	}
300
301
	/** Does nothing. */
302
	protected void clip() {
303
	}
304
305
	/** Does nothing. */
306
	protected void clipRect(float x, float y, float width, float height) {
307
	}
308
309
	/** Does nothing. */
310
	protected void moveTo(float x, float y) {
311
	}
312
313
	/** Does nothing. */
314
	protected void lineTo(float x, float y) {
315
	}
316
317
	/** Does nothing. */
318
	protected void closePath() {
319
	}
320
321
	/**
322
	 * Fills rectangle startX, startY, width, height with char 
323
	 * <code>fillChar</code>.
324
	 * 
325
	 * @param startX x-coordinate of upper left point
326
	 * @param startY y-coordinate of upper left point
327
	 * @param width width of rectangle
328
	 * @param height height of rectangle
329
	 * @param fillChar filling char 
330
	 */
331
	private void fillRect(int startX, int startY, int width, int height, 
332
			char fillChar) {
333
		for (int x = startX; x < startX + width; x++) {
334
			for (int y = startY; y < startY + height; y++) {
335
				addChar(x, y, fillChar, false);
336
			}
337
		}
338
	}
339
	
340
	protected void fillRect(float x, float y, float width, float height) {
341
		fillRect(bm.getStartX(), bm.getStartY(), bm.getWidth(), bm.getHeight(),
342
				fillChar);
343
	}
344
	
345
	protected void updateColor(ColorType col, boolean fill) {
346
		if (col == null) {
347
			return;
348
		}
349
		// fillShade evaluation was taken from fop-0.20.5 
350
		double fillShade = 0.3f  * col.getRed() + 
351
						   0.59f * col.getGreen() + 
352
						   0.11f * col.getBlue();
353
		fillShade = 1 - fillShade;
354
		
355
		if (fillShade > 0.8f) {
356
			fillChar = FULL_BLOCK;
357
		} else if (fillShade > 0.6f) {
358
			fillChar = DARK_SHADE;
359
		} else if (fillShade > 0.4f) {
360
			fillChar = MEDIUM_SHADE;
361
		} else if (fillShade > 0.2f) {
362
			fillChar = LIGHT_SHADE;
363
		} else {
364
			fillChar = ' ';
365
		}
366
	}
367
368
	/** Does nothing. */
369
	protected void drawImage(String url, Rectangle2D pos) {
370
	}
371
	
372
    public void renderImage(Image image, Rectangle2D pos) {
373
    	int x1 = Helper.ceilPosition(currentIPPosition, CHAR_WIDTH);
374
    	int y1 = Helper.ceilPosition(currentBPPosition, CHAR_HEIGHT);
375
    	int width = Helper.ceilPosition((int) pos.getWidth(), CHAR_WIDTH);
376
    	int height = Helper.ceilPosition((int) pos.getHeight(), CHAR_HEIGHT);
377
    	
378
    	fillRect(x1, y1, width, height, IMAGE_CHAR);
137
    }
379
    }
138
380
381
	protected int toMilli(float x) {
382
		return Math.round(x * 1000f);
383
	}
384
385
    /**
386
     * Adds one element of border.
387
     * 
388
     * @param x x coordinate
389
     * @param y y coordinate
390
     * @param style
391
     * @param type
392
     */
393
	private void addBitOfBorder(int x, int y, int style, int type) {
394
		Point point = currentState.transformPoint(x, y);
395
		if (isLayInside(point.x, point.y)) {
396
			bm.addBorderElement(point.x, point.y, style, type);
397
		}
398
	}
399
400
	protected void drawBorderLine(float x1, float y1, float x2, float y2,
401
			boolean horz, boolean startOrBefore, int style, ColorType col) {
402
403
		int borderHeight = bm.getHeight();
404
		int borderWidth = bm.getWidth();
405
		int borderStartX = bm.getStartX();
406
		int borderStartY = bm.getStartY();
407
408
		int x, y;
409
		if (horz && startOrBefore) { // BEFORE
410
			x = borderStartX;
411
			y = borderStartY;
412
		} else if (horz && !startOrBefore) { // AFTER
413
			x = borderStartX;
414
			y = borderStartY + borderHeight - 1;
415
		} else if (!horz && startOrBefore) { // START
416
			x = borderStartX;
417
			y = borderStartY;
418
		} else { // END
419
			x = borderStartX + borderWidth - 1;
420
			y = borderStartY;
421
		}
422
423
		int dx, dy, length, startType, endType;
424
		if (horz) {
425
			length = borderWidth;
426
			dx = 1;
427
			dy = 0;
428
			startType = 1 << AbstractBorderElement.RIGHT;
429
			endType = 1 << AbstractBorderElement.LEFT;
430
		} else {
431
			length = borderHeight;
432
			dx = 0;
433
			dy = 1;
434
			startType = 1 << AbstractBorderElement.DOWN;
435
			endType = 1 << AbstractBorderElement.UP;
436
		}
437
438
		addBitOfBorder(x, y, style, startType);
439
		for (int i = 0; i < length - 2; i++) {
440
			x += dx;
441
			y += dy;
442
			addBitOfBorder(x, y, style, startType + endType);
443
		}
444
		x += dx;
445
		y += dy;
446
		addBitOfBorder(x, y, style, endType);
447
	}
448
449
	protected void drawBackAndBorders(Area area, float startx, float starty,
450
			float width, float height) {
451
		bm.setWidth(Helper.ceilPosition(toMilli(width), CHAR_WIDTH));
452
		bm.setHeight(Helper.ceilPosition(toMilli(height), CHAR_HEIGHT));
453
		bm.setStartX(Helper.ceilPosition(toMilli(startx), CHAR_WIDTH));
454
		bm.setStartY(Helper.ceilPosition(toMilli(starty), CHAR_HEIGHT));
455
456
		super.drawBackAndBorders(area, startx, starty, width, height);
457
	}
458
459
	protected void startVParea(CTM ctm) {
460
		currentState.push(ctm);
461
	}
462
463
	protected void endVParea() {
464
		currentState.pop();
465
	}
139
}
466
}
(-)src/java/org/apache/fop/render/txt/TXTState.java (+130 lines)
Line 0 Link Here
1
/*
2
 * Copyright 2005 The Apache Software Foundation.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package org.apache.fop.render.txt;
18
19
import java.awt.Point;
20
import java.awt.geom.Rectangle2D;
21
import java.util.Iterator;
22
import java.util.LinkedList;
23
24
import org.apache.fop.area.CTM;
25
26
/**
27
 * This keeps information about the current state when writing to txt, i.e. 
28
 * manages coordinate transformation matrices for getting absolute coordinates.
29
 */
30
public class TXTState {
31
32
	/** Keeps all coordinate transformation matrices during rendering. */
33
	private LinkedList stackCTM = new LinkedList();
34
35
	/**
36
	 * Current result coordinate transformation matrix. It's product of 
37
	 * all matrices in order, saved in <code>stackCTM</code>.
38
	 */
39
	private CTM resultCTM = new CTM();
40
41
	public TXTState() {
42
	}
43
44
	/**
45
	 * Updates result coordinate transformation matrix 
46
	 * (i.e. <code>resultCTM</code>), multipliing it by given matrix.
47
	 * 
48
	 * @param ctm CTM
49
	 */
50
	private void updateResultCTM(CTM ctm) {
51
		resultCTM = resultCTM.multiply(ctm);
52
	}
53
54
	/**
55
	 * Recalculate current result coordinate transformation matrix.
56
	 */
57
	private void calcResultCTM() {
58
		resultCTM = new CTM();
59
		for (Iterator i = stackCTM.iterator(); i.hasNext(); ) {
60
			updateResultCTM((CTM) i.next());
61
		}
62
	}
63
64
	/**
65
	 * Push the current coordinate transformation matrix onto the stack and 
66
	 * reevaluate <code>resultCTM</code>.
67
	 */
68
	public void push(CTM ctm) {
69
		stackCTM.addLast(ctm);
70
		updateResultCTM(ctm);
71
	}
72
73
	/**
74
	 * Pop the coordinate transformation matrix from the stack and reevaluate
75
	 * <code>resultCTM</code>.
76
	 */
77
	public void pop() {
78
		stackCTM.removeLast();
79
		calcResultCTM();
80
	}
81
	
82
	/**
83
	 * Modifies coordinate transformation matrix in such a way, so 
84
	 * x-shift and y-shift will be transformed in text positions.
85
	 * 
86
	 * @param ctm CTM to modify
87
	 * @return instance of CTM
88
	 */
89
	public CTM refineCTM(CTM ctm) {
90
		double da[] = ctm.toArray();
91
		// refine x-shift
92
		da[4] = Helper.roundPosition((int) da[4], TXTRenderer.CHAR_WIDTH);
93
		// refine y-shift
94
		da[5] = Helper.roundPosition((int) da[5], TXTRenderer.CHAR_HEIGHT);
95
		
96
		return new CTM(da[0], da[1], da[2], da[3], da[4], da[5]);
97
	}
98
99
	/**
100
	 * Transforms <code>point</code> using <code>ctm</code>.
101
	 * 
102
	 * @param p Point
103
	 * @param ctm CTM
104
	 * @return transformed Point
105
	 */
106
	public Point transformPoint(Point p, CTM ctm) {
107
		Rectangle2D r = new Rectangle2D.Double(p.x, p.y, 0, 0);
108
		CTM nctm = refineCTM(ctm);
109
		r = nctm.transform(r);
110
		return new Point((int) r.getX(), (int) r.getY());
111
	}
112
113
	/**
114
	 * Transforms point (x, y) using <code>resultCTM</code>.
115
	 * 
116
	 * @param x x-coordinate
117
	 * @param y y-coordinate
118
	 * @return transformed Point
119
	 */
120
	public Point transformPoint(int x, int y) {
121
		return transformPoint(new Point(x, y), resultCTM);
122
	}
123
124
	/**
125
	 * @return current result coordinate transformation matrix
126
	 */
127
	public CTM getResultCTM() {
128
		return resultCTM;
129
	}
130
}

Return to bug 37253