2
* Copyright 1999-2005 The Apache Software Foundation.
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
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
14
15
* limitations under the License.
18
/* $Id: AbstractRenderer.java 542237 2007-05-28 14:31:24Z jeremias $ */
19
20
package org.apache.fop.render;
23
import java.awt.Rectangle;
22
24
import java.awt.geom.Rectangle2D;
23
25
import java.io.IOException;
24
26
import java.io.OutputStream;
26
27
import java.util.List;
27
28
import java.util.Iterator;
30
32
import org.w3c.dom.Document;
48
50
import org.apache.fop.area.RegionReference;
49
51
import org.apache.fop.area.Trait;
50
52
import org.apache.fop.area.OffDocumentItem;
53
import org.apache.fop.area.inline.Character;
51
54
import org.apache.fop.area.inline.Container;
52
55
import org.apache.fop.area.inline.ForeignObject;
53
56
import org.apache.fop.area.inline.Image;
54
57
import org.apache.fop.area.inline.InlineArea;
58
import org.apache.fop.area.inline.InlineBlockParent;
55
59
import org.apache.fop.area.inline.InlineParent;
56
60
import org.apache.fop.area.inline.Leader;
57
61
import org.apache.fop.area.inline.Space;
58
62
import org.apache.fop.area.inline.Viewport;
59
63
import org.apache.fop.area.inline.TextArea;
60
import org.apache.fop.area.inline.Character;
64
import org.apache.fop.area.inline.WordArea;
65
import org.apache.fop.area.inline.SpaceArea;
61
66
import org.apache.fop.apps.FOUserAgent;
62
67
import org.apache.fop.fo.Constants;
63
68
import org.apache.fop.fonts.FontInfo;
64
69
import org.apache.commons.logging.Log;
65
70
import org.apache.commons.logging.LogFactory;
68
import org.apache.avalon.framework.configuration.Configurable;
69
import org.apache.avalon.framework.configuration.Configuration;
70
import org.apache.avalon.framework.configuration.ConfigurationException;
73
73
* Abstract base class for all renderers. The Abstract renderer does all the
74
74
* top level processing of the area tree and adds some abstract methods to
75
75
* handle viewports. This keeps track of the current block and inline position.
77
77
public abstract class AbstractRenderer
78
implements Renderer, Configurable, Constants {
78
implements Renderer, Constants {
80
/** logging instance */
81
protected static Log log = LogFactory.getLog("org.apache.fop.render");
83
protected FOUserAgent userAgent;
86
protected FOUserAgent userAgent = null;
88
protected static Log logger = LogFactory.getLog("org.apache.fop.render");
91
89
* block progression position
93
91
protected int currentBPPosition = 0;
110
108
protected int containingIPPosition = 0;
113
* @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
115
public void configure(Configuration conf) throws ConfigurationException {
119
* Returns the Commons-Logging instance for this class
120
* @return The Commons-Logging instance
122
protected Log getLogger() {
127
* @see org.apache.fop.render.Renderer
110
/** the currently active PageViewport */
111
protected PageViewport currentPageViewport;
113
private Set warnedXMLHandlers;
116
* @see org.apache.fop.render.Renderer#setupFontInfo(FontInfo)
129
118
public abstract void setupFontInfo(FontInfo fontInfo);
132
* @see org.apache.fop.render.Renderer
121
* @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
134
123
public void setUserAgent(FOUserAgent agent) {
135
124
userAgent = agent;
138
/** @see org.apache.fop.render.Renderer */
128
* @see org.apache.fop.render.Renderer#getUserAgent()
130
public FOUserAgent getUserAgent() {
134
/** @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */
139
135
public void startRenderer(OutputStream outputStream)
140
136
throws IOException { }
142
/** @see org.apache.fop.render.Renderer */
138
/** @see org.apache.fop.render.Renderer#stopRenderer() */
143
139
public void stopRenderer()
144
140
throws IOException { }
159
* @see org.apache.fop.render.Renderer
155
* @see org.apache.fop.render.Renderer#processOffDocumentItem(OffDocumentItem)
161
public void processOffDocumentItem(OffDocumentItem oDI) { }
157
public void processOffDocumentItem(OffDocumentItem odi) { }
159
/** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
160
public Graphics2DAdapter getGraphics2DAdapter() {
164
/** @see org.apache.fop.render.Renderer#getImageAdapter() */
165
public ImageAdapter getImageAdapter() {
169
/** @return the current PageViewport or null, if none is active */
170
protected PageViewport getCurrentPageViewport() {
171
return this.currentPageViewport;
164
175
* Prepare a page for rendering. This is called if the renderer supports
165
176
* out of order rendering. The renderer should prepare the page so that a
190
201
StringBuffer sb = new StringBuffer();
191
202
for (int count = 0; count < children.size(); count++) {
192
203
InlineArea inline = (InlineArea) children.get(count);
193
if (inline instanceof Character) {
194
sb.append(((Character) inline).getChar());
195
} else if (inline instanceof TextArea) {
196
sb.append(((TextArea) inline).getTextArea());
204
//if (inline instanceof Character) {
205
// sb.append(((Character) inline).getChar());
206
/*} else*/ if (inline instanceof TextArea) {
207
sb.append(((TextArea) inline).getText());
197
208
} else if (inline instanceof InlineParent) {
198
209
sb.append(convertToString(
199
210
((InlineParent) inline).getChildAreas()));
204
215
return sb.toString();
207
/** @see org.apache.fop.render.Renderer */
218
/** @see org.apache.fop.render.Renderer#startPageSequence(LineArea) */
208
219
public void startPageSequence(LineArea seqTitle) {
212
223
// normally this would be overriden to create a page in the
214
/** @see org.apache.fop.render.Renderer */
225
/** @see org.apache.fop.render.Renderer#renderPage(PageViewport) */
215
226
public void renderPage(PageViewport page)
216
227
throws IOException, FOPException {
218
Page p = page.getPage();
229
this.currentPageViewport = page;
231
Page p = page.getPage();
234
this.currentPageViewport = null;
259
275
currentBPPosition = 0;
260
276
currentIPPosition = 0;
262
RegionReference region = port.getRegion();
278
RegionReference regionReference = port.getRegionReference();
263
279
handleRegionTraits(port);
265
281
// shouldn't the viewport have the CTM
266
startVParea(region.getCTM());
282
startVParea(regionReference.getCTM(), port.isClip() ? view : null);
267
283
// do after starting viewport area
268
if (region.getRegionClass() == FO_REGION_BODY) {
269
renderBodyRegion((BodyRegion) region);
284
if (regionReference.getRegionClass() == FO_REGION_BODY) {
285
renderBodyRegion((BodyRegion) regionReference);
271
renderRegion(region);
287
renderRegion(regionReference);
278
* (todo) Description of the Method
294
* Establishes a new viewport area.
280
* @param ctm The coordinate transformation matrix to use
282
protected void startVParea(CTM ctm) { }
296
* @param ctm the coordinate transformation matrix to use
297
* @param clippingRect the clipping rectangle if the viewport should be clipping,
298
* null if no clipping is performed.
300
protected abstract void startVParea(CTM ctm, Rectangle2D clippingRect);
303
* Signals exit from a viewport area. Subclasses can restore transformation matrices
304
* valid before the viewport area was started.
306
protected abstract void endVParea();
285
309
* Handle the traits for a region
375
395
Span span = null;
376
396
List spans = mr.getSpans();
397
int saveBPPos = currentBPPosition;
398
int saveSpanBPPos = saveBPPos;
377
399
for (int count = 0; count < spans.size(); count++) {
378
400
span = (Span) spans.get(count);
379
int offset = (mr.getWidth()
380
- (span.getColumnCount() - 1) * mr.getColumnGap())
381
/ span.getColumnCount() + mr.getColumnGap();
382
401
for (int c = 0; c < span.getColumnCount(); c++) {
383
402
NormalFlow flow = (NormalFlow) span.getNormalFlow(c);
386
currentIPPosition += offset;
405
currentBPPosition = saveSpanBPPos;
407
currentIPPosition += flow.getIPD();
408
currentIPPosition += mr.getColumnGap();
388
411
currentIPPosition = saveIPPos;
389
currentBPPosition += span.getHeight();
412
currentBPPosition = saveSpanBPPos + span.getHeight();
413
saveSpanBPPos = currentBPPosition;
415
currentBPPosition = saveBPPos;
428
453
int saveIP = currentIPPosition;
429
454
int saveBP = currentBPPosition;
456
Rectangle2D clippingRect = null;
458
clippingRect = new Rectangle(saveIP, saveBP, bv.getIPD(), bv.getBPD());
431
461
CTM ctm = bv.getCTM();
432
462
currentIPPosition = 0;
433
463
currentBPPosition = 0;
465
startVParea(ctm, clippingRect);
436
466
handleBlockTraits(bv);
437
467
renderBlocks(bv, children);
527
558
int saveBP = currentBPPosition;
529
560
if (block.getPositioning() == Block.ABSOLUTE) {
530
currentIPPosition = containingIPPosition + block.getXOffset();
531
currentBPPosition = containingBPPosition + block.getYOffset();
561
currentIPPosition += block.getXOffset();
562
currentBPPosition += block.getYOffset();
563
currentBPPosition += block.getSpaceBefore();
533
565
handleBlockTraits(block);
571
600
protected void renderLineArea(LineArea line) {
572
601
List children = line.getInlineAreas();
602
int saveBP = currentBPPosition;
603
currentBPPosition += line.getSpaceBefore();
574
604
for (int count = 0; count < children.size(); count++) {
575
605
InlineArea inline = (InlineArea) children.get(count);
576
606
renderInlineArea(inline);
608
currentBPPosition = saveBP;
612
* Render the given InlineArea.
613
* @param inlineArea inline area text to render
580
615
protected void renderInlineArea(InlineArea inlineArea) {
581
renderTextDecoration(inlineArea);
582
616
if (inlineArea instanceof TextArea) {
583
617
renderText((TextArea) inlineArea);
618
//} else if (inlineArea instanceof Character) {
619
//renderCharacter((Character) inlineArea);
620
} else if (inlineArea instanceof WordArea) {
621
renderWord((WordArea) inlineArea);
622
} else if (inlineArea instanceof SpaceArea) {
623
renderSpace((SpaceArea) inlineArea);
584
624
} else if (inlineArea instanceof InlineParent) {
585
625
renderInlineParent((InlineParent) inlineArea);
626
} else if (inlineArea instanceof InlineBlockParent) {
627
renderInlineBlockParent((InlineBlockParent) inlineArea);
586
628
} else if (inlineArea instanceof Space) {
587
629
renderInlineSpace((Space) inlineArea);
588
} else if (inlineArea instanceof Character) {
589
renderCharacter((Character) inlineArea);
590
630
} else if (inlineArea instanceof Viewport) {
591
631
renderViewport((Viewport) inlineArea);
592
632
} else if (inlineArea instanceof Leader) {
598
/** @see org.apache.fop.render.Renderer */
638
* Render the given Character.
639
* @param ch the character to render
640
* @deprecated Only TextArea should be used. This method will be removed eventually.
599
642
protected void renderCharacter(Character ch) {
600
643
currentIPPosition += ch.getAllocIPD();
603
/** @see org.apache.fop.render.Renderer */
647
* Common method to render the background and borders for any inline area.
648
* The all borders and padding are drawn outside the specified area.
649
* @param area the inline area for which the background, border and padding is to be
652
protected abstract void renderInlineAreaBackAndBorders(InlineArea area);
655
* Render the given Space.
656
* @param space the space to render
604
658
protected void renderInlineSpace(Space space) {
660
renderInlineAreaBackAndBorders(space);
605
661
// an inline space moves the inline progression position
606
662
// for the current block by the width or height of the space
607
663
// it may also have styling (only on this object) that needs
609
665
currentIPPosition += space.getAllocIPD();
612
/** @see org.apache.fop.render.Renderer */
669
* Render the given Leader.
670
* @param area the leader to render
613
672
protected void renderLeader(Leader area) {
614
673
currentIPPosition += area.getAllocIPD();
617
/** @see org.apache.fop.render.Renderer */
677
* Render the given TextArea.
678
* @param text the text to render
618
680
protected void renderText(TextArea text) {
619
currentIPPosition += text.getAllocIPD();
622
/** @see org.apache.fop.render.Renderer */
681
int saveIP = currentIPPosition;
682
int saveBP = currentBPPosition;
683
Iterator iter = text.getChildAreas().iterator();
684
while (iter.hasNext()) {
685
renderInlineArea((InlineArea) iter.next());
687
currentIPPosition = saveIP + text.getAllocIPD();
691
* Render the given WordArea.
692
* @param word the word to render
694
protected void renderWord(WordArea word) {
695
currentIPPosition += word.getAllocIPD();
699
* Render the given SpaceArea.
700
* @param space the space to render
702
protected void renderSpace(SpaceArea space) {
703
currentIPPosition += space.getAllocIPD();
707
* Render the given InlineParent.
708
* @param ip the inline parent to render
623
710
protected void renderInlineParent(InlineParent ip) {
711
renderInlineAreaBackAndBorders(ip);
624
712
int saveIP = currentIPPosition;
713
int saveBP = currentBPPosition;
714
currentIPPosition += ip.getBorderAndPaddingWidthStart();
715
currentBPPosition += ip.getOffset();
625
716
Iterator iter = ip.getChildAreas().iterator();
626
717
while (iter.hasNext()) {
627
718
renderInlineArea((InlineArea) iter.next());
629
720
currentIPPosition = saveIP + ip.getAllocIPD();
632
/** @see org.apache.fop.render.Renderer */
721
currentBPPosition = saveBP;
725
* Render the given InlineBlockParent.
726
* @param ibp the inline block parent to render
728
protected void renderInlineBlockParent(InlineBlockParent ibp) {
729
renderInlineAreaBackAndBorders(ibp);
730
currentIPPosition += ibp.getBorderAndPaddingWidthStart();
731
// For inline content the BP position is updated by the enclosing line area
732
int saveBP = currentBPPosition;
733
currentBPPosition += ibp.getOffset();
734
renderBlock(ibp.getChildArea());
735
currentBPPosition = saveBP;
739
* Render the given Viewport.
740
* @param viewport the viewport to render
633
742
protected void renderViewport(Viewport viewport) {
634
743
Area content = viewport.getContent();
635
744
int saveBP = currentBPPosition;
688
* Set the default xml handler for the given mime type.
689
* @param mime MIME type
690
* @param handler XMLHandler to use
692
public void setDefaultXMLHandler(FOUserAgent foua, String mime,
693
XMLHandler handler) {
694
foua.defaults.put(mime, handler);
698
* Add an xml handler for the given mime type and xml namespace.
699
* @param mime MIME type
700
* @param ns Namespace URI
701
* @param handler XMLHandler to use
703
public void addXMLHandler(FOUserAgent foua, String mime, String ns,
704
XMLHandler handler) {
705
Map mh = (Map) foua.handlers.get(mime);
707
mh = new java.util.HashMap();
708
foua.handlers.put(mime, mh);
714
797
* Render the xml document with the given xml namespace.
715
798
* The Render Context is by the handle to render into the current
716
799
* rendering target.
718
801
* @param doc DOM Document containing the source document
719
802
* @param namespace Namespace URI of the document
721
public void renderXML(FOUserAgent foua, RendererContext ctx, Document doc,
804
public void renderXML(RendererContext ctx, Document doc,
722
805
String namespace) {
723
String mime = ctx.getMimeType();
724
Map mh = (Map) foua.handlers.get(mime);
725
XMLHandler handler = null;
727
handler = (XMLHandler) mh.get(namespace);
729
if (handler == null) {
730
handler = (XMLHandler) foua.defaults.get(mime);
806
XMLHandler handler = userAgent.getXMLHandlerRegistry().getXMLHandler(
732
808
if (handler != null) {
810
XMLHandlerConfigurator configurator
811
= new XMLHandlerConfigurator(userAgent);
812
configurator.configure(ctx, namespace);
734
813
handler.handleXML(ctx, doc, namespace);
735
814
} catch (Throwable t) {
736
815
// could not handle document
737
getLogger().error("Some XML content will be ignored. "
816
log.error("Some XML content will be ignored. "
738
817
+ "Could not render XML", t);
741
// no handler found for document
742
getLogger().warn("Some XML content will be ignored. "
743
+ "No handler defined for XML: " + namespace);
820
if (warnedXMLHandlers == null) {
821
warnedXMLHandlers = new java.util.HashSet();
823
if (!warnedXMLHandlers.contains(namespace)) {
824
// no handler found for document
825
warnedXMLHandlers.add(namespace);
826
log.warn("Some XML content will be ignored. "
827
+ "No handler defined for XML: " + namespace);