KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > render > txt > TXTHandler


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: TXTHandler.java 426576 2006-07-28 15:44:37Z jeremias $ */
19
20 package org.apache.fop.render.txt;
21
22 import java.io.OutputStream JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26
27 import org.apache.fop.apps.FOPException;
28 import org.apache.fop.apps.FOUserAgent;
29 import org.apache.fop.apps.MimeConstants;
30 import org.apache.fop.area.AreaTreeHandler;
31 import org.apache.fop.datatypes.CompoundDatatype;
32 import org.apache.fop.datatypes.Length;
33 import org.apache.fop.datatypes.PercentBaseContext;
34 import org.apache.fop.fo.Constants;
35 import org.apache.fop.fo.FONode;
36 import org.apache.fop.fo.FOText;
37 import org.apache.fop.fo.expr.NumericProperty;
38 import org.apache.fop.fo.expr.RelativeNumericProperty;
39 import org.apache.fop.fo.flow.Block;
40 import org.apache.fop.fo.flow.BlockContainer;
41 import org.apache.fop.fo.flow.ExternalGraphic;
42 import org.apache.fop.fo.flow.Inline;
43 import org.apache.fop.fo.flow.ListBlock;
44 import org.apache.fop.fo.flow.ListItem;
45 import org.apache.fop.fo.flow.PageNumber;
46 import org.apache.fop.fo.flow.Table;
47 import org.apache.fop.fo.flow.TableCell;
48 import org.apache.fop.fo.flow.TableColumn;
49 import org.apache.fop.fo.pagination.PageSequence;
50 import org.apache.fop.fo.properties.CommonAbsolutePosition;
51 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
52 import org.apache.fop.fo.properties.CommonFont;
53 import org.apache.fop.fo.properties.CommonMarginBlock;
54 import org.apache.fop.fo.properties.FixedLength;
55 import org.apache.fop.fo.properties.Property;
56 import org.apache.fop.fo.properties.SpaceProperty;
57 import org.apache.fop.layoutmgr.BlockLayoutManager;
58
59 /**
60  * Handler for formatting objects in case of rendering to txt.
61  *
62  * This handler gets page-sequence, modifies formatting objects and return them
63  * to superclass. So areas are generated from modified FO. Idea of modifying is
64  * to quantize FO properties, making them divisible by width of char or height
65  * of char.
66  */

67 public class TXTHandler extends AreaTreeHandler {
68
69     /** Percent base context. Needed for line-height. */
70     private static final PercentBaseContext CONTEXT
71         = new BlockLayoutManager(new Block(null));
72
73     /** Modified font size in millipoints. */
74     private static final int MODIFIED_FONT_SIZE = 10000;
75
76     /** Quantum for each side (BEFORE, AFTER, START, END). */
77     private final int[] quantum = {TXTRenderer.CHAR_HEIGHT,
78             TXTRenderer.CHAR_HEIGHT, TXTRenderer.CHAR_WIDTH,
79             TXTRenderer.CHAR_WIDTH};
80
81     /** Keeps overpatching for each side. */
82     private int[] overPatching = new int[4];
83
84     /**
85      * Keeps last overpatching for each side. Needed for selective modifying of
86      * start-indent and end-indent.
87      */

88     private int[] lastOverPatching = new int[4];
89
90     /**
91      * Constructs a newly allocated <code>TXTHandler</code> object.
92      *
93      * @param userAgent FOUserAgent
94      * @param stream OutputStream
95      * @throws FOPException if the RenderPagesModel cannot be created
96      */

97     public TXTHandler(FOUserAgent userAgent, OutputStream JavaDoc stream)
98             throws FOPException {
99         super(userAgent, MimeConstants.MIME_PLAIN_TEXT, stream);
100     }
101
102     /**
103      * Sets a component <code>CP_LENGTH</code> of <code>cd</code> to
104      * <code>value</code>.
105
106      * @param cd CompoundDatatype
107      * @param value new integer value
108      */

109     private static void setLength(CompoundDatatype cd, int value) {
110         cd.setComponent(Constants.CP_LENGTH, new FixedLength(value), true);
111     }
112
113     /**
114      * Sets components <code>CP_MINIMUM, CP_OPTIMUM, CP_MAXIMUM</code> of
115      * <code>cd</code> to <code>p</code>.
116      *
117      * @param cd instance of CompoundDatatype for modifying.
118      * @param p property for setting.
119      */

120     private static void setMinOptMax(CompoundDatatype cd, Property p) {
121         cd.setComponent(Constants.CP_MINIMUM, p, true);
122         cd.setComponent(Constants.CP_OPTIMUM, p, true);
123         cd.setComponent(Constants.CP_MAXIMUM, p, true);
124     }
125
126     /**
127      * Modifies border of side. If there is no border of given side, does
128      * nothing, otherwise sets border-width to half of char width or char height
129      * depending on side. <p>
130      * Difference between values of new border-width and old border-width is
131      * saved in <code>lastOverPatching</code>.
132      *
133      * @param side side to modify.
134      * @param bpb instance of CommonBorderPaddingBackground for modifying.
135      */

136     private void modifyBorder(int side, CommonBorderPaddingBackground bpb) {
137         CommonBorderPaddingBackground.BorderInfo bi = bpb.getBorderInfo(side);
138
139         if (bi != null) {
140             int width = bpb.getBorderWidth(side, false);
141             setLength(bi.getWidth(), quantum[side] / 2);
142             lastOverPatching[side] += bpb.getBorderWidth(side, false) - width;
143         }
144     }
145
146     /**
147      * Modifies padding of side. First rounds padding to nearest integer,
148      * divisible by char width or char height depending on side. If border of
149      * given side is available, modifies padding in such a way, so sum of border
150      * width and padding will be divisible by char width or char height,
151      * depending on side. <p>
152      * Difference between values of new padding and old padding is saved
153      * in <code>lastOverPatching</code>.
154      *
155      * @param side side to modify.
156      * @param bpb instance of CommonBorderPaddingBackground for modifying.
157      */

158     private void modifyPadding(int side, CommonBorderPaddingBackground bpb) {
159         int oldPadding = bpb.getPadding(side, false, null);
160         int newPadding = Helper.round(oldPadding, quantum[side]);
161         if (bpb.getBorderInfo(side) != null) {
162             newPadding = Math.max(newPadding, quantum[side])
163                     - bpb.getBorderWidth(side, false);
164         }
165
166         setLength(bpb.getPaddingLengthProperty(side), newPadding);
167         lastOverPatching[side] += newPadding - oldPadding;
168     }
169
170     /**
171      * Modifies borders and paddings of <code>bpb</code>.
172      *
173      * @param bpb instance of CommonBorderPaddingBackground for modifying.
174      */

175     private void modifyBPB(CommonBorderPaddingBackground bpb) {
176         modifyBorder(CommonBorderPaddingBackground.BEFORE, bpb);
177         modifyBorder(CommonBorderPaddingBackground.AFTER, bpb);
178         modifyBorder(CommonBorderPaddingBackground.START, bpb);
179         modifyBorder(CommonBorderPaddingBackground.END, bpb);
180
181         modifyPadding(CommonBorderPaddingBackground.BEFORE, bpb);
182         modifyPadding(CommonBorderPaddingBackground.AFTER, bpb);
183         modifyPadding(CommonBorderPaddingBackground.START, bpb);
184         modifyPadding(CommonBorderPaddingBackground.END, bpb);
185     }
186
187     /**
188      * Rounds optimum value of <code>space</code> to nearest integer,
189      * divisible by <code>q</code>.
190      *
191      * @param space instance of SpaceProperty.
192      * @param q integer.
193      */

194     private void modifySpace(SpaceProperty space, int q) {
195         int value = space.getOptimum(null).getLength().getValue();
196         setMinOptMax(space, new FixedLength(Helper.round(value, q)));
197     }
198
199     /**
200      * @param length instance of Length.
201      * @param q integer.
202      * @return instance of Length, having value nearest to value of
203      * <code>length</code>, and divisible by <code>q</code>.
204      */

205     private Length roundLength(Length length, int q) {
206         int x = Helper.round(length.getValue(), q);
207         return new FixedLength(x);
208     }
209
210     /**
211      * @param length instance of Length.
212      * @param q integer.
213      * @return instance of Length, having minimal value, greater value of
214      * <code>length</code>, and divisible by <code>q</code>.
215      */

216     private Length ceilLength(Length length, int q) {
217         int x = Helper.ceil(length.getValue(), q);
218         return new FixedLength(x);
219     }
220
221     /**
222      * Modifies indent for given side. Summarizes value of indent and modifing
223      * error (i.e. overPatching). Rounds result to nearest integer, divisible by
224      * quantum.
225      *
226      * @param indent Length to modify.
227      * @param side an integer, representing side.
228      * @return modified Length.
229      */

230     private Length modifyIndent(Length indent, int side) {
231         if (indent instanceof NumericProperty) {
232             overPatching[side] += lastOverPatching[side];
233         }
234         int newValue = indent.getValue() + overPatching[side];
235         newValue = Helper.round(newValue, quantum[side]);
236         return new FixedLength(newValue);
237     }
238
239     /**
240      * Modifies Common Margin Properties-Block:
241      * <ul>
242      * <li>margin-top, margin-left, margin-bottom, margin-right
243      * <li>start-indent, end-indent
244      * <li>space-before, space-after.
245      * </ul>
246      *
247      * @param cmb instance of CommonMarginBlock to modify.
248      */

249     private void modifyCommonMarginBlock(CommonMarginBlock cmb) {
250         cmb.marginTop = roundLength(cmb.marginTop, TXTRenderer.CHAR_HEIGHT);
251         cmb.marginBottom = roundLength(cmb.marginBottom,
252                 TXTRenderer.CHAR_HEIGHT);
253         cmb.marginLeft = roundLength(cmb.marginLeft, TXTRenderer.CHAR_WIDTH);
254         cmb.marginRight = roundLength(cmb.marginRight, TXTRenderer.CHAR_WIDTH);
255
256         modifySpace(cmb.spaceBefore, TXTRenderer.CHAR_HEIGHT);
257         modifySpace(cmb.spaceAfter, TXTRenderer.CHAR_HEIGHT);
258
259         if (!(cmb.startIndent instanceof RelativeNumericProperty)) {
260             cmb.startIndent = modifyIndent(cmb.startIndent,
261                     CommonBorderPaddingBackground.START);
262         }
263         if (!(cmb.endIndent instanceof RelativeNumericProperty)) {
264             cmb.endIndent = modifyIndent(cmb.endIndent,
265                     CommonBorderPaddingBackground.END);
266         }
267     }
268
269     /**
270      * Modifies fo:table attributes:
271      * <ul>
272      * <li>Common Margin Properties Block
273      * <li>Common Border, Padding, and Background Properties
274      * <li>columns.
275      * </ul>
276      *
277      * @param table Table to modify.
278      */

279     private void modifyTable(Table table) {
280         CommonMarginBlock cmb = table.getCommonMarginBlock();
281         if (table.getBorderCollapse() == Constants.EN_COLLAPSE) {
282             // If border-collapse == "collapse", add space-after in order to
283
// impove interaction with other FO.
284
int value = cmb.spaceAfter.getOptimum(null).getLength().getValue();
285             value += TXTRenderer.CHAR_HEIGHT;
286             setMinOptMax(cmb.spaceAfter, new FixedLength(value));
287         }
288         modifyCommonMarginBlock(cmb);
289
290         modifyBPB(table.getCommonBorderPaddingBackground());
291
292         // modify all table-columns
293
List JavaDoc columnList = table.getColumns();
294         Iterator JavaDoc iter = columnList.iterator();
295         while (iter.hasNext()) {
296             modifyTableColumn((TableColumn) iter.next());
297         }
298     }
299
300     /**
301      * Modifies fo:table-column attributes:
302      * <ul>
303      * <li>width.
304      * </ul>
305      *
306      * @param column TableColumn to modify.
307      */

308     private void modifyTableColumn(TableColumn column) {
309         column.setColumnWidth(ceilLength(column.getColumnWidth(),
310                 TXTRenderer.CHAR_WIDTH));
311     }
312
313     /**
314      * Modifies padding of fo:table-cell.
315      *
316      * @param side side.
317      * @param bpb instance of CommonBorderPaddingBackground to modify.
318      */

319     private void modifyCellPadding(int side, CommonBorderPaddingBackground bpb) {
320         if (bpb.getBorderInfo(side) == null) {
321             int oldPadding = bpb.getPadding(side, false, null);
322             int newPadding = oldPadding + quantum[side] / 2;
323             setLength(bpb.getPaddingLengthProperty(side), newPadding);
324         }
325     }
326
327     /**
328      * Modifies table-cell properties:
329      * <ul>
330      * <li>Common Border, Padding, and Background Properties.
331      * </ul>
332      *
333      * @param c TableCell to modify.
334      */

335     private void modifyTableCell(TableCell c) {
336         CommonBorderPaddingBackground bpb = c
337                 .getCommonBorderPaddingBackground();
338         modifyBPB(bpb);
339         modifyCellPadding(CommonBorderPaddingBackground.BEFORE, bpb);
340         modifyCellPadding(CommonBorderPaddingBackground.AFTER, bpb);
341         modifyCellPadding(CommonBorderPaddingBackground.START, bpb);
342         modifyCellPadding(CommonBorderPaddingBackground.END, bpb);
343     }
344
345     /**
346      * Modifies Common Absolute Position Properties:
347      * <ul>
348      * <li>left
349      * <li>top.
350      * </ul>
351      *
352      * @param cap CommonAbsolutePosition to modify.
353      */

354     private void modifyCommonAbsolutePosition(CommonAbsolutePosition cap) {
355         if (cap.absolutePosition == Constants.EN_ABSOLUTE) {
356             cap.left = roundLength(cap.left, TXTRenderer.CHAR_WIDTH);
357             cap.top = roundLength(cap.top, TXTRenderer.CHAR_HEIGHT);
358         }
359     }
360
361     /**
362      * Modifies line-height property. Sets a value of line-height to max(char
363      * height; lowest integer, divisible by char height).
364      *
365      * @param lineHeight SpaceProperty to modify.
366      */

367     private void modifyLineHeight(SpaceProperty lineHeight) {
368         Property p = lineHeight.getOptimum(null);
369         int value = p.getLength().getValue(CONTEXT);
370
371         int height = TXTRenderer.CHAR_HEIGHT;
372         int newValue = Math.max(Helper.floor(value, height), height);
373         setMinOptMax(lineHeight, new FixedLength(newValue));
374     }
375
376     /**
377      * Modifies Common Font Properties:
378      * <ul>
379      * <li>font-family = Courier;
380      * <li>font-size = MODIFIED_FONT_SIZE;
381      * <li>font-stretch = EN_NORMAL;
382      * <li>font-weight = EN_NORMAL.
383      * </ul>
384      *
385      * @param cf the font to modify.
386      */

387     private void modifyCommonFont(CommonFont cf) {
388         if (cf != null) {
389             cf.overrideFontFamily("Courier");
390             cf.fontSize = new FixedLength(MODIFIED_FONT_SIZE);
391             cf.fontStretch = Constants.EN_NORMAL;
392             cf.fontWeight = Constants.EN_NORMAL;
393         }
394     }
395
396     /**
397      * Modifies fo:block:
398      * <ul>
399      * <li>Common Border, Padding, and Background Properties
400      * <li>Common Margin Properties-Block
401      * <li>Common Font Properties
402      * <li>line-height.
403      * </ul>
404      *
405      * @param block Block to modify.
406      */

407     private void modifyBlock(Block block) {
408         modifyBPB(block.getCommonBorderPaddingBackground());
409         modifyCommonMarginBlock(block.getCommonMarginBlock());
410         modifyCommonFont(block.getCommonFont());
411         modifyLineHeight(block.getLineHeight());
412     }
413
414     /**
415      * Modifies fo:block-container:
416      * <ul>
417      * <li>Common Border, Padding, and Background Properties
418      * <li>Common Margin Properties-Block
419      * <li>Common Absolute Position Properties.
420      * </ul>
421      *
422      * @param bc BlockContainer to modify.
423      */

424     private void modifyBlockContainer(BlockContainer bc) {
425         modifyBPB(bc.getCommonBorderPaddingBackground());
426         modifyCommonMarginBlock(bc.getCommonMarginBlock());
427         modifyCommonAbsolutePosition(bc.getCommonAbsolutePosition());
428     }
429
430     /**
431      * Modifies fo:inline:
432      * <ul>
433      * <li>Common Font Properties
434      * </ul>
435      *
436      * @param inline Inline to modify.
437      */

438     private void modifyInline(Inline inline) {
439         modifyCommonFont(inline.getCommonFont());
440     }
441
442     /**
443      * Modifies FOText:
444      * <ul>
445      * <li>Common Font Properties
446      * </ul>
447      *
448      * @param text FOText to modify.
449      */

450     private void modifyFOText(FOText text) {
451         modifyCommonFont(text.getCommonFont());
452     }
453
454     /**
455      * Modifies fo:external-graphic:
456      * <ul>
457      * <li>Common Border, Padding, and Background Properties
458      * <li>line-height.
459      * </ul>
460      *
461      * @param eg ExternalGraphic to modify.
462      */

463     private void modifyExternalGraphic(ExternalGraphic eg) {
464         modifyBPB(eg.getCommonBorderPaddingBackground());
465         modifyLineHeight(eg.getLineHeight());
466     }
467
468     /**
469      * Modifies fo:list-block:
470      * <ul>
471      * <li>Common Border, Padding, and Background Properties
472      * <li>Common Margin Properties-Block.
473      * </ul>
474      *
475      * @param lb ListBlock to modify.
476      */

477     private void modifyListBlock(ListBlock lb) {
478         modifyBPB(lb.getCommonBorderPaddingBackground());
479         modifyCommonMarginBlock(lb.getCommonMarginBlock());
480     }
481
482     /**
483      * Modifies fo:list-item:
484      * <ul>
485      * <li>Common Border, Padding, and Background Properties
486      * <li>Common Margin Properties-Block.
487      * </ul>
488      * <p>
489      * Make refinement for fo:list-item-label and fo:list-item-body.
490      *
491      * @param li ListItem to modify.
492      */

493     private void modifyListItem(ListItem li) {
494         modifyBPB(li.getCommonBorderPaddingBackground());
495         modifyCommonMarginBlock(li.getCommonMarginBlock());
496         refinement(li.getLabel());
497         refinement(li.getBody());
498     }
499     
500     /**
501      * Does refinement for particular node. Modifies node's properties and
502      * refines its children recursively.
503      *
504      * @param node the node to refine.
505      */

506     private void refinement(FONode node) {
507         int[] saveOverPatching = (int[]) overPatching.clone();
508         Arrays.fill(lastOverPatching, 0);
509
510         if (node instanceof Block) {
511             modifyBlock((Block) node);
512         } else if (node instanceof BlockContainer) {
513             modifyBlockContainer((BlockContainer) node);
514         } else if (node instanceof Inline) {
515             modifyInline((Inline) node);
516         } else if (node instanceof FOText) {
517             modifyFOText((FOText) node);
518         } else if (node instanceof Table) {
519             modifyTable((Table) node);
520             Arrays.fill(overPatching, 0);
521         } else if (node instanceof TableCell) {
522             modifyTableCell((TableCell) node);
523         } else if (node instanceof ExternalGraphic) {
524             modifyExternalGraphic((ExternalGraphic) node);
525         } else if (node instanceof ListBlock) {
526             modifyListBlock((ListBlock) node);
527         } else if (node instanceof ListItem) {
528             modifyListItem((ListItem) node);
529         } else if (node instanceof PageNumber) {
530             modifyCommonFont(((PageNumber) node).getCommonFont());
531         }
532
533         Iterator JavaDoc it = node.getChildNodes();
534         if (it != null) {
535             while (it.hasNext()) {
536                 refinement((FONode) it.next());
537             }
538         }
539         overPatching = saveOverPatching;
540     }
541
542     /**
543      * Run refinement for:
544      * <ul>
545      * <li>mainflow (xsl-region-body)
546      * <li>staticflow (xsl-region-before, xsl-region-after, xsl-region-start,
547      * xsl-region-end).
548      * </ul>
549      *
550      * @param pageSequence PageSequence to refine.
551      */

552     public void endPageSequence(PageSequence pageSequence) {
553         Arrays.fill(overPatching, 0);
554
555         refinement(pageSequence.getMainFlow());
556
557         if (pageSequence.getStaticContent("xsl-region-before") != null) {
558             refinement(pageSequence.getStaticContent("xsl-region-before"));
559         }
560         if (pageSequence.getStaticContent("xsl-region-after") != null) {
561             refinement(pageSequence.getStaticContent("xsl-region-after"));
562         }
563         if (pageSequence.getStaticContent("xsl-region-start") != null) {
564             refinement(pageSequence.getStaticContent("xsl-region-start"));
565         }
566         if (pageSequence.getStaticContent("xsl-region-end") != null) {
567             refinement(pageSequence.getStaticContent("xsl-region-end"));
568         }
569
570         super.endPageSequence(pageSequence);
571     }
572 }
573
Popular Tags