KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > area > AreaTreeParser


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$ */
19
20 package org.apache.fop.area;
21
22 import java.awt.Color JavaDoc;
23 import java.awt.geom.Rectangle2D JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Stack JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28
29 import javax.xml.transform.Source JavaDoc;
30 import javax.xml.transform.Transformer JavaDoc;
31 import javax.xml.transform.TransformerConfigurationException JavaDoc;
32 import javax.xml.transform.TransformerException JavaDoc;
33 import javax.xml.transform.dom.DOMResult JavaDoc;
34 import javax.xml.transform.sax.SAXResult JavaDoc;
35 import javax.xml.transform.sax.SAXTransformerFactory JavaDoc;
36 import javax.xml.transform.sax.TransformerHandler JavaDoc;
37
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.apache.fop.apps.FOUserAgent;
41 import org.apache.fop.area.Trait.Background;
42 import org.apache.fop.area.inline.AbstractTextArea;
43 import org.apache.fop.area.inline.Character;
44 import org.apache.fop.area.inline.ForeignObject;
45 import org.apache.fop.area.inline.Image;
46 import org.apache.fop.area.inline.InlineBlockParent;
47 import org.apache.fop.area.inline.InlineParent;
48 import org.apache.fop.area.inline.Leader;
49 import org.apache.fop.area.inline.Space;
50 import org.apache.fop.area.inline.SpaceArea;
51 import org.apache.fop.area.inline.TextArea;
52 import org.apache.fop.area.inline.Viewport;
53 import org.apache.fop.area.inline.WordArea;
54 import org.apache.fop.fo.Constants;
55 import org.apache.fop.fo.ElementMappingRegistry;
56 import org.apache.fop.fo.expr.PropertyException;
57 import org.apache.fop.fo.extensions.ExtensionAttachment;
58 import org.apache.fop.fonts.Font;
59 import org.apache.fop.fonts.FontInfo;
60 import org.apache.fop.image.FopImage;
61 import org.apache.fop.image.ImageFactory;
62 import org.apache.fop.traits.BorderProps;
63 import org.apache.fop.util.ColorUtil;
64 import org.apache.fop.util.ContentHandlerFactory;
65 import org.apache.fop.util.ContentHandlerFactoryRegistry;
66 import org.apache.fop.util.DefaultErrorListener;
67 import org.apache.fop.util.QName;
68 import org.w3c.dom.DOMImplementation JavaDoc;
69 import org.w3c.dom.Document JavaDoc;
70 import org.xml.sax.Attributes JavaDoc;
71 import org.xml.sax.ContentHandler JavaDoc;
72 import org.xml.sax.SAXException JavaDoc;
73 import org.xml.sax.helpers.DefaultHandler JavaDoc;
74
75 /**
76  * This is a parser for the area tree XML (intermediate format) which is used to reread an area
77  * tree (or part of it) into memory again for rendering to the final output format.
78  */

79 public class AreaTreeParser {
80
81     /** Logger instance */
82     protected static Log log = LogFactory.getLog(AreaTreeParser.class);
83
84     private static SAXTransformerFactory JavaDoc tFactory
85         = (SAXTransformerFactory JavaDoc)SAXTransformerFactory.newInstance();
86
87     /**
88      * Parses an intermediate file (area tree XML) into an AreaTreeModel instance by adding
89      * pages to it.
90      * @param src the Source instance pointing to the intermediate file
91      * @param treeModel the AreaTreeModel that the parsed pages are added to
92      * @param userAgent the user agent
93      * @throws TransformerException if an error occurs while parsing the area tree XML
94      */

95     public void parse(Source JavaDoc src, AreaTreeModel treeModel, FOUserAgent userAgent)
96             throws TransformerException JavaDoc {
97         Transformer JavaDoc transformer = tFactory.newTransformer();
98         transformer.setErrorListener(new DefaultErrorListener(log));
99         
100         SAXResult JavaDoc res = new SAXResult JavaDoc(getContentHandler(treeModel, userAgent));
101         
102         transformer.transform(src, res);
103     }
104     
105     /**
106      * Creates a new ContentHandler instance that you can send the area tree XML to. The parsed
107      * pages are added to the AreaTreeModel instance you pass in as a parameter.
108      * @param treeModel the AreaTreeModel that the parsed pages are added to
109      * @param userAgent the user agent
110      * @return the ContentHandler instance to receive the SAX stream from the area tree XML
111      */

112     public ContentHandler JavaDoc getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) {
113         ElementMappingRegistry elementMappingRegistry
114             = userAgent.getFactory().getElementMappingRegistry();
115         return new Handler JavaDoc(treeModel, userAgent, elementMappingRegistry);
116     }
117     
118     private static class Handler extends DefaultHandler JavaDoc {
119      
120         private Map JavaDoc makers = new java.util.HashMap JavaDoc();
121         
122         private AreaTreeModel treeModel;
123         private FOUserAgent userAgent;
124         private ElementMappingRegistry elementMappingRegistry;
125         
126         private Attributes JavaDoc lastAttributes;
127         private StringBuffer JavaDoc content = new StringBuffer JavaDoc();
128
129         private PageViewport currentPageViewport;
130         private Stack JavaDoc areaStack = new Stack JavaDoc();
131         private boolean firstFlow;
132         private boolean pendingStartPageSequence;
133         
134         private Stack JavaDoc delegateStack = new Stack JavaDoc();
135         private ContentHandler JavaDoc delegate;
136         private DOMImplementation JavaDoc domImplementation;
137         
138         
139         public Handler(AreaTreeModel treeModel, FOUserAgent userAgent,
140                 ElementMappingRegistry elementMappingRegistry) {
141             this.treeModel = treeModel;
142             this.userAgent = userAgent;
143             this.elementMappingRegistry = elementMappingRegistry;
144             makers.put("areaTree", new AreaTreeMaker());
145             makers.put("page", new PageMaker());
146             makers.put("pageSequence", new PageSequenceMaker());
147             makers.put("title", new TitleMaker());
148             makers.put("pageViewport", new PageViewportMaker());
149             makers.put("regionViewport", new RegionViewportMaker());
150             makers.put("regionBefore", new RegionBeforeMaker());
151             makers.put("regionAfter", new RegionAfterMaker());
152             makers.put("regionStart", new RegionStartMaker());
153             makers.put("regionEnd", new RegionEndMaker());
154             makers.put("regionBody", new RegionBodyMaker());
155             makers.put("flow", new FlowMaker());
156             makers.put("mainReference", new MainReferenceMaker());
157             makers.put("span", new SpanMaker());
158             makers.put("footnote", new FootnoteMaker());
159             makers.put("beforeFloat", new BeforeFloatMaker());
160             makers.put("block", new BlockMaker());
161             makers.put("lineArea", new LineAreaMaker());
162             makers.put("inlineparent", new InlineParentMaker());
163             makers.put("inlineblockparent", new InlineBlockParentMaker());
164             makers.put("text", new TextMaker());
165             makers.put("word", new WordMaker());
166             makers.put("space", new SpaceMaker());
167             makers.put("char", new CharMaker());
168             makers.put("leader", new LeaderMaker());
169             makers.put("viewport", new ViewportMaker());
170             makers.put("image", new ImageMaker());
171             makers.put("foreignObject", new ForeignObjectMaker());
172         }
173
174         private static Rectangle2D JavaDoc parseRect(String JavaDoc rect) {
175             StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(rect, " ");
176             return new Rectangle2D.Double JavaDoc(
177                     Double.parseDouble(tokenizer.nextToken()),
178                     Double.parseDouble(tokenizer.nextToken()),
179                     Double.parseDouble(tokenizer.nextToken()),
180                     Double.parseDouble(tokenizer.nextToken()));
181         }
182         
183         private Area findAreaType(Class JavaDoc clazz) {
184             if (areaStack.size() > 0) {
185                 int pos = areaStack.size() - 1;
186                 Object JavaDoc obj = null;
187                 while (pos >= 0 && !(clazz.isInstance(obj = areaStack.get(pos)))) {
188                     pos--;
189                 }
190                 if (pos >= 0) {
191                     return (Area)obj;
192                 }
193             }
194             return null;
195         }
196         
197         private RegionViewport getCurrentRegionViewport() {
198             return (RegionViewport)findAreaType(RegionViewport.class);
199         }
200
201         private BodyRegion getCurrentBodyRegion() {
202             return (BodyRegion)findAreaType(BodyRegion.class);
203         }
204         
205         private BlockParent getCurrentBlockParent() {
206             return (BlockParent)findAreaType(BlockParent.class);
207         }
208         
209         private AbstractTextArea getCurrentText() {
210             return (AbstractTextArea)findAreaType(AbstractTextArea.class);
211         }
212         
213         private Viewport getCurrentViewport() {
214             return (Viewport)findAreaType(Viewport.class);
215         }
216         
217         /** @see org.xml.sax.helpers.DefaultHandler */
218         public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc attributes)
219                     throws SAXException JavaDoc {
220             if (delegate != null) {
221                 delegateStack.push(qName);
222                 delegate.startElement(uri, localName, qName, attributes);
223             } else if (domImplementation != null) {
224                 //domImplementation is set so we need to start a new DOM building sub-process
225
TransformerHandler JavaDoc handler;
226                 try {
227                     handler = tFactory.newTransformerHandler();
228                 } catch (TransformerConfigurationException JavaDoc e) {
229                     throw new SAXException JavaDoc("Error creating a new TransformerHandler", e);
230                 }
231                 Document JavaDoc doc = domImplementation.createDocument(uri, qName, null);
232                 //It's easier to work with an empty document, so remove the root element
233
doc.removeChild(doc.getDocumentElement());
234                 handler.setResult(new DOMResult JavaDoc(doc));
235                 Area parent = (Area)areaStack.peek();
236                 ((ForeignObject)parent).setDocument(doc);
237                 
238                 //activate delegate for nested foreign document
239
domImplementation = null; //Not needed anymore now
240
this.delegate = handler;
241                 delegateStack.push(qName);
242                 delegate.startDocument();
243                 delegate.startElement(uri, localName, qName, attributes);
244             } else {
245                 lastAttributes = attributes;
246                 boolean handled = true;
247                 if ("".equals(uri)) {
248                     Maker maker = (Maker)makers.get(localName);
249                     if (maker != null) {
250                         maker.startElement(attributes);
251                     } else if ("extension-attachments".equals(localName)) {
252                         //TODO implement me
253
} else {
254                         handled = false;
255                     }
256                 } else {
257                     ContentHandlerFactoryRegistry registry
258                             = userAgent.getFactory().getContentHandlerFactoryRegistry();
259                     ContentHandlerFactory factory = registry.getFactory(uri);
260                     if (factory != null) {
261                         delegate = factory.createContentHandler();
262                         delegateStack.push(qName);
263                         delegate.startDocument();
264                         delegate.startElement(uri, localName, qName, attributes);
265                     } else {
266                         handled = false;
267                     }
268                 }
269                 if (!handled) {
270                     if (uri == null || uri.length() == 0) {
271                         throw new SAXException JavaDoc("Unhandled element " + localName
272                                 + " in namespace: " + uri);
273                     } else {
274                         log.warn("Unhandled element " + localName
275                                 + " in namespace: " + uri);
276                     }
277                 }
278             }
279         }
280         
281         /** @see org.xml.sax.helpers.DefaultHandler */
282         public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName) throws SAXException JavaDoc {
283             if (delegate != null) {
284                 delegate.endElement(uri, localName, qName);
285                 delegateStack.pop();
286                 if (delegateStack.size() == 0) {
287                     delegate.endDocument();
288                     if (delegate instanceof ContentHandlerFactory.ObjectSource) {
289                         Object JavaDoc obj = ((ContentHandlerFactory.ObjectSource)delegate).getObject();
290                         handleExternallyGeneratedObject(obj);
291                     }
292                     delegate = null; //Sub-document is processed, return to normal processing
293
}
294             } else {
295                 if ("".equals(uri)) {
296                     Maker maker = (Maker)makers.get(localName);
297                     if (maker != null) {
298                         maker.endElement();
299                     }
300                 } else {
301                     //log.debug("Ignoring " + localName + " in namespace: " + uri);
302
}
303                 content.setLength(0); //Reset text buffer (see characters())
304
}
305         }
306         
307         // ============== Maker classes for the area tree objects =============
308

309         private static interface Maker {
310             void startElement(Attributes JavaDoc attributes) throws SAXException JavaDoc;
311             void endElement();
312         }
313         
314         private abstract class AbstractMaker implements Maker {
315
316             public void startElement(Attributes JavaDoc attributes) throws SAXException JavaDoc {
317                 //nop
318
}
319
320             public void endElement() {
321                 //nop
322
}
323         }
324         
325         private class AreaTreeMaker extends AbstractMaker {
326             //no overrides
327
}
328         
329         private class PageSequenceMaker extends AbstractMaker {
330
331             public void startElement(Attributes JavaDoc attributes) {
332                 pendingStartPageSequence = true;
333                 //treeModel.startPageSequence(null); Done after title or on the first viewport
334
}
335         }
336         
337         private class TitleMaker extends AbstractMaker {
338
339             public void startElement(Attributes JavaDoc attributes) {
340                 LineArea line = new LineArea();
341                 transferForeignObjects(attributes, line);
342                 areaStack.push(line);
343             }
344
345             public void endElement() {
346                 LineArea line = (LineArea)areaStack.pop();
347                 treeModel.startPageSequence(line);
348                 pendingStartPageSequence = false;
349             }
350             
351             
352         }
353         
354         private class PageViewportMaker extends AbstractMaker {
355
356             public void startElement(Attributes JavaDoc attributes) {
357                 if (pendingStartPageSequence) {
358                     treeModel.startPageSequence(null);
359                     pendingStartPageSequence = false;
360                 }
361                 if (currentPageViewport != null) {
362                     throw new IllegalStateException JavaDoc("currentPageViewport must be null");
363                 }
364                 Rectangle2D JavaDoc viewArea = parseRect(attributes.getValue("bounds"));
365                 int pageNumber = getAttributeAsInteger(attributes, "nr", -1);
366                 String JavaDoc key = attributes.getValue("key");
367                 String JavaDoc pageNumberString = attributes.getValue("formatted-nr");
368                 String JavaDoc pageMaster = attributes.getValue("simple-page-master-name");
369                 boolean blank = getAttributeAsBoolean(attributes, "blank", false);
370                 currentPageViewport = new PageViewport(viewArea,
371                         pageNumber, pageNumberString,
372                         pageMaster, blank);
373                 transferForeignObjects(attributes, currentPageViewport);
374                 currentPageViewport.setKey(key);
375             }
376
377         }
378         
379         private class PageMaker extends AbstractMaker {
380
381             public void startElement(Attributes JavaDoc attributes) {
382                 Page p = new Page();
383                 currentPageViewport.setPage(p);
384             }
385
386             public void endElement() {
387                 treeModel.addPage(currentPageViewport);
388                 currentPageViewport = null;
389             }
390         }
391         
392         private class RegionViewportMaker extends AbstractMaker {
393
394             public void startElement(Attributes JavaDoc attributes) {
395                 RegionViewport rv = getCurrentRegionViewport();
396                 if (rv != null) {
397                     throw new IllegalStateException JavaDoc("Current RegionViewport must be null");
398                 }
399                 Rectangle2D JavaDoc viewArea = parseRect(attributes.getValue("rect"));
400                 rv = new RegionViewport(viewArea);
401                 transferForeignObjects(attributes, rv);
402                 rv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
403                 setAreaAttributes(attributes, rv);
404                 setTraits(attributes, rv, SUBSET_COMMON);
405                 setTraits(attributes, rv, SUBSET_BOX);
406                 setTraits(attributes, rv, SUBSET_COLOR);
407                 areaStack.push(rv);
408             }
409             
410             public void endElement() {
411                 assertObjectOfClass(areaStack.pop(), RegionViewport.class);
412             }
413         }
414         
415         private class RegionBeforeMaker extends AbstractMaker {
416
417             public void startElement(Attributes JavaDoc attributes) {
418                 pushNewRegionReference(attributes, Constants.FO_REGION_BEFORE);
419             }
420             
421             public void endElement() {
422                 assertObjectOfClass(areaStack.pop(), RegionReference.class);
423             }
424         }
425
426         private class RegionAfterMaker extends AbstractMaker {
427
428             public void startElement(Attributes JavaDoc attributes) {
429                 pushNewRegionReference(attributes, Constants.FO_REGION_AFTER);
430             }
431             
432             public void endElement() {
433                 assertObjectOfClass(areaStack.pop(), RegionReference.class);
434             }
435         }
436
437         private class RegionStartMaker extends AbstractMaker {
438
439             public void startElement(Attributes JavaDoc attributes) {
440                 pushNewRegionReference(attributes, Constants.FO_REGION_START);
441             }
442             
443             public void endElement() {
444                 assertObjectOfClass(areaStack.pop(), RegionReference.class);
445             }
446         }
447         
448         private class RegionEndMaker extends AbstractMaker {
449
450             public void startElement(Attributes JavaDoc attributes) {
451                 pushNewRegionReference(attributes, Constants.FO_REGION_END);
452             }
453             
454             public void endElement() {
455                 assertObjectOfClass(areaStack.pop(), RegionReference.class);
456             }
457         }
458
459         private class RegionBodyMaker extends AbstractMaker {
460
461             public void startElement(Attributes JavaDoc attributes) {
462                 BodyRegion body = getCurrentBodyRegion();
463                 if (body != null) {
464                     throw new IllegalStateException JavaDoc("Current BodyRegion must be null");
465                 }
466                 String JavaDoc regionName = attributes.getValue("name");
467                 int columnCount = getAttributeAsInteger(attributes, "columnCount", 1);
468                 int columnGap = getAttributeAsInteger(attributes, "columnGap", 0);
469                 RegionViewport rv = getCurrentRegionViewport();
470                 body = new BodyRegion(Constants.FO_REGION_BODY,
471                         regionName, rv, columnCount, columnGap);
472                 transferForeignObjects(attributes, body);
473                 body.setCTM(getAttributeAsCTM(attributes, "ctm"));
474                 setAreaAttributes(attributes, body);
475                 rv.setRegionReference(body);
476                 currentPageViewport.getPage().setRegionViewport(
477                         Constants.FO_REGION_BODY, rv);
478                 areaStack.push(body);
479             }
480             
481             public void endElement() {
482                 assertObjectOfClass(areaStack.pop(), BodyRegion.class);
483             }
484         }
485
486         private class FlowMaker extends AbstractMaker {
487
488             public void startElement(Attributes JavaDoc attributes) {
489                 BodyRegion body = getCurrentBodyRegion();
490                 if (!firstFlow) {
491                     body.getMainReference().getCurrentSpan().moveToNextFlow();
492                 } else {
493                     firstFlow = false;
494                 }
495                 NormalFlow flow = body.getMainReference().getCurrentSpan().getCurrentFlow();
496                 transferForeignObjects(attributes, flow);
497                 setAreaAttributes(attributes, flow);
498                 areaStack.push(flow);
499             }
500             
501             public void endElement() {
502                 assertObjectOfClass(areaStack.pop(), NormalFlow.class);
503             }
504         }
505         
506         private class MainReferenceMaker extends AbstractMaker {
507
508             public void startElement(Attributes JavaDoc attributes) {
509                 //mainReference is created by the BodyRegion
510
MainReference mr = getCurrentBodyRegion().getMainReference();
511                 transferForeignObjects(attributes, mr);
512                 setAreaAttributes(attributes, mr);
513             }
514         }
515
516         private class SpanMaker extends AbstractMaker {
517
518             public void startElement(Attributes JavaDoc attributes) {
519                 int ipd = getAttributeAsInteger(attributes, "ipd", 0);
520                 int columnCount = getAttributeAsInteger(attributes, "columnCount", 1);
521                 BodyRegion body = getCurrentBodyRegion();
522                 Span span = new Span(columnCount,
523                         body.getColumnGap(), ipd);
524                 transferForeignObjects(attributes, span);
525                 setAreaAttributes(attributes, span);
526                 body.getMainReference().getSpans().add(span);
527                 firstFlow = true;
528             }
529         }
530
531         private class FootnoteMaker extends AbstractMaker {
532
533             public void startElement(Attributes JavaDoc attributes) {
534                 Footnote fn = getCurrentBodyRegion().getFootnote();
535                 transferForeignObjects(attributes, fn);
536                 areaStack.push(fn);
537             }
538             
539             public void endElement() {
540                 assertObjectOfClass(areaStack.pop(), Footnote.class);
541             }
542         }
543
544         private class BeforeFloatMaker extends AbstractMaker {
545
546             public void startElement(Attributes JavaDoc attributes) {
547                 BeforeFloat bf = getCurrentBodyRegion().getBeforeFloat();
548                 transferForeignObjects(attributes, bf);
549                 areaStack.push(bf);
550             }
551             
552             public void endElement() {
553                 assertObjectOfClass(areaStack.pop(), BeforeFloat.class);
554             }
555         }
556
557         private class BlockMaker extends AbstractMaker {
558
559             public void startElement(Attributes JavaDoc attributes) {
560                 boolean isViewport = getAttributeAsBoolean(attributes,
561                         "is-viewport-area", false);
562                 Block block;
563                 if (isViewport) {
564                     BlockViewport bv = new BlockViewport();
565                     bv.setClip(getAttributeAsBoolean(attributes, "clipped", false));
566                     bv.setCTM(getAttributeAsCTM(attributes, "ctm"));
567                     if (bv.getPositioning() != BlockViewport.RELATIVE) {
568                         bv.setXOffset(
569                                 getAttributeAsInteger(attributes, "left-position", 0));
570                         bv.setYOffset(
571                                 getAttributeAsInteger(attributes, "top-position", 0));
572                     }
573                     block = bv;
574                 } else {
575                     block = new Block();
576                 }
577                 String JavaDoc positioning = attributes.getValue("positioning");
578                 if ("absolute".equalsIgnoreCase(positioning)) {
579                     block.setPositioning(Block.ABSOLUTE);
580                 } else if ("fixed".equalsIgnoreCase(positioning)) {
581                     block.setPositioning(Block.FIXED);
582                 } else if ("relative".equalsIgnoreCase(positioning)) {
583                     block.setPositioning(Block.RELATIVE);
584                 } else {
585                     block.setPositioning(Block.STACK);
586                 }
587                 if (attributes.getValue("left-offset") != null) {
588                     block.setXOffset(getAttributeAsInteger(attributes, "left-offset", 0));
589                 }
590                 if (attributes.getValue("top-offset") != null) {
591                     block.setYOffset(getAttributeAsInteger(attributes, "top-offset", 0));
592                 }
593                 transferForeignObjects(attributes, block);
594                 setAreaAttributes(attributes, block);
595                 setTraits(attributes, block, SUBSET_COMMON);
596                 setTraits(attributes, block, SUBSET_BOX);
597                 setTraits(attributes, block, SUBSET_COLOR);
598                 Area parent = (Area)areaStack.peek();
599                 //BlockParent parent = getCurrentBlockParent();
600
parent.addChildArea(block);
601                 areaStack.push(block);
602             }
603             
604             public void endElement() {
605                 assertObjectOfClass(areaStack.pop(), Block.class);
606             }
607         }
608
609         private class LineAreaMaker extends AbstractMaker {
610
611             public void startElement(Attributes JavaDoc attributes) {
612                 LineArea line = new LineArea();
613                 setAreaAttributes(attributes, line);
614                 setTraits(attributes, line, SUBSET_COMMON);
615                 setTraits(attributes, line, SUBSET_BOX);
616                 setTraits(attributes, line, SUBSET_COLOR);
617                 BlockParent parent = getCurrentBlockParent();
618                 parent.addChildArea(line);
619                 areaStack.push(line);
620             }
621             
622             public void endElement() {
623                 assertObjectOfClass(areaStack.pop(), LineArea.class);
624             }
625         }
626
627         private class InlineParentMaker extends AbstractMaker {
628
629             public void startElement(Attributes JavaDoc attributes) {
630                 InlineParent ip = new InlineParent();
631                 transferForeignObjects(attributes, ip);
632                 ip.setOffset(getAttributeAsInteger(attributes, "offset", 0));
633                 setAreaAttributes(attributes, ip);
634                 setTraits(attributes, ip, SUBSET_COMMON);
635                 setTraits(attributes, ip, SUBSET_BOX);
636                 setTraits(attributes, ip, SUBSET_COLOR);
637                 setTraits(attributes, ip, SUBSET_LINK);
638                 Area parent = (Area)areaStack.peek();
639                 parent.addChildArea(ip);
640                 areaStack.push(ip);
641             }
642             
643             public void endElement() {
644                 assertObjectOfClass(areaStack.pop(), InlineParent.class);
645             }
646         }
647
648         private class InlineBlockParentMaker extends AbstractMaker {
649
650             public void startElement(Attributes JavaDoc attributes) {
651                 InlineBlockParent ibp = new InlineBlockParent();
652                 transferForeignObjects(attributes, ibp);
653                 ibp.setOffset(getAttributeAsInteger(attributes, "offset", 0));
654                 setAreaAttributes(attributes, ibp);
655                 setTraits(attributes, ibp, SUBSET_COMMON);
656                 setTraits(attributes, ibp, SUBSET_BOX);
657                 setTraits(attributes, ibp, SUBSET_COLOR);
658                 Area parent = (Area)areaStack.peek();
659                 parent.addChildArea(ibp);
660                 areaStack.push(ibp);
661             }
662             
663             public void endElement() {
664                 assertObjectOfClass(areaStack.pop(), InlineBlockParent.class);
665             }
666         }
667
668         private class TextMaker extends AbstractMaker {
669
670             public void startElement(Attributes JavaDoc attributes) {
671                 if (getCurrentText() != null) {
672                     throw new IllegalStateException JavaDoc("Current Text must be null");
673                 }
674                 TextArea text = new TextArea();
675                 setAreaAttributes(attributes, text);
676                 setTraits(attributes, text, SUBSET_COMMON);
677                 setTraits(attributes, text, SUBSET_BOX);
678                 setTraits(attributes, text, SUBSET_COLOR);
679                 setTraits(attributes, text, SUBSET_FONT);
680                 text.setBaselineOffset(getAttributeAsInteger(attributes, "baseline", 0));
681                 text.setOffset(getAttributeAsInteger(attributes, "offset", 0));
682                 text.setTextLetterSpaceAdjust(getAttributeAsInteger(attributes,
683                         "tlsadjust", 0));
684                 text.setTextWordSpaceAdjust(getAttributeAsInteger(attributes,
685                         "twsadjust", 0));
686                 Area parent = (Area)areaStack.peek();
687                 parent.addChildArea(text);
688                 areaStack.push(text);
689             }
690             
691             public void endElement() {
692                 assertObjectOfClass(areaStack.pop(), TextArea.class);
693             }
694         }
695
696         private class WordMaker extends AbstractMaker {
697
698             private int[] toIntArray(String JavaDoc s) {
699                 if (s == null || s.length() == 0) {
700                     return null;
701                 }
702                 StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(s, " ");
703                 List JavaDoc values = new java.util.ArrayList JavaDoc();
704                 while (tokenizer.hasMoreTokens()) {
705                     values.add(new Integer JavaDoc(tokenizer.nextToken()));
706                 }
707                 int[] res = new int[values.size()];
708                 for (int i = 0, c = res.length; i < c; i++) {
709                     res[i] = ((Integer JavaDoc)values.get(i)).intValue();
710                 }
711                 return res;
712             }
713             
714             public void endElement() {
715                 int offset = getAttributeAsInteger(lastAttributes, "offset", 0);
716                 int[] letterAdjust = toIntArray(lastAttributes.getValue("letter-adjust"));
717                 String JavaDoc txt = content.toString();
718                 WordArea word = new WordArea(txt, offset, letterAdjust);
719                 AbstractTextArea text = getCurrentText();
720                 word.setParentArea(text);
721                 text.addChildArea(word);
722             }
723         }
724
725         private class SpaceMaker extends AbstractMaker {
726
727             public void endElement() {
728                 int offset = getAttributeAsInteger(lastAttributes, "offset", 0);
729                 String JavaDoc txt = content.toString();
730                 //TODO the isAdjustable parameter is currently not used/implemented
731
if (txt.length() > 0) {
732                     boolean adjustable = getAttributeAsBoolean(lastAttributes, "adj", true);
733                     SpaceArea space = new SpaceArea(txt.charAt(0), offset, adjustable);
734                     AbstractTextArea text = getCurrentText();
735                     space.setParentArea(text);
736                     text.addChildArea(space);
737                 } else {
738                     Space space = new Space();
739                     setAreaAttributes(lastAttributes, space);
740                     setTraits(lastAttributes, space, SUBSET_COMMON);
741                     setTraits(lastAttributes, space, SUBSET_BOX);
742                     setTraits(lastAttributes, space, SUBSET_COLOR);
743                     space.setOffset(offset);
744                     Area parent = (Area)areaStack.peek();
745                     parent.addChildArea(space);
746                 }
747             }
748         }
749
750         private class CharMaker extends AbstractMaker {
751
752             public void endElement() {
753                 String JavaDoc txt = content.toString();
754                 Character JavaDoc ch = new Character JavaDoc(txt.charAt(0));
755                 transferForeignObjects(lastAttributes, ch);
756                 setAreaAttributes(lastAttributes, ch);
757                 setTraits(lastAttributes, ch, SUBSET_COMMON);
758                 setTraits(lastAttributes, ch, SUBSET_BOX);
759                 setTraits(lastAttributes, ch, SUBSET_COLOR);
760                 setTraits(lastAttributes, ch, SUBSET_FONT);
761                 ch.setOffset(getAttributeAsInteger(lastAttributes, "offset", 0));
762                 ch.setBaselineOffset(getAttributeAsInteger(lastAttributes, "baseline", 0));
763                 Area parent = (Area)areaStack.peek();
764                 parent.addChildArea(ch);
765             }
766         }
767
768         private class LeaderMaker extends AbstractMaker {
769
770             public void startElement(Attributes JavaDoc attributes) {
771                 Leader leader = new Leader();
772                 transferForeignObjects(attributes, leader);
773                 setAreaAttributes(attributes, leader);
774                 setTraits(attributes, leader, SUBSET_COMMON);
775                 setTraits(attributes, leader, SUBSET_BOX);
776                 setTraits(attributes, leader, SUBSET_COLOR);
777                 setTraits(attributes, leader, SUBSET_FONT);
778                 leader.setOffset(getAttributeAsInteger(attributes, "offset", 0));
779                 String JavaDoc ruleStyle = attributes.getValue("ruleStyle");
780                 if (ruleStyle != null) {
781                     leader.setRuleStyle(ruleStyle);
782                 }
783                 leader.setRuleThickness(
784                         getAttributeAsInteger(attributes, "ruleThickness", 0));
785                 Area parent = (Area)areaStack.peek();
786                 parent.addChildArea(leader);
787             }
788             
789             public void endElement() {
790             }
791         }
792
793         private class ViewportMaker extends AbstractMaker {
794
795             public void startElement(Attributes JavaDoc attributes) {
796                 Viewport viewport = new Viewport(null);
797                 transferForeignObjects(attributes, viewport);
798                 setAreaAttributes(attributes, viewport);
799                 setTraits(attributes, viewport, SUBSET_COMMON);
800                 setTraits(attributes, viewport, SUBSET_BOX);
801                 setTraits(attributes, viewport, SUBSET_COLOR);
802                 viewport.setContentPosition(getAttributeAsRectangle2D(attributes, "pos"));
803                 viewport.setClip(getAttributeAsBoolean(attributes, "clip", false));
804                 viewport.setOffset(getAttributeAsInteger(attributes, "offset", 0));
805                 Area parent = (Area)areaStack.peek();
806                 parent.addChildArea(viewport);
807                 areaStack.push(viewport);
808             }
809             
810             public void endElement() {
811                 assertObjectOfClass(areaStack.pop(), Viewport.class);
812             }
813         }
814         
815         private class ImageMaker extends AbstractMaker {
816
817             public void startElement(Attributes JavaDoc attributes) {
818                 String JavaDoc url = attributes.getValue("url");
819                 Image image = new Image(url);
820                 transferForeignObjects(attributes, image);
821                 setAreaAttributes(attributes, image);
822                 setTraits(attributes, image, SUBSET_COMMON);
823                 getCurrentViewport().setContent(image);
824             }
825         }
826         
827         private class ForeignObjectMaker extends AbstractMaker {
828
829             public void startElement(Attributes JavaDoc attributes) throws SAXException JavaDoc {
830                 String JavaDoc ns = attributes.getValue("ns");
831                 domImplementation
832                     = elementMappingRegistry.getDOMImplementationForNamespace(ns);
833                 if (domImplementation == null) {
834                     throw new SAXException JavaDoc("No DOMImplementation could be"
835                             + " identified to handle namespace: " + ns);
836                 }
837                 ForeignObject foreign = new ForeignObject(ns);
838                 transferForeignObjects(attributes, foreign);
839                 setAreaAttributes(attributes, foreign);
840                 setTraits(attributes, foreign, SUBSET_COMMON);
841                 getCurrentViewport().setContent(foreign);
842                 areaStack.push(foreign);
843             }
844             
845             public void endElement() {
846                 assertObjectOfClass(areaStack.pop(), ForeignObject.class);
847             }
848         }
849
850         // ====================================================================
851

852
853         private void pushNewRegionReference(Attributes JavaDoc attributes, int side) {
854             String JavaDoc regionName = attributes.getValue("name");
855             RegionViewport rv = getCurrentRegionViewport();
856             RegionReference reg = new RegionReference(side,
857                     regionName, rv);
858             transferForeignObjects(attributes, reg);
859             reg.setCTM(getAttributeAsCTM(attributes, "ctm"));
860             setAreaAttributes(attributes, reg);
861             rv.setRegionReference(reg);
862             currentPageViewport.getPage().setRegionViewport(
863                     side, rv);
864             areaStack.push(reg);
865         }
866
867         private void assertObjectOfClass(Object JavaDoc obj, Class JavaDoc clazz) {
868             if (!clazz.isInstance(obj)) {
869                 throw new IllegalStateException JavaDoc("Object is not an instance of "
870                         + clazz.getName() + " but of " + obj.getClass().getName());
871             }
872         }
873         
874         /**
875          * Handles objects created by "sub-parsers" that implement the ObjectSource interface.
876          * An example of object handled here are ExtensionAttachments.
877          * @param obj the Object to be handled.
878          */

879         protected void handleExternallyGeneratedObject(Object JavaDoc obj) {
880             if (areaStack.size() == 0 && obj instanceof ExtensionAttachment) {
881                 ExtensionAttachment attachment = (ExtensionAttachment)obj;
882                 if (this.currentPageViewport == null) {
883                     this.treeModel.handleOffDocumentItem(
884                             new OffDocumentExtensionAttachment(attachment));
885                 } else {
886                     this.currentPageViewport.addExtensionAttachment(attachment);
887                 }
888             } else {
889                 log.warn("Don't know how to handle externally generated object: " + obj);
890             }
891         }
892
893         private void setAreaAttributes(Attributes JavaDoc attributes, Area area) {
894             area.setIPD(Integer.parseInt(attributes.getValue("ipd")));
895             area.setBPD(Integer.parseInt(attributes.getValue("bpd")));
896         }
897         
898         private static final Object JavaDoc[] SUBSET_COMMON = new Object JavaDoc[] {
899             Trait.PROD_ID};
900         private static final Object JavaDoc[] SUBSET_LINK = new Object JavaDoc[] {
901             Trait.INTERNAL_LINK, Trait.EXTERNAL_LINK};
902         private static final Object JavaDoc[] SUBSET_COLOR = new Object JavaDoc[] {
903             Trait.BACKGROUND, Trait.COLOR};
904         private static final Object JavaDoc[] SUBSET_FONT = new Object JavaDoc[] {
905             Trait.FONT, Trait.FONT_SIZE, Trait.BLINK,
906             Trait.OVERLINE, Trait.OVERLINE_COLOR,
907             Trait.LINETHROUGH, Trait.LINETHROUGH_COLOR,
908             Trait.UNDERLINE, Trait.UNDERLINE_COLOR};
909         private static final Object JavaDoc[] SUBSET_BOX = new Object JavaDoc[] {
910             Trait.BORDER_BEFORE, Trait.BORDER_AFTER, Trait.BORDER_START, Trait.BORDER_END,
911             Trait.SPACE_BEFORE, Trait.SPACE_AFTER, Trait.SPACE_START, Trait.SPACE_END,
912             Trait.PADDING_BEFORE, Trait.PADDING_AFTER, Trait.PADDING_START, Trait.PADDING_END,
913             Trait.START_INDENT, Trait.END_INDENT,
914             Trait.IS_REFERENCE_AREA, Trait.IS_VIEWPORT_AREA};
915
916         private void setTraits(Attributes JavaDoc attributes, Area area, Object JavaDoc[] traitSubset) {
917             for (int i = 0, c = traitSubset.length; i < c; i++) {
918                 Object JavaDoc trait = traitSubset[i];
919                 String JavaDoc traitName = Trait.getTraitName(trait);
920                 String JavaDoc value = attributes.getValue(traitName);
921                 if (value != null) {
922                     Class JavaDoc cl = Trait.getTraitClass(trait);
923                     if (cl == Integer JavaDoc.class) {
924                         area.addTrait(trait, new Integer JavaDoc(value));
925                     } else if (cl == Boolean JavaDoc.class) {
926                         area.addTrait(trait, Boolean.valueOf(value));
927                     } else if (cl == String JavaDoc.class) {
928                         area.addTrait(trait, value);
929                     } else if (cl == Color JavaDoc.class) {
930                         try {
931                             area.addTrait(trait, ColorUtil.parseColorString(this.userAgent, value));
932                         } catch (PropertyException e) {
933                             throw new IllegalArgumentException JavaDoc(e.getMessage());
934                         }
935                     } else if (cl == Background.class) {
936                         Background bkg = new Background();
937                         try {
938                             Color JavaDoc col = ColorUtil.parseColorString(
939                                         this.userAgent, attributes.getValue("bkg-color"));
940                             bkg.setColor(col);
941                         } catch (PropertyException e) {
942                             throw new IllegalArgumentException JavaDoc(e.getMessage());
943                         }
944                         String JavaDoc url = attributes.getValue("bkg-img");
945                         if (url != null) {
946                             bkg.setURL(url);
947                             
948                             ImageFactory fact = userAgent.getFactory().getImageFactory();
949                             FopImage img = fact.getImage(url, userAgent);
950                             if (img == null) {
951                                 log.error("Background image not available: " + url);
952                             } else {
953                                 // load dimensions
954
if (!img.load(FopImage.DIMENSIONS)) {
955                                     log.error("Cannot read background image dimensions: "
956                                             + url);
957                                 }
958                             }
959                             bkg.setFopImage(img);
960
961                             String JavaDoc repeat = attributes.getValue("bkg-repeat");
962                             if (repeat != null) {
963                                 bkg.setRepeat(repeat);
964                             }
965                             bkg.setHoriz(getAttributeAsInteger(attributes,
966                                     "bkg-horz-offset", 0));
967                             bkg.setVertical(getAttributeAsInteger(attributes,
968                                     "bkg-vert-offset", 0));
969                         }
970                         area.addTrait(trait, bkg);
971                     } else if (cl == BorderProps.class) {
972                         area.addTrait(trait, BorderProps.valueOf(this.userAgent, value));
973                     }
974                 } else {
975                     if (trait == Trait.FONT) {
976                         String JavaDoc fontName = attributes.getValue("font-name");
977                         if (fontName != null) {
978                             String JavaDoc fontStyle = attributes.getValue("font-style");
979                             int fontWeight = getAttributeAsInteger(
980                                     attributes, "font-weight", Font.NORMAL);
981                             area.addTrait(trait,
982                                     FontInfo.createFontKey(fontName, fontStyle, fontWeight));
983                         }
984                     }
985                 }
986             }
987         }
988         
989         private boolean getAttributeAsBoolean(Attributes JavaDoc attributes, String JavaDoc name,
990                 boolean defaultValue) {
991             String JavaDoc s = attributes.getValue(name);
992             if (s == null) {
993                 return defaultValue;
994             } else {
995                 return Boolean.valueOf(s).booleanValue();
996             }
997         }
998
999         private int getAttributeAsInteger(Attributes JavaDoc attributes, String JavaDoc name,
1000                int defaultValue) {
1001            String JavaDoc s = attributes.getValue(name);
1002            if (s == null) {
1003                return defaultValue;
1004            } else {
1005                return Integer.parseInt(s);
1006            }
1007        }
1008
1009        private CTM getAttributeAsCTM(Attributes JavaDoc attributes, String JavaDoc name) {
1010            String JavaDoc s = attributes.getValue(name).trim();
1011            if (s.startsWith("[") && s.endsWith("]")) {
1012                s = s.substring(1, s.length() - 1);
1013                StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(s, " ");
1014                double[] values = new double[] {
1015                        Double.parseDouble(tokenizer.nextToken()),
1016                        Double.parseDouble(tokenizer.nextToken()),
1017                        Double.parseDouble(tokenizer.nextToken()),
1018                        Double.parseDouble(tokenizer.nextToken()),
1019                        Double.parseDouble(tokenizer.nextToken()),
1020                        Double.parseDouble(tokenizer.nextToken())};
1021                return new CTM(values[0], values[1], values[2], values[3], values[4], values[5]);
1022            } else {
1023                throw new IllegalArgumentException JavaDoc("CTM must be surrounded by square brackets");
1024            }
1025        }
1026
1027        private Rectangle2D JavaDoc getAttributeAsRectangle2D(Attributes JavaDoc attributes, String JavaDoc name) {
1028            String JavaDoc s = attributes.getValue(name).trim();
1029            StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(s, " ");
1030            double[] values = new double[] {
1031                    Double.parseDouble(tokenizer.nextToken()),
1032                    Double.parseDouble(tokenizer.nextToken()),
1033                    Double.parseDouble(tokenizer.nextToken()),
1034                    Double.parseDouble(tokenizer.nextToken())};
1035            return new Rectangle2D.Double JavaDoc(values[0], values[1], values[2], values[3]);
1036        }
1037
1038        private void transferForeignObjects(Attributes JavaDoc atts, AreaTreeObject ato) {
1039            for (int i = 0, c = atts.getLength(); i < c; i++) {
1040                String JavaDoc ns = atts.getURI(i);
1041                if (ns.length() > 0) {
1042                    if ("http://www.w3.org/2000/xmlns/".equals(ns)) {
1043                        continue;
1044                    }
1045                    QName qname = new QName(ns, atts.getQName(i));
1046                    ato.setForeignAttribute(qname, atts.getValue(i));
1047                }
1048            }
1049        }
1050        
1051        /** @see org.xml.sax.ContentHandler#characters(char[], int, int) */
1052        public void characters(char[] ch, int start, int length) throws SAXException JavaDoc {
1053            if (delegate != null) {
1054                delegate.characters(ch, start, length);
1055            } else {
1056                content.append(ch, start, length);
1057            }
1058        }
1059
1060    }
1061    
1062}
1063
Popular Tags