From 2f451f9c4dae507df76e77bc13e0839c98724fd0 Mon Sep 17 00:00:00 2001 From: Adrian Cumiskey Date: Mon, 23 Jun 2008 09:46:41 +0000 Subject: Merged revisions 669423,669436,669835,670217,670222,670323,670325,670332,670335-670336,670341,670344,670401,670409,670411-670412,670422-670424,670492 via svnmerge from https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r669423 | jeremias | 2008-06-19 09:25:46 +0100 (Thu, 19 Jun 2008) | 1 line Simplifications and a Checkstyle fix. ........ r669436 | jeremias | 2008-06-19 10:46:12 +0100 (Thu, 19 Jun 2008) | 2 lines Separation of concerns: Split FOEventHandler into FOEventHandler and FOTreeBuilderContext. The latter contains stuff only used at tree-building stage. FOEventHandler is oriented towards output. ........ r669835 | acumiskey | 2008-06-20 10:18:56 +0100 (Fri, 20 Jun 2008) | 1 line Strict/loose validation of ordering somehow got lost in processing feedback branch merge. ........ r670217 | acumiskey | 2008-06-21 17:10:03 +0100 (Sat, 21 Jun 2008) | 1 line Moved the contents of TableBody into a new abstract base class TablePart, which is now subclassed by TableBody, TableHeader and TableFooter. ........ r670222 | acumiskey | 2008-06-21 17:28:56 +0100 (Sat, 21 Jun 2008) | 1 line Moved the contents of TableBody into a new abstract base class TablePart, which is now subclassed by TableBody, TableHeader and TableFooter. ........ r670323 | adelmelle | 2008-06-22 10:07:47 +0100 (Sun, 22 Jun 2008) | 1 line Addition to r670217 ........ r670325 | adelmelle | 2008-06-22 10:28:56 +0100 (Sun, 22 Jun 2008) | 1 line Minor javadoc correction ........ r670332 | adelmelle | 2008-06-22 11:21:03 +0100 (Sun, 22 Jun 2008) | 1 line Minor tweak: avoid warning when running through Saxon ........ r670335 | adelmelle | 2008-06-22 11:53:51 +0100 (Sun, 22 Jun 2008) | 1 line Avoid StackOverflow on TableColumn.toString() during debugging. ........ r670336 | adelmelle | 2008-06-22 12:01:27 +0100 (Sun, 22 Jun 2008) | 1 line Minor tweak: use XG Commons version of the interface ........ r670341 | adelmelle | 2008-06-22 12:18:03 +0100 (Sun, 22 Jun 2008) | 2 lines Changed FONode.addCharacters() signature to match the characters() event (use 'length' as a parameter instead of 'end') ........ r670344 | adelmelle | 2008-06-22 12:28:06 +0100 (Sun, 22 Jun 2008) | 1 line Changed signature for static handleWhiteSpaceFor(), and used internally to make the code a bit more compact ........ r670401 | adelmelle | 2008-06-22 20:19:17 +0100 (Sun, 22 Jun 2008) | 1 line Correction: characters() expects a 'length' not an 'endIndex' ........ r670409 | adelmelle | 2008-06-22 21:18:27 +0100 (Sun, 22 Jun 2008) | 1 line Very minor tweak: simplify conditional ........ r670411 | adelmelle | 2008-06-22 21:38:28 +0100 (Sun, 22 Jun 2008) | 2 lines Deleted deprecated interface; unused after r670336 ........ r670412 | adelmelle | 2008-06-22 21:57:43 +0100 (Sun, 22 Jun 2008) | 6 lines Partial fix of FOEventHandler call sequence (see also Bugzilla #45237): call startOfNode() after addChildNode() moved initialization for tableFOs to processNode() moved finishing code to a finalizeNode() method (which is now also used by AbstractRetrieveMarker) restored protected status of startOfNode()/endOfNode() in fo.flow.table package ........ r670422 | adelmelle | 2008-06-22 23:10:55 +0100 (Sun, 22 Jun 2008) | 4 lines Switch FOText to use a java.nio.CharBuffer, and implement the CharSequence interface. TextLayoutManager no longer duplicates the char array, operates on the FOText (charAt(i)) Additionally: endOfNode() for FOText and Character deferred until after white-space handling. ........ r670423 | adelmelle | 2008-06-22 23:17:00 +0100 (Sun, 22 Jun 2008) | 1 line Added missing file from r670422 ........ r670424 | adelmelle | 2008-06-22 23:18:53 +0100 (Sun, 22 Jun 2008) | 1 line Another missing file... ........ r670492 | lfurini | 2008-06-23 10:24:14 +0100 (Mon, 23 Jun 2008) | 2 lines Added support for non-zero borders and padding on page regions. Testcase included, now disabled because it is supposed to run with relaxed validation switched on. ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@670500 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/area/Page.java | 5 + src/java/org/apache/fop/area/RegionReference.java | 14 +- src/java/org/apache/fop/fo/FOEventHandler.java | 109 +---- src/java/org/apache/fop/fo/FONode.java | 36 +- src/java/org/apache/fop/fo/FOText.java | 445 +++++++++++---------- src/java/org/apache/fop/fo/FOTreeBuilder.java | 45 ++- .../org/apache/fop/fo/FOTreeBuilderContext.java | 107 +++++ src/java/org/apache/fop/fo/FObj.java | 4 +- src/java/org/apache/fop/fo/FObjMixed.java | 169 ++++---- .../org/apache/fop/fo/RecursiveCharIterator.java | 2 +- .../org/apache/fop/fo/expr/PropertyException.java | 2 +- .../apache/fop/fo/extensions/xmp/XMPMetadata.java | 2 +- .../apache/fop/fo/flow/AbstractRetrieveMarker.java | 35 +- src/java/org/apache/fop/fo/flow/Marker.java | 10 +- .../apache/fop/fo/flow/table/BorderResolver.java | 2 +- .../fo/flow/table/CollapsingBorderResolver.java | 10 +- .../fop/fo/flow/table/FixedColRowGroupBuilder.java | 6 +- .../apache/fop/fo/flow/table/PrimaryGridUnit.java | 4 +- .../apache/fop/fo/flow/table/RowGroupBuilder.java | 8 +- .../fop/fo/flow/table/SeparateBorderResolver.java | 2 +- src/java/org/apache/fop/fo/flow/table/Table.java | 51 +-- .../org/apache/fop/fo/flow/table/TableBody.java | 219 +--------- .../org/apache/fop/fo/flow/table/TableCell.java | 19 +- .../fop/fo/flow/table/TableCellContainer.java | 4 +- .../org/apache/fop/fo/flow/table/TableColumn.java | 2 +- .../org/apache/fop/fo/flow/table/TableFObj.java | 16 +- .../org/apache/fop/fo/flow/table/TableFooter.java | 18 +- .../org/apache/fop/fo/flow/table/TableHeader.java | 18 +- .../org/apache/fop/fo/flow/table/TablePart.java | 239 +++++++++++ .../org/apache/fop/fo/flow/table/TableRow.java | 29 +- .../fo/flow/table/VariableColRowGroupBuilder.java | 4 +- src/java/org/apache/fop/fo/pagination/Root.java | 25 +- .../fop/fo/properties/PageDimensionMaker.java | 5 +- src/java/org/apache/fop/fonts/FontSelector.java | 7 +- .../apache/fop/layoutmgr/LayoutManagerMapping.java | 4 +- .../fop/layoutmgr/inline/TextLayoutManager.java | 124 +++--- .../org/apache/fop/layoutmgr/table/RowPainter.java | 4 +- .../layoutmgr/table/TableCellLayoutManager.java | 4 +- .../layoutmgr/table/TableContentLayoutManager.java | 23 +- .../fop/layoutmgr/table/TableContentPosition.java | 6 +- .../fop/layoutmgr/table/TableRowIterator.java | 6 +- .../fop/render/AbstractPathOrientedRenderer.java | 85 +++- src/java/org/apache/fop/render/rtf/RTFHandler.java | 64 ++- .../fop/render/rtf/TableAttributesConverter.java | 5 +- src/java/org/apache/fop/util/CharUtilities.java | 24 +- src/java/org/apache/fop/util/XMLizable.java | 35 -- 46 files changed, 1152 insertions(+), 905 deletions(-) create mode 100644 src/java/org/apache/fop/fo/FOTreeBuilderContext.java create mode 100644 src/java/org/apache/fop/fo/flow/table/TablePart.java delete mode 100644 src/java/org/apache/fop/util/XMLizable.java (limited to 'src/java/org/apache') diff --git a/src/java/org/apache/fop/area/Page.java b/src/java/org/apache/fop/area/Page.java index 64a6db576..94a394014 100644 --- a/src/java/org/apache/fop/area/Page.java +++ b/src/java/org/apache/fop/area/Page.java @@ -126,6 +126,10 @@ public class Page extends AreaTreeObject implements Serializable, Cloneable { } else { rr = new RegionReference(r, rvp); } + // set borders and padding traits + // (a little extensions wrt what prescribed by the specs at 6.4.14) + TraitSetter.addBorders(rr, r.getCommonBorderPaddingBackground(), false, false, false, false, null); + TraitSetter.addPadding(rr, r.getCommonBorderPaddingBackground(), false, false, false, false, null); setRegionReferencePosition(rr, r, rvp.getViewArea()); rvp.setRegionReference(rr); setRegionViewport(r.getNameId(), rvp); @@ -289,3 +293,4 @@ public class Page extends AreaTreeObject implements Serializable, Cloneable { } + diff --git a/src/java/org/apache/fop/area/RegionReference.java b/src/java/org/apache/fop/area/RegionReference.java index c41de7c7a..467aadd85 100644 --- a/src/java/org/apache/fop/area/RegionReference.java +++ b/src/java/org/apache/fop/area/RegionReference.java @@ -73,6 +73,18 @@ public class RegionReference extends Area implements Cloneable { blocks.add(child); } + /** {@inheritDoc} */ + public int getBPD() { + // subtract bpd of borders and padding before / after + return super.getBPD() - getBorderAndPaddingWidthBefore() - getBorderAndPaddingWidthAfter(); + } + + /** {@inheritDoc} */ + public int getIPD() { + // subtract ipd of borders and padding start / end + return super.getIPD() - getBorderAndPaddingWidthStart() - getBorderAndPaddingWidthEnd(); + } + /** * Set the Coordinate Transformation Matrix which transforms content * coordinates in this region reference area which are specified in @@ -133,7 +145,7 @@ public class RegionReference extends Area implements Cloneable { public void addBlock(Block block) { addChildArea(block); } - + /** * Clone this region. * This is used when cloning the page by the page master. diff --git a/src/java/org/apache/fop/fo/FOEventHandler.java b/src/java/org/apache/fop/fo/FOEventHandler.java index 7521d398c..90856d57a 100644 --- a/src/java/org/apache/fop/fo/FOEventHandler.java +++ b/src/java/org/apache/fop/fo/FOEventHandler.java @@ -19,9 +19,6 @@ package org.apache.fop.fo; -import java.util.HashSet; -import java.util.Set; - import org.xml.sax.SAXException; import org.apache.fop.apps.FOUserAgent; @@ -43,6 +40,9 @@ import org.apache.fop.fo.flow.PageNumberCitation; import org.apache.fop.fo.flow.PageNumberCitationLast; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TableFooter; +import org.apache.fop.fo.flow.table.TableHeader; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableColumn; import org.apache.fop.fo.flow.table.TableRow; @@ -74,27 +74,6 @@ public abstract class FOEventHandler { */ protected FontInfo fontInfo; - /** - * The current set of id's in the FO tree. - * This is used so we know if the FO tree contains duplicates. - */ - private Set idReferences = new HashSet(); - - /** - * The property list maker. - */ - protected PropertyListMaker propertyListMaker; - - /** - * The XMLWhitespaceHandler for this tree - */ - protected XMLWhiteSpaceHandler whiteSpaceHandler = new XMLWhiteSpaceHandler(); - - /** - * Indicates whether processing descendants of a marker - */ - private boolean inMarker = false; - /** * Main constructor * @param foUserAgent the apps.FOUserAgent instance for this process @@ -105,14 +84,6 @@ public abstract class FOEventHandler { this.fontInfo.setEventListener(new FontEventAdapter(foUserAgent.getEventBroadcaster())); } - /** - * Retuns the set of ID references. - * @return the ID references - */ - public Set getIDReferences() { - return idReferences; - } - /** * Returns the User Agent object associated with this FOEventHandler. * @return the User Agent object @@ -129,54 +100,6 @@ public abstract class FOEventHandler { return this.fontInfo; } - /** - * Return the propertyListMaker. - * - * @return the currently active {@link PropertyListMaker} - */ - public PropertyListMaker getPropertyListMaker() { - return propertyListMaker; - } - - /** - * Set a new propertyListMaker. - * - * @param propertyListMaker the new {@link PropertyListMaker} to use - */ - public void setPropertyListMaker(PropertyListMaker propertyListMaker) { - this.propertyListMaker = propertyListMaker; - } - - /** - * Return the XMLWhiteSpaceHandler - * @return the whiteSpaceHandler - */ - public XMLWhiteSpaceHandler getXMLWhiteSpaceHandler() { - return whiteSpaceHandler; - } - - /** - * Switch to or from marker context - * (used by FOTreeBuilder when processing - * a marker) - * - * @param inMarker true if a marker is being processed; - * false otherwise - * - */ - protected void switchMarkerContext(boolean inMarker) { - this.inMarker = inMarker; - } - - /** - * Check whether in marker context - * - * @return true if a marker is being processed - */ - protected boolean inMarker() { - return this.inMarker; - } - /** * This method is called to indicate the start of a new document run. * @throws SAXException In case of a problem @@ -337,44 +260,44 @@ public abstract class FOEventHandler { /** * - * @param th TableBody that is starting; + * @param header TableHeader that is starting; */ - public void startHeader(TableBody th) { + public void startHeader(TableHeader header) { } /** * - * @param th TableBody that is ending. + * @param header TableHeader that is ending. */ - public void endHeader(TableBody th) { + public void endHeader(TableHeader header) { } /** * - * @param tf TableFooter that is starting. + * @param footer TableFooter that is starting. */ - public void startFooter(TableBody tf) { + public void startFooter(TableFooter footer) { } /** * - * @param tf TableFooter that is ending. + * @param footer TableFooter that is ending. */ - public void endFooter(TableBody tf) { + public void endFooter(TableFooter footer) { } /** * - * @param tb TableBody that is starting. + * @param body TableBody that is starting. */ - public void startBody(TableBody tb) { + public void startBody(TableBody body) { } /** * - * @param tb TableBody that is ending. + * @param body TableBody that is ending. */ - public void endBody(TableBody tb) { + public void endBody(TableBody body) { } /** @@ -566,7 +489,7 @@ public abstract class FOEventHandler { * @param start Offset for characters to process. * @param length Portion of array to process. */ - public void characters(char data[], int start, int length) { + public void characters(char[] data, int start, int length) { } /** diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java index 951e4c430..87d3bfa3c 100644 --- a/src/java/org/apache/fop/fo/FONode.java +++ b/src/java/org/apache/fop/fo/FONode.java @@ -22,7 +22,6 @@ package org.apache.fop.fo; // Java import java.util.ListIterator; import java.util.Map; -import java.util.NoSuchElementException; import org.xml.sax.Attributes; import org.xml.sax.Locator; @@ -157,12 +156,20 @@ public abstract class FONode implements Cloneable { return parent.getFOEventHandler(); } + /** + * Returns the context class providing information used during FO tree building. + * @return the builder context + */ + public FOTreeBuilderContext getBuilderContext() { + return parent.getBuilderContext(); + } + /** * Indicates whether this node is a child of an fo:marker. * @return true if this node is a child of an fo:marker */ protected boolean inMarker() { - return getFOEventHandler().inMarker(); + return getBuilderContext().inMarker(); } /** @@ -267,12 +274,12 @@ public abstract class FONode implements Cloneable { * * @param data array of characters containing text to be added * @param start starting array element to add - * @param end ending array element to add + * @param length number of elements to add * @param pList currently applicable PropertyList * @param locator location in the XSL-FO source file. * @throws FOPException if there's a problem during processing */ - protected void addCharacters(char[] data, int start, int end, + protected void addCharacters(char[] data, int start, int length, PropertyList pList, Locator locator) throws FOPException { // ignore @@ -291,11 +298,16 @@ public abstract class FONode implements Cloneable { * Primarily used for making final content model validation checks * and/or informing the {@link FOEventHandler} that the end of this FO * has been reached. + * The default implementation simply calls {@link #finalizeNode()}, without + * sending any event to the {@link FOEventHandler}. + *
Note: the recommended way to override this method in subclasses is + *

super.endOfNode(); // invoke finalizeNode() + *
getFOEventHandler().endXXX(); // send endOfNode() notification
* * @throws FOPException if there's a problem during processing */ protected void endOfNode() throws FOPException { - // do nothing by default + this.finalizeNode(); } /** @@ -319,6 +331,20 @@ public abstract class FONode implements Cloneable { //nop } + /** + * Finalize this node. + * This method can be overridden by subclasses to perform finishing + * tasks (cleanup, validation checks, ...) without triggering + * endXXX() events in the {@link FOEventHandler}. + * The method is called by the default {@link #endOfNode()} + * implementation. + * + * @throws FOPException in case there was an error + */ + public void finalizeNode() throws FOPException { + // do nothing by default + } + /** * Return the parent node of this node * diff --git a/src/java/org/apache/fop/fo/FOText.java b/src/java/org/apache/fop/fo/FOText.java index f21386075..217997ace 100644 --- a/src/java/org/apache/fop/fo/FOText.java +++ b/src/java/org/apache/fop/fo/FOText.java @@ -20,6 +20,7 @@ package org.apache.fop.fo; import java.awt.Color; +import java.nio.CharBuffer; import java.util.NoSuchElementException; import org.xml.sax.Locator; @@ -33,48 +34,17 @@ import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.SpaceProperty; +import org.apache.fop.util.CharUtilities; /** * A text node (PCDATA) in the formatting object tree. - * - * Unfortunately the BufferManager implementation holds - * onto references to the character data in this object - * longer than the lifetime of the object itself, causing - * excessive memory consumption and OOM errors. */ -public class FOText extends FONode { +public class FOText extends FONode implements CharSequence { - /** - * the character array containing the text - */ - public char[] ca; - - /** - * The starting valid index of the ca array - * to be processed. - * - * This value is originally equal to 0, but becomes - * incremented during leading whitespace removal by the flow.Block class, - * via the TextCharIterator.remove() method below. - */ - public int startIndex = 0; + /** the CharBuffer containing the text */ + private CharBuffer charBuffer; - /** - * The ending valid index of the ca array - * to be processed. - * - * This value is originally equal to ca.length, but becomes - * decremented during between-word whitespace removal by the - * XMLWhiteSpaceHandler via the TextCharIterator.remove() - * method below. - */ - public int endIndex = 0; - - /** properties relevant for PCDATA */ - /* TODO: these are basically always the same as the parent FObj or FObjMixed - * so maybe those can be removed, and the accessors could - * dispatch the call to the parent? - */ + /** properties relevant for #PCDATA */ private CommonFont commonFont; private CommonHyphenation commonHyphenation; private Color color; @@ -105,10 +75,10 @@ public class FOText extends FONode { * which FOText nodes are descendants of the same block. */ private Block ancestorBlock = null; - + /** Holds the text decoration values. May be null */ private CommonTextDecoration textDecoration; - + private static final int IS_WORD_CHAR_FALSE = 0; private static final int IS_WORD_CHAR_TRUE = 1; private static final int IS_WORD_CHAR_MAYBE = 2; @@ -123,37 +93,61 @@ public class FOText extends FONode { } /** {@inheritDoc} */ - protected void addCharacters(char[] data, int start, int end, + protected void addCharacters(char[] data, int start, int length, PropertyList list, Locator locator) throws FOPException { - int length = end - start; - int calength = 0; - char[] nca; - if (ca != null) { - calength = ca.length; - nca = new char[calength + length]; - System.arraycopy(ca, 0, nca, 0, calength); + if (this.charBuffer == null) { + // buffer not yet initialized, do so now + this.charBuffer = CharBuffer.allocate(length); } else { - nca = new char[length]; + // allocate a larger buffer, and transfer contents + int newLength = this.charBuffer.limit() + length; + CharBuffer newBuffer = CharBuffer.allocate(newLength); + this.charBuffer.rewind(); + newBuffer.put(this.charBuffer); + this.charBuffer = newBuffer; } - System.arraycopy(data, start, nca, calength, length); - endIndex = nca.length; - this.ca = nca; - } + // append characters + this.charBuffer.put(data, start, length); + + } /** - * {@inheritDoc} + * Return the array of characters for this instance. + * + * @return a char array containing the text */ + public char[] getCharArray() { + + if (this.charBuffer == null) { + return null; + } + + if (this.charBuffer.hasArray()) { + return this.charBuffer.array(); + } + + // only if the buffer implementation has + // no accessible backing array, return a new one + char[] ca = new char[this.charBuffer.limit()]; + this.charBuffer.rewind(); + this.charBuffer.get(ca); + return ca; + + } + + /** {@inheritDoc} */ public FONode clone(FONode parent, boolean removeChildren) throws FOPException { FOText ft = (FOText) super.clone(parent, removeChildren); if (removeChildren) { - //not really removing, but just make sure the char array - //pointed to is really a different one, and reset any - //possible whitespace-handling effects - if (ca != null) { - ft.ca = new char[ca.length]; - System.arraycopy(ca, 0, ft.ca, 0, ca.length); + // not really removing, just make sure the char buffer + // pointed to is really a different one + if (this.charBuffer != null) { + ft.charBuffer = CharBuffer.allocate(this.charBuffer.limit()); + this.charBuffer.rewind(); + ft.charBuffer.put(this.charBuffer); + ft.charBuffer.rewind(); } } ft.prevFOTextThisBlock = null; @@ -162,29 +156,33 @@ public class FOText extends FONode { return ft; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { - commonFont = pList.getFontProps(); - commonHyphenation = pList.getHyphenationProps(); - color = pList.get(Constants.PR_COLOR).getColor(getUserAgent()); - keepTogether = pList.get(Constants.PR_KEEP_TOGETHER).getKeep(); - lineHeight = pList.get(Constants.PR_LINE_HEIGHT).getSpace(); - letterSpacing = pList.get(Constants.PR_LETTER_SPACING); - whiteSpaceCollapse = pList.get(Constants.PR_WHITE_SPACE_COLLAPSE).getEnum(); - whiteSpaceTreatment = pList.get(Constants.PR_WHITE_SPACE_TREATMENT).getEnum(); - textTransform = pList.get(Constants.PR_TEXT_TRANSFORM).getEnum(); - wordSpacing = pList.get(Constants.PR_WORD_SPACING); - wrapOption = pList.get(Constants.PR_WRAP_OPTION).getEnum(); - textDecoration = pList.getTextDecorationProps(); - baselineShift = pList.get(Constants.PR_BASELINE_SHIFT).getLength(); + this.commonFont = pList.getFontProps(); + this.commonHyphenation = pList.getHyphenationProps(); + this.color = pList.get(Constants.PR_COLOR).getColor(getUserAgent()); + this.keepTogether = pList.get(Constants.PR_KEEP_TOGETHER).getKeep(); + this.lineHeight = pList.get(Constants.PR_LINE_HEIGHT).getSpace(); + this.letterSpacing = pList.get(Constants.PR_LETTER_SPACING); + this.whiteSpaceCollapse = pList.get(Constants.PR_WHITE_SPACE_COLLAPSE).getEnum(); + this.whiteSpaceTreatment = pList.get(Constants.PR_WHITE_SPACE_TREATMENT).getEnum(); + this.textTransform = pList.get(Constants.PR_TEXT_TRANSFORM).getEnum(); + this.wordSpacing = pList.get(Constants.PR_WORD_SPACING); + this.wrapOption = pList.get(Constants.PR_WRAP_OPTION).getEnum(); + this.textDecoration = pList.getTextDecorationProps(); + this.baselineShift = pList.get(Constants.PR_BASELINE_SHIFT).getLength(); } /** {@inheritDoc} */ protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().characters( + this.getCharArray(), 0, this.charBuffer.limit()); + } + + /** {@inheritDoc} */ + public void finalizeNode() { textTransform(); - getFOEventHandler().characters(ca, startIndex, endIndex); } /** @@ -198,16 +196,20 @@ public class FOText extends FONode { */ public boolean willCreateArea() { if (whiteSpaceCollapse == Constants.EN_FALSE - && endIndex - startIndex > 0) { + && this.charBuffer.limit() > 0) { return true; } - for (int i = startIndex; i < endIndex; i++) { - char ch = ca[i]; - if (!((ch == ' ') - || (ch == '\n') - || (ch == '\r') - || (ch == '\t'))) { // whitespace + char ch; + this.charBuffer.rewind(); + while (this.charBuffer.hasRemaining()) { + ch = this.charBuffer.get(); + if (!((ch == CharUtilities.SPACE) + || (ch == CharUtilities.LINEFEED_CHAR) + || (ch == CharUtilities.CARRIAGE_RETURN) + || (ch == CharUtilities.TAB))) { + // not whitespace + this.charBuffer.rewind(); return true; } } @@ -222,7 +224,7 @@ public class FOText extends FONode { } /** - * This method is run as part of the ancestor Block's flushText(), to + * This method is run as part of the ancestor Block's flushText(), to * create xref pointers to the previous FOText objects within the same Block * @param ancestorBlock the ancestor fo:block */ @@ -230,7 +232,7 @@ public class FOText extends FONode { this.ancestorBlock = ancestorBlock; // if the last FOText is a sibling, point to it, and have it point here if (ancestorBlock.lastFOTextProcessed != null) { - if (ancestorBlock.lastFOTextProcessed.ancestorBlock + if (ancestorBlock.lastFOTextProcessed.ancestorBlock == this.ancestorBlock) { prevFOTextThisBlock = ancestorBlock.lastFOTextProcessed; prevFOTextThisBlock.nextFOTextThisBlock = this; @@ -241,16 +243,47 @@ public class FOText extends FONode { } /** - * This method is run as part of the Constructor, to handle the - * text-transform property. + * This method is run as part of endOfNode(), to handle the + * text-transform property for accumulated FOText */ private void textTransform() { - if (getFOEventHandler().inMarker() + if (getBuilderContext().inMarker() || textTransform == Constants.EN_NONE) { return; } - for (int i = 0; i < endIndex; i++) { - ca[i] = charTransform(i); + + this.charBuffer.rewind(); + CharBuffer tmp = this.charBuffer.slice(); + char c; + int lim = this.charBuffer.limit(); + int pos = -1; + while (++pos < lim) { + c = this.charBuffer.get(); + switch (textTransform) { + case Constants.EN_UPPERCASE: + tmp.put(Character.toUpperCase(c)); + break; + case Constants.EN_LOWERCASE: + tmp.put(Character.toLowerCase(c)); + break; + case Constants.EN_CAPITALIZE: + if (isStartOfWord(pos)) { + /* + Use toTitleCase here. Apparently, some languages use + a different character to represent a letter when using + initial caps than when all of the letters in the word + are capitalized. We will try to let Java handle this. + */ + tmp.put(Character.toTitleCase(c)); + } else { + tmp.put(c); + } + break; + default: + //should never happen as the property subsystem catches that case + assert false; + //nop + } } } @@ -261,7 +294,7 @@ public class FOText extends FONode { * well, such as word-spacing. The definition of "word" is somewhat ambiguous * and appears to be definable by the user agent. * - * @param i index into ca[] + * @param i index into charBuffer * * @return True if the character at this location is the start of a new * word. @@ -269,33 +302,33 @@ public class FOText extends FONode { private boolean isStartOfWord(int i) { char prevChar = getRelativeCharInBlock(i, -1); /* All we are really concerned about here is of what type prevChar - is. If inputChar is not part of a word, then the Java - conversions will (we hope) simply return inputChar. - */ - switch (isWordChar(prevChar)) { - case IS_WORD_CHAR_TRUE: - return false; - case IS_WORD_CHAR_FALSE: - return true; - /* "MAYBE" implies that additional context is needed. An example is a - * single-quote, either straight or closing, which might be interpreted - * as a possessive or a contraction, or might be a closing quote. + * is. If inputChar is not part of a word, then the Java + * conversions will (we hope) simply return inputChar. */ - case IS_WORD_CHAR_MAYBE: - char prevPrevChar = getRelativeCharInBlock(i, -2); - switch (isWordChar(prevPrevChar)) { + switch (isWordChar(prevChar)) { case IS_WORD_CHAR_TRUE: return false; case IS_WORD_CHAR_FALSE: return true; + /* "MAYBE" implies that additional context is needed. An example is a + * single-quote, either straight or closing, which might be interpreted + * as a possessive or a contraction, or might be a closing quote. + */ case IS_WORD_CHAR_MAYBE: - return true; + char prevPrevChar = getRelativeCharInBlock(i, -2); + switch (isWordChar(prevPrevChar)) { + case IS_WORD_CHAR_TRUE: + return false; + case IS_WORD_CHAR_FALSE: + return true; + case IS_WORD_CHAR_MAYBE: + return true; + default: + return false; + } default: return false; } - default: - return false; - } } /** @@ -304,7 +337,7 @@ public class FOText extends FONode { * block as one unit, allowing text in adjoining FOText objects to be * returned if the parameters are outside of the current object. * - * @param i index into ca[] + * @param i index into the CharBuffer * @param offset signed integer with relative position within the * block of the character to return. To return the character immediately * preceding i, pass -1. To return the character immediately after i, @@ -313,30 +346,34 @@ public class FOText extends FONode { * the offset points to an area outside of the block. */ private char getRelativeCharInBlock(int i, int offset) { + + int charIndex = i + offset; // The easy case is where the desired character is in the same FOText - if (((i + offset) >= 0) && ((i + offset) <= this.endIndex)) { - return ca[i + offset]; + if (charIndex >= 0 && charIndex < this.length()) { + return this.charAt(i + offset); } + // For now, we can't look at following FOText nodes if (offset > 0) { - return '\u0000'; - } + return CharUtilities.NULL_CHAR; + } + // Remaining case has the text in some previous FOText node boolean foundChar = false; - char charToReturn = '\u0000'; + char charToReturn = CharUtilities.NULL_CHAR; FOText nodeToTest = this; int remainingOffset = offset + i; while (!foundChar) { if (nodeToTest.prevFOTextThisBlock == null) { - foundChar = true; break; } nodeToTest = nodeToTest.prevFOTextThisBlock; - if ((nodeToTest.endIndex + remainingOffset) >= 0) { - charToReturn = nodeToTest.ca[nodeToTest.endIndex + remainingOffset]; + int diff = nodeToTest.length() + remainingOffset - 1; + if (diff >= 0) { + charToReturn = nodeToTest.charAt(diff); foundChar = true; } else { - remainingOffset = remainingOffset + nodeToTest.endIndex; + remainingOffset += diff; } } return charToReturn; @@ -366,39 +403,6 @@ public class FOText extends FONode { return ancestorBlock; } - /** - * Transforms one character in ca[] using the text-transform property. - * - * @param i the index into ca[] - * @return char with transformed value - */ - private char charTransform(int i) { - switch (textTransform) { - /* put NONE first, as this is probably the common case */ - case Constants.EN_NONE: - return ca[i]; - case Constants.EN_UPPERCASE: - return Character.toUpperCase(ca[i]); - case Constants.EN_LOWERCASE: - return Character.toLowerCase(ca[i]); - case Constants.EN_CAPITALIZE: - if (isStartOfWord(i)) { - /* - Use toTitleCase here. Apparently, some languages use - a different character to represent a letter when using - initial caps than when all of the letters in the word - are capitalized. We will try to let Java handle this. - */ - return Character.toTitleCase(ca[i]); - } else { - return ca[i]; - } - default: - assert false; //should never happen as the property subsystem catches that case - return ca[i]; - } - } - /** * Determines whether the input char should be considered part of a * "word". This is used primarily to determine whether the character @@ -484,57 +488,64 @@ public class FOText extends FONode { } private class TextCharIterator extends CharIterator { - private int curIndex = 0; - - /* Current space removal process: just increment the startIndex - to "remove" leading spaces from ca, until an unremoved character - is found. Then perform arraycopy's to remove extra spaces - between words. nextCharCalled is used to determine if an - unremoved character has already been found--if its value > 2 - than it means that has occurred (it is reset to zero each time we - remove a space via incrementing the startIndex.) */ - private int nextCharCalled = 0; - + + int currentPosition = 0; + + boolean canRemove = false; + boolean canReplace = false; + + /** {@inheritDoc} */ public boolean hasNext() { - if (curIndex == 0) { -// log.debug("->" + new String(ca) + "<-"); - } - return (curIndex < endIndex); + return (this.currentPosition < charBuffer.limit()); } + /** {@inheritDoc} */ public char nextChar() { - if (curIndex < endIndex) { - nextCharCalled++; - // Just a char class? Don't actually care about the value! - return ca[curIndex++]; + + if (this.currentPosition < charBuffer.limit()) { + this.canRemove = true; + this.canReplace = true; + return charBuffer.get(currentPosition++); } else { throw new NoSuchElementException(); } + } + /** {@inheritDoc} */ public void remove() { - if (curIndex < endIndex && nextCharCalled < 2) { - startIndex++; - nextCharCalled = 0; -// log.debug("removeA: " + new String(ca, startIndex, endIndex - startIndex)); - } else if (curIndex < endIndex) { - // copy from curIndex to end to curIndex-1 - System.arraycopy(ca, curIndex, ca, curIndex - 1, - endIndex - curIndex); - endIndex--; - curIndex--; -// log.debug("removeB: " + new String(ca, startIndex, endIndex - startIndex)); - } else if (curIndex == endIndex) { -// log.debug("removeC: " + new String(ca, startIndex, endIndex - startIndex)); - endIndex--; - curIndex--; + + if (this.canRemove) { + charBuffer.position(currentPosition); + // Slice the buffer at the current position + CharBuffer tmp = charBuffer.slice(); + // Reset position to before current character + charBuffer.position(--currentPosition); + if (tmp.hasRemaining()) { + // Transfer any remaining characters + charBuffer.mark(); + charBuffer.put(tmp); + charBuffer.reset(); + } + // Decrease limit + charBuffer.limit(charBuffer.limit() - 1); + // Make sure following calls fail, unless nextChar() was called + this.canRemove = false; + } else { + throw new IllegalStateException(); } + } + /** {@inheritDoc} */ public void replaceChar(char c) { - if (curIndex > 0 && curIndex <= endIndex) { - ca[curIndex - 1] = c; + + if (this.canReplace) { + charBuffer.put(currentPosition - 1, c); + } else { + throw new IllegalStateException(); } + } } @@ -560,7 +571,7 @@ public class FOText extends FONode { return color; } - /** + /** * @return the "keep-together" property. */ public KeepProperty getKeepTogether() { @@ -571,40 +582,40 @@ public class FOText extends FONode { * @return the "letter-spacing" property. */ public Property getLetterSpacing() { - return letterSpacing; + return letterSpacing; } - + /** * @return the "line-height" property. */ public SpaceProperty getLineHeight() { return lineHeight; } - + /** * @return the "white-space-treatment" property */ public int getWhitespaceTreatment() { return whiteSpaceTreatment; } - + /** * @return the "word-spacing" property. */ public Property getWordSpacing() { - return wordSpacing; + return wordSpacing; } - + /** * @return the "wrap-option" property. */ public int getWrapOption() { - return wrapOption; + return wrapOption; } - + /** @return the "text-decoration" property. */ public CommonTextDecoration getTextDecoration() { - return textDecoration; + return textDecoration; } /** @return the baseline-shift property */ @@ -614,14 +625,12 @@ public class FOText extends FONode { /** {@inheritDoc} */ public String toString() { - StringBuffer sb = new StringBuffer(super.toString()); - sb.append(" (").append(ca).append(")"); - return sb.toString(); + return (this.charBuffer == null) ? "" : this.charBuffer.toString(); } - + /** {@inheritDoc} */ public String getLocalName() { - return null; + return "#PCDATA"; } /** {@inheritDoc} */ @@ -631,10 +640,34 @@ public class FOText extends FONode { /** {@inheritDoc} */ protected String gatherContextInfo() { - if (getLocator() != null) { + if (this.locator != null) { return super.gatherContextInfo(); } else { - return new String(ca).trim(); + return this.toString(); + } + } + + /** {@inheritDoc} */ + public char charAt(int position) { + return this.charBuffer.get(position); + } + + /** {@inheritDoc} */ + public CharSequence subSequence(int start, int end) { + return this.charBuffer.subSequence(start, end); + } + + /** {@inheritDoc} */ + public int length() { + return this.charBuffer.limit(); + } + + /** + * Resets the backing java.nio.CharBuffer + */ + public void resetBuffer() { + if (this.charBuffer != null) { + this.charBuffer.rewind(); } - } -} \ No newline at end of file + } +} diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java index 84abc4b8b..6682ff703 100644 --- a/src/java/org/apache/fop/fo/FOTreeBuilder.java +++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java @@ -66,6 +66,9 @@ public class FOTreeBuilder extends DefaultHandler { /** Current delegate ContentHandler to receive the SAX events */ protected ContentHandler delegate; + + /** Provides information used during tree building stage. */ + private FOTreeBuilderContext builderContext; /** The object that handles formatting and rendering to a stream */ private FOEventHandler foEventHandler; @@ -101,7 +104,8 @@ public class FOTreeBuilder extends DefaultHandler { //one of the RTF-, MIF- etc. Handlers. foEventHandler = foUserAgent.getRendererFactory().createFOEventHandler( foUserAgent, outputFormat, stream); - foEventHandler.setPropertyListMaker(new PropertyListMaker() { + builderContext = new FOTreeBuilderContext(); + builderContext.setPropertyListMaker(new PropertyListMaker() { public PropertyList make(FObj fobj, PropertyList parentPropertyList) { return new StaticPropertyList(fobj, parentPropertyList); } @@ -140,7 +144,7 @@ public class FOTreeBuilder extends DefaultHandler { log.debug("Building formatting object tree"); } foEventHandler.startDocument(); - this.mainFOHandler = new MainFOHandler(); + this.mainFOHandler = new MainFOHandler(); this.mainFOHandler.startDocument(); this.delegate = this.mainFOHandler; } @@ -150,8 +154,7 @@ public class FOTreeBuilder extends DefaultHandler { this.delegate.endDocument(); if (this.rootFObj == null && empty) { FOValidationEventProducer eventProducer - = FOValidationEventProducer.Provider.get( - foEventHandler.getUserAgent().getEventBroadcaster()); + = FOValidationEventProducer.Provider.get(userAgent.getEventBroadcaster()); eventProducer.emptyDocument(this); } rootFObj = null; @@ -221,7 +224,7 @@ public class FOTreeBuilder extends DefaultHandler { } else { //No formatting results available for output formats no //involving the layout engine. - return null; + return null; } } @@ -254,7 +257,7 @@ public class FOTreeBuilder extends DefaultHandler { || !localName.equals("root")) { FOValidationEventProducer eventProducer = FOValidationEventProducer.Provider.get( - foEventHandler.getUserAgent().getEventBroadcaster()); + userAgent.getEventBroadcaster()); eventProducer.invalidFORoot(this, FONode.getNodeString(namespaceURI, localName), getEffectiveLocator()); } @@ -271,6 +274,7 @@ public class FOTreeBuilder extends DefaultHandler { foNode = fobjMaker.make(currentFObj); if (rootFObj == null) { rootFObj = (Root) foNode; + rootFObj.setBuilderContext(builderContext); rootFObj.setFOEventHandler(foEventHandler); } propertyList = foNode.createPropertyList( @@ -278,13 +282,12 @@ public class FOTreeBuilder extends DefaultHandler { foNode.processNode(localName, getEffectiveLocator(), attlist, propertyList); if (foNode.getNameId() == Constants.FO_MARKER) { - if (foEventHandler.inMarker()) { + if (builderContext.inMarker()) { nestedMarkerDepth++; } else { - foEventHandler.switchMarkerContext(true); + builderContext.switchMarkerContext(true); } } - foNode.startOfNode(); } catch (IllegalArgumentException e) { throw new SAXException(e); } @@ -310,9 +313,16 @@ public class FOTreeBuilder extends DefaultHandler { } currentFObj = foNode; - if (propertyList != null && !foEventHandler.inMarker()) { + if (propertyList != null && !builderContext.inMarker()) { currentPropertyList = propertyList; } + + // fo:characters can potentially be removed during + // white-space handling. + // Do not notify the FOEventHandler. + if (currentFObj.getNameId() != Constants.FO_CHARACTER) { + currentFObj.startOfNode(); + } } /** {@inheritDoc} */ @@ -329,17 +339,22 @@ public class FOTreeBuilder extends DefaultHandler { + ") vs. " + localName + " (" + uri + ")"); } - currentFObj.endOfNode(); + // fo:characters can potentially be removed during + // white-space handling. + // Do not notify the FOEventHandler. + if (currentFObj.getNameId() != Constants.FO_CHARACTER) { + currentFObj.endOfNode(); + } if (currentPropertyList != null && currentPropertyList.getFObj() == currentFObj - && !foEventHandler.inMarker()) { + && !builderContext.inMarker()) { currentPropertyList = currentPropertyList.getParentPropertyList(); } if (currentFObj.getNameId() == Constants.FO_MARKER) { if (nestedMarkerDepth == 0) { - foEventHandler.switchMarkerContext(false); + builderContext.switchMarkerContext(false); } else { nestedMarkerDepth--; } @@ -356,7 +371,7 @@ public class FOTreeBuilder extends DefaultHandler { public void characters(char[] data, int start, int length) throws FOPException { if (currentFObj != null) { - currentFObj.addCharacters(data, start, start + length, + currentFObj.addCharacters(data, start, length, currentPropertyList, getEffectiveLocator()); } } @@ -379,7 +394,7 @@ public class FOTreeBuilder extends DefaultHandler { if (maker instanceof UnknownXMLObj.Maker) { FOValidationEventProducer eventProducer = FOValidationEventProducer.Provider.get( - foEventHandler.getUserAgent().getEventBroadcaster()); + userAgent.getEventBroadcaster()); eventProducer.unknownFormattingObject(this, currentFObj.getName(), new QName(namespaceURI, localName), getEffectiveLocator()); diff --git a/src/java/org/apache/fop/fo/FOTreeBuilderContext.java b/src/java/org/apache/fop/fo/FOTreeBuilderContext.java new file mode 100644 index 000000000..0cbdd7797 --- /dev/null +++ b/src/java/org/apache/fop/fo/FOTreeBuilderContext.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo; + +import java.util.HashSet; +import java.util.Set; + +/** + * Context class providing information needed while building the FO tree. + */ +public class FOTreeBuilderContext { + + /** + * The current set of id's in the FO tree. + * This is used so we know if the FO tree contains duplicates. + */ + private Set idReferences = new HashSet(); + + /** + * The property list maker. + */ + protected PropertyListMaker propertyListMaker; + + /** + * The XMLWhitespaceHandler for this tree + */ + protected XMLWhiteSpaceHandler whiteSpaceHandler = new XMLWhiteSpaceHandler(); + + /** + * Indicates whether processing descendants of a marker + */ + private boolean inMarker = false; + + /** + * Returns the set of ID references. + * @return the ID references + */ + public Set getIDReferences() { + return idReferences; + } + + /** + * Return the propertyListMaker. + * + * @return the currently active {@link PropertyListMaker} + */ + public PropertyListMaker getPropertyListMaker() { + return propertyListMaker; + } + + /** + * Set a new propertyListMaker. + * + * @param propertyListMaker the new {@link PropertyListMaker} to use + */ + public void setPropertyListMaker(PropertyListMaker propertyListMaker) { + this.propertyListMaker = propertyListMaker; + } + + /** + * Return the XMLWhiteSpaceHandler + * @return the whiteSpaceHandler + */ + public XMLWhiteSpaceHandler getXMLWhiteSpaceHandler() { + return whiteSpaceHandler; + } + + /** + * Switch to or from marker context + * (used by FOTreeBuilder when processing + * a marker) + * + * @param inMarker true if a marker is being processed; + * false otherwise + * + */ + protected void switchMarkerContext(boolean inMarker) { + this.inMarker = inMarker; + } + + /** + * Check whether in marker context + * + * @return true if a marker is being processed + */ + protected boolean inMarker() { + return this.inMarker; + } + +} diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 150abda24..20573fa7a 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -130,7 +130,7 @@ public abstract class FObj extends FONode implements Constants { */ protected PropertyList createPropertyList(PropertyList parent, FOEventHandler foEventHandler) throws FOPException { - return foEventHandler.getPropertyListMaker().make(this, parent); + return getBuilderContext().getPropertyListMaker().make(this, parent); } /** @@ -165,7 +165,7 @@ public abstract class FObj extends FONode implements Constants { */ private void checkId(String id) throws ValidationException { if (!inMarker() && !id.equals("")) { - Set idrefs = getFOEventHandler().getIDReferences(); + Set idrefs = getBuilderContext().getIDReferences(); if (!idrefs.contains(id)) { idrefs.add(id); } else { diff --git a/src/java/org/apache/fop/fo/FObjMixed.java b/src/java/org/apache/fop/fo/FObjMixed.java index bf7383398..068c2d635 100644 --- a/src/java/org/apache/fop/fo/FObjMixed.java +++ b/src/java/org/apache/fop/fo/FObjMixed.java @@ -28,29 +28,29 @@ import org.apache.fop.apps.FOPException; * (= those that can contain both child {@link FONode}s and #PCDATA). */ public abstract class FObjMixed extends FObj { - + /** Represents accumulated, pending FO text. See {@link #flushText()}. */ - protected FOText ft = null; - + private FOText ft = null; + /** Used for white-space handling; start CharIterator at node ... */ protected FONode currentTextNode; - + /** Used in creating pointers between subsequent {@link FOText} nodes - * in the same {@link org.apache.fop.fo.flow.Block} + * in the same {@link org.apache.fop.fo.flow.Block} * (for handling text-transform) */ protected FOText lastFOTextProcessed = null; - + /** * Base constructor - * + * * @param parent FONode that is the parent of this object */ protected FObjMixed(FONode parent) { super(parent); } - + /** {@inheritDoc} */ - protected void addCharacters(char[] data, int start, int end, + protected void addCharacters(char[] data, int start, int length, PropertyList pList, Locator locator) throws FOPException { if (ft == null) { @@ -60,113 +60,124 @@ public abstract class FObjMixed extends FObj { ft.bind(pList); } } - ft.addCharacters(data, start, end, null, null); + ft.addCharacters(data, start, length, null, null); } /** {@inheritDoc} */ protected void endOfNode() throws FOPException { - flushText(); - if (!inMarker() - || getNameId() == FO_MARKER) { - getFOEventHandler().whiteSpaceHandler - .handleWhiteSpace(this, currentTextNode); - } + super.endOfNode(); + if (!inMarker() || getNameId() == FO_MARKER) { + // send character[s]() events to the FOEventHandler + sendCharacters(); + } + } /** - * Handles white-space for the node that is passed in, + * Handles white-space for the node that is passed in, * starting at its current text-node - * (used by {@link org.apache.fop.fo.flow.RetrieveMarker} + * (used by {@link org.apache.fop.fo.flow.RetrieveMarker} * to trigger 'end-of-node' white-space handling) - * + * * @param fobj the node for which to handle white-space + * @param nextChild the next child to be added */ - protected static void handleWhiteSpaceFor(FObjMixed fobj) { - fobj.getFOEventHandler().getXMLWhiteSpaceHandler() - .handleWhiteSpace(fobj, fobj.currentTextNode); + protected static void handleWhiteSpaceFor(FObjMixed fobj, FONode nextChild) { + fobj.getBuilderContext().getXMLWhiteSpaceHandler() + .handleWhiteSpace(fobj, fobj.currentTextNode, nextChild); } - + /** - * Adds accumulated text as one FOText instance, unless - * the one instance's char array contains more than - * Short.MAX_VALUE characters. In the latter case the - * instance is split up into more manageable chunks. - * + * Creates block-pointers between subsequent FOText nodes + * in the same Block. (used for handling text-transform) + * + * TODO: !! Revisit: does not take into account fo:characters !! + * * @throws FOPException if there is a problem during processing */ - protected void flushText() throws FOPException { + private void flushText() throws FOPException { if (ft != null) { FOText lft = ft; /* make sure nested calls to itself have no effect */ ft = null; - FOText tmpText; - int indexStart = 0; - int indexEnd = (lft.ca.length > Short.MAX_VALUE - ? Short.MAX_VALUE : lft.ca.length) - 1; - int charCount = 0; - short tmpSize; - while (charCount < lft.ca.length) { - tmpSize = (short) (indexEnd - indexStart + 1); - charCount += tmpSize; - tmpText = (FOText) lft.clone(this, false); - tmpText.ca = new char[tmpSize]; - tmpText.startIndex = 0; - tmpText.endIndex = tmpSize; - System.arraycopy(lft.ca, indexStart, - tmpText.ca, 0, indexEnd - indexStart + 1); - if (getNameId() == FO_BLOCK) { - tmpText.createBlockPointers((org.apache.fop.fo.flow.Block) this); - this.lastFOTextProcessed = tmpText; - } else if (getNameId() != FO_MARKER - && getNameId() != FO_TITLE - && getNameId() != FO_BOOKMARK_TITLE) { - FONode fo = parent; - int foNameId = fo.getNameId(); - while (foNameId != FO_BLOCK - && foNameId != FO_MARKER - && foNameId != FO_TITLE - && foNameId != FO_BOOKMARK_TITLE - && foNameId != FO_PAGE_SEQUENCE) { - fo = fo.getParent(); - foNameId = fo.getNameId(); - } - if (foNameId == FO_BLOCK) { - tmpText.createBlockPointers((org.apache.fop.fo.flow.Block) fo); - ((FObjMixed) fo).lastFOTextProcessed = tmpText; - } else if (foNameId == FO_PAGE_SEQUENCE - && tmpText.willCreateArea()) { - log.error("Could not create block pointers." - + " FOText w/o Block ancestor."); - } + if (getNameId() == FO_BLOCK) { + lft.createBlockPointers((org.apache.fop.fo.flow.Block) this); + this.lastFOTextProcessed = lft; + } else if (getNameId() != FO_MARKER + && getNameId() != FO_TITLE + && getNameId() != FO_BOOKMARK_TITLE) { + FONode fo = parent; + int foNameId = fo.getNameId(); + while (foNameId != FO_BLOCK + && foNameId != FO_MARKER + && foNameId != FO_TITLE + && foNameId != FO_BOOKMARK_TITLE + && foNameId != FO_PAGE_SEQUENCE) { + fo = fo.getParent(); + foNameId = fo.getNameId(); + } + if (foNameId == FO_BLOCK) { + lft.createBlockPointers((org.apache.fop.fo.flow.Block) fo); + ((FObjMixed) fo).lastFOTextProcessed = lft; + } else if (foNameId == FO_PAGE_SEQUENCE + && lft.willCreateArea()) { + log.error("Could not create block pointers." + + " FOText w/o Block ancestor."); + } + } + this.addChildNode(lft); + } + } + + private void sendCharacters() throws FOPException { + + if (this.currentTextNode != null) { + FONodeIterator nodeIter + = this.getChildNodes(this.currentTextNode); + FONode node; + while (nodeIter.hasNext()) { + node = nodeIter.nextNode(); + assert (node instanceof FOText + || node.getNameId() == FO_CHARACTER); + if (node.getNameId() == FO_CHARACTER) { + node.startOfNode(); } - tmpText.endOfNode(); - addChildNode(tmpText); - indexStart = indexEnd + 1; - indexEnd = (((lft.ca.length - charCount) < Short.MAX_VALUE) - ? lft.ca.length : charCount + Short.MAX_VALUE) - 1; + node.endOfNode(); } } + this.currentTextNode = null; } /** {@inheritDoc} */ protected void addChildNode(FONode child) throws FOPException { + flushText(); if (!inMarker()) { if (child instanceof FOText || child.getNameId() == FO_CHARACTER) { - if (currentTextNode == null) { - currentTextNode = child; + if (this.currentTextNode == null) { + this.currentTextNode = child; } } else { // handle white-space for all text up to here - getFOEventHandler().whiteSpaceHandler - .handleWhiteSpace(this, currentTextNode, child); - currentTextNode = null; + handleWhiteSpaceFor(this, child); + // send character[s]() events to the FOEventHandler + sendCharacters(); } } super.addChildNode(child); } - + + /** {@inheritDoc} */ + public void finalizeNode() throws FOPException { + + flushText(); + if (!inMarker() || getNameId() == FO_MARKER) { + handleWhiteSpaceFor(this, null); + } + + } + /** * Returns a {@link CharIterator} over this FO's character content * diff --git a/src/java/org/apache/fop/fo/RecursiveCharIterator.java b/src/java/org/apache/fop/fo/RecursiveCharIterator.java index 22ece76f3..a4aa28e37 100644 --- a/src/java/org/apache/fop/fo/RecursiveCharIterator.java +++ b/src/java/org/apache/fop/fo/RecursiveCharIterator.java @@ -113,7 +113,7 @@ public class RecursiveCharIterator extends CharIterator { */ public boolean hasNext() { while (curCharIter != null) { - if (curCharIter.hasNext() == false) { + if (!curCharIter.hasNext()) { getNextCharIter(); } else { return true; diff --git a/src/java/org/apache/fop/fo/expr/PropertyException.java b/src/java/org/apache/fop/fo/expr/PropertyException.java index 16055a738..d16d1c8ff 100644 --- a/src/java/org/apache/fop/fo/expr/PropertyException.java +++ b/src/java/org/apache/fop/fo/expr/PropertyException.java @@ -37,7 +37,7 @@ public class PropertyException extends FOPException { /** * Constructor - * @param the Exception causing this PropertyException + * @param cause the Exception causing this PropertyException */ public PropertyException(Exception cause) { super(cause); diff --git a/src/java/org/apache/fop/fo/extensions/xmp/XMPMetadata.java b/src/java/org/apache/fop/fo/extensions/xmp/XMPMetadata.java index f08b1f433..bdfd1fc29 100644 --- a/src/java/org/apache/fop/fo/extensions/xmp/XMPMetadata.java +++ b/src/java/org/apache/fop/fo/extensions/xmp/XMPMetadata.java @@ -22,7 +22,7 @@ package org.apache.fop.fo.extensions.xmp; import java.io.Serializable; import org.apache.fop.fo.extensions.ExtensionAttachment; -import org.apache.fop.util.XMLizable; +import org.apache.xmlgraphics.util.XMLizable; import org.apache.xmlgraphics.xmp.Metadata; import org.apache.xmlgraphics.xmp.XMPConstants; import org.xml.sax.ContentHandler; diff --git a/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java b/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java index 83a0ddbdc..c88147350 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java @@ -16,20 +16,22 @@ */ /* $Id$ */ + package org.apache.fop.fo.flow; +import java.util.Iterator; + +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOText; import org.apache.fop.fo.FObj; import org.apache.fop.fo.FObjMixed; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; -import org.apache.fop.fo.flow.table.TableFObj; import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.apps.FOPException; -import org.xml.sax.Locator; - -import java.util.Iterator; +import org.apache.fop.fo.flow.table.TableFObj; /** * Abstract base class for the @@ -80,7 +82,7 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { } private PropertyList createPropertyListFor(FObj fo, PropertyList parent) { - return getFOEventHandler().getPropertyListMaker().make(fo, parent); + return getBuilderContext().getPropertyListMaker().make(fo, parent); } private void cloneSingleNode(FONode child, FONode newParent, @@ -100,16 +102,10 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { getLocator(), pList, newPropertyList); - if (newChild instanceof TableFObj) { - // TODO calling startOfNode (and endOfNode, below) on other fobjs may - // have undesirable side-effects. This is really ugly and will need to - // be addressed sooner or later - ((TableFObj) newChild).startOfNode(); - } addChildTo(newChild, (FObj) newParent); if (newChild.getNameId() == FO_TABLE) { Table t = (Table) child; - cloneSubtree(t.getColumns().listIterator(), + cloneSubtree(t.getColumns().iterator(), newChild, marker, newPropertyList); cloneSingleNode(t.getTableHeader(), newChild, marker, newPropertyList); @@ -118,18 +114,15 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { } cloneSubtree(child.getChildNodes(), newChild, marker, newPropertyList); - if (newChild instanceof TableFObj) { - // TODO this is ugly - ((TableFObj) newChild).endOfNode(); - } } else if (child instanceof FOText) { FOText ft = (FOText) newChild; ft.bind(parentPropertyList); addChildTo(newChild, (FObj) newParent); } - if (newChild instanceof FObjMixed) { - handleWhiteSpaceFor((FObjMixed) newChild); - } + + // trigger end-of-node white-space handling + // and finalization for table-FOs + newChild.finalizeNode(); } } @@ -167,7 +160,7 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { } cloneSubtree(marker.getChildNodes(), this, marker, propertyList); - handleWhiteSpaceFor(this); + handleWhiteSpaceFor(this, null); } /** diff --git a/src/java/org/apache/fop/fo/flow/Marker.java b/src/java/org/apache/fop/fo/flow/Marker.java index 7eda2101e..ea6721686 100644 --- a/src/java/org/apache/fop/fo/flow/Marker.java +++ b/src/java/org/apache/fop/fo/flow/Marker.java @@ -26,8 +26,8 @@ import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; -import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FOTreeBuilderContext; import org.apache.fop.fo.FObj; import org.apache.fop.fo.FObjMixed; import org.apache.fop.fo.PropertyList; @@ -84,10 +84,10 @@ public class Marker extends FObjMixed { /** {@inheritDoc} */ protected void startOfNode() { - FOEventHandler foEventHandler = getFOEventHandler(); + FOTreeBuilderContext builderContext = getBuilderContext(); // Push a new property list maker which will make MarkerPropertyLists. - savePropertyListMaker = foEventHandler.getPropertyListMaker(); - foEventHandler.setPropertyListMaker(new PropertyListMaker() { + savePropertyListMaker = builderContext.getPropertyListMaker(); + builderContext.setPropertyListMaker(new PropertyListMaker() { public PropertyList make(FObj fobj, PropertyList parentPropertyList) { PropertyList pList = new MarkerPropertyList(fobj, parentPropertyList); descendantPropertyLists.put(fobj, pList); @@ -100,7 +100,7 @@ public class Marker extends FObjMixed { protected void endOfNode() throws FOPException { super.endOfNode(); // Pop the MarkerPropertyList maker. - getFOEventHandler().setPropertyListMaker(savePropertyListMaker); + getBuilderContext().setPropertyListMaker(savePropertyListMaker); savePropertyListMaker = null; } diff --git a/src/java/org/apache/fop/fo/flow/table/BorderResolver.java b/src/java/org/apache/fop/fo/flow/table/BorderResolver.java index 5322b08d3..82bdac845 100644 --- a/src/java/org/apache/fop/fo/flow/table/BorderResolver.java +++ b/src/java/org/apache/fop/fo/flow/table/BorderResolver.java @@ -40,7 +40,7 @@ interface BorderResolver { * * @param part the part that has started */ - void startPart(TableBody part); + void startPart(TablePart part); /** * Receives notification of the end of a table-header/footer/body. diff --git a/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java index 2d48380ee..3a887166a 100644 --- a/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java +++ b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java @@ -73,7 +73,7 @@ class CollapsingBorderResolver implements BorderResolver { */ private abstract class Resolver { - protected TableBody tablePart; + protected TablePart tablePart; protected boolean firstInPart; @@ -177,7 +177,7 @@ class CollapsingBorderResolver implements BorderResolver { } } - void startPart(TableBody part) { + void startPart(TablePart part) { tablePart = part; firstInPart = true; borderStartTableAndBody = collapsingBorderModel.determineWinner(table.borderStart, @@ -415,8 +415,8 @@ class CollapsingBorderResolver implements BorderResolver { } /** {@inheritDoc} */ - public void startPart(TableBody part) { - if (part.isTableHeader()) { + public void startPart(TablePart part) { + if (part instanceof TableHeader) { delegate = new ResolverInHeader(); } else { if (leadingBorders == null || table.omitHeaderAtBreak()) { @@ -427,7 +427,7 @@ class CollapsingBorderResolver implements BorderResolver { leadingBorders.add(border); } } - if (part.isTableFooter()) { + if (part instanceof TableFooter) { resolverInFooter = new ResolverInFooter(); delegate = resolverInFooter; } else { diff --git a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java index 0d24491d9..a7719528a 100644 --- a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java @@ -143,8 +143,8 @@ class FixedColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void endRow(TableBody body) { - handleRowEnd(body); + void endRow(TablePart part) { + handleRowEnd(part); } private void handleRowEnd(TableCellContainer container) { @@ -172,7 +172,7 @@ class FixedColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void startTablePart(TableBody part) { + void startTablePart(TablePart part) { firstInPart = true; borderResolver.startPart(part); } diff --git a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java index 915208e2d..a4b064a53 100644 --- a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java @@ -78,12 +78,12 @@ public class PrimaryGridUnit extends GridUnit { * * @return the enclosing table part */ - public TableBody getTableBody() { + public TablePart getTablePart() { FONode node = cell.getParent(); if (node instanceof TableRow) { node = node.getParent(); } - return (TableBody) node; + return (TablePart) node; } public TableCellLayoutManager getCellLM() { diff --git a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java index c954be711..9748a77aa 100644 --- a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java @@ -57,7 +57,7 @@ abstract class RowGroupBuilder { /** * Receives notification of the end of the current row. If the current row finishes - * the row group, the {@link TableBody#addRowGroup(List)} method of the parent table + * the row group, the {@link TablePart#addRowGroup(List)} method of the parent table * part will be called. */ abstract void endTableRow(); @@ -65,21 +65,21 @@ abstract class RowGroupBuilder { /** * Receives notification of the end of the current row, when the source contains no * fo:table-row element. If the current row finishes the row group, the - * {@link TableBody#addRowGroup(List)} method of the given table part will be called. + * {@link TablePart#addRowGroup(List)} method of the given table part will be called. * *

If the source does contain explicit fo:table-row elements, then the * {@link #endTableRow()} method will be called instead.

* * @param part the part containing the current row */ - abstract void endRow(TableBody part); + abstract void endRow(TablePart part); /** * Receives notification of the start of a table-header/footer/body. * * @param part the part being started */ - abstract void startTablePart(TableBody part); + abstract void startTablePart(TablePart part); /** * Receives notification of the end of a table-header/footer/body. The current diff --git a/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java index c6d46ecf5..afd05823b 100644 --- a/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java +++ b/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java @@ -31,7 +31,7 @@ class SeparateBorderResolver implements BorderResolver { } /** {@inheritDoc} */ - public void startPart(TableBody part) { + public void startPart(TablePart part) { } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/flow/table/Table.java b/src/java/org/apache/fop/fo/flow/table/Table.java index 5b96a668e..9feb77c9c 100644 --- a/src/java/org/apache/fop/fo/flow/table/Table.java +++ b/src/java/org/apache/fop/fo/flow/table/Table.java @@ -76,8 +76,8 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { private ColumnNumberManager columnNumberManager = new ColumnNumberManager(); /** the table-header and -footer */ - private TableBody tableHeader = null; - private TableBody tableFooter = null; + private TableHeader tableHeader = null; + private TableFooter tableFooter = null; /** used for validation */ private boolean tableColumnFound = false; @@ -157,10 +157,8 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { this.propList = pList; } - /** - * {@inheritDoc} - */ - public void startOfNode() throws FOPException { + /** {@inheritDoc} */ + protected void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startTable(this); } @@ -200,7 +198,9 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } else { tableFooterFound = true; if (tableBodyFound) { - nodesOutOfOrderError(loc, "fo:table-footer", "(table-body+)", true); + if (getUserAgent().validateStrictly()) { + nodesOutOfOrderError(loc, "fo:table-footer", "(table-body+)", true); + } if (!isSeparateBorderModel()) { TableEventProducer eventProducer = TableEventProducer.Provider.get( getUserAgent().getEventBroadcaster()); @@ -216,11 +216,15 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } } - /** - * {@inheritDoc} - */ - public void endOfNode() throws FOPException { + /** {@inheritDoc} */ + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endTable(this); + } + /** {@inheritDoc} */ + public void finalizeNode() throws FOPException { + if (!tableBodyFound) { missingChildElementError( "(marker*,table-column*,table-header?,table-footer?" @@ -242,13 +246,10 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { this.propList = null; rowGroupBuilder = null; } - getFOEventHandler().endTable(this); - + } - - /** - * {@inheritDoc} - */ + + /** {@inheritDoc} */ protected void addChildNode(FONode child) throws FOPException { int childId = child.getNameId(); @@ -277,10 +278,10 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } switch (childId) { case FO_TABLE_FOOTER: - tableFooter = (TableBody) child; + tableFooter = (TableFooter) child; break; case FO_TABLE_HEADER: - tableHeader = (TableBody) child; + tableHeader = (TableHeader) child; break; default: super.addChildNode(child); @@ -402,12 +403,12 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } /** @return the body for the table-header. */ - public TableBody getTableHeader() { + public TableHeader getTableHeader() { return tableHeader; } /** @return the body for the table-footer. */ - public TableBody getTableFooter() { + public TableFooter getTableFooter() { return tableFooter; } @@ -521,17 +522,17 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { return FO_TABLE; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public FONode clone(FONode parent, boolean removeChildren) throws FOPException { Table clone = (Table) super.clone(parent, removeChildren); - clone.columnsFinalized = false; if (removeChildren) { clone.columns = new ArrayList(); + clone.columnsFinalized = false; + clone.columnNumberManager = new ColumnNumberManager(); clone.tableHeader = null; clone.tableFooter = null; + clone.rowGroupBuilder = null; } return clone; } diff --git a/src/java/org/apache/fop/fo/flow/table/TableBody.java b/src/java/org/apache/fop/fo/flow/table/TableBody.java index b4e48d2e6..b4071e255 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/table/TableBody.java @@ -15,53 +15,18 @@ * limitations under the License. */ -/* $Id$ */ +/* $Id: $ */ package org.apache.fop.fo.flow.table; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.xml.sax.Attributes; -import org.xml.sax.Locator; - -import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.PropertyList; -import org.apache.fop.fo.ValidationException; -import org.apache.fop.fo.properties.CommonBorderPaddingBackground; +import org.apache.fop.apps.FOPException; /** * Class modelling the
* fo:table-body object. */ -public class TableBody extends TableCellContainer { - // The value of properties relevant for fo:table-body. - private CommonBorderPaddingBackground commonBorderPaddingBackground; - // Unused but valid items, commented out for performance: - // private CommonAccessibility commonAccessibility; - // private CommonAural commonAural; - // private CommonRelativePosition commonRelativePosition; - // private int visibility; - // End of property values - - /** - * used for validation - */ - protected boolean tableRowsFound = false; - protected boolean tableCellsFound = false; - - private boolean firstRow = true; - - private boolean rowsStarted = false; - - private boolean lastCellEndsRow = true; - - /** The last encountered table-row. */ - private TableRow lastRow; - - private List rowGroups = new LinkedList(); +public class TableBody extends TablePart { /** * Create a TableBody instance with the given {@link FONode} @@ -73,159 +38,15 @@ public class TableBody extends TableCellContainer { } /** {@inheritDoc} */ - public void bind(PropertyList pList) throws FOPException { - commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); - super.bind(pList); - } - - /** {@inheritDoc} */ - public void processNode(String elementName, Locator locator, - Attributes attlist, PropertyList pList) - throws FOPException { - if (!inMarker()) { - Table t = getTable(); - if (t.hasExplicitColumns()) { - int size = t.getNumberOfColumns(); - pendingSpans = new ArrayList(size); - for (int i = 0; i < size; i++) { - pendingSpans.add(null); - } - } else { - pendingSpans = new ArrayList(); - } - columnNumberManager = new ColumnNumberManager(); - } - super.processNode(elementName, locator, attlist, pList); - } - - /** {@inheritDoc} */ - public void startOfNode() throws FOPException { + protected void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startBody(this); } /** {@inheritDoc} */ - public void endOfNode() throws FOPException { - - if (!inMarker()) { - pendingSpans = null; - columnNumberManager = null; - } - + protected void endOfNode() throws FOPException { + super.endOfNode(); getFOEventHandler().endBody(this); - - if (!(tableRowsFound || tableCellsFound)) { - missingChildElementError("marker* (table-row+|table-cell+)", true); - getParent().removeChild(this); - } else { - finishLastRowGroup(); - } - } - - /** {@inheritDoc} */ - TableBody getTablePart() { - return this; - } - - protected void finishLastRowGroup() throws ValidationException { - if (!inMarker()) { - RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); - if (tableRowsFound) { - rowGroupBuilder.endTableRow(); - } else if (!lastCellEndsRow) { - rowGroupBuilder.endRow(this); - } - try { - rowGroupBuilder.endTablePart(); - } catch (ValidationException e) { - e.setLocator(locator); - throw e; - } - } - } - - /** - * {@inheritDoc} - *
XSL Content Model: marker* (table-row+|table-cell+) - */ - protected void validateChildNode(Locator loc, String nsURI, String localName) - throws ValidationException { - if (FO_URI.equals(nsURI)) { - if (localName.equals("marker")) { - if (tableRowsFound || tableCellsFound) { - nodesOutOfOrderError(loc, "fo:marker", "(table-row+|table-cell+)"); - } - } else if (localName.equals("table-row")) { - tableRowsFound = true; - if (tableCellsFound) { - TableEventProducer eventProducer = TableEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.noMixRowsAndCells(this, getName(), getLocator()); - } - } else if (localName.equals("table-cell")) { - tableCellsFound = true; - if (tableRowsFound) { - TableEventProducer eventProducer = TableEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.noMixRowsAndCells(this, getName(), getLocator()); - } - } else { - invalidChildError(loc, nsURI, localName); - } - } - } - - /** {@inheritDoc} */ - protected void addChildNode(FONode child) throws FOPException { - if (!inMarker()) { - switch (child.getNameId()) { - case FO_TABLE_ROW: - if (!rowsStarted) { - getTable().getRowGroupBuilder().startTablePart(this); - } else { - columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().endTableRow(); - } - rowsStarted = true; - lastRow = (TableRow) child; - getTable().getRowGroupBuilder().startTableRow(lastRow); - break; - case FO_TABLE_CELL: - if (!rowsStarted) { - getTable().getRowGroupBuilder().startTablePart(this); - } - rowsStarted = true; - TableCell cell = (TableCell) child; - addTableCellChild(cell, firstRow); - lastCellEndsRow = cell.endsRow(); - if (lastCellEndsRow) { - firstRow = false; - columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().endRow(this); - } - break; - default: - //nop - } - } - super.addChildNode(child); - } - - void addRowGroup(List rowGroup) { - rowGroups.add(rowGroup); - } - - public List getRowGroups() { - return rowGroups; - } - - /** - * Get the {@link CommonBorderPaddingBackground} instance attached - * to this TableBody. - * @return the {@link CommonBorderPaddingBackground} instance. - */ - public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { - return commonBorderPaddingBackground; } /** {@inheritDoc} */ @@ -240,32 +61,4 @@ public class TableBody extends TableCellContainer { public int getNameId() { return FO_TABLE_BODY; } - - protected boolean isTableHeader() { - return false; - } - - protected boolean isTableFooter() { - return false; - } - - /** - * @param obj table row in question - * @return true if the given table row is the first row of this body. - */ - public boolean isFirst(TableRow obj) { - return (firstChild == null - || firstChild == obj); - } - - void signalNewRow() { - if (rowsStarted) { - firstRow = false; - if (!lastCellEndsRow) { - columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().endRow(this); - } - } - } - } diff --git a/src/java/org/apache/fop/fo/flow/table/TableCell.java b/src/java/org/apache/fop/fo/flow/table/TableCell.java index 2781bf082..21da54128 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCell.java @@ -81,7 +81,7 @@ public class TableCell extends TableFObj { startsRow = pList.get(PR_STARTS_ROW).getEnum(); // For properly computing columnNumber if (startsRow() && getParent().getNameId() != FO_TABLE_ROW) { - ((TableBody) getParent()).signalNewRow(); + ((TablePart) getParent()).signalNewRow(); } endsRow = pList.get(PR_ENDS_ROW).getEnum(); columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric().getValue(); @@ -91,17 +91,24 @@ public class TableCell extends TableFObj { } /** {@inheritDoc} */ - public void startOfNode() throws FOPException { + protected void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startCell(this); } /** * Make sure content model satisfied, if so then tell the - * FOEventHandler that we are at the end of the flow. + * FOEventHandler that we are at the end of the table-cell. * {@inheritDoc} */ - public void endOfNode() throws FOPException { + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endCell(this); + } + + /** {@inheritDoc} */ + public void finalizeNode() throws FOPException { + if (!blockItemFound) { missingChildElementError("marker* (%block;)+", true); } @@ -111,9 +118,9 @@ public class TableCell extends TableFObj { getUserAgent().getEventBroadcaster()); eventProducer.startEndRowUnderTableRowWarning(this, getLocator()); } - getFOEventHandler().endCell(this); + } - + /** * {@inheritDoc} *
XSL Content Model: marker* (%block;)+ diff --git a/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java b/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java index de9f271b5..1d1a29b35 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java @@ -95,9 +95,9 @@ public abstract class TableCellContainer extends TableFObj implements ColumnNumb /** * Returns the enclosing table-header/footer/body of this container. * - * @return this for TableBody, or the parent element for TableRow + * @return this for TablePart, or the parent element for TableRow */ - abstract TableBody getTablePart(); + abstract TablePart getTablePart(); /** {@inheritDoc} */ public ColumnNumberManager getColumnNumberManager() { diff --git a/src/java/org/apache/fop/fo/flow/table/TableColumn.java b/src/java/org/apache/fop/fo/flow/table/TableColumn.java index 6916e090b..025f5a74f 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableColumn.java +++ b/src/java/org/apache/fop/fo/flow/table/TableColumn.java @@ -239,7 +239,7 @@ public class TableColumn extends TableFObj { sb.append(" number-columns-spanned=") .append(getNumberColumnsSpanned()); } - sb.append(" column-width=").append(getColumnWidth()); + sb.append(" column-width=").append(((Property)getColumnWidth()).getString()); return sb.toString(); } diff --git a/src/java/org/apache/fop/fo/flow/table/TableFObj.java b/src/java/org/apache/fop/fo/flow/table/TableFObj.java index 016046ae2..370bb9de4 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFObj.java @@ -34,6 +34,8 @@ import org.apache.fop.fo.properties.NumberProperty; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.PropertyMaker; import org.apache.fop.layoutmgr.table.CollapsingBorderModel; +import org.xml.sax.Locator; +import org.xml.sax.Attributes; /** * Common base class for table-related FOs @@ -207,8 +209,8 @@ public abstract class TableFObj extends FObj { } /** {@inheritDoc} */ - public void startOfNode() throws FOPException { - super.startOfNode(); + public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException { + super.processNode(elementName, locator, attlist, pList); Table table = getTable(); if (!inMarker() && !table.isSeparateBorderModel()) { collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table @@ -216,15 +218,7 @@ public abstract class TableFObj extends FObj { setCollapsedBorders(); } } - - /* - * TODO made public so that RetrieveMarker can access it. - */ - /** {@inheritDoc} */ - public void endOfNode() throws FOPException { - super.endOfNode(); - } - + /** * Prepares the borders of this element if the collapsing-border model is in use. * Conflict resolution with parent elements is done where applicable. diff --git a/src/java/org/apache/fop/fo/flow/table/TableFooter.java b/src/java/org/apache/fop/fo/flow/table/TableFooter.java index d05824e95..a89a2e431 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFooter.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFooter.java @@ -28,7 +28,7 @@ import org.apache.fop.fo.FONode; * Class modelling the * fo:table-footer object. */ -public class TableFooter extends TableBody { +public class TableFooter extends TablePart { /** * Create a TableFooter instance with the given {@link FONode} @@ -41,17 +41,15 @@ public class TableFooter extends TableBody { } /** {@inheritDoc} */ - public void startOfNode() throws FOPException { + protected void startOfNode() throws FOPException { super.startOfNode(); + getFOEventHandler().startFooter(this); } /** {@inheritDoc} */ - public void endOfNode() throws FOPException { - if (!(tableRowsFound || tableCellsFound)) { - missingChildElementError("marker* (table-row+|table-cell+)"); - } else { - finishLastRowGroup(); - } + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endFooter(this); } /** {@inheritDoc} */ @@ -67,8 +65,4 @@ public class TableFooter extends TableBody { return FO_TABLE_FOOTER; } - /** {@inheritDoc} */ - protected boolean isTableFooter() { - return true; - } } diff --git a/src/java/org/apache/fop/fo/flow/table/TableHeader.java b/src/java/org/apache/fop/fo/flow/table/TableHeader.java index 252ba1b8b..7f4173754 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableHeader.java +++ b/src/java/org/apache/fop/fo/flow/table/TableHeader.java @@ -28,7 +28,7 @@ import org.apache.fop.fo.FONode; * Class modelling the * fo:table-header object. */ -public class TableHeader extends TableBody { +public class TableHeader extends TablePart { /** * Create a TableHeader instance with the given {@link FONode} @@ -40,17 +40,15 @@ public class TableHeader extends TableBody { } /** {@inheritDoc} */ - public void startOfNode() throws FOPException { + protected void startOfNode() throws FOPException { super.startOfNode(); + getFOEventHandler().startHeader(this); } /** {@inheritDoc} */ - public void endOfNode() throws FOPException { - if (!(tableRowsFound || tableCellsFound)) { - missingChildElementError("marker* (table-row+|table-cell+)"); - } else { - finishLastRowGroup(); - } + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endHeader(this); } /** {@inheritDoc} */ @@ -66,8 +64,4 @@ public class TableHeader extends TableBody { return FO_TABLE_HEADER; } - /** {@inheritDoc} */ - protected boolean isTableHeader() { - return true; - } } diff --git a/src/java/org/apache/fop/fo/flow/table/TablePart.java b/src/java/org/apache/fop/fo/flow/table/TablePart.java new file mode 100644 index 000000000..4d20db8c4 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/TablePart.java @@ -0,0 +1,239 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id: TableBody.java 655614 2008-05-12 19:37:39Z vhennebert $ */ + +package org.apache.fop.fo.flow.table; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; + +/** + * An abstract base class modelling a TablePart + * (i.e. fo:table-header, fo:table-footer and fo:table-body). + */ +public abstract class TablePart extends TableCellContainer { + // The value of properties relevant for fo:table-body. + private CommonBorderPaddingBackground commonBorderPaddingBackground; + // Unused but valid items, commented out for performance: + // private CommonAccessibility commonAccessibility; + // private CommonAural commonAural; + // private CommonRelativePosition commonRelativePosition; + // private int visibility; + // End of property values + + /** + * used for validation + */ + protected boolean tableRowsFound = false; + protected boolean tableCellsFound = false; + + private boolean firstRow = true; + + private boolean rowsStarted = false; + + private boolean lastCellEndsRow = true; + + private List rowGroups = new LinkedList(); + + /** + * Create a TablePart instance with the given {@link FONode} + * as parent. + * @param parent FONode that is the parent of the object + */ + public TablePart(FONode parent) { + super(parent); + } + + /** {@inheritDoc} */ + public void bind(PropertyList pList) throws FOPException { + commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); + super.bind(pList); + } + + /** {@inheritDoc} */ + public void processNode(String elementName, Locator locator, + Attributes attlist, PropertyList pList) + throws FOPException { + + super.processNode(elementName, locator, attlist, pList); + if (!inMarker()) { + Table t = getTable(); + if (t.hasExplicitColumns()) { + int size = t.getNumberOfColumns(); + pendingSpans = new ArrayList(size); + for (int i = 0; i < size; i++) { + pendingSpans.add(null); + } + } else { + pendingSpans = new ArrayList(); + } + columnNumberManager = new ColumnNumberManager(); + } + + } + + /** {@inheritDoc} */ + public void finalizeNode() throws FOPException { + if (!inMarker()) { + pendingSpans = null; + columnNumberManager = null; + } + + if (!(tableRowsFound || tableCellsFound)) { + missingChildElementError("marker* (table-row+|table-cell+)", true); + getParent().removeChild(this); + } else { + finishLastRowGroup(); + } + } + + /** {@inheritDoc} */ + TablePart getTablePart() { + return this; + } + + protected void finishLastRowGroup() throws ValidationException { + if (!inMarker()) { + RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); + if (tableRowsFound) { + rowGroupBuilder.endTableRow(); + } else if (!lastCellEndsRow) { + rowGroupBuilder.endRow(this); + } + try { + rowGroupBuilder.endTablePart(); + } catch (ValidationException e) { + e.setLocator(locator); + throw e; + } + } + } + + /** + * {@inheritDoc} + *
XSL Content Model: marker* (table-row+|table-cell+) + */ + protected void validateChildNode(Locator loc, String nsURI, String localName) + throws ValidationException { + if (FO_URI.equals(nsURI)) { + if (localName.equals("marker")) { + if (tableRowsFound || tableCellsFound) { + nodesOutOfOrderError(loc, "fo:marker", "(table-row+|table-cell+)"); + } + } else if (localName.equals("table-row")) { + tableRowsFound = true; + if (tableCellsFound) { + TableEventProducer eventProducer = TableEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.noMixRowsAndCells(this, getName(), getLocator()); + } + } else if (localName.equals("table-cell")) { + tableCellsFound = true; + if (tableRowsFound) { + TableEventProducer eventProducer = TableEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.noMixRowsAndCells(this, getName(), getLocator()); + } + } else { + invalidChildError(loc, nsURI, localName); + } + } + } + + /** {@inheritDoc} */ + protected void addChildNode(FONode child) throws FOPException { + if (!inMarker()) { + switch (child.getNameId()) { + case FO_TABLE_ROW: + if (!rowsStarted) { + getTable().getRowGroupBuilder().startTablePart(this); + } else { + columnNumberManager.prepareForNextRow(pendingSpans); + getTable().getRowGroupBuilder().endTableRow(); + } + rowsStarted = true; + getTable().getRowGroupBuilder().startTableRow((TableRow)child); + break; + case FO_TABLE_CELL: + if (!rowsStarted) { + getTable().getRowGroupBuilder().startTablePart(this); + } + rowsStarted = true; + TableCell cell = (TableCell) child; + addTableCellChild(cell, firstRow); + lastCellEndsRow = cell.endsRow(); + if (lastCellEndsRow) { + firstRow = false; + columnNumberManager.prepareForNextRow(pendingSpans); + getTable().getRowGroupBuilder().endRow(this); + } + break; + default: + //nop + } + } + super.addChildNode(child); + } + + void addRowGroup(List rowGroup) { + rowGroups.add(rowGroup); + } + + public List getRowGroups() { + return rowGroups; + } + + /** + * Get the {@link CommonBorderPaddingBackground} instance attached + * to this TableBody. + * @return the {@link CommonBorderPaddingBackground} instance. + */ + public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { + return commonBorderPaddingBackground; + } + + /** + * @param obj table row in question + * @return true if the given table row is the first row of this body. + */ + public boolean isFirst(TableRow obj) { + return (firstChild == null + || firstChild == obj); + } + + void signalNewRow() { + if (rowsStarted) { + firstRow = false; + if (!lastCellEndsRow) { + columnNumberManager.prepareForNextRow(pendingSpans); + getTable().getRowGroupBuilder().endRow(this); + } + } + } + +} diff --git a/src/java/org/apache/fop/fo/flow/table/TableRow.java b/src/java/org/apache/fop/fo/flow/table/TableRow.java index 3be794fbd..ac6eafc2f 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableRow.java +++ b/src/java/org/apache/fop/fo/flow/table/TableRow.java @@ -78,32 +78,38 @@ public class TableRow extends TableCellContainer { /** {@inheritDoc} */ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException { + super.processNode(elementName, locator, attlist, pList); if (!inMarker()) { - TableBody body = (TableBody) parent; - pendingSpans = body.pendingSpans; - columnNumberManager = body.columnNumberManager; + TablePart part = (TablePart) parent; + pendingSpans = part.pendingSpans; + columnNumberManager = part.columnNumberManager; } - super.processNode(elementName, locator, attlist, pList); } /** {@inheritDoc} */ protected void addChildNode(FONode child) throws FOPException { if (!inMarker()) { TableCell cell = (TableCell) child; - TableBody body = (TableBody) getParent(); - addTableCellChild(cell, body.isFirst(this)); + TablePart part = (TablePart) getParent(); + addTableCellChild(cell, part.isFirst(this)); } super.addChildNode(child); } /** {@inheritDoc} */ - public void startOfNode() throws FOPException { + protected void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startRow(this); } /** {@inheritDoc} */ - public void endOfNode() throws FOPException { + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endRow(this); + } + + /** {@inheritDoc} */ + public void finalizeNode() throws FOPException { if (firstChild == null) { missingChildElementError("(table-cell+)"); } @@ -111,9 +117,8 @@ public class TableRow extends TableCellContainer { pendingSpans = null; columnNumberManager = null; } - getFOEventHandler().endRow(this); } - + /** * {@inheritDoc} String, String) *
XSL Content Model: (table-cell+) @@ -129,8 +134,8 @@ public class TableRow extends TableCellContainer { } /** {@inheritDoc} */ - TableBody getTablePart() { - return (TableBody) parent; + TablePart getTablePart() { + return (TablePart) parent; } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java index d59870f0a..23c16d1f2 100644 --- a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java @@ -82,7 +82,7 @@ class VariableColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void endRow(final TableBody part) { + void endRow(final TablePart part) { events.add(new Event() { public void play(RowGroupBuilder rowGroupBuilder) { rowGroupBuilder.endRow(part); @@ -91,7 +91,7 @@ class VariableColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void startTablePart(final TableBody part) { + void startTablePart(final TablePart part) { events.add(new Event() { public void play(RowGroupBuilder rowGroupBuilder) { rowGroupBuilder.startTablePart(part); diff --git a/src/java/org/apache/fop/fo/pagination/Root.java b/src/java/org/apache/fop/fo/pagination/Root.java index 04014f6fc..c6346e9fb 100644 --- a/src/java/org/apache/fop/fo/pagination/Root.java +++ b/src/java/org/apache/fop/fo/pagination/Root.java @@ -27,6 +27,7 @@ import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FOTreeBuilderContext; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; @@ -58,6 +59,11 @@ public class Root extends FObj { private int endingPageNumberOfPreviousSequence = 0; private int totalPagesGenerated = 0; + /** + * Context class used while building the FO tree. + */ + private FOTreeBuilderContext builderContext; + /** * FOEventHandler object for this FO Tree */ @@ -164,10 +170,23 @@ public class Root extends FObj { return foEventHandler; } - /** - * Gets the last page number generated by the previous page-sequence - * @return the last page number, 0 if no page sequences yet generated + /** + * Sets the builder context for this FO tree. + * @param context the builder context to be used */ + public void setBuilderContext(FOTreeBuilderContext context) { + this.builderContext = context; + } + + /** {@inheritDoc} */ + public FOTreeBuilderContext getBuilderContext() { + return this.builderContext; + } + + /** + * Gets the last page number generated by the previous page-sequence + * @return the last page number, 0 if no page sequences yet generated + */ public int getEndingPageNumberOfPreviousSequence() { return endingPageNumberOfPreviousSequence; } diff --git a/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java b/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java index 839ac7022..542dcac32 100644 --- a/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java +++ b/src/java/org/apache/fop/fo/properties/PageDimensionMaker.java @@ -23,7 +23,6 @@ import org.apache.fop.fo.Constants; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.expr.PropertyException; -import org.apache.fop.fo.properties.LengthProperty; /** * Custom Maker for page-height / page-width @@ -54,8 +53,8 @@ public class PageDimensionMaker extends LengthProperty.Maker { Property p = super.get(0, propertyList, tryInherit, tryDefault); FObj fo = propertyList.getFObj(); String fallbackValue = (propId == Constants.PR_PAGE_HEIGHT) - ? fo.getFOEventHandler().getUserAgent().getPageHeight() - : fo.getFOEventHandler().getUserAgent().getPageWidth(); + ? fo.getUserAgent().getPageHeight() + : fo.getUserAgent().getPageWidth(); if (p.getEnum() == Constants.EN_INDEFINITE) { int otherId = (propId == Constants.PR_PAGE_HEIGHT) diff --git a/src/java/org/apache/fop/fonts/FontSelector.java b/src/java/org/apache/fop/fonts/FontSelector.java index ec5ea26bf..5e3ed816e 100644 --- a/src/java/org/apache/fop/fonts/FontSelector.java +++ b/src/java/org/apache/fop/fonts/FontSelector.java @@ -88,7 +88,7 @@ public final class FontSelector { /** * Selects a font which is able to display the most of the given characters. * - * @param textArray + * @param charSeq * Text to go through * @param firstIndex * first index within text. @@ -100,9 +100,10 @@ public final class FontSelector { * the Percent-based context needed for creating the actual font. * @return a Font object. */ - public static Font selectFontForCharactersInText(char[] textArray, + public static Font selectFontForCharactersInText(CharSequence charSeq, int firstIndex, int breakIndex, FOText text, PercentBaseContext context) { + final FontInfo fi = text.getFOEventHandler().getFontInfo(); final CommonFont commonFont = text.getCommonFont(); final FontTriplet[] fontkeys = commonFont.getFontState(fi); @@ -115,7 +116,7 @@ public final class FontSelector { commonFont.fontSize.getValue(context)); fonts[fontnum] = font; for (int pos = firstIndex; pos < breakIndex; pos++) { - if (font.hasChar(textArray[pos])) { + if (font.hasChar(charSeq.charAt(pos))) { fontCount[fontnum]++; } } diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java index 087963013..862c0a4be 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java @@ -41,8 +41,8 @@ import org.apache.fop.fo.flow.Character; import org.apache.fop.fo.flow.ExternalGraphic; import org.apache.fop.fo.flow.Footnote; import org.apache.fop.fo.flow.Inline; -import org.apache.fop.fo.flow.InlineLevel; import org.apache.fop.fo.flow.InlineContainer; +import org.apache.fop.fo.flow.InlineLevel; import org.apache.fop.fo.flow.InstreamForeignObject; import org.apache.fop.fo.flow.Leader; import org.apache.fop.fo.flow.ListBlock; @@ -224,7 +224,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker { public static class FOTextLayoutManagerMaker extends Maker { public void make(FONode node, List lms) { FOText foText = (FOText) node; - if (foText.endIndex - foText.startIndex > 0) { + if (foText.length() > 0) { lms.add(new TextLayoutManager(foText)); } } diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index 575728f0d..c6210edce 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -61,20 +61,20 @@ public class TextLayoutManager extends LeafNodeLayoutManager { * Number of word-spaces? */ private class AreaInfo { - private final short startIndex; - private final short breakIndex; - private final short wordSpaceCount; - private short letterSpaceCount; + private final int startIndex; + private final int breakIndex; + private final int wordSpaceCount; + private int letterSpaceCount; private final MinOptMax areaIPD; private final boolean isHyphenated; private final boolean isSpace; private boolean breakOppAfter; private final Font font; - AreaInfo(final short startIndex, - final short breakIndex, - final short wordSpaceCount, - final short letterSpaceCount, + AreaInfo(final int startIndex, + final int breakIndex, + final int wordSpaceCount, + final int letterSpaceCount, final MinOptMax areaIPD, final boolean isHyphenated, final boolean isSpace, @@ -132,7 +132,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private static final MinOptMax ZERO_MINOPTMAX = new MinOptMax(0); private final FOText foText; - private final char[] textArray; + /** * Contains an array of widths to adjust for kerning. The first entry can * be used to influence the start position of the first letter. The entry i+1 defines the @@ -143,7 +143,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { /** Font used for the space between words. */ private Font spaceFont = null; /** Start index of next TextArea */ - private short nextStart = 0; + private int nextStart = 0; /** size of a space character (U+0020) glyph in current font */ private int spaceCharIPD; private MinOptMax wordSpaceIPD; @@ -155,8 +155,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private boolean hasChanged = false; private int returnedIndex = 0; - private short thisStart = 0; - private short tempStart = 0; + private int thisStart = 0; + private int tempStart = 0; private List changeList = null; private AlignmentContext alignmentContext = null; @@ -177,10 +177,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { super(); this.foText = node; - this.textArray = new char[node.endIndex - node.startIndex]; - System.arraycopy(node.ca, node.startIndex, this.textArray, 0, - node.endIndex - node.startIndex); - this.letterAdjustArray = new MinOptMax[this.textArray.length + 1]; + this.letterAdjustArray = new MinOptMax[node.length() + 1]; this.vecAreaInfo = new java.util.ArrayList(); } @@ -205,6 +202,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { /** {@inheritDoc} */ public void initialize() { + this.foText.resetBuffer(); + this.spaceFont = FontSelector.selectFontForCharacterInText(' ', this.foText, this); // With CID fonts, space isn't neccesary currentFontState.width(32) @@ -296,7 +295,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { int letterSpaceCount, final int firstAreaInfoIndex, final int lastAreaInfoIndex, final MinOptMax realWidth, final LayoutContext context) { - // TODO: These two statements (if, for) where like this before my recent + // TODO: These two statements (if, for) were like this before my recent // changes. However, it seems as if they should use the AreaInfo from // firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last ai. // This needs to be checked. @@ -441,7 +440,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // areaInfo stores information about spaces // add the spaces - except zero-width spaces - to the TextArea for (int j = areaInfo.startIndex; j < areaInfo.breakIndex; j++) { - final char spaceChar = this.textArray[j]; + final char spaceChar = this.foText.charAt(j); if (!CharUtilities.isZeroWidthSpace(spaceChar)) { textArea.addSpace(spaceChar, 0, CharUtilities.isAdjustableSpace(spaceChar)); @@ -469,8 +468,15 @@ public class TextLayoutManager extends LeafNodeLayoutManager { for (int j = wordStartIndex; j <= i; j++) { final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(j); int lsCount = ai.letterSpaceCount; - wordChars.append(this.textArray, ai.startIndex, - ai.breakIndex - ai.startIndex); + /* TODO: in Java 5, StringBuffer has an append() variant + * for CharSequence, so the below iteration can be replaced + * by: + * wordChars.append(this.foText, ai.startIndex, + * ai.breakIndex - ai.startIndex); + */ + for (int ci = ai.startIndex; ci < ai.breakIndex; ci++) { + wordChars.append(this.foText.charAt(ci)); + } for (int k = 0; k < ai.breakIndex - ai.startIndex; k++) { final MinOptMax adj = this.letterAdjustArray[ai.startIndex + k]; if (letter > 0) { @@ -522,7 +528,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { || CharUtilities.isNonBreakableSpace(ch) || CharUtilities.isFixedWidthSpace(ch); } - + /** {@inheritDoc} */ public List getNextKnuthElements(final LayoutContext context, final int alignment) { this.lineStartBAP = context.getLineStartBorderAndPaddingWidth(); @@ -540,8 +546,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { boolean inWord = false; boolean inWhitespace = false; char ch = 0; - while (this.nextStart < this.textArray.length) { - ch = this.textArray[this.nextStart]; + while (this.nextStart < this.foText.length()) { + ch = this.foText.charAt(this.nextStart); boolean breakOpportunity = false; final byte breakAction = this.keepTogether ? LineBreakStatus.PROHIBITED_BREAK : lbs.nextChar(ch); @@ -560,10 +566,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager { TextLayoutManager.LOG.error("Unexpected breakAction: " + breakAction); } if (inWord) { - if (breakOpportunity + if (breakOpportunity || TextLayoutManager.isSpace(ch) || CharUtilities.isExplicitBreak(ch)) { - // this.textArray[lastIndex] == CharUtilities.SOFT_HYPHEN + // this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN prevAi = this.processWord(alignment, sequence, prevAi, ch, breakOpportunity, true); } @@ -588,24 +594,24 @@ public class TextLayoutManager extends LeafNodeLayoutManager { || ch == CharUtilities.NBSPACE) { // preserved space or non-breaking space: // create the AreaInfo object - ai = new AreaInfo(this.nextStart, (short) (this.nextStart + 1), - (short) 1, (short) 0, this.wordSpaceIPD, false, true, + ai = new AreaInfo(this.nextStart, this.nextStart + 1, + 1, 0, this.wordSpaceIPD, false, true, breakOpportunity, this.spaceFont); - this.thisStart = (short) (this.nextStart + 1); + this.thisStart = this.nextStart + 1; } else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) { // create the AreaInfo object final Font font = FontSelector.selectFontForCharacterInText(ch, this.foText, this); final MinOptMax ipd = new MinOptMax(font.getCharWidth(ch)); - ai = new AreaInfo(this.nextStart, (short) (this.nextStart + 1), - (short) 0, (short) 0, ipd, false, true, + ai = new AreaInfo(this.nextStart, this.nextStart + 1, + 0, 0, ipd, false, true, breakOpportunity, font); - this.thisStart = (short) (this.nextStart + 1); + this.thisStart = this.nextStart + 1; } else if (CharUtilities.isExplicitBreak(ch)) { //mandatory break-character: only advance index - this.thisStart = (short) (this.nextStart + 1); + this.thisStart = this.nextStart + 1; } - + inWord = !TextLayoutManager.isSpace(ch) && !CharUtilities.isExplicitBreak(ch); inWhitespace = ch == CharUtilities.SPACE @@ -619,17 +625,17 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } else if (inWhitespace) { this.processWhitespace(alignment, sequence, true); } else if (ai != null) { - ai = this.processLeftoverAi(alignment, sequence, ai, ch, + this.processLeftoverAi(alignment, sequence, ai, ch, ch == CharUtilities.ZERO_WIDTH_SPACE); } else if (CharUtilities.isExplicitBreak(ch)) { - sequence = this.processLinebreak(returnList, sequence); + this.processLinebreak(returnList, sequence); } if (((List) ListUtil.getLast(returnList)).isEmpty()) { //Remove an empty sequence because of a trailing newline ListUtil.removeLast(returnList); } - + this.setFinished(true); if (returnList.isEmpty()) { return null; @@ -663,24 +669,20 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private AreaInfo processWhitespace(final int alignment, final KnuthSequence sequence, final boolean breakOpportunity) { - AreaInfo ai; - AreaInfo prevAi; // End of whitespace // create the AreaInfo object - ai = new AreaInfo(this.thisStart, this.nextStart, - (short) (this.nextStart - this.thisStart), (short) 0, + AreaInfo ai = new AreaInfo(this.thisStart, this.nextStart, + this.nextStart - this.thisStart, 0, MinOptMax.multiply(this.wordSpaceIPD, this.nextStart - this.thisStart), false, true, breakOpportunity, this.spaceFont); this.vecAreaInfo.add(ai); - prevAi = ai; // create the elements this.addElementsForASpace(sequence, alignment, ai, this.vecAreaInfo.size() - 1); - ai = null; this.thisStart = this.nextStart; - return prevAi; + return ai; } private AreaInfo processWord(final int alignment, final KnuthSequence sequence, @@ -688,21 +690,21 @@ public class TextLayoutManager extends LeafNodeLayoutManager { final boolean checkEndsWithHyphen) { AreaInfo ai; //Word boundary found, process widths and kerning - short lastIndex = this.nextStart; + int lastIndex = this.nextStart; while (lastIndex > 0 - && this.textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) { + && this.foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) { lastIndex--; } final boolean endsWithHyphen = checkEndsWithHyphen - && this.textArray[lastIndex] == CharUtilities.SOFT_HYPHEN; + && this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN; final Font font = FontSelector - .selectFontForCharactersInText(this.textArray, + .selectFontForCharactersInText(this.foText, this.thisStart, lastIndex, this.foText, this); final int wordLength = lastIndex - this.thisStart; final boolean kerning = font.hasKerning(); final MinOptMax wordIPD = new MinOptMax(0); for (int i = this.thisStart; i < lastIndex; i++) { - final char c = this.textArray[i]; + final char c = this.foText.charAt(i); //character width final int charWidth = font.getCharWidth(c); @@ -712,10 +714,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager { if (kerning) { int kern = 0; if (i > this.thisStart) { - final char previous = this.textArray[i - 1]; + final char previous = this.foText.charAt(i - 1); kern = font.getKernValue(previous, c) * font.getFontSize() / 1000; } else if (prevAi != null && !prevAi.isSpace && prevAi.breakIndex > 0) { - final char previous = this.textArray[prevAi.breakIndex - 1]; + final char previous = this.foText.charAt(prevAi.breakIndex - 1); kern = font.getKernValue(previous, c) * font.getFontSize() / 1000; } if (kern != 0) { @@ -730,7 +732,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { && lastIndex > 0 && endsWithHyphen) { final int kern = font.getKernValue( - this.textArray[lastIndex - 1], ch) + this.foText.charAt(lastIndex - 1), ch) * font.getFontSize() / 1000; if (kern != 0) { this.addToLetterAdjust(lastIndex, kern); @@ -746,8 +748,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { wordIPD.add(MinOptMax.multiply(this.letterSpaceIPD, iLetterSpaces)); // create the AreaInfo object - ai = new AreaInfo(this.thisStart, lastIndex, (short) 0, - (short) iLetterSpaces, wordIPD, + ai = new AreaInfo(this.thisStart, lastIndex, 0, + iLetterSpaces, wordIPD, endsWithHyphen, false, breakOpportunity, font); prevAi = ai; @@ -776,7 +778,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(idx); ai.letterSpaceCount++; ai.areaIPD.add(this.letterSpaceIPD); - if (TextLayoutManager.BREAK_CHARS.indexOf(this.textArray[this.tempStart - 1]) >= 0) { + if (TextLayoutManager.BREAK_CHARS.indexOf(this.foText.charAt(this.tempStart - 1)) >= 0) { // the last character could be used as a line break // append new elements to oldList oldListIterator = oldList.listIterator(oldList.size()); @@ -867,7 +869,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { //log.info("Word: " + new String(textArray, startIndex, stopIndex - startIndex)); for (int i = startIndex; i < stopIndex; i++) { - final char c = this.textArray[i]; + final char c = this.foText.charAt(i); newIPD.add(new MinOptMax(font.getCharWidth(c))); //if (i > startIndex) { if (i < stopIndex) { @@ -899,8 +901,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { this.changeList = new LinkedList(); } this.changeList.add(new PendingChange(new AreaInfo( - (short) startIndex, (short) stopIndex, (short) 0, - (short) (isWordEnd ? stopIndex - startIndex - 1 + startIndex, stopIndex, 0, + (isWordEnd ? stopIndex - startIndex - 1 : stopIndex - startIndex), newIPD, hyphenFollows, false, false, font), ((LeafPosition) pos).getLeafPos())); @@ -973,7 +975,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager { final int leafValue = ((LeafPosition) pos).getLeafPos(); if (leafValue != -1) { final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(leafValue); - sbChars.append(this.textArray, ai.startIndex, ai.breakIndex - ai.startIndex); + for (int i = ai.startIndex; i < ai.breakIndex; ++i) { + sbChars.append(this.foText.charAt(i)); + } } } @@ -999,7 +1003,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { mainPosition, true)); } } else { - if (this.textArray[ai.startIndex] != CharUtilities.SPACE + if (this.foText.charAt(ai.startIndex) != CharUtilities.SPACE || this.foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) { // a breaking space that needs to be preserved this.addElementsForBreakingSpace(baseList, alignment, ai, @@ -1153,7 +1157,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // or it ends with a character that can be used as a line break if (ai.isHyphenated) { MinOptMax widthIfNoBreakOccurs = null; - if (ai.breakIndex < this.textArray.length) { + if (ai.breakIndex < this.foText.length()) { //Add in kerning in no-break condition widthIfNoBreakOccurs = this.letterAdjustArray[ai.breakIndex]; } diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index d432c7657..38f1a7b30 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -32,7 +32,7 @@ import org.apache.fop.fo.flow.table.ConditionalBorder; import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; -import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.KnuthElement; @@ -94,7 +94,7 @@ class RowPainter { this.firstRowOnPageIndex = -1; } - void startTablePart(TableBody tablePart) { + void startTablePart(TablePart tablePart) { CommonBorderPaddingBackground background = tablePart.getCommonBorderPaddingBackground(); if (background.hasBackground()) { tablePartBackground = background; diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 43b34e4b7..52915c008 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -31,7 +31,7 @@ import org.apache.fop.fo.flow.table.ConditionalBorder; import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableColumn; import org.apache.fop.fo.flow.table.TableRow; @@ -439,7 +439,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager -startIndent); } - TableBody body = primaryGridUnit.getTableBody(); + TablePart body = primaryGridUnit.getTablePart(); if (body.getCommonBorderPaddingBackground().hasBackground()) { painter.registerPartBackgroundArea( getBackgroundArea(paddingRectBPD, borderBeforeWidth)); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index 9b4a03a67..80e904f8f 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -19,7 +19,6 @@ package org.apache.fop.layoutmgr.table; -import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -35,7 +34,7 @@ import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListUtils; @@ -324,7 +323,7 @@ public class TableContentLayoutManager implements PercentBaseContext { this.usedBPD = 0; RowPainter painter = new RowPainter(this, layoutContext); - List tablePositions = new ArrayList(); + List tablePositions = new java.util.ArrayList(); List headerElements = null; List footerElements = null; Position firstPos = null; @@ -417,9 +416,9 @@ public class TableContentLayoutManager implements PercentBaseContext { } } - private void addHeaderFooterAreas(List elements, TableBody part, RowPainter painter, + private void addHeaderFooterAreas(List elements, TablePart part, RowPainter painter, boolean lastOnPage) { - List lst = new ArrayList(elements.size()); + List lst = new java.util.ArrayList(elements.size()); for (Iterator iter = new KnuthPossPosIter(elements); iter.hasNext();) { Position pos = (Position) iter.next(); /* @@ -446,32 +445,32 @@ public class TableContentLayoutManager implements PercentBaseContext { private void addBodyAreas(Iterator iterator, RowPainter painter, boolean lastOnPage) { painter.startBody(); - List lst = new ArrayList(); + List lst = new java.util.ArrayList(); TableContentPosition pos = (TableContentPosition) iterator.next(); boolean isFirstPos = pos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP) && pos.getRow().getFlag(EffRow.FIRST_IN_PART); - TableBody body = pos.getTableBody(); + TablePart part = pos.getTablePart(); lst.add(pos); while (iterator.hasNext()) { pos = (TableContentPosition) iterator.next(); - if (pos.getTableBody() != body) { - addTablePartAreas(lst, painter, body, isFirstPos, true, false, false); + if (pos.getTablePart() != part) { + addTablePartAreas(lst, painter, part, isFirstPos, true, false, false); isFirstPos = true; lst.clear(); - body = pos.getTableBody(); + part = pos.getTablePart(); } lst.add(pos); } boolean isLastPos = pos.getFlag(TableContentPosition.LAST_IN_ROWGROUP) && pos.getRow().getFlag(EffRow.LAST_IN_PART); - addTablePartAreas(lst, painter, body, isFirstPos, isLastPos, true, lastOnPage); + addTablePartAreas(lst, painter, part, isFirstPos, isLastPos, true, lastOnPage); painter.endBody(); } /** * Adds the areas corresponding to a single fo:table-header/footer/body element. */ - private void addTablePartAreas(List positions, RowPainter painter, TableBody body, + private void addTablePartAreas(List positions, RowPainter painter, TablePart body, boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { getTableLM().getCurrentPV().addMarkers(body.getMarkers(), true, isFirstPos, isLastPos); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java index 260b8cfdf..62d25fcb1 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java @@ -22,7 +22,7 @@ package org.apache.fop.layoutmgr.table; import java.util.List; import org.apache.fop.fo.flow.table.EffRow; -import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.layoutmgr.LayoutManager; import org.apache.fop.layoutmgr.Position; @@ -80,8 +80,8 @@ class TableContentPosition extends Position { return row; } - TableBody getTableBody() { - return ((CellPart) cellParts.get(0)).pgu.getTableBody(); + TablePart getTablePart() { + return ((CellPart) cellParts.get(0)).pgu.getTablePart(); } /** diff --git a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java index 62e308c13..282cd0fd5 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java @@ -28,6 +28,7 @@ import org.apache.fop.fo.FONode.FONodeIterator; import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TablePart; /** @@ -69,7 +70,7 @@ public class TableRowIterator { case FOOTER: rowGroupsIter = table.getTableFooter().getRowGroups().iterator(); break; - default: + case BODY: List rowGroupsList = new LinkedList(); // TODO this is ugly for (FONodeIterator iter = table.getChildNodes(); iter.hasNext();) { @@ -79,6 +80,9 @@ public class TableRowIterator { } } rowGroupsIter = rowGroupsList.iterator(); + break; + default: + throw new IllegalArgumentException("Unrecognised TablePart: " + tablePart); } } diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index 86210b07a..a6c08747f 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -38,6 +38,7 @@ import org.apache.fop.area.Block; import org.apache.fop.area.BlockViewport; import org.apache.fop.area.CTM; import org.apache.fop.area.NormalFlow; +import org.apache.fop.area.RegionReference; import org.apache.fop.area.RegionViewport; import org.apache.fop.area.Trait; import org.apache.fop.area.inline.ForeignObject; @@ -96,19 +97,20 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { */ protected void handleRegionTraits(RegionViewport region) { Rectangle2D viewArea = region.getViewArea(); + RegionReference referenceArea = region.getRegionReference(); float startx = (float)(viewArea.getX() / 1000f); float starty = (float)(viewArea.getY() / 1000f); float width = (float)(viewArea.getWidth() / 1000f); float height = (float)(viewArea.getHeight() / 1000f); - if (region.getRegionReference().getRegionClass() == FO_REGION_BODY) { - currentBPPosition = region.getBorderAndPaddingWidthBefore(); - currentIPPosition = region.getBorderAndPaddingWidthStart(); - } - drawBackAndBorders(region, startx, starty, width, height); + // adjust the current position according to region borders and padding + currentBPPosition = referenceArea.getBorderAndPaddingWidthBefore(); + currentIPPosition = referenceArea.getBorderAndPaddingWidthStart(); + // draw background (traits are in the RegionViewport) + // and borders (traits are in the RegionReference) + drawBackAndBorders(region, referenceArea, startx, starty, width, height); } - /** * Draw the background and borders. * This draws the background and border traits for an area given @@ -123,14 +125,57 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { protected void drawBackAndBorders(Area area, float startx, float starty, float width, float height) { + drawBackAndBorders(area, area, startx, starty, width, height); + } + + /** + * Draw the background and borders. + * This draws the background and border traits for an area given + * the position. + * + * @param backgroundArea the area to get the background traits from + * @param borderArea the area to get the border traits from + * @param startx the start x position + * @param starty the start y position + * @param width the width of the area + * @param height the height of the area + */ + protected void drawBackAndBorders(Area backgroundArea, Area borderArea, + float startx, float starty, + float width, float height) { // draw background then border - BorderProps bpsBefore = (BorderProps)area.getTrait(Trait.BORDER_BEFORE); - BorderProps bpsAfter = (BorderProps)area.getTrait(Trait.BORDER_AFTER); - BorderProps bpsStart = (BorderProps)area.getTrait(Trait.BORDER_START); - BorderProps bpsEnd = (BorderProps)area.getTrait(Trait.BORDER_END); + BorderProps bpsBefore = (BorderProps)borderArea.getTrait(Trait.BORDER_BEFORE); + BorderProps bpsAfter = (BorderProps)borderArea.getTrait(Trait.BORDER_AFTER); + BorderProps bpsStart = (BorderProps)borderArea.getTrait(Trait.BORDER_START); + BorderProps bpsEnd = (BorderProps)borderArea.getTrait(Trait.BORDER_END); - Trait.Background back = (Trait.Background)area.getTrait(Trait.BACKGROUND); + drawBackground(startx, starty, width, height, + (Trait.Background) backgroundArea.getTrait(Trait.BACKGROUND), + bpsBefore, bpsAfter, bpsStart, bpsEnd); + drawBorders(startx, starty, width, height, + bpsBefore, bpsAfter, bpsStart, bpsEnd); + } + + /** + * Draw the background. + * This draws the background given the position and the traits. + * + * @param startx the start x position + * @param starty the start y position + * @param width the width of the area + * @param height the height of the area + * @param back the background traits + * @param bpsBefore the border-before traits + * @param bpsAfter the border-after traits + * @param bpsStart the border-start traits + * @param bpsEnd the border-end traits + */ + protected void drawBackground(float startx, float starty, + float width, float height, + Trait.Background back, + BorderProps bpsBefore, BorderProps bpsAfter, + BorderProps bpsStart, BorderProps bpsEnd) { if (back != null) { endTextObject(); @@ -201,7 +246,25 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { restoreGraphicsState(); } } + } + /** + * Draw the borders. + * This draws the border traits given the position and the traits. + * + * @param startx the start x position + * @param starty the start y position + * @param width the width of the area + * @param height the height of the area + * @param bpsBefore the border-before traits + * @param bpsAfter the border-after traits + * @param bpsStart the border-start traits + * @param bpsEnd the border-end traits + */ + protected void drawBorders(float startx, float starty, + float width, float height, + BorderProps bpsBefore, BorderProps bpsAfter, + BorderProps bpsStart, BorderProps bpsEnd) { Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height); drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd); } diff --git a/src/java/org/apache/fop/render/rtf/RTFHandler.java b/src/java/org/apache/fop/render/rtf/RTFHandler.java index 05aade551..6171e68b4 100644 --- a/src/java/org/apache/fop/render/rtf/RTFHandler.java +++ b/src/java/org/apache/fop/render/rtf/RTFHandler.java @@ -76,6 +76,8 @@ import org.apache.fop.fo.flow.ListItemLabel; import org.apache.fop.fo.flow.PageNumber; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TableFooter; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableColumn; import org.apache.fop.fo.flow.table.TableHeader; @@ -611,25 +613,29 @@ public class RTFHandler extends FOEventHandler { /** * {@inheritDoc} */ - public void startHeader(TableBody th) { + public void startHeader(TableHeader header) { + startPart(header); } /** * {@inheritDoc} */ - public void endHeader(TableBody th) { + public void endHeader(TableHeader header) { + endPart(header); } /** * {@inheritDoc} */ - public void startFooter(TableBody tf) { + public void startFooter(TableFooter footer) { + startPart(footer); } /** * {@inheritDoc} */ - public void endFooter(TableBody tf) { + public void endFooter(TableFooter footer) { + endPart(footer); } /** @@ -687,31 +693,25 @@ public class RTFHandler extends FOEventHandler { } } - /** - * {@inheritDoc} - */ - public void startBody(TableBody tb) { + private void startPart(TablePart part) { if (bDefer) { return; } try { - RtfAttributes atts = TableAttributesConverter.convertTableBodyAttributes(tb); + RtfAttributes atts = TableAttributesConverter.convertTablePartAttributes(part); RtfTable tbl = (RtfTable)builderContext.getContainer(RtfTable.class, true, this); tbl.setHeaderAttribs(atts); } catch (IOException ioe) { handleIOTrouble(ioe); } catch (Exception e) { - log.error("startBody: " + e.getMessage()); + log.error("startPart: " + e.getMessage()); throw new RuntimeException(e.getMessage()); - } + } } - /** - * {@inheritDoc} - */ - public void endBody(TableBody tb) { + private void endPart(TablePart tb) { if (bDefer) { return; } @@ -722,9 +722,25 @@ public class RTFHandler extends FOEventHandler { } catch (IOException ioe) { handleIOTrouble(ioe); } catch (Exception e) { - log.error("endBody: " + e.getMessage()); + log.error("endPart: " + e.getMessage()); throw new RuntimeException(e.getMessage()); - } + } + } + + + /** + * {@inheritDoc} + */ + public void startBody(TableBody body) { + startPart(body); + } + + + /** + * {@inheritDoc} + */ + public void endBody(TableBody body) { + endPart(body); } /** @@ -1552,7 +1568,7 @@ public class RTFHandler extends FOEventHandler { } else if (foNode instanceof FOText) { if (bStart) { FOText text = (FOText) foNode; - text(text, text.ca, text.startIndex, text.endIndex); + text(text, text.getCharArray(), 0, text.length()); } } else if (foNode instanceof Character) { if (bStart) { @@ -1607,6 +1623,18 @@ public class RTFHandler extends FOEventHandler { } else { endTable( (Table) foNode); } + } else if (foNode instanceof TableHeader) { + if (bStart) { + startHeader( (TableHeader) foNode); + } else { + endHeader( (TableHeader) foNode); + } + } else if (foNode instanceof TableFooter) { + if (bStart) { + startFooter( (TableFooter) foNode); + } else { + endFooter( (TableFooter) foNode); + } } else if (foNode instanceof TableBody) { if (bStart) { startBody( (TableBody) foNode); diff --git a/src/java/org/apache/fop/render/rtf/TableAttributesConverter.java b/src/java/org/apache/fop/render/rtf/TableAttributesConverter.java index 677832418..a28d91d36 100644 --- a/src/java/org/apache/fop/render/rtf/TableAttributesConverter.java +++ b/src/java/org/apache/fop/render/rtf/TableAttributesConverter.java @@ -24,12 +24,11 @@ import java.awt.Color; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.Constants; import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.fo.flow.table.TableBody; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableHeader; import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; -import org.apache.fop.fo.properties.FixedLength; import org.apache.fop.render.rtf.rtflib.rtfdoc.ITableAttributes; import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes; @@ -91,7 +90,7 @@ public final class TableAttributesConverter { * * @throws ConverterException On convertion error */ - static RtfAttributes convertTableBodyAttributes(TableBody fobj) + static RtfAttributes convertTablePartAttributes(TablePart part) throws FOPException { FOPRtfAttributes attrib = new FOPRtfAttributes(); return attrib; diff --git a/src/java/org/apache/fop/util/CharUtilities.java b/src/java/org/apache/fop/util/CharUtilities.java index 6baa5c0fd..eb56cd331 100644 --- a/src/java/org/apache/fop/util/CharUtilities.java +++ b/src/java/org/apache/fop/util/CharUtilities.java @@ -54,10 +54,14 @@ public class CharUtilities { public static final int XMLWHITESPACE = 4; + /** null char */ + public static final char NULL_CHAR = '\u0000'; /** linefeed character */ public static final char LINEFEED_CHAR = '\n'; /** carriage return */ public static final char CARRIAGE_RETURN = '\r'; + /** normal tab */ + public static final char TAB = '\t'; /** normal space */ public static final char SPACE = '\u0020'; /** non-breaking space */ @@ -80,9 +84,12 @@ public class CharUtilities { public static final char PARAGRAPH_SEPARATOR = '\u2029'; /** missing ideograph */ public static final char MISSING_IDEOGRAPH = '\u25A1'; + /** Ideogreaphic space */ + public static final char IDEOGRAPHIC_SPACE = '\u3000'; /** Unicode value indicating the the character is "not a character". */ public static final char NOT_A_CHARACTER = '\uFFFF'; + /** * Utility class: Constructor prevents instantiating when subclassed. */ @@ -97,11 +104,18 @@ public class CharUtilities { * @return the determined character class */ public static int classOf(char c) { - if (c == CODE_EOT) { return EOT; } - if (c == '\n') { return LINEFEED; } - if (c == ' ' || c == '\r' || c == '\t') { return XMLWHITESPACE; } - if (isAnySpace(c)) { return UCWHITESPACE; } - return NONWHITESPACE; + switch (c) { + case CODE_EOT: + return EOT; + case LINEFEED_CHAR: + return LINEFEED; + case SPACE: + case CARRIAGE_RETURN: + case TAB: + return XMLWHITESPACE; + default: + return isAnySpace(c) ? UCWHITESPACE : NONWHITESPACE; + } } diff --git a/src/java/org/apache/fop/util/XMLizable.java b/src/java/org/apache/fop/util/XMLizable.java deleted file mode 100644 index a16131989..000000000 --- a/src/java/org/apache/fop/util/XMLizable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.util; - -/* - * Copied from Apache Excalibur: - * https://svn.apache.org/repos/asf/excalibur/trunk/components/xmlutil/ - * src/java/org/apache/excalibur/xml/sax/XMLizable.java - */ - -/** - * This interface can be implemented by classes willing to provide an XML representation - * of their current state as SAX events. - * @deprecated Use the interface in Apache XML Graphics Commons instead. - */ -public interface XMLizable extends org.apache.xmlgraphics.util.XMLizable { - -} -- cgit v1.2.3