diff options
author | Simon Pepping <spepping@apache.org> | 2007-11-21 20:50:23 +0000 |
---|---|---|
committer | Simon Pepping <spepping@apache.org> | 2007-11-21 20:50:23 +0000 |
commit | 80cfd33695575c7016602bb8184b0f57c87a0784 (patch) | |
tree | df6e62fd5c93a3bdc560675fb8cca8235a8d9d0c /src | |
parent | cfd5d35721756e5695ce28e1c685d54836615b89 (diff) | |
download | xmlgraphics-fop-80cfd33695575c7016602bb8184b0f57c87a0784.tar.gz xmlgraphics-fop-80cfd33695575c7016602bb8184b0f57c87a0784.zip |
Merged revisions 593297-597199 via svnmerge from
https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk
........
r593452 | jeremias | 2007-11-09 09:33:52 +0100 (Fri, 09 Nov 2007) | 1 line
Bugfix: An invalid PDF was created if a grayscale JPEG image with an sRGB profile was embedded undecoded. I didn't find any other way than to disable the the ICC profile in this case.
........
r593573 | jeremias | 2007-11-09 16:54:11 +0100 (Fri, 09 Nov 2007) | 1 line
Attempt to shed light on what this method does.
........
r593909 | jeremias | 2007-11-11 16:30:34 +0100 (Sun, 11 Nov 2007) | 3 lines
Bugzilla #43835:
Bugfix: Use Font.getName() (logical font name) instead of Font.getFontName() (localized) when registering fonts from AWT.
Submitted by: David Churavy <churavy.at.kadel.cz>
........
r594046 | jeremias | 2007-11-12 09:27:46 +0100 (Mon, 12 Nov 2007) | 1 line
Issue a clear warning if the selected hyphenation character is not available in a font. Otherwise you'd just get a "glyph not available" error and you wonder why the hell FOP wants to use that character.
........
r594054 | jeremias | 2007-11-12 09:52:11 +0100 (Mon, 12 Nov 2007) | 1 line
Better solution for missing hyphenation character problem.
........
r594067 | jeremias | 2007-11-12 10:40:16 +0100 (Mon, 12 Nov 2007) | 2 lines
Avoid null values in generated Font classes so the encoding can be inspected.
Don't warn about missing hyphenation characters for fonts such as Symbol and ZapfDingbats which don't have the default hyphenation character.
........
r594079 | vhennebert | 2007-11-12 11:40:21 +0100 (Mon, 12 Nov 2007) | 2 lines
Use tableLM instead of the primary grid unit to retrieve the Table fobj
........
r594223 | cbowditch | 2007-11-12 18:25:41 +0100 (Mon, 12 Nov 2007) | 1 line
bug fix: avoid NPE when GC has removed a weak reference in the Property Cache
........
r594509 | jeremias | 2007-11-13 13:35:31 +0100 (Tue, 13 Nov 2007) | 1 line
Expose a method so I can easily extract the renderer configuration from outside the rendering domain (for a test tool).
........
r594512 | jeremias | 2007-11-13 13:40:38 +0100 (Tue, 13 Nov 2007) | 4 lines
Improved PFM loading:
- Fixed bug with Flags (resulted in bad PDFs for certain fonts)
- Warn about possible charset problems.
- Fixed bug for "last char" (probably a copy/paste mistake)
........
r594513 | jeremias | 2007-11-13 13:41:24 +0100 (Tue, 13 Nov 2007) | 1 line
Some TTF fonts don't have a PostScript name, so just emulate it in this case to avoid problems with font lookup further down.
........
r594515 | jeremias | 2007-11-13 13:42:35 +0100 (Tue, 13 Nov 2007) | 2 lines
Better error messages in fontLookup().
Expose font triplets to the outside (used by a test tool I wrote).
........
r594516 | jeremias | 2007-11-13 13:44:29 +0100 (Tue, 13 Nov 2007) | 2 lines
Filter single quotes from the filenames as this will interfere with font-family parsing.
Fixed bug: InputStream opened by URL.openConnection() wasn't closed which leads to "too many open files" when you have lots of fonts on Java 1.4.
........
r594517 | jeremias | 2007-11-13 13:45:15 +0100 (Tue, 13 Nov 2007) | 1 line
Log element list length for convenience.
........
r594522 | jeremias | 2007-11-13 14:07:33 +0100 (Tue, 13 Nov 2007) | 1 line
More informative overflow message (sometimes the overflow is just a few millipoints and it's nice to know how many).
........
r594552 | jeremias | 2007-11-13 15:37:00 +0100 (Tue, 13 Nov 2007) | 1 line
Fix two javadoc warnings.
........
r594571 | vhennebert | 2007-11-13 17:24:32 +0100 (Tue, 13 Nov 2007) | 7 lines
Moved the creation of grid units to the FO tree building stage. Brought a few improvements along with the move:
- bugfix: border-resolution for border-end on row-spanning cells was wrong
- bugfix: in case of missing cells the border-end of the table was applied to an inner cell, instead of the cell in the last column (but missing cells aren't painted yet :-\)
- bugfix: in collapsing-border model, border-before and -after specified on table-column were applied to every cell of the column, instead of only the first and the last ones
- border resolution is now made progressively when possible, and no longer triggers the fetching of all the rows of the table
Added testcases for the border conflict resolution (between the various elements of a table and not only the cells)
........
r594578 | vhennebert | 2007-11-13 17:50:09 +0100 (Tue, 13 Nov 2007) | 2 lines
Moved *GridUnit from layoutmgr/table to fo/flow/table
........
r594579 | vhennebert | 2007-11-13 17:55:54 +0100 (Tue, 13 Nov 2007) | 2 lines
Changed back visibility of fields from public to package-private, due to the move of *GridUnit in the fo.flow.table package
........
r594584 | vhennebert | 2007-11-13 18:13:19 +0100 (Tue, 13 Nov 2007) | 2 lines
Use a singleton for a default BorderInfo of style none, instead of every time a new instance
........
r594592 | vhennebert | 2007-11-13 18:39:17 +0100 (Tue, 13 Nov 2007) | 2 lines
Cleaned up RowGroupLayoutManager and TableRowIterator
........
r594821 | vhennebert | 2007-11-14 11:18:45 +0100 (Wed, 14 Nov 2007) | 2 lines
Moved EffRow to the fo.flow.table package
........
r594829 | vhennebert | 2007-11-14 11:41:52 +0100 (Wed, 14 Nov 2007) | 2 lines
Reduced visibility of some methods and constructors from public to package-private, as a consequence of the move of *GridUnit to the fo.flow.table package
........
r594836 | vhennebert | 2007-11-14 12:14:03 +0100 (Wed, 14 Nov 2007) | 2 lines
Restored the setting of the parent table-row element on grid units
........
r594852 | vhennebert | 2007-11-14 13:21:53 +0100 (Wed, 14 Nov 2007) | 2 lines
Restored the setting of rowIndex on primary grid units (although testcases were already working...)
........
r595297 | jeremias | 2007-11-15 14:28:58 +0100 (Thu, 15 Nov 2007) | 2 lines
Bugzilla #43143:
Had to remove the Expert(Subset) Encoding detection as this caused problems with a barcode font that used dfCharset=2 but was not using ExpertSubset encoding. To detect Expert(Subset)Encoding, the AFM needs to be parsed. And since we don't support that encoding, yet, the fallback to WinAnsiEncoding should work well enough.
........
r595637 | acumiskey | 2007-11-16 13:12:52 +0100 (Fri, 16 Nov 2007) | 3 lines
This should improve the ability of the FontLoader when resolving PFM files
for Type 1 fonts on case sensitive Unix systems.
........
r596072 | jeremias | 2007-11-18 11:48:53 +0100 (Sun, 18 Nov 2007) | 4 lines
ApacheCon US is over.
OSSSummit was cancelled/postponed.
Added example for total page count using XSL 1.1
Adjusted total page count example to new FOP API. (Thanks to Miroslav Gregan for the hint)
........
r596097 | jeremias | 2007-11-18 17:56:09 +0100 (Sun, 18 Nov 2007) | 6 lines
Bugzilla #43605:
Added methods for page-number-citation and page-number-citation-last in FOEventHandler.java
Submitted by: V. Schappert <vschappert.at.bloomberg.net>
Patch modified by Jeremias:
Bugfix: FOEventHandler.startPageNumberCitation() was also called in the case of a page-number-citation-last. Introduced abstract base classes to avoid this.
........
r596100 | jeremias | 2007-11-18 18:17:24 +0100 (Sun, 18 Nov 2007) | 1 line
Added sample as suggested by Kumar Puppala.
........
r596390 | vhennebert | 2007-11-19 19:25:27 +0100 (Mon, 19 Nov 2007) | 2 lines
Bugzilla #43766: breaks generated by the merging algorithm for table rows containing empty cells has always a penalty of 900
........
r596554 | jeremias | 2007-11-20 08:14:33 +0100 (Tue, 20 Nov 2007) | 2 lines
Bugzilla #43904:
Buffer the OutputStreams in our transcoders if the users forget.
........
r596600 | jeremias | 2007-11-20 11:20:29 +0100 (Tue, 20 Nov 2007) | 3 lines
Bugzilla #43910:
Avoid a NullPointerException in AreaTreeHandler.endDocument().
Submitted by: David Delbecq <delbd.at.oma.be>
........
r596724 | jeremias | 2007-11-20 16:56:33 +0100 (Tue, 20 Nov 2007) | 3 lines
Bugfix: Bugfix for URI resolution: Make StreamSources without system identifier work again.
Bugfix: Close streams opened by test font resolution in font configuration (the font URIs will be resolved again later anyway).
Better error message when the loading of font metric files doesn't work due to missing information in the returned Source instances.
........
r596727 | vhennebert | 2007-11-20 17:07:32 +0100 (Tue, 20 Nov 2007) | 2 lines
Bugfix in tables: wrong element generation by the merging algorithm when glues must be produced to cope with conditional spaces. The corresponding length was added twice: one in the glue itself and one in the following box.
........
r596739 | cbowditch | 2007-11-20 17:49:13 +0100 (Tue, 20 Nov 2007) | 1 line
bug fix: memory leak in PropertyCache. Fix provided by Jeremias. There are still some thread synchronization issues to be addressed in the PropertyCache. See the following thread for details: http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200711.mbox/%3cBAY117-DAV109E36CC066889386AB917FB870@phx.gbl%3e
........
r596742 | vhennebert | 2007-11-20 18:08:46 +0100 (Tue, 20 Nov 2007) | 2 lines
Added a news entry about Max Berger becoming a committer. Welcome Max!
........
r596776 | vhennebert | 2007-11-20 19:47:39 +0100 (Tue, 20 Nov 2007) | 2 lines
Bugzilla #43803: table cells having no children are allowed in relaxed validation mode.
........
r597052 | vhennebert | 2007-11-21 13:23:59 +0100 (Wed, 21 Nov 2007) | 2 lines
Bugfix: the last element generated by the merging algorithm may now be a glue
........
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking@597205 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
67 files changed, 2033 insertions, 1611 deletions
diff --git a/src/codegen/fonts/font-file.xsl b/src/codegen/fonts/font-file.xsl index 17d6de2e3..dbca3eba5 100644 --- a/src/codegen/fonts/font-file.xsl +++ b/src/codegen/fonts/font-file.xsl @@ -30,7 +30,6 @@ <xsl:output method="text"/> <xsl:param name="encoding" select="/font-metrics/encoding"/> - <xsl:variable name="native-encoding" select="/font-metrics/encoding"/> <xsl:variable name="glyphs" select="document('encodings.xml')/encoding-set/encoding[@id=$encoding]/glyph"/> <xsl:template match="font-metrics"> @@ -48,7 +47,7 @@ public class <xsl:value-of select="class-name"/> extends Typeface { private final static String fontName = "<xsl:value-of select="font-name"/>"; private final static String fullName = "<xsl:value-of select="full-name"/>"; private final static Set familyNames; - private final static String encoding = <xsl:choose><xsl:when test="$encoding != $native-encoding">"<xsl:value-of select="$encoding"/>"</xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>; + private final static String encoding = "<xsl:value-of select="$encoding"/>"; private final static int capHeight = <xsl:value-of select="cap-height"/>; private final static int xHeight = <xsl:value-of select="x-height"/>; private final static int ascender = <xsl:value-of select="ascender"/>; diff --git a/src/documentation/content/xdocs/fo.xml b/src/documentation/content/xdocs/fo.xml index 5ab95fe8d..dc7d45ab0 100644 --- a/src/documentation/content/xdocs/fo.xml +++ b/src/documentation/content/xdocs/fo.xml @@ -362,9 +362,14 @@ Omit your normal headers and footers, and use (for example) an extended header t <section id="fo-total-pages"> <title>Total Document Pages</title> <p> - It is frequently desirable to know the total number of pages in a document and to use that number within the document. -For example, you might wish to show the page number on the first page as being "page 1 of 12". -To accomplish this, place an empty block with an id at the end of the flow: + It is frequently desirable to know the total number of pages in a + document and to use that number within the document. For example, you + might wish to show the page number on the first page as being + "page 1 of 12". + </p> + <p> + To accomplish this in <strong>XSL 1.0</strong>, place an empty block + with an id at the end of the flow: </p> <source><![CDATA[<fo:flow ...> ... @@ -373,10 +378,20 @@ To accomplish this, place an empty block with an id at the end of the flow: <p> Get the number of the last page as follows: </p> - <source><![CDATA[ <fo:page-number-citation ref-id="last-page"/>]]></source> + <source><![CDATA[<fo:page-number-citation ref-id="last-page"/>]]></source> <p> This does not work in certain situations: multiple page sequences, an initial page number other than 1, or forcing a certain page count, thereby producing blank pages at the end. </p> + <p> + In <strong>XSL 1.1</strong>, you get another option to do this: make + sure an "id" is set on the page-sequence and reference it using + fo:page-number-citation-last. First, the page-sequence: + </p> + <source><![CDATA[<fo:page-sequence id="seq1" ...]]></source> + <p> + After that, reference the last page the page-sequence generates: + </p> + <source><![CDATA[<fo:page-number-citation-last ref-id="seq1"/>]]></source> <warning> There is no reliable way to get the real total page count with FO mechanisms. You can only get <em>page numbers</em>. </warning> @@ -394,27 +409,42 @@ import javax.xml.transform.stream.*; class rendtest { + private static FopFactory fopFactory = FopFactory.newInstance(); + private static TransformerFactory tFactory = TransformerFactory.newInstance(); + public static void main(String args[]) { + OutputStream out; try { - Driver driver=new Driver(); - driver.setOutputStream(new FileOutputStream(args[2])); - driver.setRenderer(Driver.RENDER_PDF); - Transformer transformer=TransformerFactory.newInstance() - .newTransformer(new StreamSource(new File(args[1]))); - transformer.setParameter("page-count","#"); + //Load the stylesheet + Templates templates = tFactory.newTemplates( + new StreamSource(new File(args[1]))); + + //First run (to /dev/null) + out = new org.apache.commons.io.output.NullOutputStream(); + FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); + Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); + Transformer transformer = templates.newTransformer(); + transformer.setParameter("page-count", "#"); transformer.transform(new StreamSource(new File(args[0])), - new SAXResult(driver.getContentHandler())); - String pageCount=Integer.toString(driver.getResults().getPageCount()); - driver=new Driver(); - driver.setOutputStream(new FileOutputStream(args[2])); - driver.setRenderer(Driver.RENDER_PDF); - transformer=TransformerFactory.newInstance() - .newTransformer(new StreamSource(new File(args[1]))); - transformer.setParameter("page-count",pageCount); + new SAXResult(fop.getDefaultHandler())); + + //Get total page count + String pageCount = Integer.toString(driver.getResults().getPageCount()); + + //Second run (the real thing) + out = new java.io.FileOutputStream(args[2]); + out = new java.io.BufferedOutputStream(out); + try { + foUserAgent = fopFactory.newFOUserAgent(); + fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); + transformer = templates.newTransformer(); + transformer.setParameter("page-count", pageCount); transformer.transform(new StreamSource(new File(args[0])), - new SAXResult(driver.getContentHandler())); - } - catch( Exception e) { + new SAXResult(fop.getDefaultHandler())); + } finally { + out.close(); + } + } catch( Exception e) { e.printStackTrace(); } } diff --git a/src/documentation/content/xdocs/news.xml b/src/documentation/content/xdocs/news.xml index 58fbb2e57..c72d76129 100644 --- a/src/documentation/content/xdocs/news.xml +++ b/src/documentation/content/xdocs/news.xml @@ -26,6 +26,10 @@ </header> <body> <section> + <title>30 October 2007 - New Committer</title> + <p>Welcome Max Berger!</p> + </section> + <section> <title>15 October 2007 - New Committer</title> <p>Welcome Adrian Cumiskey!</p> </section> diff --git a/src/documentation/skinconf.xml b/src/documentation/skinconf.xml index 1211d4de6..65a271a64 100644 --- a/src/documentation/skinconf.xml +++ b/src/documentation/skinconf.xml @@ -369,20 +369,6 @@ which will be used to configure the chosen Forrest skin. <height>31</height> </credit> <credit box-location="alt2"> - <name>ApacheCon US 2007 (Atlanta)</name> - <url>http://apachecon.com/2007/US/</url> - <image>http://www.apache.org/ads/ApacheCon/2007-usa-125x125.png</image> - <width>125</width> - <height>125</height> - </credit> - <credit box-location="alt2"> - <name>OS Summit Asia 2007</name> - <url>http://www.ossummit.com/</url> - <image>http://www.ossummit.com/ads/ossummit_button_3.jpg</image> - <width>125</width> - <height>125</height> - </credit> - <credit box-location="alt2"> <name>ApacheCon Europe 2008</name> <url>http://eu.apachecon.com/</url> <image>http://apache.org/ads/ApacheCon/2008-europe-125x125.png</image> diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java index be06aabfc..6eb2d738b 100644 --- a/src/java/org/apache/fop/area/AreaTreeHandler.java +++ b/src/java/org/apache/fop/area/AreaTreeHandler.java @@ -21,30 +21,27 @@ package org.apache.fop.area; // Java import java.io.OutputStream; -import java.util.List; import java.util.Iterator; +import java.util.List; -// XML import org.xml.sax.SAXException; -// Apache import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FormattingResults; import org.apache.fop.datatypes.Numeric; import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.extensions.ExtensionAttachment; +import org.apache.fop.fo.extensions.destination.Destination; import org.apache.fop.fo.pagination.PageSequence; import org.apache.fop.fo.pagination.Root; import org.apache.fop.fo.pagination.bookmarks.BookmarkTree; -import org.apache.fop.layoutmgr.PageSequenceLayoutManager; import org.apache.fop.layoutmgr.LayoutManagerMaker; import org.apache.fop.layoutmgr.LayoutManagerMapping; - -import org.apache.fop.area.DestinationData; -import org.apache.fop.fo.extensions.destination.Destination; +import org.apache.fop.layoutmgr.PageSequenceLayoutManager; /** * Area tree handler for formatting objects. @@ -261,25 +258,26 @@ public class AreaTreeHandler extends FOEventHandler { finishPrevPageSequence(null); // process fox:destination elements - List destinationList = rootFObj.getDestinationList(); - if (destinationList != null) { - while (destinationList.size() > 0) { - Destination destination = (Destination) destinationList.remove(0); - DestinationData destinationData = new DestinationData(destination); - addOffDocumentItem(destinationData); + if (rootFObj != null) { + List destinationList = rootFObj.getDestinationList(); + if (destinationList != null) { + while (destinationList.size() > 0) { + Destination destination = (Destination) destinationList.remove(0); + DestinationData destinationData = new DestinationData(destination); + addOffDocumentItem(destinationData); + } } - } - // process fo:bookmark-tree - BookmarkTree bookmarkTree = rootFObj.getBookmarkTree(); - if (bookmarkTree != null) { - BookmarkData data = new BookmarkData(bookmarkTree); - addOffDocumentItem(data); - if (!data.isResolved()) { - // bookmarks did not fully resolve, add anyway. (hacky? yeah) - model.handleOffDocumentItem(data); + // process fo:bookmark-tree + BookmarkTree bookmarkTree = rootFObj.getBookmarkTree(); + if (bookmarkTree != null) { + BookmarkData data = new BookmarkData(bookmarkTree); + addOffDocumentItem(data); + if (!data.isResolved()) { + // bookmarks did not fully resolve, add anyway. (hacky? yeah) + model.handleOffDocumentItem(data); + } } } - model.endDocument(); if (statistics != null) { diff --git a/src/java/org/apache/fop/fo/FOEventHandler.java b/src/java/org/apache/fop/fo/FOEventHandler.java index b2297ae6f..4af703c12 100644 --- a/src/java/org/apache/fop/fo/FOEventHandler.java +++ b/src/java/org/apache/fop/fo/FOEventHandler.java @@ -19,12 +19,11 @@ package org.apache.fop.fo; -// Java import java.util.HashSet; import java.util.Set; + import org.xml.sax.SAXException; -// Apache import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.flow.BasicLink; import org.apache.fop.fo.flow.Block; @@ -39,6 +38,8 @@ import org.apache.fop.fo.flow.Leader; import org.apache.fop.fo.flow.ListBlock; import org.apache.fop.fo.flow.ListItem; import org.apache.fop.fo.flow.PageNumber; +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.TableCell; @@ -48,7 +49,6 @@ import org.apache.fop.fo.pagination.Flow; import org.apache.fop.fo.pagination.PageSequence; import org.apache.fop.fonts.FontInfo; - /** * Abstract class defining what should be done with SAX events that map to * XSL-FO input. The events are actually captured by fo/FOTreeBuilder, passed @@ -207,6 +207,34 @@ public abstract class FOEventHandler { } /** + * + * @param pageCite PageNumberCitation that is starting. + */ + public void startPageNumberCitation(PageNumberCitation pageCite) { + } + + /** + * + * @param pageCite PageNumberCitation that is ending. + */ + public void endPageNumberCitation(PageNumberCitation pageCite) { + } + + /** + * + * @param pageLast PageNumberCitationLast that is starting. + */ + public void startPageNumberCitationLast(PageNumberCitationLast pageLast) { + } + + /** + * + * @param pageLast PageNumberCitationLast that is ending. + */ + public void endPageNumberCitationLast(PageNumberCitationLast pageLast) { + } + + /** * This method is called to indicate the start of a new fo:flow * or fo:static-content. * This method also handles fo:static-content tags, because the diff --git a/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java b/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java new file mode 100644 index 000000000..b6b827248 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java @@ -0,0 +1,180 @@ +/* + * 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.flow; + +import java.awt.Color; + +import org.xml.sax.Locator; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.datatypes.Length; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; +import org.apache.fop.fo.properties.CommonFont; +import org.apache.fop.fo.properties.CommonTextDecoration; +import org.apache.fop.fo.properties.SpaceProperty; + +/** + * Base class modelling the fo:page-number-citation object. + */ +public abstract class AbstractPageNumberCitation extends FObj { + + // The value of properties relevant for fo:page-number-citation(-last). + private CommonBorderPaddingBackground commonBorderPaddingBackground; + private CommonFont commonFont; + private Length alignmentAdjust; + private int alignmentBaseline; + private Length baselineShift; + private int dominantBaseline; + // private ToBeImplementedProperty letterSpacing; + private SpaceProperty lineHeight; + private String refId; + /** Holds the text decoration values. May be null */ + private CommonTextDecoration textDecoration; + // private ToBeImplementedProperty textShadow; + // Unused but valid items, commented out for performance: + // private CommonAccessibility commonAccessibility; + // private CommonAural commonAural; + // private CommonMarginInline commonMarginInline; + // private CommonRelativePosition commonRelativePosition; + // private KeepProperty keepWithNext; + // private KeepProperty keepWithPrevious; + // private int scoreSpaces; + // private Length textAltitude; + // private Length textDepth; + // private int textTransform; + // private int visibility; + // private SpaceProperty wordSpacing; + // private int wrapOption; + // End of property values + + // Properties which are not explicitely listed but are still applicable + private Color color; + + /** + * @param parent FONode that is the parent of this object + */ + public AbstractPageNumberCitation(FONode parent) { + super(parent); + } + + /** + * {@inheritDoc} + */ + public void bind(PropertyList pList) throws FOPException { + super.bind(pList); + commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); + commonFont = pList.getFontProps(); + alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); + alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); + baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); + dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); + // letterSpacing = pList.get(PR_LETTER_SPACING); + lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); + refId = pList.get(PR_REF_ID).getString(); + textDecoration = pList.getTextDecorationProps(); + // textShadow = pList.get(PR_TEXT_SHADOW); + + // implicit properties + color = pList.get(Constants.PR_COLOR).getColor(getUserAgent()); + } + + /** {@inheritDoc} */ + protected void startOfNode() throws FOPException { + super.startOfNode(); + if (refId.equals("")) { + missingPropertyError("ref-id"); + } + } + + /** + * {@inheritDoc} + * XSL Content Model: empty + */ + protected void validateChildNode(Locator loc, String nsURI, String localName) + throws ValidationException { + invalidChildError(loc, nsURI, localName); + } + + /** @return the Common Font Properties. */ + public CommonFont getCommonFont() { + return commonFont; + } + + /** @return the "color" property. */ + public Color getColor() { + return color; + } + + /** @return the "text-decoration" property. */ + public CommonTextDecoration getTextDecoration() { + return textDecoration; + } + + /** + * @return the "alignment-adjust" property + */ + public Length getAlignmentAdjust() { + return alignmentAdjust; + } + + /** + * @return the "alignment-baseline" property + */ + public int getAlignmentBaseline() { + return alignmentBaseline; + } + + /** + * @return the "baseline-shift" property + */ + public Length getBaselineShift() { + return baselineShift; + } + + /** + * @return the "dominant-baseline" property + */ + public int getDominantBaseline() { + return dominantBaseline; + } + + /** @return the Common Border, Padding, and Background Properties. */ + public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { + return commonBorderPaddingBackground; + } + + /** + * @return the "line-height" property + */ + public SpaceProperty getLineHeight() { + return lineHeight; + } + + /** @return the "ref-id" property. */ + public String getRefId() { + return refId; + } + +} diff --git a/src/java/org/apache/fop/fo/flow/PageNumberCitation.java b/src/java/org/apache/fop/fo/flow/PageNumberCitation.java index dc824e142..feea07433 100644 --- a/src/java/org/apache/fop/fo/flow/PageNumberCitation.java +++ b/src/java/org/apache/fop/fo/flow/PageNumberCitation.java @@ -19,21 +19,8 @@ package org.apache.fop.fo.flow; -import java.awt.Color; - -import org.xml.sax.Locator; - import org.apache.fop.apps.FOPException; -import org.apache.fop.datatypes.Length; -import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FObj; -import org.apache.fop.fo.PropertyList; -import org.apache.fop.fo.ValidationException; -import org.apache.fop.fo.properties.CommonBorderPaddingBackground; -import org.apache.fop.fo.properties.CommonFont; -import org.apache.fop.fo.properties.CommonTextDecoration; -import org.apache.fop.fo.properties.SpaceProperty; /** * Class modelling the fo:page-number-citation object. @@ -41,146 +28,28 @@ import org.apache.fop.fo.properties.SpaceProperty; * The page number used is the page that contains the start of the * block referenced with the ref-id attribute. */ -public class PageNumberCitation extends FObj { - // The value of properties relevant for fo:page-number-citation. - private CommonBorderPaddingBackground commonBorderPaddingBackground; - private CommonFont commonFont; - private Length alignmentAdjust; - private int alignmentBaseline; - private Length baselineShift; - private int dominantBaseline; - // private ToBeImplementedProperty letterSpacing; - private SpaceProperty lineHeight; - private String refId; - /** Holds the text decoration values. May be null */ - private CommonTextDecoration textDecoration; - // private ToBeImplementedProperty textShadow; - // Unused but valid items, commented out for performance: - // private CommonAccessibility commonAccessibility; - // private CommonAural commonAural; - // private CommonMarginInline commonMarginInline; - // private CommonRelativePosition commonRelativePosition; - // private KeepProperty keepWithNext; - // private KeepProperty keepWithPrevious; - // private int scoreSpaces; - // private Length textAltitude; - // private Length textDepth; - // private int textTransform; - // private int visibility; - // private SpaceProperty wordSpacing; - // private int wrapOption; - // End of property values - - // Properties which are not explicitely listed but are still applicable - private Color color; +public class PageNumberCitation extends AbstractPageNumberCitation { /** + * Main constructor * @param parent FONode that is the parent of this object */ public PageNumberCitation(FONode parent) { super(parent); } - /** - * {@inheritDoc} - */ - public void bind(PropertyList pList) throws FOPException { - super.bind(pList); - commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); - commonFont = pList.getFontProps(); - alignmentAdjust = pList.get(PR_ALIGNMENT_ADJUST).getLength(); - alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); - baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); - dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); - // letterSpacing = pList.get(PR_LETTER_SPACING); - lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); - refId = pList.get(PR_REF_ID).getString(); - textDecoration = pList.getTextDecorationProps(); - // textShadow = pList.get(PR_TEXT_SHADOW); - - // implicit properties - color = pList.get(Constants.PR_COLOR).getColor(getUserAgent()); - } - - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ protected void startOfNode() throws FOPException { super.startOfNode(); - if (refId.equals("")) { - missingPropertyError("ref-id"); - } - } - - /** - * {@inheritDoc} - * XSL Content Model: empty - */ - protected void validateChildNode(Locator loc, String nsURI, String localName) - throws ValidationException { - invalidChildError(loc, nsURI, localName); - } - - /** @return the Common Font Properties. */ - public CommonFont getCommonFont() { - return commonFont; - } - - /** @return the "color" property. */ - public Color getColor() { - return color; + getFOEventHandler().startPageNumberCitation(this); } - /** @return the "text-decoration" property. */ - public CommonTextDecoration getTextDecoration() { - return textDecoration; - } - - /** - * @return the "alignment-adjust" property - */ - public Length getAlignmentAdjust() { - return alignmentAdjust; - } - - /** - * @return the "alignment-baseline" property - */ - public int getAlignmentBaseline() { - return alignmentBaseline; - } - - /** - * @return the "baseline-shift" property - */ - public Length getBaselineShift() { - return baselineShift; - } - - /** - * @return the "dominant-baseline" property - */ - public int getDominantBaseline() { - return dominantBaseline; - } - - /** @return the Common Border, Padding, and Background Properties. */ - public CommonBorderPaddingBackground getCommonBorderPaddingBackground() { - return commonBorderPaddingBackground; + /** {@inheritDoc} */ + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endPageNumberCitation(this); } - /** - * @return the "line-height" property - */ - public SpaceProperty getLineHeight() { - return lineHeight; - } - - /** @return the "ref-id" property. */ - public String getRefId() { - return refId; - } - /** {@inheritDoc} */ public String getLocalName() { return "page-number-citation"; diff --git a/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java b/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java index 44ef52aec..a9b5b90df 100644 --- a/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java +++ b/src/java/org/apache/fop/fo/flow/PageNumberCitationLast.java @@ -19,6 +19,7 @@ package org.apache.fop.fo.flow; +import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FONode; /** @@ -28,7 +29,7 @@ import org.apache.fop.fo.FONode; * block referenced with the ref-id attribute. * @since XSL 1.1 */ -public class PageNumberCitationLast extends PageNumberCitation { +public class PageNumberCitationLast extends AbstractPageNumberCitation { /** * Main constructor @@ -39,6 +40,18 @@ public class PageNumberCitationLast extends PageNumberCitation { } /** {@inheritDoc} */ + protected void startOfNode() throws FOPException { + super.startOfNode(); + getFOEventHandler().startPageNumberCitationLast(this); + } + + /** {@inheritDoc} */ + protected void endOfNode() throws FOPException { + super.endOfNode(); + getFOEventHandler().endPageNumberCitationLast(this); + } + + /** {@inheritDoc} */ public String getLocalName() { return "page-number-citation-last"; } @@ -47,4 +60,5 @@ public class PageNumberCitationLast extends PageNumberCitation { public int getNameId() { return FO_PAGE_NUMBER_CITATION_LAST; } + } diff --git a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java index f2679d04b..7356bc72e 100644 --- a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java @@ -23,12 +23,13 @@ import java.util.Iterator; 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.FOText; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.flow.table.Table; +import org.apache.fop.fo.flow.table.TableFObj; import org.xml.sax.Locator; /** @@ -126,6 +127,12 @@ public class RetrieveMarker 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; @@ -138,6 +145,10 @@ public class RetrieveMarker 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); diff --git a/src/java/org/apache/fop/fo/flow/table/BorderResolver.java b/src/java/org/apache/fop/fo/flow/table/BorderResolver.java new file mode 100644 index 000000000..0a8f3d39e --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/BorderResolver.java @@ -0,0 +1,56 @@ +/* + * 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.flow.table; + +import java.util.List; + +/** + * A class dedicated to the resolution of borders in tables. It receives a series of + * events as the table is parsed and performs border resolution accordingly. + */ +interface BorderResolver { + + /** + * Receives notification of the end of a row. + * + * @param row the row that has just been finished + * @param container the FO element holding the given row + */ + void endRow(List/*<GridUnit>*/ row, TableCellContainer container); + + /** + * Receives notification of the start of a table-header/footer/body. + * + * @param part the part that has started + */ + void startPart(TableBody part); + + /** + * Receives notification of the end of a table-header/footer/body. + * + * @param part the part that has ended + */ + void endPart(TableBody part); + + /** + * Receives notification of the end of the table. + */ + void endTable(); +} diff --git a/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java b/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java new file mode 100644 index 000000000..214f9be07 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java @@ -0,0 +1,71 @@ +/* + * 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.flow.table; + +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; + +/** + * A border's informations, along with the FO element which declared it. Used for border + * resolution in the collapsing-border model. + */ +public/*TODO*/ class BorderSpecification { + + private BorderInfo borderInfo; + + private int holder; + + /** + * Creates a new border specification. + * + * @param borderInfo the border's informations + * @param holder the FO element declaring this border + */ + public/*TODO*/ BorderSpecification(BorderInfo borderInfo, int holder) { + this.borderInfo = borderInfo; + this.holder = holder; + } + + /** + * Returns this border's informations. + * + * @return this border's informations + */ + public/*TODO*/ BorderInfo getBorderInfo() { + return borderInfo; + } + + /** + * Returns the FO element declaring this border. + * + * @return one of {@link Constants#FO_TABLE}, {@link Constants#FO_TABLE_COLUMN}, + * {@link Constants#FO_TABLE_HEADER}, {@link Constants#FO_TABLE_FOOTER}, + * {@link Constants#FO_TABLE_BODY}, {@link Constants#FO_TABLE_ROW}, + * {@link Constants#FO_TABLE_CELL} + */ + public/*TODO*/ int getHolder() { + return holder; + } + + /** {@inheritDoc} */ + public String toString() { + return "{" + borderInfo + ", " + holder + "}"; + } +} diff --git a/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java new file mode 100644 index 000000000..c4f7f9a78 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java @@ -0,0 +1,168 @@ +/* + * 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.flow.table; + +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; + +/** + * A class that implements the border-collapsing model. + */ +class CollapsingBorderResolver implements BorderResolver { + + private Table table; + + private List previousRow; + + /** + * The flow of rows is interrupted by the table-footer. Save the header's last row (if + * any) for resolution between it and the body's first row. + */ + private List previousRowSave; + + private TableBody currentTablePart; + + private boolean firstInTable; + + private boolean firstInPart; + + private List footerFirstRow; + + private List footerLastRow; + + private boolean inFooter; + + CollapsingBorderResolver(Table table) { + this.table = table; + firstInTable = true; + } + + /** {@inheritDoc} */ + public void endRow(List row, TableCellContainer container) { + // Resolve before- and after-borders for the table-row + if (container instanceof TableRow) { + TableRow tableRow = (TableRow) container; + for (Iterator iter = row.iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + if (gu.getRowSpanIndex() == 0) { + gu.resolveBorder(CommonBorderPaddingBackground.BEFORE, tableRow); + } + if (gu.isLastGridUnitRowSpan()) { + gu.resolveBorder(CommonBorderPaddingBackground.AFTER, tableRow); + } + } + } + if (inFooter) { + if (footerFirstRow == null) { + footerFirstRow = row; + } + footerLastRow = row; + } else if (firstInTable) { + // Resolve border-before for the first row in the table + for (int i = 0; i < row.size(); i++) { + TableColumn column = table.getColumn(i); + ((GridUnit) row.get(i)).resolveBorder(CommonBorderPaddingBackground.BEFORE, column); + } + firstInTable = false; + } + if (firstInPart) { + // Resolve border-before for the first row in the part + for (int i = 0; i < row.size(); i++) { + ((GridUnit) row.get(i)).resolveBorder(CommonBorderPaddingBackground.BEFORE, + currentTablePart); + } + firstInPart = false; + } + if (previousRow != null) { + // Resolve after/before borders between rows + for (int i = 0; i < row.size(); i++) { + GridUnit gu = (GridUnit) row.get(i); + if (gu.getRowSpanIndex() == 0) { + GridUnit beforeGU = (GridUnit) previousRow.get(i); + gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE); + } + } + } + // Resolve start/end borders in the row + Iterator guIter = row.iterator(); + GridUnit gu = (GridUnit) guIter.next(); + gu.resolveBorder(CommonBorderPaddingBackground.START, container); + while (guIter.hasNext()) { + GridUnit guEnd = (GridUnit) guIter.next(); + if (gu.isLastGridUnitColSpan()) { + gu.resolveBorder(guEnd, CommonBorderPaddingBackground.END); + } + gu = guEnd; + } + gu.resolveBorder(CommonBorderPaddingBackground.END, container); + + previousRow = row; + } + + /** {@inheritDoc} */ + public void startPart(TableBody part) { + firstInPart = true; + currentTablePart = part; + if (part.isTableFooter()) { + inFooter = true; + previousRowSave = previousRow; + previousRow = null; + } + } + + /** {@inheritDoc} */ + public void endPart(TableBody part) { + // Resolve border-after for the last row in the part + for (int i = 0; i < previousRow.size(); i++) { + ((GridUnit) previousRow.get(i)) + .resolveBorder(CommonBorderPaddingBackground.AFTER, part); + } + if (inFooter) { + inFooter = false; + previousRow = previousRowSave; + } + } + + /** {@inheritDoc} */ + public void endTable() { + if (footerFirstRow != null) { + // Resolve after/before border between the last row of table-body and the + // first row of table-footer + for (int i = 0; i < footerFirstRow.size(); i++) { + GridUnit gu = (GridUnit) footerFirstRow.get(i); + GridUnit beforeGU = (GridUnit) previousRow.get(i); + gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE); + } + } + List lastRow; + if (footerLastRow != null) { + lastRow = footerLastRow; + } else { + lastRow = previousRow; + } + // Resolve border-after for the last row of the table + for (int i = 0; i < lastRow.size(); i++) { + TableColumn column = table.getColumn(i); + ((GridUnit) lastRow.get(i)).resolveBorder(CommonBorderPaddingBackground.AFTER, column); + } + } +} diff --git a/src/java/org/apache/fop/layoutmgr/table/EffRow.java b/src/java/org/apache/fop/fo/flow/table/EffRow.java index 1e4924a5a..17ab67f98 100644 --- a/src/java/org/apache/fop/layoutmgr/table/EffRow.java +++ b/src/java/org/apache/fop/fo/flow/table/EffRow.java @@ -17,19 +17,19 @@ /* $Id$ */ -package org.apache.fop.layoutmgr.table; +package org.apache.fop.fo.flow.table; import java.util.Iterator; import java.util.List; -import org.apache.fop.fo.flow.table.TableRow; +import org.apache.fop.layoutmgr.table.TableRowIterator; import org.apache.fop.traits.MinOptMax; /** * This class represents an effective row in a table and holds a list of grid units occupying * the row as well as some additional values. */ -class EffRow { +public class EffRow { /** Indicates that the row is the first in a table-body */ public static final int FIRST_IN_PART = GridUnit.FIRST_IN_PART; @@ -47,12 +47,21 @@ class EffRow { * Creates a new effective row instance. * @param index index of the row * @param bodyType type of body (one of HEADER, FOOTER, BODY as found on TableRowIterator) + * @param gridUnits the grid units this row is made of */ - public EffRow(int index, int bodyType) { + public EffRow(int index, int bodyType, List gridUnits) { this.index = index; this.bodyType = bodyType; + this.gridUnits = gridUnits; + // TODO this is ugly, but we may eventually be able to do without that index + for (Iterator guIter = gridUnits.iterator(); guIter.hasNext();) { + Object gu = guIter.next(); + if (gu instanceof PrimaryGridUnit) { + ((PrimaryGridUnit) gu).setStartRow(index); + } + } } - + /** @return the index of the EffRow in the sequence of rows */ public int getIndex() { return this.index; @@ -126,19 +135,6 @@ class EffRow { return null; } } - - /** - * Sets a flag on all grid units of this effective row. - * @param flag which flag to set (on of the GridUnit.* constants) - * @param value new value for the flag - */ - public void setFlagForAllGridUnits(int flag, boolean value) { - Iterator iter = gridUnits.iterator(); - while (iter.hasNext()) { - GridUnit gu = (GridUnit)iter.next(); - gu.setFlag(flag, value); - } - } /** * Returns a flag for this effective row. Only a subset of the flags on GridUnit is supported. diff --git a/src/java/org/apache/fop/layoutmgr/table/EmptyGridUnit.java b/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java index 5c208b84b..be487931b 100644 --- a/src/java/org/apache/fop/layoutmgr/table/EmptyGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java @@ -17,45 +17,58 @@ /* $Id$ */ -package org.apache.fop.layoutmgr.table; +package org.apache.fop.fo.flow.table; -import org.apache.fop.fo.flow.table.TableBody; -import org.apache.fop.fo.flow.table.TableColumn; -import org.apache.fop.fo.flow.table.TableRow; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; /** * GridUnit subclass for empty grid units. */ public class EmptyGridUnit extends GridUnit { - private TableRow row; private TableBody body; - + /** - * @param row Optional table-row instance - * @param column table-column instance - * @param body table-body the grid unit belongs to - * @param startCol column index + * @param table the containing table + * @param row the table-row element this grid unit belongs to (if any) + * @param startRow index of the row this grid unit belongs to, 0-based + * @param startCol column index, 0-based */ - public EmptyGridUnit(TableRow row, TableColumn column, TableBody body, - int startCol) { - super(null, null, column, startCol, 0); - this.row = row; - this.body = body; + EmptyGridUnit(Table table, TableRow row, int startRow, int startCol) { + super(table, row, table.getColumn(startCol), startCol, 0, 0); + } + + /** {@inheritDoc} */ + protected void setBorder(int side) { + resolvedBorders[side] = new BorderSpecification( + CommonBorderPaddingBackground.getDefaultBorderInfo(), + Constants.FO_TABLE_CELL); + } + + /** {@inheritDoc} */ + public PrimaryGridUnit getPrimary() { + throw new UnsupportedOperationException(); +// return this; TODO } - + /** {@inheritDoc} */ public boolean isPrimary() { return true; } - + /** {@inheritDoc} */ public TableBody getBody() { return this.body; } /** {@inheritDoc} */ - public TableRow getRow() { - return this.row; + public boolean isLastGridUnitColSpan() { + return true; + } + + /** {@inheritDoc} */ + public boolean isLastGridUnitRowSpan() { + return true; } } 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 22e5c02b8..a5c0b1b8b 100644 --- a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java @@ -19,6 +19,12 @@ package org.apache.fop.fo.flow.table; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import org.apache.fop.fo.ValidationException; + /** * A row group builder optimised for a fixed number of columns, known before the parsing @@ -26,10 +32,157 @@ package org.apache.fop.fo.flow.table; */ class FixedColRowGroupBuilder extends RowGroupBuilder { + /** Number of columns in the corresponding table. */ + private int numberOfColumns; + + private TableRow currentTableRow = null; + + /** 0-based, index in the row group. */ + private int currentRowIndex; + + /** The rows belonging to this row group. List of List of {@link GridUnit}s. */ + private List/*<List<GridUnit>>*/ rows; + + private boolean firstInTable = true; + + private boolean firstInPart = true; + + /** The last encountered row. This is the last row of the table if it has no footer. */ + private List lastRow; + + private BorderResolver borderResolver; + + private boolean inFooter; + + private List lastFooterRow; FixedColRowGroupBuilder(Table t) { super(t); numberOfColumns = t.getNumberOfColumns(); + if (t.isSeparateBorderModel()) { + borderResolver = new SeparateBorderResolver(); + } else { + borderResolver = new CollapsingBorderResolver(t); + } + initialize(); + } + + /** + * Prepares this builder for creating a new row group. + */ + private void initialize() { + rows = new ArrayList(); + currentRowIndex = 0; } + /** {@inheritDoc} */ + void addTableCell(TableCell cell) { + for (int i = rows.size(); i < currentRowIndex + cell.getNumberRowsSpanned(); i++) { + List effRow = new ArrayList(numberOfColumns); + for (int j = 0; j < numberOfColumns; j++) { + effRow.add(null); + } + rows.add(effRow); + } + int columnIndex = cell.getColumnNumber() - 1; + PrimaryGridUnit pgu = new PrimaryGridUnit(cell, currentTableRow, + table.getColumn(columnIndex), columnIndex); + List row = (List) rows.get(currentRowIndex); + row.set(columnIndex, pgu); + // TODO + GridUnit[] cellRow = new GridUnit[cell.getNumberColumnsSpanned()]; + cellRow[0] = pgu; + for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) { + GridUnit gu = new GridUnit(pgu, currentTableRow, table.getColumn(columnIndex + j), + columnIndex + j, j, 0); + row.set(columnIndex + j, gu); + cellRow[j] = gu; + } + pgu.addRow(cellRow); + for (int i = 1; i < cell.getNumberRowsSpanned(); i++) { + row = (List) rows.get(currentRowIndex + i); + cellRow = new GridUnit[cell.getNumberColumnsSpanned()]; + for (int j = 0; j < cell.getNumberColumnsSpanned(); j++) { + GridUnit gu = new GridUnit(pgu, currentTableRow, table.getColumn(columnIndex + j), + columnIndex + j, j, i); + row.set(columnIndex + j, gu); + cellRow[j] = gu; + } + pgu.addRow(cellRow); + } + } + + private static void setFlagForCols(int flag, List row) { + for (ListIterator iter = row.listIterator(); iter.hasNext();) { + ((GridUnit) iter.next()).setFlag(flag); + } + } + + /** {@inheritDoc} */ + void startRow(TableRow tableRow) { + currentTableRow = tableRow; + } + + /** {@inheritDoc} */ + void endRow(TableCellContainer container) { + List currentRow = (List) rows.get(currentRowIndex); + lastRow = currentRow; + // Fill gaps with empty grid units + for (int i = 0; i < numberOfColumns; i++) { + if (currentRow.get(i) == null) { + currentRow.set(i, new EmptyGridUnit(table, currentTableRow, currentRowIndex, i)); + } + } + borderResolver.endRow(currentRow, container); + ((GridUnit) currentRow.get(0)).setFlag(GridUnit.IN_FIRST_COLUMN); + ((GridUnit) currentRow.get(numberOfColumns - 1)).setFlag(GridUnit.IN_LAST_COLUMN); + if (inFooter) { + lastFooterRow = currentRow; + } else if (firstInTable) { + setFlagForCols(GridUnit.FIRST_IN_TABLE, currentRow); + firstInTable = false; + } + if (firstInPart) { + setFlagForCols(GridUnit.FIRST_IN_PART, currentRow); + firstInPart = false; + } + if (currentRowIndex == rows.size() - 1) { + // Means that the current row has no cell spanning over following rows + container.getTablePart().addRowGroup(rows); + initialize(); + } else { + currentRowIndex++; + } + currentTableRow = null; + } + + /** {@inheritDoc} */ + void startTablePart(TableBody part) { + firstInPart = true; + inFooter = part.isTableFooter(); + borderResolver.startPart(part); + } + + /** {@inheritDoc} */ + void endTablePart(TableBody tableBody) throws ValidationException { + if (rows.size() > 0) { + throw new ValidationException( + "A table-cell is spanning more rows than available in its parent element."); + } + setFlagForCols(GridUnit.LAST_IN_PART, lastRow); + borderResolver.endPart(tableBody); + inFooter = false; + } + + /** {@inheritDoc} */ + void endTable(TableBody lastTablePart) { + List lastTableRow; + if (lastFooterRow != null) { + lastTableRow = lastFooterRow; + } else { + lastTableRow = lastRow; + } + setFlagForCols(GridUnit.LAST_IN_TABLE, lastTableRow); + borderResolver.endTable(); + } } diff --git a/src/java/org/apache/fop/layoutmgr/table/GridUnit.java b/src/java/org/apache/fop/fo/flow/table/GridUnit.java index 79b2cca9e..f7c7672e3 100644 --- a/src/java/org/apache/fop/layoutmgr/table/GridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/GridUnit.java @@ -17,18 +17,14 @@ /* $Id$ */ -package org.apache.fop.layoutmgr.table; +package org.apache.fop.fo.flow.table; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.fo.flow.table.TableBody; -import org.apache.fop.fo.flow.table.TableCell; -import org.apache.fop.fo.flow.table.TableColumn; -import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; +import org.apache.fop.layoutmgr.table.CollapsingBorderModel; /** * This class represents one grid unit inside a table. @@ -39,81 +35,147 @@ public class GridUnit { /** Indicates that the grid unit is in the first column. */ public static final int IN_FIRST_COLUMN = 0; + /** Indicates that the grid unit is in the last column. */ public static final int IN_LAST_COLUMN = 1; + /** Indicates that the grid unit is in the first row of the table. */ public static final int FIRST_IN_TABLE = 2; - /** Indicates that the grid unit is in the first row of the table part (header, footer, body). */ + + /** + * Indicates that the grid unit is in the first row of the table part (header, footer, + * body). + */ public static final int FIRST_IN_PART = 3; - /** Indicates that the grid unit is in the last row of the table part (header, footer, body). */ + + /** + * Indicates that the grid unit is in the last row of the table part (header, footer, + * body). + */ public static final int LAST_IN_PART = 4; + /** Indicates that the grid unit is in the last row of the table. */ public static final int LAST_IN_TABLE = 5; + /** Indicates that the primary grid unit has a pending keep-with-next. */ public static final int KEEP_WITH_NEXT_PENDING = 6; + /** Indicates that the primary grid unit has a pending keep-with-previous. */ public static final int KEEP_WITH_PREVIOUS_PENDING = 7; /** Primary grid unit */ private PrimaryGridUnit primary; + /** Table cell which occupies this grid unit */ - private TableCell cell; - /** Table row which occupies this grid unit (may be null) */ + protected TableCell cell; + + /** Table row occupied by this grid unit (may be null). */ private TableRow row; + /** Table column that this grid unit belongs to */ private TableColumn column; /** start index of grid unit within row in column direction */ private int startCol; + /** index of grid unit within cell in column direction */ private int colSpanIndex; + /** index of grid unit within cell in row direction */ private int rowSpanIndex; + /** effective borders for a cell slot */ private CommonBorderPaddingBackground effectiveBorders; + /** flags for the grid unit */ private byte flags = 0; + protected BorderSpecification[] resolvedBorders; + + private CollapsingBorderModel collapsingBorderModel; /** * Creates a new grid unit. - * - * @param cell table cell which occupies this grid unit + * + * @param table the containing table + * @param row the table-row element this grid unit belongs to (if any) * @param column table column this grid unit belongs to * @param startCol index of the column this grid unit belongs to * @param colSpanIndex index of this grid unit in the span, in column direction + * @param rowSpanIndex index of this grid unit in the span, in row direction */ - public GridUnit(TableCell cell, TableColumn column, int startCol, int colSpanIndex) { - this(null, cell, column, startCol, colSpanIndex); + protected GridUnit(Table table, TableRow row, TableColumn column, int startCol, + int colSpanIndex, int rowSpanIndex) { + this(row, column, startCol, colSpanIndex, rowSpanIndex); + setBorders(table); } /** * Creates a new grid unit. - * - * @param primary the before-start grid unit of the cell containing this grid unit + * + * @param cell table cell which occupies this grid unit + * @param row the table-row element this grid unit belongs to (if any) * @param column table column this grid unit belongs to * @param startCol index of the column this grid unit belongs to * @param colSpanIndex index of this grid unit in the span, in column direction + * @param rowSpanIndex index of this grid unit in the span, in row direction */ - public GridUnit(PrimaryGridUnit primary, TableColumn column, int startCol, int colSpanIndex) { - this(primary, primary.getCell(), column, startCol, colSpanIndex); + protected GridUnit(TableCell cell, TableRow row, TableColumn column, int startCol, + int colSpanIndex, int rowSpanIndex) { + this(row, column, startCol, colSpanIndex, rowSpanIndex); + this.cell = cell; + setBorders(cell.getTable()); } /** * Creates a new grid unit. - * + * * @param primary the before-start grid unit of the cell containing this grid unit - * @param cell table cell which occupies this grid unit + * @param row the table-row element this grid unit belongs to (if any) * @param column table column this grid unit belongs to * @param startCol index of the column this grid unit belongs to * @param colSpanIndex index of this grid unit in the span, in column direction + * @param rowSpanIndex index of this grid unit in the span, in row direction */ - protected GridUnit(PrimaryGridUnit primary, TableCell cell, TableColumn column, int startCol, int colSpanIndex) { + GridUnit(PrimaryGridUnit primary, TableRow row, TableColumn column, int startCol, + int colSpanIndex, int rowSpanIndex) { + this(primary.getCell(), row, column, startCol, colSpanIndex, rowSpanIndex); this.primary = primary; - this.cell = cell; + } + + private GridUnit(TableRow row, TableColumn column, int startCol, int colSpanIndex, + int rowSpanIndex) { + this.row = row; this.column = column; this.startCol = startCol; this.colSpanIndex = colSpanIndex; + this.rowSpanIndex = rowSpanIndex; + } + + private void setBorders(Table table/*TODO*/) { + if (table.isSeparateBorderModel()) { + assignBorderForSeparateBorderModel(); + } else { + resolvedBorders = new BorderSpecification[4]; + collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table + .getBorderCollapse()); + if (rowSpanIndex == 0) { + setBorder(CommonBorderPaddingBackground.BEFORE); + } + if (isLastGridUnitRowSpan()) { + setBorder(CommonBorderPaddingBackground.AFTER); + } + if (colSpanIndex == 0) { + setBorder(CommonBorderPaddingBackground.START); + } + if (isLastGridUnitColSpan()) { + setBorder(CommonBorderPaddingBackground.END); + } + } + } + + protected void setBorder(int side) { + resolvedBorders[side] = cell.resolvedBorders[side]; } public TableCell getCell() { @@ -124,22 +186,14 @@ public class GridUnit { return column; } - public TableRow getRow() { - if (row != null) { - return row; - } else if (getCell().getParent() instanceof TableRow) { - return (TableRow)getCell().getParent(); - } else { - return null; - } - } - /** - * Sets the table-row FO, if applicable. - * @param row the table-row FO + * Returns the fo:table-row element (if any) this grid unit belongs to. + * + * @return the row containing this grid unit, or null if there is no fo:table-row + * element in the corresponding table-part */ - public void setRow(TableRow row) { - this.row = row; + public TableRow getRow() { + return row; } public TableBody getBody() { @@ -147,18 +201,7 @@ public class GridUnit { while (node != null && !(node instanceof TableBody)) { node = node.getParent(); } - return (TableBody)node; - } - - public Table getTable() { - FONode node = getBody(); - while (node != null && !(node instanceof Table)) { - node = node.getParent(); - } - if (node == null && getColumn() != null) { - node = getColumn().getParent(); - } - return (Table)node; + return (TableBody) node; } /** @@ -167,7 +210,7 @@ public class GridUnit { * @return the before-start grid unit of the cell containing this grid unit. */ public PrimaryGridUnit getPrimary() { - return (isPrimary() ? (PrimaryGridUnit)this : primary); + return primary; } /** @@ -194,20 +237,12 @@ public class GridUnit { /** @return true if the grid unit is the last in column spanning direction */ public boolean isLastGridUnitColSpan() { - if (cell != null) { - return (colSpanIndex == cell.getNumberColumnsSpanned() - 1); - } else { - return true; - } + return (colSpanIndex == cell.getNumberColumnsSpanned() - 1); } /** @return true if the grid unit is the last in row spanning direction */ public boolean isLastGridUnitRowSpan() { - if (cell != null) { - return (rowSpanIndex == cell.getNumberRowsSpanned() - 1); - } else { - return true; - } + return (rowSpanIndex == cell.getNumberRowsSpanned() - 1); } /** @@ -225,9 +260,10 @@ public class GridUnit { } /** - * Returns a BorderInfo instance for a side of the currently applicable cell before border - * resolution (i.e. the value from the FO). A return value of null indicates an empty cell. - * See CollapsingBorderModel(EyeCatching) where this method is used. + * Returns a BorderInfo instance for a side of the currently applicable cell before + * border resolution (i.e. the value from the FO). A return value of null indicates an + * empty cell. See CollapsingBorderModel(EyeCatching) where this method is used. + * * @param side for which side to return the BorderInfo * @return the requested BorderInfo instance or null if the grid unit is an empty cell */ @@ -243,9 +279,33 @@ public class GridUnit { * @return the resolved normal borders for this grid unit */ public CommonBorderPaddingBackground getBorders() { + // TODO + if (effectiveBorders == null) { + effectiveBorders = new CommonBorderPaddingBackground(); + setBorderInfo(CommonBorderPaddingBackground.BEFORE); + setBorderInfo(CommonBorderPaddingBackground.AFTER); + setBorderInfo(CommonBorderPaddingBackground.START); + setBorderInfo(CommonBorderPaddingBackground.END); + if (cell != null) { + effectiveBorders.setPadding(cell.getCommonBorderPaddingBackground()); + } + if (log.isDebugEnabled()) { + log.debug(this + " resolved borders: " + "before=" + + effectiveBorders.getBorderBeforeWidth(false) + ", " + "after=" + + effectiveBorders.getBorderAfterWidth(false) + ", " + "start=" + + effectiveBorders.getBorderStartWidth(false) + ", " + "end=" + + effectiveBorders.getBorderEndWidth(false)); + } + } return effectiveBorders; } + private void setBorderInfo(int side) { + if (resolvedBorders[side] != null) { + effectiveBorders.setBorderInfo(resolvedBorders[side].getBorderInfo(), side); + } + } + /** * @return true if the grid unit has any borders. */ @@ -254,52 +314,49 @@ public class GridUnit { } /** - * Assigns the borders from the given cell to this cell info. Used in - * case of separate border model. + * Assigns the borders from the given cell to this cell info. Used in case of separate + * border model. */ - public void assignBorderForSeparateBorderModel() { + void assignBorderForSeparateBorderModel() { if (cell != null) { effectiveBorders = cell.getCommonBorderPaddingBackground(); } } /** - * Resolve collapsing borders for the given cell. Used in case of the collapsing border model. - * @param other neighbouring grid unit if any - * @param side the side to resolve (one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END) + * Resolve collapsing borders for the given cell. Used in case of the collapsing + * border model. + * + * @param other neighbouring grid unit + * @param side the side to resolve (one of + * CommonBorderPaddingBackground.BEFORE|AFTER|START|END) */ - public void resolveBorder(GridUnit other, int side) { - resolveBorder(other, side, 0); + void resolveBorder(GridUnit other, int side) { + BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner( + resolvedBorders[side], other.resolvedBorders[CollapsingBorderModel + .getOtherSide(side)]); + if (resolvedBorder != null) { + this.resolvedBorders[side] = resolvedBorder; + other.resolvedBorders[CollapsingBorderModel.getOtherSide(side)] = resolvedBorder; + } } /** - * Resolve collapsing borders for the given cell. Used in case of the collapsing border model. - * @param other neighbouring grid unit if any - * @param side the side to resolve (one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END) - * @param resFlags flags for the border resolution + * Resolves the border on the given side of this grid unit, comparing it against the + * same border of the given parent element. + * + * @param side the side to resolve (one of + * CommonBorderPaddingBackground.BEFORE|AFTER|START|END) + * @param parent the parent element holding a competing border */ - public void resolveBorder(GridUnit other, int side, int resFlags) { - CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor( - getTable().getBorderCollapse()); - if (effectiveBorders == null) { - effectiveBorders = new CommonBorderPaddingBackground(); - } - effectiveBorders.setBorderInfo(borderModel.determineWinner(this, other, - side, resFlags), side); - if (cell != null) { - effectiveBorders.setPadding(cell.getCommonBorderPaddingBackground()); - } - if (log.isDebugEnabled()) { - log.debug(this + " resolved borders: " - + "before=" + effectiveBorders.getBorderBeforeWidth(false) + ", " - + "after=" + effectiveBorders.getBorderAfterWidth(false) + ", " - + "start=" + effectiveBorders.getBorderStartWidth(false) + ", " - + "end=" + effectiveBorders.getBorderEndWidth(false)); - } + void resolveBorder(int side, TableFObj parent) { + resolvedBorders[side] = collapsingBorderModel.determineWinner(resolvedBorders[side], + parent.resolvedBorders[side]); } /** * Returns a flag for this GridUnit. + * * @param which the requested flag * @return the value of the flag */ @@ -309,29 +366,25 @@ public class GridUnit { /** * Sets a flag on a GridUnit. + * * @param which the flag to set * @param value the new value for the flag */ public void setFlag(int which, boolean value) { if (value) { - flags |= (1 << which); //set flag + flags |= (1 << which); // set flag } else { - flags &= ~(1 << which); //clear flag + flags &= ~(1 << which); // clear flag } } /** - * @return the grid unit just below this grid unit if the cell is spanning. + * Sets the given flag on this grid unit. + * + * @param which the flag to set */ - public GridUnit createNextRowSpanningGridUnit() { - if (isLastGridUnitRowSpan()) { - return null; - } else { - //cloning the current GridUnit with adjustments - GridUnit gu = new GridUnit(getPrimary(), getColumn(), startCol, colSpanIndex); - gu.rowSpanIndex = rowSpanIndex + 1; - return gu; - } + public void setFlag(int which) { + setFlag(which, true); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/layoutmgr/table/PrimaryGridUnit.java b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java index ece022556..2f2cd940e 100644 --- a/src/java/org/apache/fop/layoutmgr/table/PrimaryGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java @@ -17,15 +17,14 @@ /* $Id$ */ -package org.apache.fop.layoutmgr.table; +package org.apache.fop.fo.flow.table; import java.util.LinkedList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fop.fo.flow.table.TableCell; -import org.apache.fop.fo.flow.table.TableColumn; +import org.apache.fop.layoutmgr.table.TableCellLayoutManager; /** * This class represents a primary grid unit of a spanned cell. This is the "before-start" @@ -50,23 +49,27 @@ public class PrimaryGridUnit extends GridUnit { * Creates a new primary grid unit. * * @param cell table cell which occupies this grid unit + * @param row the table-row element this grid unit belongs to (if any) * @param column table column this grid unit belongs to * @param startCol index of the column this grid unit belongs to, zero-based * @param startRow index of the row this grid unit belongs to, zero-based */ - public PrimaryGridUnit(TableCell cell, TableColumn column, int startCol, int startRow) { - super(cell, column, startCol, 0); - this.startRow = startRow; + PrimaryGridUnit(TableCell cell, TableRow row, TableColumn column, int startCol) { + super(cell, row, column, startCol, 0, 0); log.trace("PrimaryGridUnit created, row " + startRow + " col " + startCol); - if (cell != null) { - cellLM = new TableCellLayoutManager(cell, this); - } } public TableCellLayoutManager getCellLM() { + assert cellLM != null; return cellLM; } + /** {@inheritDoc} */ + public PrimaryGridUnit getPrimary() { + return this; + } + + /** {@inheritDoc} */ public boolean isPrimary() { return true; } @@ -177,6 +180,10 @@ public class PrimaryGridUnit extends GridUnit { rows.add(row); } + void setStartRow(int startRow) { + this.startRow = startRow; + } + /** * Returns the index of the row this grid unit belongs to. * @@ -225,4 +232,12 @@ public class PrimaryGridUnit extends GridUnit { || (getCell().getNumberRowsSpanned() > 1); } + /** + * Creates a cellLM for the corresponding table-cell. A new one must be created + * for each new static-content (TODO). + */ + public void createCellLM() { + cellLM = new TableCellLayoutManager(cell, this); + } + } 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 2f9a009c2..220eff85b 100644 --- a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java @@ -19,12 +19,7 @@ package org.apache.fop.fo.flow.table; -import java.util.ArrayList; -import java.util.List; - import org.apache.fop.fo.ValidationException; -import org.apache.fop.layoutmgr.table.GridUnit; -import org.apache.fop.layoutmgr.table.PrimaryGridUnit; /** * A class that creates groups of rows belonging to a same set of spans. The first row of @@ -34,16 +29,7 @@ import org.apache.fop.layoutmgr.table.PrimaryGridUnit; */ abstract class RowGroupBuilder { - /** Number of columns in the corresponding table. */ - protected int numberOfColumns; - - /** 0-based, index in the row group. */ - private int currentRowIndex; - - private Table table; - - /** The rows belonging to this row group. List of List of {@link GridUnit}s. */ - protected List rows; + protected Table table; /** * Creates and initialises a new builder for the given table. @@ -52,81 +38,55 @@ abstract class RowGroupBuilder { */ protected RowGroupBuilder(Table t) { table = t; - initialize(); } + /** - * Prepares this builder for creating a new row group. + * Adds a table-cell to the current row-group, creating {@link GridUnit}s accordingly. + * + * @param cell the cell to add */ - private void initialize() { - rows = new ArrayList(); - currentRowIndex = 0; - } + abstract void addTableCell(TableCell cell); /** - * Adds a table-cell to the row-group, creating {@link GridUnit}s accordingly. + * Receives notification of the start of an fo:table-row element. * - * @param cell + * @param tableRow the row being started */ - void addTableCell(TableCell cell) { - for (int i = rows.size(); i < currentRowIndex + cell.getNumberRowsSpanned(); i++) { - List effRow = new ArrayList(numberOfColumns); - for (int j = 0; j < numberOfColumns; j++) { - effRow.add(null); - } - rows.add(effRow); - } - int columnIndex = cell.getColumnNumber() - 1; - PrimaryGridUnit pgu = new PrimaryGridUnit(cell, table.getColumn(columnIndex), columnIndex, - currentRowIndex); - List row = (List) rows.get(currentRowIndex); - row.set(columnIndex, pgu); - for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) { - row.set(j + columnIndex, - new GridUnit(pgu, table.getColumn(columnIndex + j), columnIndex + j, j)); - } - for (int i = 1; i < cell.getNumberRowsSpanned(); i++) { - row = (List) rows.get(currentRowIndex + i); - for (int j = 0; j < cell.getNumberColumnsSpanned(); j++) { - row.set(j + columnIndex, - new GridUnit(pgu, table.getColumn(columnIndex + j), columnIndex + j, j)); - } - } - - } + abstract void startRow(TableRow tableRow); /** - * Signals that a table row has just ended, potentially finishing the current row - * group. + * 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 + * part (i.e., the given container itself or its parent if this is a table-row) will + * be called * - * @param body the table-body containing the row. Its - * {@link TableBody#addRowGroup(List)} method will be called if the current row group - * is finished. + * @param container the parent element of the current row */ - void signalRowEnd(TableBody body) { - if (currentRowIndex == rows.size() - 1) { - // Means that the current row has no cell spanning over following rows - body.addRowGroup(rows); - initialize(); - } else { - currentRowIndex++; - } - } + abstract void endRow(TableCellContainer container); /** - * Signals that the end of a table-header/footer/body has been reached. The current + * Receives notification of the start of a table-header/footer/body. + * + * @param part the part being started + */ + abstract void startTablePart(TableBody part); + + /** + * Receives notification of the end of a table-header/footer/body. The current * row-group is checked for emptiness. This row group builder is reset for handling * further possible table parts. * - * @param tableBody the table part being finished - * @throws ValidationException if a cell is spanning further than the given table part + * @param tableBody the table part being ended + * @throws ValidationException if a row-spanning cell overflows the given table part */ - void signalEndOfPart(TableBody tableBody) throws ValidationException { - if (rows.size() > 0) { - throw new ValidationException( - "A table-cell is spanning more rows than available in its parent element."); - } - initialize(); - } + abstract void endTablePart(TableBody tableBody) throws ValidationException; + /** + * Receives notification of the end of the table. + * + * @param lastTablePart the last part of the table + * @throws ValidationException if a row-spanning cell overflows one of the table's parts + */ + abstract void endTable(TableBody lastTablePart) throws ValidationException; } diff --git a/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java new file mode 100644 index 000000000..37e3cb6e8 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java @@ -0,0 +1,44 @@ +/* + * 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.flow.table; + +import java.util.List; + +/** + * A resolver for the separate-border model. Basically this class does nothing. + */ +class SeparateBorderResolver implements BorderResolver { + + /** {@inheritDoc} */ + public void endRow(List row, TableCellContainer container) { + } + + /** {@inheritDoc} */ + public void startPart(TableBody part) { + } + + /** {@inheritDoc} */ + public void endPart(TableBody part) { + } + + /** {@inheritDoc} */ + public void endTable() { + } +} 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 07fc95f7e..4933ab4dc 100644 --- a/src/java/org/apache/fop/fo/flow/table/Table.java +++ b/src/java/org/apache/fop/fo/flow/table/Table.java @@ -20,7 +20,6 @@ package org.apache.fop.fo.flow.table; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.apache.fop.apps.FOPException; @@ -154,7 +153,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startTable(this); } @@ -211,7 +210,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (!tableBodyFound) { missingChildElementError( @@ -219,6 +218,11 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { + ",table-body+)"); } if (!inMarker()) { + if (tableFooter != null) { + rowGroupBuilder.endTable(tableFooter); + } else { + rowGroupBuilder.endTable((TableBody) getChildNodes().lastNode()); + } /* clean up */ for (int i = columns.size(); --i >= 0;) { TableColumn col = (TableColumn) columns.get(i); @@ -278,6 +282,13 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } } + protected void setCollapsedBorders() { + createBorder(CommonBorderPaddingBackground.START); + createBorder(CommonBorderPaddingBackground.END); + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + } + private void finalizeColumns() throws FOPException { for (int i = 0; i < columns.size(); i++) { if (columns.get(i) == null) { @@ -305,32 +316,6 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { for (int i = columns.size() + 1; i <= columnNumber; i++) { columns.add(createImplicitColumn(i)); } - ((VariableColRowGroupBuilder) rowGroupBuilder).ensureNumberOfColumns(columnNumber); - if (tableHeader != null) { - for (Iterator iter = tableHeader.getRowGroups().iterator(); iter.hasNext();) { - VariableColRowGroupBuilder.fillWithEmptyGridUnits((List) iter.next(), - columnNumber); - } - } - if (tableFooter != null) { - for (Iterator iter = tableFooter.getRowGroups().iterator(); iter.hasNext();) { - VariableColRowGroupBuilder.fillWithEmptyGridUnits((List) iter.next(), - columnNumber); - } - } - FONodeIterator bodyIter = getChildNodes(); - if (bodyIter != null) { - while (bodyIter.hasNext()) { - FONode node = bodyIter.nextNode(); - if (node instanceof TableBody) { // AFAIK, may be a marker - for (Iterator iter = ((TableBody) node).getRowGroups().iterator(); - iter.hasNext();) { - VariableColRowGroupBuilder.fillWithEmptyGridUnits((List) iter.next(), - columnNumber); - } - } - } - } } private TableColumn createImplicitColumn(int colNumber) @@ -342,6 +327,9 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { implicitColumn.bind(pList); implicitColumn.setColumnWidth(new TableColLength(1.0, implicitColumn)); implicitColumn.setColumnNumber(colNumber); + if (!isSeparateBorderModel()) { + implicitColumn.setCollapsedBorders(collapsingBorderModel); // TODO + } return implicitColumn; } 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 7e4ee2fb0..6b12271fc 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/table/TableBody.java @@ -50,15 +50,15 @@ public class TableBody extends TableCellContainer { protected boolean tableRowsFound = false; protected boolean tableCellsFound = false; - /** - * used for initial values of column-number property - */ 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(); /** @@ -101,14 +101,15 @@ public class TableBody extends TableCellContainer { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); getFOEventHandler().startBody(this); } /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (!inMarker()) { pendingSpans = null; @@ -130,16 +131,25 @@ public class TableBody extends TableCellContainer { } } + /** {@inheritDoc} */ + TableBody getTablePart() { + return this; + } + protected void finishLastRowGroup() throws ValidationException { - RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); - if (tableRowsFound || !lastCellEndsRow) { - rowGroupBuilder.signalRowEnd(this); - } - try { - rowGroupBuilder.signalEndOfPart(this); - } catch (ValidationException e) { - e.setLocator(locator); - throw e; + if (!inMarker()) { + RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); + if (tableRowsFound) { + rowGroupBuilder.endRow(lastRow); + } else if (!lastCellEndsRow) { + rowGroupBuilder.endRow(this); + } + try { + rowGroupBuilder.endTablePart(this); + } catch (ValidationException e) { + e.setLocator(locator); + throw e; + } } } @@ -184,13 +194,20 @@ public class TableBody extends TableCellContainer { if (!inMarker()) { switch (child.getNameId()) { case FO_TABLE_ROW: - if (rowsStarted) { + if (!rowsStarted) { + getTable().getRowGroupBuilder().startTablePart(this); + } else { columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().signalRowEnd(this); + getTable().getRowGroupBuilder().endRow(lastRow); } rowsStarted = true; + lastRow = (TableRow) child; + getTable().getRowGroupBuilder().startRow(lastRow); break; case FO_TABLE_CELL: + if (!rowsStarted) { + getTable().getRowGroupBuilder().startTablePart(this); + } rowsStarted = true; TableCell cell = (TableCell) child; addTableCellChild(cell, firstRow); @@ -198,7 +215,7 @@ public class TableBody extends TableCellContainer { if (lastCellEndsRow) { firstRow = false; columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().signalRowEnd(this); + getTable().getRowGroupBuilder().endRow(this); } break; default: @@ -208,11 +225,20 @@ public class TableBody extends TableCellContainer { super.addChildNode(child); } + /** {inheritDoc} */ + protected void setCollapsedBorders() { + Table table = (Table) parent; + createBorder(CommonBorderPaddingBackground.START, table); + createBorder(CommonBorderPaddingBackground.END, table); + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + } + void addRowGroup(List rowGroup) { rowGroups.add(rowGroup); } - List getRowGroups() { + public List getRowGroups() { return rowGroups; } @@ -235,6 +261,10 @@ public class TableBody extends TableCellContainer { return FO_TABLE_BODY; } + 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. @@ -249,7 +279,7 @@ public class TableBody extends TableCellContainer { firstRow = false; if (!lastCellEndsRow) { columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().signalRowEnd(this); + getTable().getRowGroupBuilder().endRow(this); } } rowsStarted = true; 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 34c6266a7..f85d0e97e 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCell.java @@ -90,7 +90,7 @@ public class TableCell extends TableFObj { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startCell(this); } @@ -100,7 +100,7 @@ public class TableCell extends TableFObj { * FOEventHandler that we are at the end of the flow. * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (!blockItemFound) { if (getUserAgent().validateStrictly()) { missingChildElementError("marker* (%block;)+"); @@ -135,6 +135,21 @@ public class TableCell extends TableFObj { } /** {@inheritDoc} */ + protected void setCollapsedBorders() { + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + Table table = getTable(); + if (table.hasExplicitColumns()) { + TableColumn col = table.getColumn(getColumnNumber() - 1); + createBorder(CommonBorderPaddingBackground.START, col); + createBorder(CommonBorderPaddingBackground.END, col); + } else { + createBorder(CommonBorderPaddingBackground.START); + createBorder(CommonBorderPaddingBackground.END); + } + } + + /** {@inheritDoc} */ public boolean generatesReferenceAreas() { return true; } 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 ebb066c5c..7c91be351 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java @@ -93,6 +93,13 @@ public abstract class TableCellContainer extends TableFObj implements ColumnNumb } } + /** + * Returns the enclosing table-header/footer/body of this container. + * + * @return <code>this</code> for TableBody, or the parent element for TableRow + */ + abstract TableBody getTablePart(); + /** {@inheritDoc} */ public ColumnNumberManager getColumnNumberManager() { return columnNumberManager; 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 aa2dfcb0a..aeb401893 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableColumn.java +++ b/src/java/org/apache/fop/fo/flow/table/TableColumn.java @@ -31,6 +31,7 @@ import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.TableColLength; +import org.apache.fop.layoutmgr.table.CollapsingBorderModel; /** * Class modelling the fo:table-column object. @@ -114,14 +115,27 @@ public class TableColumn extends TableFObj { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); getFOEventHandler().startColumn(this); } - /** - * {@inheritDoc} - */ - protected void endOfNode() throws FOPException { + void setCollapsedBorders(CollapsingBorderModel collapsingBorderModel) { + this.collapsingBorderModel = collapsingBorderModel; + setCollapsedBorders(); + } + + /** {@inheritDoc} */ + protected void setCollapsedBorders() { + Table table = (Table) parent; + createBorder(CommonBorderPaddingBackground.BEFORE, table); + createBorder(CommonBorderPaddingBackground.AFTER, table); + createBorder(CommonBorderPaddingBackground.START); + createBorder(CommonBorderPaddingBackground.END); + } + + /** {@inheritDoc} */ + public void endOfNode() throws FOPException { getFOEventHandler().endColumn(this); } 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 53995464b..236556a05 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFObj.java @@ -30,6 +30,7 @@ import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.NumberProperty; import org.apache.fop.fo.properties.Property; +import org.apache.fop.layoutmgr.table.CollapsingBorderModel; /** * Common base class for table-related FOs @@ -41,6 +42,10 @@ public abstract class TableFObj extends FObj { private Numeric borderEndPrecedence; private Numeric borderStartPrecedence; + BorderSpecification[] resolvedBorders = new BorderSpecification[4]; // TODO + + CollapsingBorderModel collapsingBorderModel; + /** * Main constructor * @@ -122,9 +127,7 @@ public abstract class TableFObj extends FObj { super(propId); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public Property make(PropertyList propertyList) throws PropertyException { FObj fo = propertyList.getFObj(); @@ -189,4 +192,55 @@ public abstract class TableFObj extends FObj { return p; } } + + /** {@inheritDoc} */ + public void startOfNode() throws FOPException { + super.startOfNode(); + Table table = getTable(); + if (!inMarker() && !table.isSeparateBorderModel()) { + collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table + .getBorderCollapse()); + resolvedBorders = new BorderSpecification[4]; + 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. + */ + protected abstract void setCollapsedBorders(); + + /** + * Creates a BorderSpecification from the border set on the given side. If no border + * is set, a BorderSpecification with border-style none is created. + * + * @param side one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END + */ + protected void createBorder(int side) { + resolvedBorders[side] = new BorderSpecification(getCommonBorderPaddingBackground() + .getBorderInfo(side), getNameId()); + } + + /** + * Creates a BorderSpecification from the border set on the given side, performing + * conflict resolution with the same border on the given object. + * + * @param side one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END + * @param competitor a parent table element whose side coincides with the given side + * on this element + */ + protected void createBorder(int side, TableFObj competitor) { + createBorder(side); + resolvedBorders[side] = collapsingBorderModel.determineWinner(resolvedBorders[side], + competitor.resolvedBorders[side]); + } } 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 a7ee21406..e886d2ee1 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFooter.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFooter.java @@ -39,14 +39,15 @@ public class TableFooter extends TableBody { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); //getFOEventHandler().startBody(this); } /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { // getFOEventHandler().endFooter(this); if (!(tableRowsFound || tableCellsFound)) { missingChildElementError("marker* (table-row+|table-cell+)"); @@ -65,4 +66,9 @@ public class TableFooter extends TableBody { public int getNameId() { 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 bc9d88952..01ada2aa7 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableHeader.java +++ b/src/java/org/apache/fop/fo/flow/table/TableHeader.java @@ -39,14 +39,15 @@ public class TableHeader extends TableBody { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); //getFOEventHandler().startHeader(this); } /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { // getFOEventHandler().endHeader(this); if (!(tableRowsFound || tableCellsFound)) { missingChildElementError("marker* (table-row+|table-cell+)"); 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 edc8d13df..a025f92fd 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableRow.java +++ b/src/java/org/apache/fop/fo/flow/table/TableRow.java @@ -97,7 +97,7 @@ public class TableRow extends TableCellContainer { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startRow(this); } @@ -105,7 +105,7 @@ public class TableRow extends TableCellContainer { /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (firstChild == null) { missingChildElementError("(table-cell+)"); } @@ -128,6 +128,25 @@ public class TableRow extends TableCellContainer { } } + /** {@inheritDoc} */ + TableBody getTablePart() { + return (TableBody) parent; + } + + /** {@inheritDoc} */ + boolean isTableRow() { + return true; + } + + /** {inheritDoc} */ + protected void setCollapsedBorders() { + TableBody body = (TableBody) parent; + createBorder(CommonBorderPaddingBackground.START, body); + createBorder(CommonBorderPaddingBackground.END, body); + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + } + /** @return the "break-after" property. */ public int getBreakAfter() { return breakAfter; 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 53b7bfca1..66322b1b7 100644 --- a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java @@ -19,9 +19,12 @@ package org.apache.fop.fo.flow.table; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import org.apache.fop.layoutmgr.table.EmptyGridUnit; +import org.apache.fop.fo.ValidationException; + /** * A row group builder accommodating a variable number of columns. More flexible, but less @@ -31,34 +34,78 @@ class VariableColRowGroupBuilder extends RowGroupBuilder { VariableColRowGroupBuilder(Table t) { super(t); - numberOfColumns = 1; } /** - * Fills the given row group with empty grid units if necessary, so that it matches - * the given number of columns. - * - * @param rowGroup a List of List of GridUnit - * @param numberOfColumns the number of columns that the row group must have + * Each event is recorded and will be played once the table is finished, and the final + * number of columns known. */ - static void fillWithEmptyGridUnits(List rowGroup, int numberOfColumns) { - for (int i = 0; i < rowGroup.size(); i++) { - List effRow = (List) rowGroup.get(i); - for (int j = effRow.size(); j < numberOfColumns; j++) { - effRow.add(new EmptyGridUnit(null, null, null, j)); + private static interface Event { + /** + * Plays this event + * + * @param rowGroupBuilder the delegate builder which will actually create the row + * groups + * @throws ValidationException if a row-spanning cell overflows its parent body + */ + void play(RowGroupBuilder rowGroupBuilder) throws ValidationException; + } + + /** The queue of events sent to this builder. */ + private List events = new LinkedList(); + + /** {@inheritDoc} */ + void addTableCell(final TableCell cell) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.addTableCell(cell); } - } + }); } - /** - * Updates the current row group to match the given number of columns, by adding empty - * grid units if necessary. - * - * @param numberOfColumns new number of columns - */ - void ensureNumberOfColumns(int numberOfColumns) { - this.numberOfColumns = numberOfColumns; - fillWithEmptyGridUnits(rows, numberOfColumns); + /** {@inheritDoc} */ + void startRow(final TableRow tableRow) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.startRow(tableRow); + } + }); } + /** {@inheritDoc} */ + void endRow(final TableCellContainer container) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.endRow(container); + } + }); + } + + /** {@inheritDoc} */ + void startTablePart(final TableBody part) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.startTablePart(part); + } + }); + } + + /** {@inheritDoc} */ + void endTablePart(final TableBody tableBody) throws ValidationException { + // TODO catch the ValidationException sooner? + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) throws ValidationException { + rowGroupBuilder.endTablePart(tableBody); + } + }); + } + + /** {@inheritDoc} */ + void endTable(final TableBody lastTablePart) throws ValidationException { + RowGroupBuilder delegate = new FixedColRowGroupBuilder(table); + for (Iterator eventIter = events.iterator(); eventIter.hasNext();) { + ((Event) eventIter.next()).play(delegate); + } + delegate.endTable(lastTablePart); + } } diff --git a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java index e41685019..6ea08f19c 100755 --- a/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java +++ b/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java @@ -25,7 +25,6 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.PercentBaseContext; 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.image.FopImage; @@ -125,6 +124,25 @@ public class CommonBorderPaddingBackground { } } + /** + * A border info with style none. Used as a singleton, in the collapsing-border model, + * for elements which don't specify any border on some of their sides. + */ + private static BorderInfo defaultBorderInfo; + + /** + * Returns a default BorderInfo of style none. + * + * @return a BorderInfo instance with style set to {@link Constants#EN_NONE} + */ + public static synchronized BorderInfo getDefaultBorderInfo() { + if (defaultBorderInfo == null) { + /* It is enough to set color and width to null, as they should never be consulted */ + defaultBorderInfo = new BorderInfo(Constants.EN_NONE, null, null); + } + return defaultBorderInfo; + } + private BorderInfo[] borderInfo = new BorderInfo[4]; private CondLengthProperty[] padding = new CondLengthProperty[4]; @@ -139,7 +157,6 @@ public class CommonBorderPaddingBackground { * Construct a CommonBorderPaddingBackground object. * * @param pList The PropertyList to get properties from. - * @param fobj The FO to create this instance for. * @throws PropertyException if there's an error while binding the properties */ public CommonBorderPaddingBackground(PropertyList pList) throws PropertyException { @@ -229,7 +246,11 @@ public class CommonBorderPaddingBackground { * @return the border info for a side */ public BorderInfo getBorderInfo(int side) { - return this.borderInfo[side]; + if (this.borderInfo[side] == null) { + return getDefaultBorderInfo(); + } else { + return this.borderInfo[side]; + } } /** diff --git a/src/java/org/apache/fop/fo/properties/CommonHyphenation.java b/src/java/org/apache/fop/fo/properties/CommonHyphenation.java index d08d18312..26747c24d 100644 --- a/src/java/org/apache/fop/fo/properties/CommonHyphenation.java +++ b/src/java/org/apache/fop/fo/properties/CommonHyphenation.java @@ -19,9 +19,13 @@ package org.apache.fop.fo.properties; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.fop.fo.Constants; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.expr.PropertyException; +import org.apache.fop.fonts.FontMetrics; +import org.apache.fop.fonts.Typeface; /** * Store all common hyphenation properties. @@ -29,6 +33,9 @@ import org.apache.fop.fo.expr.PropertyException; * Public "structure" allows direct member access. */ public final class CommonHyphenation { + + /** Logger */ + protected static Log log = LogFactory.getLog(CommonHyphenation.class); private static final PropertyCache cache = new PropertyCache(); @@ -111,7 +118,71 @@ public final class CommonHyphenation { } - /** {@inheritDoc */ + private static final char HYPHEN_MINUS = '-'; + private static final char MINUS_SIGN = '\u2212'; + + /** + * Returns the effective hyphenation character for a font. The hyphenation character specified + * in XSL-FO may be substituted if it's not available in the font. + * @param font the font + * @return the effective hyphenation character. + */ + public char getHyphChar(org.apache.fop.fonts.Font font) { + char hyphChar = hyphenationCharacter.getCharacter(); + if (font.hasChar(hyphChar)) { + return hyphChar; //short-cut + } + char effHyphChar = hyphChar; + boolean warn = false; + if (font.hasChar(HYPHEN_MINUS)) { + effHyphChar = HYPHEN_MINUS; + warn = true; + } else if (font.hasChar(MINUS_SIGN)) { + effHyphChar = MINUS_SIGN; + FontMetrics metrics = font.getFontMetrics(); + if (metrics instanceof Typeface) { + Typeface typeface = (Typeface)metrics; + if ("SymbolEncoding".equals(typeface.getEncoding())) { + //SymbolEncoding doesn't have HYPHEN_MINUS, so replace by MINUS_SIGN + } else { + //only warn if the encoding is not SymbolEncoding + warn = true; + } + } + } else { + effHyphChar = ' '; + FontMetrics metrics = font.getFontMetrics(); + if (metrics instanceof Typeface) { + Typeface typeface = (Typeface)metrics; + if ("ZapfDingbatsEncoding".equals(typeface.getEncoding())) { + //ZapfDingbatsEncoding doesn't have HYPHEN_MINUS, so replace by ' ' + } else { + //only warn if the encoding is not ZapfDingbatsEncoding + warn = true; + } + } + } + if (warn) { + log.warn("Substituted specified hyphenation character (0x" + + Integer.toHexString(hyphChar) + + ") with 0x" + Integer.toHexString(effHyphChar) + + " because the font doesn't have the specified hyphenation character: " + + font.getFontTriplet()); + } + return effHyphChar; + } + + /** + * Returns the IPD for the hyphenation character for a font. + * @param font the font + * @return the IPD in millipoints for the hyphenation character. + */ + public int getHyphIPD(org.apache.fop.fonts.Font font) { + char hyphChar = getHyphChar(font); + return font.getCharWidth(hyphChar); + } + + /** {@inheritDoc} */ public boolean equals(Object obj) { if (obj == this) { return true; diff --git a/src/java/org/apache/fop/fo/properties/CorrespondingPropertyMaker.java b/src/java/org/apache/fop/fo/properties/CorrespondingPropertyMaker.java index 6f76a1cc7..add38161e 100644 --- a/src/java/org/apache/fop/fo/properties/CorrespondingPropertyMaker.java +++ b/src/java/org/apache/fop/fo/properties/CorrespondingPropertyMaker.java @@ -46,6 +46,11 @@ public class CorrespondingPropertyMaker { this.tb_rl = tb_rl; } + /** + * Controls whether the PropertyMaker accesses the parent property list or the current + * property list for determining the writing mode. + * @param useParent true if the parent property list should be used. + */ public void setUseParent(boolean useParent) { this.useParent = useParent; } diff --git a/src/java/org/apache/fop/fo/properties/PropertyCache.java b/src/java/org/apache/fop/fo/properties/PropertyCache.java index 22f001a07..6d9adb998 100644 --- a/src/java/org/apache/fop/fo/properties/PropertyCache.java +++ b/src/java/org/apache/fop/fo/properties/PropertyCache.java @@ -76,6 +76,10 @@ public final class PropertyCache { this.ref = old.ref; this.hash = old.hash; } + + public boolean isCleared() { + return (ref == null || ref.get() == null); + } } @@ -116,10 +120,8 @@ public final class PropertyCache { int index = this.hash & (table.length - 1); CacheEntry first = table[index]; - WeakReference ref; for (CacheEntry e = first; e != null; e = e.next) { - ref = e.ref; - if (ref != null && ref.get() == null) { + if (e.isCleared()) { /* remove obsolete entry /* 1. clear value, cause interference for non-blocking get() */ e.ref = null; @@ -127,7 +129,9 @@ public final class PropertyCache { /* 2. clone the segment, without the obsolete entry */ CacheEntry head = e.next; for (CacheEntry c = first; c != e; c = c.next) { - head = new CacheEntry(c, head); + if (!c.isCleared()) { + head = new CacheEntry(c, head); + } } table[index] = head; segment.count--; @@ -177,7 +181,7 @@ public final class PropertyCache { /* launch cleanup in a separate thread, * so it acquires its own lock, and put() * can return immediately */ - Thread cleaner = new Thread(new CacheCleaner(hash)); + Thread cleaner = new Thread(new CacheCleaner(hash), "FOP PropertyCache Cleaner"); cleaner.start(); } } @@ -273,11 +277,13 @@ public final class PropertyCache { for (int i = table.length; --i >= 0;) { for (CacheEntry c = table[i]; c != null; c = c.next) { ref = c.ref; - if ((o = ref.get()) != null) { - hash = hash(o); - idx = hash & newLength; - newTable[idx] = new CacheEntry(c, newTable[idx]); - segments[hash & SEGMENT_MASK].count++; + if (ref != null) { + if ((o = ref.get()) != null) { + hash = hash(o); + idx = hash & newLength; + newTable[idx] = new CacheEntry(c, newTable[idx]); + segments[hash & SEGMENT_MASK].count++; + } } } } diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java index 96aaf80d2..e123513c2 100644 --- a/src/java/org/apache/fop/fonts/Font.java +++ b/src/java/org/apache/fop/fonts/Font.java @@ -81,6 +81,14 @@ public class Font { } /** + * Returns the associated font metrics object. + * @return the font metrics + */ + public FontMetrics getFontMetrics() { + return this.metric; + } + + /** * Returns the font's ascender. * @return the ascender */ diff --git a/src/java/org/apache/fop/fonts/FontInfo.java b/src/java/org/apache/fop/fonts/FontInfo.java index 83bd123eb..af0fba579 100644 --- a/src/java/org/apache/fop/fonts/FontInfo.java +++ b/src/java/org/apache/fop/fonts/FontInfo.java @@ -47,13 +47,13 @@ public class FontInfo { protected static Log log = LogFactory.getLog(FontInfo.class); /** Map containing fonts that have been used */ - private Map usedFonts; + private Map usedFonts; //Map<String,FontMetrics> (String = font key) /** look up a font-triplet to find a font-name */ - private Map triplets; + private Map triplets; //Map<FontTriplet,String> (String = font key) /** look up a font-name to get a font (that implements FontMetrics at least) */ - private Map fonts; + private Map fonts; //Map<String,FontMetrics> (String = font key) /** collection of missing fonts; used to make sure the user gets * a warning for a missing font only once (not every time the font is used) @@ -290,21 +290,30 @@ public class FontInfo { */ public FontTriplet[] fontLookup(String[] families, String style, int weight) { + if (families.length == 0) { + throw new IllegalArgumentException("Specify at least one font family"); + } FontTriplet triplet; List tmpTriplets = new ArrayList(); - for (int i = 0; i < families.length; i++) { + for (int i = 0, c = families.length; i < c; i++) { triplet = fontLookup(families[i], style, weight, (i >= families.length - 1)); if (triplet != null) { tmpTriplets.add(triplet); } } if (tmpTriplets.size() != 0) { - FontTriplet[] triplets = (FontTriplet[]) tmpTriplets.toArray(TRIPLETS_TYPE); - return (FontTriplet[]) triplets; + return (FontTriplet[]) tmpTriplets.toArray(TRIPLETS_TYPE); + } + StringBuffer sb = new StringBuffer(); + for (int i = 0, c = families.length; i < c; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(families[i]); } throw new IllegalStateException( "fontLookup must return an array with at least one " - + "FontTriplet on the last call."); + + "FontTriplet on the last call. Lookup: " + sb.toString()); } private void notifyFontReplacement(FontTriplet replacedKey, FontTriplet newKey) { @@ -399,7 +408,7 @@ public class FontInfo { } /** - * Gets a Map of all registred fonts. + * Gets a Map of all registered fonts. * @return a read-only Map with font key/FontMetrics pairs */ public Map getFonts() { @@ -407,6 +416,14 @@ public class FontInfo { } /** + * Gets a Map of all registered font triplets. + * @return a read-only Map with FontTriplet/font key pairs + */ + public Map getFontTriplets() { + return java.util.Collections.unmodifiableMap(this.triplets); + } + + /** * This is used by the renderers to retrieve all the * fonts used in the document. * This is for embedded font or creating a list of used fonts. diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java index d45e72f1b..8b682f1ae 100644 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ b/src/java/org/apache/fop/fonts/FontLoader.java @@ -110,7 +110,10 @@ public abstract class FontLoader { String effURI; boolean type1 = isType1(fontFileURI); if (type1) { - effURI = fontFileURI.substring(0, fontFileURI.length() - 4) + ".pfm"; + String pfmExt = fontFileURI.substring( + fontFileURI.length() - 3, fontFileURI.length()); + pfmExt = pfmExt.substring(0, 2) + (Character.isUpperCase(pfmExt.charAt(2)) ? "M" : "m"); + effURI = fontFileURI.substring(0, fontFileURI.length() - 4) + "." + pfmExt; } else { effURI = fontFileURI; } diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index cc05d31b8..e6ed7e881 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -27,10 +27,12 @@ import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; +import org.xml.sax.InputSource; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.apps.FOPException; -import org.xml.sax.InputSource; /** * This class is used to defer the loading of a font until it is really used. @@ -95,8 +97,10 @@ public class LazyFont extends Typeface implements FontDescriptor { in = new java.net.URL(source.getSystemId()).openStream(); } if (in == null) { - String err = "Cannot load font: failed to create InputStream from" - + " Source for metrics file " + metricsFileName; + String err = "Cannot load font: After URI resolution, the returned" + + " Source object does not contain an InputStream" + + " or a valid URL (system identifier) for metrics file: " + + metricsFileName; if (fail) { throw new RuntimeException(err); } else { diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java index 1baee3f98..1df44b3a2 100644 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ b/src/java/org/apache/fop/fonts/SingleByteFont.java @@ -103,8 +103,8 @@ public class SingleByteFont extends CustomFont { if (d != 0) { return d; } else { - log.warn("Glyph " + (int) c + " not available in font " - + getFontName()); + log.warn("Glyph " + (int)c + " (0x" + Integer.toHexString(c) + + ") not available in font " + getFontName()); return '#'; } } diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java index 759327ad0..7c0b4fcfa 100644 --- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java +++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java @@ -21,11 +21,14 @@ package org.apache.fop.fonts.autodetect; import java.io.IOException; import java.net.URL; +import java.net.URLConnection; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.fonts.CachedFontInfo; @@ -62,7 +65,7 @@ public class FontInfoFinder { } // default style and weight triplet vales (fallback) - String strippedName = customFont.getStrippedFontName(); + String strippedName = stripQuotes(customFont.getStrippedFontName()); String subName = customFont.getFontSubName(); String searchName = strippedName.toLowerCase(); if (subName != null) { @@ -74,7 +77,7 @@ public class FontInfoFinder { //Full Name usually includes style/weight info so don't use these traits //If we still want to use these traits, we have to make FontInfo.fontLookup() smarter - String fullName = customFont.getFullName(); + String fullName = stripQuotes(customFont.getFullName()); triplets.add(new FontTriplet(fullName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); if (!fullName.equals(strippedName)) { triplets.add(new FontTriplet(strippedName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); @@ -82,12 +85,18 @@ public class FontInfoFinder { Set familyNames = customFont.getFamilyNames(); Iterator iter = familyNames.iterator(); while (iter.hasNext()) { - String familyName = (String)iter.next(); + String familyName = stripQuotes((String)iter.next()); if (!fullName.equals(familyName)) { triplets.add(new FontTriplet(familyName, style, weight)); } } } + + private final Pattern quotePattern = Pattern.compile("'"); + + private String stripQuotes(String name) { + return quotePattern.matcher(name).replaceAll(""); + } private String guessStyle(CustomFont customFont, String fontName) { // style @@ -136,7 +145,13 @@ public class FontInfoFinder { long fileLastModified = -1; if (fontCache != null) { try { - fileLastModified = fontUrl.openConnection().getLastModified(); + URLConnection conn = fontUrl.openConnection(); + try { + fileLastModified = conn.getLastModified(); + } finally { + //An InputStream is created even if it's not accessed, but we need to close it. + IOUtils.closeQuietly(conn.getInputStream()); + } } catch (IOException e) { // Should never happen, because URL must be local log.debug("IOError: " + e.getMessage()); diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java index f46bcadd9..e46029709 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFile.java @@ -27,6 +27,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.fonts.FontUtil; import org.apache.fop.fonts.Glyphs; /** @@ -543,7 +544,11 @@ public class TTFFile { * @return String The PostScript name */ public String getPostScriptName() { - return postScriptName; + if (postScriptName.length() == 0) { + return FontUtil.stripWhiteSpace(getFullName()); + } else { + return postScriptName; + } } /** diff --git a/src/java/org/apache/fop/fonts/type1/PFMFile.java b/src/java/org/apache/fop/fonts/type1/PFMFile.java index 490e9da90..a1e560746 100644 --- a/src/java/org/apache/fop/fonts/type1/PFMFile.java +++ b/src/java/org/apache/fop/fonts/type1/PFMFile.java @@ -28,6 +28,7 @@ import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.fonts.Glyphs; /** @@ -297,22 +298,24 @@ public class PFMFile { * @return The name of the charset. */ public String getCharSetName() { + //TODO Had to remove the detection for Expert(Subset) encoding. The PFM is not suitable + //for detecting these character sets. We have to parse the AFM for that. switch (dfCharSet) { case 0: return "WinAnsi"; // AKA ISOAdobe - case 1: - return "Expert"; case 2: if ("Symbol".equals(getPostscriptName())) { return "Symbol"; - } else { - return "ExpertSubset"; } + break; case 128: return "Shift-JIS (Japanese)"; default: - return "Unknown (" + dfCharSet + ", 0x" + Integer.toHexString(dfCharSet) + ")"; + log.warn("Unknown charset detected (" + dfCharSet + + ", 0x" + Integer.toHexString(dfCharSet) + + "). Trying fallback to WinAnsi."); } + return "WinAnsi"; } /** @@ -403,6 +406,15 @@ public class PFMFile { } /** + * Indicates whether the font is non-symbolic (Font uses the Adobe standard Latin character + * set or a subset of it). + * @return true if the font is non-symbolic + */ + public boolean isNonSymbolic() { + return (dfCharSet != 2); //!= Symbol fonts + } + + /** * Returns the characteristics flags for the font as * needed for a PDF font descriptor (See PDF specs). * @@ -411,19 +423,22 @@ public class PFMFile { public int getFlags() { int flags = 0; if (!getIsProportional()) { - flags |= 1; + flags |= 1; //bit 1: FixedPitch } - if ((dfPitchAndFamily & 16) == 16) { - flags |= 2; + if (isNonSymbolic()) { + flags |= 32; //bit 6: Nonsymbolic + } else { + flags |= 4; //bit 3: Symbolic } - if ((dfPitchAndFamily & 64) == 64) { - flags |= 4; + //int serif = dfPitchAndFamily & 0xFFFE; + if ((dfPitchAndFamily & 16) != 0) { + flags |= 2; //bit 2: Serif } - if (dfCharSet == 0) { - flags |= 6; + if ((dfPitchAndFamily & 64) != 0) { + flags |= 8; //bit 4: Script } if (dfItalic != 0) { - flags |= 7; + flags |= 64; //bit 7: Italic } return flags; } diff --git a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java index 336435b33..63962321c 100644 --- a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java +++ b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java @@ -56,7 +56,13 @@ public class Type1FontLoader extends FontLoader { pfm.load(in);
singleFont = new SingleByteFont();
singleFont.setFontType(FontType.TYPE1);
- singleFont.setEncoding(pfm.getCharSetName() + "Encoding");
+ if (pfm.getCharSet() >= 0 && pfm.getCharSet() <= 2) {
+ singleFont.setEncoding(pfm.getCharSetName() + "Encoding");
+ } else {
+ log.warn("The PFM reports an unsupported encoding ("
+ + pfm.getCharSetName() + "). The font may not work as expected.");
+ singleFont.setEncoding("WinAnsiEncoding"); //Try fallback, no guarantees!
+ }
singleFont.setResolver(this.resolver);
returnFont = singleFont;
returnFont.setFontName(pfm.getPostscriptName());
@@ -73,7 +79,7 @@ public class Type1FontLoader extends FontLoader { returnFont.setDescender(pfm.getLowerCaseDescent());
returnFont.setFontBBox(pfm.getFontBBox());
returnFont.setFirstChar(pfm.getFirstChar());
- returnFont.setLastChar(pfm.getFirstChar());
+ returnFont.setLastChar(pfm.getLastChar());
returnFont.setFlags(pfm.getFlags());
returnFont.setStemV(pfm.getStemV());
returnFont.setItalicAngle(pfm.getItalicAngle());
diff --git a/src/java/org/apache/fop/image/JpegImage.java b/src/java/org/apache/fop/image/JpegImage.java index 658d48286..1de6b0d48 100644 --- a/src/java/org/apache/fop/image/JpegImage.java +++ b/src/java/org/apache/fop/image/JpegImage.java @@ -19,11 +19,9 @@ package org.apache.fop.image; -// Java import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; -// FOP import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.fop.util.CMYKColorSpace; @@ -100,13 +98,14 @@ public class JpegImage extends AbstractFopImage { this.width = calcBytes(this.raw[index + 7], this.raw[index + 8]); - if (this.raw[index + 9] == 1) { + int numComponents = this.raw[index + 9]; + if (numComponents == 1) { this.colorSpace = ColorSpace.getInstance( ColorSpace.CS_GRAY); - } else if (this.raw[index + 9] == 3) { + } else if (numComponents == 3) { this.colorSpace = ColorSpace.getInstance( ColorSpace.CS_LINEAR_RGB); - } else if (this.raw[index + 9] == 4) { + } else if (numComponents == 4) { // howto create CMYK color space /* this.colorSpace = ColorSpace.getInstance( @@ -194,6 +193,14 @@ public class JpegImage extends AbstractFopImage { + iae.getMessage() + "). The color profile will be ignored. (" + this.getOriginalURI() + ")"); } + if (iccProfile.getNumComponents() != this.colorSpace.getNumComponents()) { + log.warn("The number of components of the ICC profile (" + + iccProfile.getNumComponents() + + ") doesn't match the image (" + + this.colorSpace.getNumComponents() + + "). Ignoring the ICC color profile."); + this.iccProfile = null; + } } else if (this.colorSpace == null) { log.error("ColorSpace not specified for JPEG image"); return false; diff --git a/src/java/org/apache/fop/layoutmgr/LineBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/LineBreakingAlgorithm.java index 602fe30c2..614d27318 100644 --- a/src/java/org/apache/fop/layoutmgr/LineBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/LineBreakingAlgorithm.java @@ -97,11 +97,14 @@ public class LineBreakingAlgorithm extends BreakingAlgorithm { addedPositions = 0; } - if (difference + bestActiveNode.availableShrink < 0) { - if (super.log.isWarnEnabled()) { - super.log.warn(FONode.decorateWithContextInfo( - "Line " + (addedPositions + 1) - + " of a paragraph overflows the available area.", thisLLM.getFObj())); + if (log.isWarnEnabled()) { + int lack = difference + bestActiveNode.availableShrink; + if (lack < 0) { + String textDiff = (lack < -50000 ? "more than 50 points" : (-lack) + "mpt"); + log.warn(FONode.decorateWithContextInfo + ("Line " + (addedPositions + 1) + + " of a paragraph overflows the available area by " + + textDiff + ".", thisLLM.getFObj())); } } diff --git a/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java new file mode 100644 index 000000000..41d4af1c1 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java @@ -0,0 +1,158 @@ +/* + * 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.layoutmgr.inline; + +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.Resolvable; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.InlineArea; +import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.inline.UnresolvedPageNumber; +import org.apache.fop.fo.flow.AbstractPageNumberCitation; +import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; +import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.TraitSetter; + +/** + * LayoutManager for the fo:page-number-citation(-last) formatting object + */ +public abstract class AbstractPageNumberCitationLayoutManager extends LeafNodeLayoutManager { + + /** The page number citation object */ + protected AbstractPageNumberCitation fobj; + /** Font for the page-number-citation */ + protected Font font; + + /** Indicates whether the page referred to by the citation has been resolved yet */ + protected boolean resolved = false; + + /** + * Constructor + * + * @param node the formatting object that creates this area + * @todo better retrieval of font info + */ + public AbstractPageNumberCitationLayoutManager(AbstractPageNumberCitation node) { + super(node); + fobj = node; + } + + /** {@inheritDoc} */ + public void initialize() { + FontInfo fi = fobj.getFOEventHandler().getFontInfo(); + FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi); + font = fi.getFontInstance(fontkeys[0], fobj.getCommonFont().fontSize.getValue(this)); + setCommonBorderPaddingBackground(fobj.getCommonBorderPaddingBackground()); + } + + /** + * {@inheritDoc} + */ + protected AlignmentContext makeAlignmentContext(LayoutContext context) { + return new AlignmentContext( + font + , fobj.getLineHeight().getOptimum(this).getLength().getValue(this) + , fobj.getAlignmentAdjust() + , fobj.getAlignmentBaseline() + , fobj.getBaselineShift() + , fobj.getDominantBaseline() + , context.getAlignmentContext() + ); + } + + /** {@inheritDoc} */ + public InlineArea get(LayoutContext context) { + curArea = getPageNumberCitationInlineArea(parentLM); + return curArea; + } + + /** + * {@inheritDoc} + * , LayoutContext) + */ + public void addAreas(PositionIterator posIter, LayoutContext context) { + super.addAreas(posIter, context); + if (!resolved) { + getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable) curArea); + } + } + + /** + * if id can be resolved then simply return a word, otherwise + * return a resolvable area + */ + private InlineArea getPageNumberCitationInlineArea(LayoutManager parentLM) { + PageViewport page = getPSLM().getFirstPVWithID(fobj.getRefId()); + TextArea text = null; + if (page != null) { + String str = page.getPageNumberString(); + // get page string from parent, build area + text = new TextArea(); + int width = getStringWidth(str); + text.addWord(str, 0); + text.setIPD(width); + resolved = true; + } else { + resolved = false; + text = new UnresolvedPageNumber(fobj.getRefId(), font); + String str = "MMM"; // reserve three spaces for page number + int width = getStringWidth(str); + text.setIPD(width); + } + updateTextAreaTraits(text); + + return text; + } + + /** + * Updates the traits for the generated text area. + * @param text the text area + */ + protected void updateTextAreaTraits(TextArea text) { + TraitSetter.setProducerID(text, fobj.getId()); + text.setBPD(font.getAscender() - font.getDescender()); + text.setBaselineOffset(font.getAscender()); + TraitSetter.addFontTraits(text, font); + text.addTrait(Trait.COLOR, fobj.getColor()); + TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); + } + + /** + * @param str string to be measured + * @return width (in millipoints ??) of the string + */ + protected int getStringWidth(String str) { + int width = 0; + for (int count = 0; count < str.length(); count++) { + width += font.getCharWidth(str.charAt(count)); + } + return width; + } + + /** {@inheritDoc} */ + protected void addId() { + getPSLM().addIDToPage(fobj.getId()); + } +} + diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java index f470e137e..0430eef0c 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java @@ -19,7 +19,12 @@ package org.apache.fop.layoutmgr.inline; +import java.util.LinkedList; +import java.util.List; + +import org.apache.fop.area.Trait; import org.apache.fop.fo.flow.Character; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; @@ -32,16 +37,10 @@ import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LeafPosition; import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.TraitSetter; -import org.apache.fop.area.Trait; import org.apache.fop.traits.MinOptMax; import org.apache.fop.traits.SpaceVal; import org.apache.fop.util.CharUtilities; -import java.util.List; -import java.util.LinkedList; -import org.apache.fop.fo.properties.CommonBorderPaddingBackground; -import org.apache.fop.layoutmgr.inline.AlignmentContext; - /** * LayoutManager for the fo:character formatting object */ @@ -70,7 +69,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { font = fi.getFontInstance(fontkeys[0], fobj.getCommonFont().fontSize.getValue(this)); SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing()); letterSpaceIPD = ls.getSpace(); - hyphIPD = font.getCharWidth(fobj.getCommonHyphenation().hyphenationCharacter.getCharacter()); + hyphIPD = fobj.getCommonHyphenation().getHyphIPD(font); borderProps = fobj.getCommonBorderPaddingBackground(); setCommonBorderPaddingBackground(borderProps); org.apache.fop.area.inline.TextArea chArea = getCharacterInlineArea(fobj); diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java index c012f351e..331d48b75 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java @@ -19,22 +19,20 @@ package org.apache.fop.layoutmgr.inline; -import org.apache.fop.fo.flow.PageNumberCitationLast; import org.apache.fop.area.PageViewport; import org.apache.fop.area.Resolvable; import org.apache.fop.area.inline.InlineArea; -import org.apache.fop.area.inline.UnresolvedPageNumber; import org.apache.fop.area.inline.TextArea; +import org.apache.fop.area.inline.UnresolvedPageNumber; +import org.apache.fop.fo.flow.PageNumberCitationLast; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutManager; /** * LayoutManager for the fo:page-number-citation-last formatting object */ -public class PageNumberCitationLastLayoutManager extends PageNumberCitationLayoutManager { +public class PageNumberCitationLastLayoutManager extends AbstractPageNumberCitationLayoutManager { - private PageNumberCitationLast fobj; - /** * Constructor * diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java index f3a83b9f2..4f5c78540 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java @@ -19,33 +19,19 @@ package org.apache.fop.layoutmgr.inline; -import org.apache.fop.fo.flow.PageNumberCitation; import org.apache.fop.area.PageViewport; -import org.apache.fop.area.Resolvable; -import org.apache.fop.area.Trait; import org.apache.fop.area.inline.InlineArea; -import org.apache.fop.area.inline.UnresolvedPageNumber; import org.apache.fop.area.inline.TextArea; -import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontTriplet; +import org.apache.fop.area.inline.UnresolvedPageNumber; +import org.apache.fop.fo.flow.PageNumberCitation; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutManager; -import org.apache.fop.layoutmgr.PositionIterator; -import org.apache.fop.layoutmgr.TraitSetter; /** * LayoutManager for the fo:page-number-citation formatting object */ -public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager { +public class PageNumberCitationLayoutManager extends AbstractPageNumberCitationLayoutManager { - private PageNumberCitation fobj; - /** Font for the page-number-citation */ - protected Font font; - - /** Indicates whether the page referred to by the citation has been resolved yet */ - protected boolean resolved = false; - /** * Constructor * @@ -54,50 +40,15 @@ public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager { */ public PageNumberCitationLayoutManager(PageNumberCitation node) { super(node); - fobj = node; } /** {@inheritDoc} */ - public void initialize() { - FontInfo fi = fobj.getFOEventHandler().getFontInfo(); - FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi); - font = fi.getFontInstance(fontkeys[0], fobj.getCommonFont().fontSize.getValue(this)); - setCommonBorderPaddingBackground(fobj.getCommonBorderPaddingBackground()); - } - - /** - * {@inheritDoc} - */ - protected AlignmentContext makeAlignmentContext(LayoutContext context) { - return new AlignmentContext( - font - , fobj.getLineHeight().getOptimum(this).getLength().getValue(this) - , fobj.getAlignmentAdjust() - , fobj.getAlignmentBaseline() - , fobj.getBaselineShift() - , fobj.getDominantBaseline() - , context.getAlignmentContext() - ); - } - - /** {@inheritDoc} */ public InlineArea get(LayoutContext context) { curArea = getPageNumberCitationInlineArea(parentLM); return curArea; } /** - * {@inheritDoc} - * , LayoutContext) - */ - public void addAreas(PositionIterator posIter, LayoutContext context) { - super.addAreas(posIter, context); - if (!resolved) { - getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable) curArea); - } - } - - /** * if id can be resolved then simply return a word, otherwise * return a resolvable area */ @@ -124,34 +75,5 @@ public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager { return text; } - /** - * Updates the traits for the generated text area. - * @param text the text area - */ - protected void updateTextAreaTraits(TextArea text) { - TraitSetter.setProducerID(text, fobj.getId()); - text.setBPD(font.getAscender() - font.getDescender()); - text.setBaselineOffset(font.getAscender()); - TraitSetter.addFontTraits(text, font); - text.addTrait(Trait.COLOR, fobj.getColor()); - TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); - } - - /** - * @param str string to be measured - * @return width (in millipoints ??) of the string - */ - protected int getStringWidth(String str) { - int width = 0; - for (int count = 0; count < str.length(); count++) { - width += font.getCharWidth(str.charAt(count)); - } - return width; - } - - /** {@inheritDoc} */ - protected void addId() { - getPSLM().addIDToPage(fobj.getId()); - } } diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index e62f3dc2a..63f11147c 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -20,8 +20,8 @@ package org.apache.fop.layoutmgr.inline; import java.util.ArrayList; -import java.util.List; import java.util.LinkedList; +import java.util.List; import java.util.ListIterator; import org.apache.commons.logging.Log; @@ -195,7 +195,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // With CID fonts, space isn't neccesary currentFontState.width(32) spaceCharIPD = font.getCharWidth(' '); // Use hyphenationChar property - hyphIPD = font.getCharWidth(foText.getCommonHyphenation().hyphenationCharacter.getCharacter()); + hyphIPD = foText.getCommonHyphenation().getHyphIPD(font); SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing()); halfLS = new SpaceVal(MinOptMax.multiply(ls.getSpace(), 0.5), @@ -508,7 +508,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { && i == lastIndex && areaInfo.bHyphenated) { // add the hyphenation character - wordChars.append(foText.getCommonHyphenation().hyphenationCharacter.getCharacter()); + wordChars.append(foText.getCommonHyphenation().getHyphChar(font)); } textArea.addWord(wordChars.toString(), 0, letterAdjust); wordStartIndex = -1; diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java index 8af0b87a9..139eacf43 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java +++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java @@ -22,6 +22,9 @@ package org.apache.fop.layoutmgr.table; import java.util.List; import java.util.ListIterator; +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.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthElement; @@ -74,7 +77,7 @@ class ActiveCell { } if (pgu.isLastGridUnitRowSpan() && pgu.getRow() != null) { makeBoxForWholeRow |= pgu.getRow().mustKeepTogether(); - makeBoxForWholeRow |= pgu.getTable().mustKeepTogether(); + makeBoxForWholeRow |= tableLM.getTable().mustKeepTogether(); } if (makeBoxForWholeRow) { elementList = new java.util.ArrayList(1); @@ -94,7 +97,7 @@ class ActiveCell { this.previousRowsLength = previousRowsLength; nextStepLength = previousRowsLength; totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList); - if (pgu.getTable().isSeparateBorderModel()) { + if (tableLM.getTable().isSeparateBorderModel()) { borderBefore = pgu.getBorders().getBorderBeforeWidth(false) + tableLM.getHalfBorderSeparationBPD(); borderAfter = pgu.getBorders().getBorderAfterWidth(false) @@ -239,6 +242,8 @@ class ActiveCell { * @return true if this cell's next step is inferior or equal to the next minimal step */ boolean contributesContent() { + // return includedInLastStep() && the cell hasn't finished yet, otherwise there's + // nothing more to contribute return includedInLastStep() && end >= start; } @@ -248,7 +253,7 @@ class ActiveCell { * @return true if this cell's first step is inferior or equal to the current one */ boolean hasStarted() { - return includedLength > 0; + return includedLength >= 0; } /** diff --git a/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java b/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java index 5c60ee6fd..a0bff3b5e 100644 --- a/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java +++ b/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java @@ -20,8 +20,8 @@ package org.apache.fop.layoutmgr.table; import org.apache.fop.fo.Constants; +import org.apache.fop.fo.flow.table.BorderSpecification; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; -import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; /** * This class is a superclass for the two collapsing border models defined @@ -37,10 +37,7 @@ public abstract class CollapsingBorderModel { protected static final int START = CommonBorderPaddingBackground.START; /** end side */ protected static final int END = CommonBorderPaddingBackground.END; - - /** Flag: current grid unit is either start or end of the table. */ - public static final int VERTICAL_START_END_OF_TABLE = 1; - + /** Indicates that the cell is/starts in the first row being painted on a particular page */ //public static final int FIRST_ROW_IN_TABLE_PART = 1; /** Indicates that the cell is/ends in the last row being painted on a particular page */ @@ -53,7 +50,7 @@ public abstract class CollapsingBorderModel { //These statics are used singleton-style. No MT issues here. private static CollapsingBorderModel collapse = null; private static CollapsingBorderModel collapseWithPrecedence = null; - + /** * @param borderCollapse border collapse control * @return the border model for the cell @@ -74,12 +71,12 @@ public abstract class CollapsingBorderModel { throw new IllegalArgumentException("Illegal border-collapse mode."); } } - + /** * @param side the side on the current cell * @return the adjacent side on the neighbouring cell */ - public static int getOtherSide(int side) { + public/*TODO*/ static int getOtherSide(int side) { switch (side) { case CommonBorderPaddingBackground.BEFORE: return CommonBorderPaddingBackground.AFTER; @@ -93,23 +90,32 @@ public abstract class CollapsingBorderModel { throw new IllegalArgumentException("Illegal parameter: side"); } } - + /** * @param side the side to investigate * @return true if the adjacent cell is before or after */ protected boolean isVerticalRelation(int side) { - return (side == CommonBorderPaddingBackground.BEFORE + return (side == CommonBorderPaddingBackground.BEFORE || side == CommonBorderPaddingBackground.AFTER); } - + private static int compareInt(int value1, int value2) { + if (value1 < value2) { + return -1; + } else if (value1 == value2) { + return 0; + } else { + return 1; + } + } + /** * See rule 4 in 6.7.10 for the collapsing border model. * @param style the border style to get the preference value for * @return the preference value of the style */ - public int getPreferenceValue(int style) { + private static int getStylePreferenceValue(int style) { switch (style) { case Constants.EN_DOUBLE: return 0; case Constants.EN_SOLID: return -1; @@ -122,14 +128,62 @@ public abstract class CollapsingBorderModel { default: throw new IllegalStateException("Illegal border style: " + style); } } - + + /** + * Compares the two given styles (see {@link Constants}). + * + * @param style1 a style constant + * @param style2 another style constant + * @return a value < 0 if style1 has less priority than style2, 0 if both are + * equal, a value > 0 if style1 has more priority than style2 + */ + static int compareStyles(int style1, int style2) { + int value1 = getStylePreferenceValue(style1); + int value2 = getStylePreferenceValue(style2); + return compareInt(value1, value2); + } + + private static int getHolderPreferenceValue(int id) { + switch (id) { + case Constants.FO_TABLE_CELL: return 0; + case Constants.FO_TABLE_ROW: return -1; + case Constants.FO_TABLE_HEADER: + case Constants.FO_TABLE_FOOTER: + case Constants.FO_TABLE_BODY: + return -2; + case Constants.FO_TABLE_COLUMN: return -3; + // TODO colgroup + case Constants.FO_TABLE: return -4; + default: throw new IllegalStateException(); + } + } + + /** + * Compares the two given FO ids ({@link Constants}.FO*) in terms of border + * declaration. + * + * @param id1 a FO id ({@link Constants#FO_TABLE}, {@link Constants#FO_TABLE_BODY}, + * etc.) + * @param id2 another FO id + * @return a value < 0 if id1 has less priority than id2, 0 if both are equal, a + * value > 0 if id1 has more priority than id2 + */ + static int compareFOs(int id1, int id2) { + int p1 = getHolderPreferenceValue(id1); + int p2 = getHolderPreferenceValue(id2); + return compareInt(p1, p2); + } + /** - * Determines the winning BorderInfo. - * @param current grid unit of the current element - * @param neighbour grid unit of the neighbouring element - * @return the winning BorderInfo + * Returns the border which wins the border conflict resolution. In case the two + * borders are equivalent (identical, or only the color is different), null is + * returned. + * + * @param border1 a border specification + * @param border2 another border specification + * @return the winning border, null if the two borders are equivalent */ - public abstract BorderInfo determineWinner( - GridUnit current, GridUnit neighbour, int side, int flags); - + public abstract BorderSpecification determineWinner(BorderSpecification border1, + BorderSpecification border2); + } diff --git a/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java b/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java index ddbb20c47..5f979c986 100644 --- a/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java +++ b/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java @@ -20,11 +20,7 @@ package org.apache.fop.layoutmgr.table; 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.TableCell; -import org.apache.fop.fo.flow.table.TableColumn; -import org.apache.fop.fo.flow.table.TableRow; +import org.apache.fop.fo.flow.table.BorderSpecification; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; /** @@ -34,268 +30,45 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; */ public class CollapsingBorderModelEyeCatching extends CollapsingBorderModel { - public BorderInfo determineWinner(GridUnit currentGridUnit, - GridUnit otherGridUnit, int side, int flags) { - final boolean vertical = isVerticalRelation(side); - final int otherSide = getOtherSide(side); - - //Get cells - TableCell currentCell = currentGridUnit.getCell(); - TableCell otherCell = null; - if (otherGridUnit != null) { - otherCell = otherGridUnit.getCell(); - } - - //Get rows - TableRow currentRow = currentGridUnit.getRow(); - TableRow otherRow = null; - if (vertical && otherCell != null) { - otherRow = otherGridUnit.getRow(); - } - - //get bodies - TableBody currentBody = currentGridUnit.getBody(); - TableBody otherBody = null; - if (otherRow != null) { - otherBody = otherGridUnit.getBody(); - } - - //get columns - TableColumn currentColumn = currentGridUnit.getColumn(); - TableColumn otherColumn = null; - if (otherGridUnit != null) { - otherColumn = otherGridUnit.getColumn(); - } - - //TODO get column groups - - //Get table - Table table = currentGridUnit.getTable(); - - //---------------------------------------------------------------------- - //We're creating two arrays containing the applicable BorderInfos for - //each cell in question. - //0 = cell, 1 = row, 2 = row group (body), 3 = column, - //4 = col group (spanned column, see 6.7.3), 5 = table - - BorderInfo[] current = new BorderInfo[6]; - BorderInfo[] other = new BorderInfo[6]; - //cell - current[0] = currentGridUnit.getOriginalBorderInfoForCell(side); - if (otherGridUnit != null) { - other[0] = otherGridUnit.getOriginalBorderInfoForCell(otherSide); - } - if ((currentRow != null) - && (side == BEFORE - || side == AFTER - || (currentGridUnit.getFlag(GridUnit.IN_FIRST_COLUMN) && side == START) - || (currentGridUnit.getFlag(GridUnit.IN_LAST_COLUMN) && side == END))) { - //row - current[1] = currentRow.getCommonBorderPaddingBackground().getBorderInfo(side); - } - if (otherRow != null) { - //row - other[1] = otherRow.getCommonBorderPaddingBackground().getBorderInfo(otherSide); - } - if (currentBody != null - && ((side == BEFORE && currentGridUnit.getFlag(GridUnit.FIRST_IN_PART)) - || (side == AFTER && currentGridUnit.getFlag(GridUnit.LAST_IN_PART)) - || (currentGridUnit.getFlag(GridUnit.IN_FIRST_COLUMN) && side == START) - || (currentGridUnit.getFlag(GridUnit.IN_LAST_COLUMN) && side == END))) { - //row group (=body, table-header or table-footer) - current[2] = currentBody.getCommonBorderPaddingBackground().getBorderInfo(side); - } - if (otherGridUnit != null - && otherBody != null - && ((otherSide == BEFORE && otherGridUnit.getFlag(GridUnit.FIRST_IN_PART)) - || (otherSide == AFTER && otherGridUnit.getFlag(GridUnit.LAST_IN_PART)))) { - //row group (=body, table-header or table-footer) - other[2] = otherBody.getCommonBorderPaddingBackground().getBorderInfo(otherSide); - } - if ((side == BEFORE && otherGridUnit == null) - || (side == AFTER && otherGridUnit == null) - || (side == START) - || (side == END)) { - //column - current[3] = currentColumn.getCommonBorderPaddingBackground().getBorderInfo(side); - } - if (otherColumn != null) { - //column - other[3] = otherColumn.getCommonBorderPaddingBackground().getBorderInfo(otherSide); - } - //TODO current[4] and other[4] for column groups - if (otherGridUnit == null - && ((side == BEFORE && (flags & VERTICAL_START_END_OF_TABLE) > 0) - || (side == AFTER && (flags & VERTICAL_START_END_OF_TABLE) > 0) - || (side == START) - || (side == END))) { - //table - current[5] = table.getCommonBorderPaddingBackground().getBorderInfo(side); - } - //other[6] is always null, since it's always the same table - - BorderInfo resolved = null; - - // *** Rule 1 *** - resolved = doRule1(current, other); - if (resolved != null) { - return resolved; - } - - // *** Rule 2 *** - if (!doRule2(current, other)) { - } - - // *** Rule 3 *** - resolved = doRule3(current, other); - if (resolved != null) { - return resolved; - } - - // *** Rule 4 *** - resolved = doRule4(current, other); - if (resolved != null) { - return resolved; - } - - // *** Rule 5 *** - resolved = doRule5(current, other); - if (resolved != null) { - return resolved; - } - - return null; //no winner, no border - } - - private BorderInfo doRule1(BorderInfo[] current, BorderInfo[] other) { - for (int i = 0; i < current.length; i++) { - if ((current[i] != null) && (current[i].getStyle() == Constants.EN_HIDDEN)) { - return current[i]; - } - if ((other[i] != null) && (other[i].getStyle() == Constants.EN_HIDDEN)) { - return other[i]; - } - } - return null; - } - - private boolean doRule2(BorderInfo[] current, BorderInfo[] other) { - boolean found = false; - for (int i = 0; i < current.length; i++) { - if ((current[i] != null) && (current[i].getStyle() != Constants.EN_NONE)) { - found = true; - break; + /** {@inheritDoc} */ + public BorderSpecification determineWinner(BorderSpecification border1, + BorderSpecification border2) { + BorderInfo bi1 = border1.getBorderInfo(); + BorderInfo bi2 = border2.getBorderInfo(); + // Rule 1 + if (bi1.getStyle() == Constants.EN_HIDDEN) { + return border1; + } else if (bi2.getStyle() == Constants.EN_HIDDEN) { + return border2; + } + // Rule 2 + if (bi2.getStyle() == Constants.EN_NONE) { + return border1; + } else if (bi1.getStyle() == Constants.EN_NONE) { + return border2; + } + // Rule 3 + int width1 = bi1.getRetainedWidth(); + int width2 = bi2.getRetainedWidth(); + if (width1 > width2) { + return border1; + } else if (width1 == width2) { + int cmp = compareStyles(bi1.getStyle(), bi2.getStyle()); + if (cmp > 0) { + return border1; + } else if (cmp < 0) { + return border2; } - if ((other[i] != null) && (other[i].getStyle() != Constants.EN_NONE)) { - found = true; - break; - } - } - return found; - } - - private BorderInfo doRule3(BorderInfo[] current, BorderInfo[] other) { - int width = 0; - //Find max border width - for (int i = 0; i < current.length; i++) { - if ((current[i] != null) && (current[i].getRetainedWidth() > width)) { - width = current[i].getRetainedWidth(); - } - if ((other[i] != null) && (other[i].getRetainedWidth() > width)) { - width = other[i].getRetainedWidth(); - } - } - BorderInfo widest = null; - int count = 0; - //See if there's only one with the widest border - for (int i = 0; i < current.length; i++) { - if ((current[i] != null) && (current[i].getRetainedWidth() == width)) { - count++; - if (widest == null) { - widest = current[i]; - } - } else { - current[i] = null; //Discard the narrower ones - } - if ((other[i] != null) && (other[i].getRetainedWidth() == width)) { - count++; - if (widest == null) { - widest = other[i]; - } - } else { - other[i] = null; //Discard the narrower ones - } - } - if (count == 1) { - return widest; } else { - return null; + return border2; } - } - - private BorderInfo doRule4(BorderInfo[] current, BorderInfo[] other) { - int pref = getPreferenceValue(Constants.EN_INSET); //Lowest preference - //Find highest preference value - for (int i = 0; i < current.length; i++) { - if (current[i] != null) { - int currPref = getPreferenceValue(current[i].getStyle()); - if (currPref > pref) { - pref = currPref; - } - } - if (other[i] != null) { - int currPref = getPreferenceValue(other[i].getStyle()); - if (currPref > pref) { - pref = currPref; - } - } - } - BorderInfo preferred = null; - int count = 0; - //See if there's only one with the preferred border style - for (int i = 0; i < current.length; i++) { - if (current[i] != null) { - int currPref = getPreferenceValue(current[i].getStyle()); - if (currPref == pref) { - count++; - if (preferred == null) { - preferred = current[i]; - } - break; - } - } else { - current[i] = null; //Discard the ones that are not preferred - } - if (other[i] != null) { - int currPref = getPreferenceValue(other[i].getStyle()); - if (currPref == pref) { - count++; - if (preferred == null) { - preferred = other[i]; - } - break; - } - } else { - other[i] = null; //Discard the ones that are not preferred - } - } - if (count == 1) { - return preferred; - } else { - return null; - } - } - - private BorderInfo doRule5(BorderInfo[] current, BorderInfo[] other) { - for (int i = 0; i < current.length; i++) { - if (current[i] != null) { - return current[i]; - } - if (other[i] != null) { - return other[i]; - } + // Rule 4 + int cmp = compareFOs(border1.getHolder(), border2.getHolder()); + if (cmp > 0) { + return border1; + } else if (cmp < 0) { + return border2; } return null; } - } diff --git a/src/java/org/apache/fop/layoutmgr/table/GridUnitPart.java b/src/java/org/apache/fop/layoutmgr/table/GridUnitPart.java index 28064b3e3..e0cdfccf1 100644 --- a/src/java/org/apache/fop/layoutmgr/table/GridUnitPart.java +++ b/src/java/org/apache/fop/layoutmgr/table/GridUnitPart.java @@ -19,6 +19,9 @@ package org.apache.fop.layoutmgr.table; +import org.apache.fop.fo.flow.table.GridUnit; +import org.apache.fop.fo.flow.table.PrimaryGridUnit; + /** * Represents a non-dividable part of a grid unit. Used by the table stepper. */ diff --git a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java index 4dd42110f..028d60bf3 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java @@ -26,6 +26,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; +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.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.LengthRangeProperty; @@ -47,21 +50,12 @@ class RowGroupLayoutManager { private TableLayoutManager tableLM; - private TableRowIterator bodyIter; - private TableRowIterator headerIter; - private TableRowIterator footerIter; - private TableRowIterator thisIter; private TableStepper tableStepper; - RowGroupLayoutManager(TableLayoutManager tableLM, EffRow[] rowGroup, TableRowIterator bodyIter, - TableRowIterator headerIter, TableRowIterator footerIter, TableRowIterator thisIter, + RowGroupLayoutManager(TableLayoutManager tableLM, EffRow[] rowGroup, TableStepper tableStepper) { this.tableLM = tableLM; this.rowGroup = rowGroup; - this.bodyIter = bodyIter; - this.headerIter = headerIter; - this.footerIter = footerIter; - this.thisIter = thisIter; this.tableStepper = tableStepper; } @@ -97,10 +91,6 @@ class RowGroupLayoutManager { public LinkedList getNextKnuthElements(LayoutContext context, int alignment, int bodyType) { LinkedList returnList = new LinkedList(); - //Border resolution - if (!tableLM.getTable().isSeparateBorderModel()) { - resolveNormalBeforeAfterBordersForRowGroup(); - } //Reset keep-with-next when remaining inside the table. //The context flag is only used to propagate keep-with-next to the outside. @@ -134,107 +124,6 @@ class RowGroupLayoutManager { } /** - * Resolves normal borders for a row group. - * @param iter Table row iterator to operate on - */ - private void resolveNormalBeforeAfterBordersForRowGroup() { - for (int rgi = 0; rgi < rowGroup.length; rgi++) { - EffRow row = rowGroup[rgi]; - EffRow prevRow = thisIter.getPrecedingRow(row); - EffRow nextRow = thisIter.getFollowingRow(row); - if ((prevRow == null) && (thisIter == bodyIter) && (headerIter != null)) { - prevRow = headerIter.getLastRow(); - } - if ((nextRow == null) && (thisIter == headerIter)) { - nextRow = bodyIter.getFirstRow(); - } - if ((nextRow == null) && (thisIter == bodyIter) && (footerIter != null)) { - nextRow = footerIter.getFirstRow(); - } - if ((prevRow == null) && (thisIter == footerIter)) { - //TODO This could be bad for memory consumption because it already causes the - //whole body iterator to be prefetched! - prevRow = bodyIter.getLastRow(); - } - log.debug("prevRow-row-nextRow: " + prevRow + " - " + row + " - " + nextRow); - - //Determine the grid units necessary for getting all the borders right - int guCount = row.getGridUnits().size(); - if (prevRow != null) { - guCount = Math.max(guCount, prevRow.getGridUnits().size()); - } - if (nextRow != null) { - guCount = Math.max(guCount, nextRow.getGridUnits().size()); - } - GridUnit gu = row.getGridUnit(0); - //Create empty grid units to hold resolved borders of neighbouring cells - //TODO maybe this needs to be done differently (and sooner) - for (int i = 0; i < guCount - row.getGridUnits().size(); i++) { - //TODO This block is untested! - int pos = row.getGridUnits().size() + i; - row.getGridUnits().add(new EmptyGridUnit(gu.getRow(), - tableLM.getColumns().getColumn(pos + 1), gu.getBody(), - pos)); - } - - //Now resolve normal borders - if (tableLM.getTable().isSeparateBorderModel()) { - //nop, borders are already assigned at this point - } else { - for (int i = 0; i < row.getGridUnits().size(); i++) { - gu = row.getGridUnit(i); - GridUnit other; - int flags = 0; - if (prevRow != null && i < prevRow.getGridUnits().size()) { - other = prevRow.getGridUnit(i); - } else { - other = null; - } - if (other == null - || other.isEmpty() - || gu.isEmpty() - || gu.getPrimary() != other.getPrimary()) { - if ((thisIter == bodyIter) - && gu.getFlag(GridUnit.FIRST_IN_TABLE) - && (headerIter == null)) { - flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; - } - if ((thisIter == headerIter) - && gu.getFlag(GridUnit.FIRST_IN_TABLE)) { - flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; - } - gu.resolveBorder(other, - CommonBorderPaddingBackground.BEFORE, flags); - } - - flags = 0; - if (nextRow != null && i < nextRow.getGridUnits().size()) { - other = nextRow.getGridUnit(i); - } else { - other = null; - } - if (other == null - || other.isEmpty() - || gu.isEmpty() - || gu.getPrimary() != other.getPrimary()) { - if ((thisIter == bodyIter) - && gu.getFlag(GridUnit.LAST_IN_TABLE) - && (footerIter == null)) { - flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; - } - if ((thisIter == footerIter) - && gu.getFlag(GridUnit.LAST_IN_TABLE)) { - flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE; - } - gu.resolveBorder(other, - CommonBorderPaddingBackground.AFTER, flags); - } - } - } - } - } - - /** * Creates Knuth elements for a row group (see TableRowIterator.getNextRowGroup()). * @param context Active LayoutContext * @param alignment alignment indicator @@ -263,7 +152,7 @@ class RowGroupLayoutManager { int maxCellHeight = 0; int effRowContentHeight = 0; for (int j = 0; j < row.getGridUnits().size(); j++) { -// assert maxColumnCount == 0 || maxColumnCount == row.getGridUnits().size(); // TODO vh + assert maxColumnCount == 0 || maxColumnCount == row.getGridUnits().size(); maxColumnCount = Math.max(maxColumnCount, row.getGridUnits().size()); GridUnit gu = row.getGridUnit(j); if ((gu.isPrimary() || (gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan())) @@ -271,6 +160,7 @@ class RowGroupLayoutManager { PrimaryGridUnit primary = gu.getPrimary(); if (gu.isPrimary()) { + primary.createCellLM(); // TODO a new LM must be created for every new static-content primary.getCellLM().setParent(tableLM); //Determine the table-row if any diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 5b5fece32..1ea0d308e 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -25,6 +25,9 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +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.TableRow; import org.apache.fop.fo.properties.LengthRangeProperty; import org.apache.fop.layoutmgr.ElementListUtils; diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 61b7c9e65..46bdecf63 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -23,8 +23,13 @@ import java.util.LinkedList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.Trait; import org.apache.fop.datatypes.PercentBaseContext; import org.apache.fop.fo.FONode; +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.TableCell; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; @@ -32,18 +37,16 @@ import org.apache.fop.layoutmgr.AreaAdditionUtil; import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; import org.apache.fop.layoutmgr.BreakElement; +import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.ListElement; -import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.Position; +import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.SpaceResolver; import org.apache.fop.layoutmgr.TraitSetter; -import org.apache.fop.area.Area; -import org.apache.fop.area.Block; -import org.apache.fop.area.Trait; import org.apache.fop.traits.MinOptMax; /** @@ -230,8 +233,15 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager } returnedList = new LinkedList(); - wrapPositionElements(contentList, returnList); - + if (contentList.size() > 0) { + wrapPositionElements(contentList, returnList); + } else { + // In relaxed validation mode, table-cells having no children are authorised. + // Add a zero-width block here to not have to take this special case into + // account later + // Copied from BlockStackingLM + returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true)); + } //Space resolution SpaceResolver.resolveElementList(returnList); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index 8f3c3195c..c08216480 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -31,6 +31,8 @@ import org.apache.fop.area.Trait; import org.apache.fop.datatypes.PercentBaseContext; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.flow.table.EffRow; +import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableBody; import org.apache.fop.fo.flow.table.TableRow; @@ -75,15 +77,12 @@ public class TableContentLayoutManager implements PercentBaseContext { public TableContentLayoutManager(TableLayoutManager parent) { this.tableLM = parent; Table table = getTableLM().getTable(); - this.bodyIter = new TableRowIterator(table, getTableLM().getColumns(), - TableRowIterator.BODY); + this.bodyIter = new TableRowIterator(table, TableRowIterator.BODY); if (table.getTableHeader() != null) { - headerIter = new TableRowIterator(table, - getTableLM().getColumns(), TableRowIterator.HEADER); + headerIter = new TableRowIterator(table, TableRowIterator.HEADER); } if (table.getTableFooter() != null) { - footerIter = new TableRowIterator(table, - getTableLM().getColumns(), TableRowIterator.FOOTER); + footerIter = new TableRowIterator(table, TableRowIterator.FOOTER); } } @@ -212,7 +211,7 @@ public class TableContentLayoutManager implements PercentBaseContext { int breakBetween = Constants.EN_AUTO; while ((rowGroup = iter.getNextRowGroup()) != null) { RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, - bodyIter, headerIter, footerIter, iter, stepper); + stepper); if (breakBetween == Constants.EN_AUTO) { // TODO improve breakBetween = rowGroupLM.getBreakBefore(); @@ -233,7 +232,8 @@ public class TableContentLayoutManager implements PercentBaseContext { // Break after the table's last row // TODO should eventually be handled at the table level if (breakBetween != Constants.EN_AUTO) { - if (returnList.size() > 0) { + if (returnList.size() > 0 && ((ListElement) returnList.getLast()).isPenalty()) { + // May be a glue if the unbroken height is greater than the broken heights BreakElement breakPoss = (BreakElement) returnList.getLast(); breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE); breakPoss.setBreakClass(breakBetween); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java index e8024bfe5..8986ea85f 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java @@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table; import java.util.List; +import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.layoutmgr.LayoutManager; import org.apache.fop.layoutmgr.Position; diff --git a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java index dfac329a8..62e308c13 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java @@ -20,18 +20,14 @@ package org.apache.fop.layoutmgr.table; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import java.util.ListIterator; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.FONode; +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.TableCell; -import org.apache.fop.fo.flow.table.TableColumn; -import org.apache.fop.fo.flow.table.TableRow; -import org.apache.fop.fo.properties.CommonBorderPaddingBackground; /** @@ -48,82 +44,41 @@ public class TableRowIterator { /** Selects the table-footer elements for iteration. */ public static final int FOOTER = 2; - /** Logger **/ - private static Log log = LogFactory.getLog(TableRowIterator.class); - /** The table on which this instance operates. */ protected Table table; - /** Column setup of the operated table. */ - private ColumnSetup columns; /** Part of the table over which to iterate. One of BODY, HEADER or FOOTER. */ private int tablePart; - /** Holds the currently fetched row (TableCell instances). */ - private List currentRow = new java.util.ArrayList(); - - /** - * Holds the grid units of cells from the previous row which will span over the - * current row. Should be read "previous row's spanning cells". List of GridUnit - * instances. - */ - private List previousRowsSpanningCells = new java.util.ArrayList(); - - /** Index of the row currently being fetched. */ - private int fetchIndex = -1; - - /** - * Number of spans found on the current row which will also span over the next row. - */ - private int pendingRowSpans; + private Iterator rowGroupsIter; - //TODO rows should later be a Jakarta Commons LinkedList so concurrent modifications while - //using a ListIterator are possible - /** List of cached rows. This is a list of EffRow elements. */ - private List fetchedRows = new java.util.ArrayList(); - - /** - * Index of the row that will be returned at the next iteration step. Note that there - * is no direct relation between this field and {@link - * TableRowIterator#fetchIndex}. The fetching of rows and the iterating over them are - * two different processes. Hence the two indices. */ - private int iteratorIndex = 0; - - //prefetch state - /** - * Iterator over the requested table's part(s) (header, footer, body). Note that - * a table may have several table-body children, hence the iterator. - */ - private ListIterator tablePartIterator = null; - /** Iterator over a part's child elements (either table-rows or table-cells). */ - private ListIterator tablePartChildIterator = null; + private int rowIndex = 0; /** * Creates a new TableRowIterator. * @param table the table to iterate over - * @param columns the column setup for the table * @param tablePart indicates what part of the table to iterate over (HEADER, FOOTER, BODY) */ - public TableRowIterator(Table table, ColumnSetup columns, int tablePart) { + public TableRowIterator(Table table, int tablePart) { this.table = table; - this.columns = columns; this.tablePart = tablePart; switch(tablePart) { - case HEADER: { - List bodyList = new java.util.ArrayList(); - bodyList.add(table.getTableHeader()); - this.tablePartIterator = bodyList.listIterator(); + case HEADER: + rowGroupsIter = table.getTableHeader().getRowGroups().iterator(); break; - } - case FOOTER: { - List bodyList = new java.util.ArrayList(); - bodyList.add(table.getTableFooter()); - this.tablePartIterator = bodyList.listIterator(); + case FOOTER: + rowGroupsIter = table.getTableFooter().getRowGroups().iterator(); break; - } - default: { - this.tablePartIterator = table.getChildNodes(); - } + default: + List rowGroupsList = new LinkedList(); + // TODO this is ugly + for (FONodeIterator iter = table.getChildNodes(); iter.hasNext();) { + FONode node = iter.nextNode(); + if (node instanceof TableBody) { + rowGroupsList.addAll(((TableBody) node).getRowGroups()); + } + } + rowGroupsIter = rowGroupsList.iterator(); } } @@ -132,429 +87,18 @@ public class TableRowIterator { * consecutive rows which contains all spanned grid units of its cells. * @return the next row group, or null */ - public EffRow[] getNextRowGroup() { - EffRow firstRowInGroup = getNextRow(); - if (firstRowInGroup == null) { - return null; - } - EffRow lastRowInGroup = firstRowInGroup; - int lastIndex = lastRowInGroup.getIndex(); - boolean allFinished; - do { - allFinished = true; - Iterator iter = lastRowInGroup.getGridUnits().iterator(); - while (iter.hasNext()) { - GridUnit gu = (GridUnit)iter.next(); - if (!gu.isLastGridUnitRowSpan()) { - allFinished = false; - break; - } - } - lastIndex = lastRowInGroup.getIndex(); - if (!allFinished) { - lastRowInGroup = getNextRow(); - if (lastRowInGroup == null) { - allFinished = true; - } - } - } while (!allFinished); - int rowCount = lastIndex - firstRowInGroup.getIndex() + 1; - EffRow[] rowGroup = new EffRow[rowCount]; - for (int i = 0; i < rowCount; i++) { - rowGroup[i] = getCachedRow(i + firstRowInGroup.getIndex()); - } - return rowGroup; - } - - /** - * Returns the row at the given index, fetching rows up to the requested one if - * necessary. - * - * @return the requested row, or null if there is no row at the given index (index - * < 0 or end of table-part reached) - */ - private EffRow getRow(int index) { - boolean moreRows = true; - while (moreRows && fetchedRows.size() <= index) { - moreRows = prefetchNext(); - } - // Whatever the value of index, getCachedRow will handle it nicely - return getCachedRow(index); - } - - /** - * Returns the next effective row. - * @return the requested effective row or null if there is no more row. - */ - private EffRow getNextRow() { - return getRow(iteratorIndex++); - } - - /** - * Returns the row preceding the given row, without moving the iterator. - * - * @param row a row in the iterated table part - * @return the preceding row, or null if there is no such row (the given row is the - * first one in the table part) - */ - public EffRow getPrecedingRow(EffRow row) { - return getRow(row.getIndex() - 1); - } - - /** - * Returns the row following the given row, without moving the iterator. - * - * @param row a row in the iterated table part - * @return the following row, or null if there is no more row - */ - public EffRow getFollowingRow(EffRow row) { - return getRow(row.getIndex() + 1); - } - - /** - * Returns the first effective row. - * @return the requested effective row. - */ - public EffRow getFirstRow() { - if (fetchedRows.size() == 0) { - prefetchNext(); - } - return getCachedRow(0); - } - - /** - * Returns the last effective row. - * <p>Note:This is inefficient for large tables because the whole table - * if preloaded.</p> - * @return the requested effective row. - */ - public EffRow getLastRow() { - while (prefetchNext()) { - //nop - } - return getCachedRow(fetchedRows.size() - 1); - } - - /** - * Returns a cached effective row. If the given index points outside the range of rows - * (negative or greater than the number of already fetched rows), this methods - * terminates nicely by returning null. - * - * @param index index of the row (zero-based) - * @return the requested effective row or null if (index < 0 || index >= the - * number of already fetched rows) - */ - private EffRow getCachedRow(int index) { - if (index < 0 || index >= fetchedRows.size()) { - return null; - } else { - return (EffRow)fetchedRows.get(index); - } - } - - /** - * Fetches the next row. - * - * @return true if there was a row to fetch; otherwise, false (the end of the - * table-part has been reached) - */ - private boolean prefetchNext() { - boolean firstInTable = false; - boolean firstInTablePart = false; - // If we are at the end of the current table part - if (tablePartChildIterator != null && !tablePartChildIterator.hasNext()) { - //force skip on to next component - if (pendingRowSpans > 0) { - this.currentRow.clear(); - this.fetchIndex++; - EffRow gridUnits = buildGridRow(this.currentRow, null); - log.debug(gridUnits); - fetchedRows.add(gridUnits); - return true; - } - tablePartChildIterator = null; - if (fetchedRows.size() > 0) { - getCachedRow(fetchedRows.size() - 1).setFlagForAllGridUnits( - GridUnit.LAST_IN_PART, true); - } - } - // If the iterating over the current table-part has not started yet - if (tablePartChildIterator == null) { - if (tablePartIterator.hasNext()) { - tablePartChildIterator = ((TableBody)tablePartIterator.next()).getChildNodes(); - if (fetchedRows.size() == 0) { - firstInTable = true; - } - firstInTablePart = true; - } else { - //no more rows in that part of the table - if (fetchedRows.size() > 0) { - getCachedRow(fetchedRows.size() - 1).setFlagForAllGridUnits( - GridUnit.LAST_IN_PART, true); - // If the last row is the last of the table - if (tablePart == FOOTER - || (tablePart == BODY && table.getTableFooter() == null)) { - getCachedRow(fetchedRows.size() - 1).setFlagForAllGridUnits( - GridUnit.LAST_IN_TABLE, true); - } - } - return false; - } - } - Object node = tablePartChildIterator.next(); - while (node instanceof Marker) { - node = tablePartChildIterator.next(); - } - this.currentRow.clear(); - this.fetchIndex++; - TableRow rowFO = null; - if (node instanceof TableRow) { - rowFO = (TableRow)node; - ListIterator cellIterator = rowFO.getChildNodes(); - while (cellIterator.hasNext()) { - this.currentRow.add(cellIterator.next()); - } - } else if (node instanceof TableCell) { - this.currentRow.add(node); - if (!((TableCell)node).endsRow()) { - while (tablePartChildIterator.hasNext()) { - TableCell cell = (TableCell)tablePartChildIterator.next(); - if (cell.startsRow()) { - //next row already starts here, one step back - tablePartChildIterator.previous(); - break; - } - this.currentRow.add(cell); - if (cell.endsRow()) { - break; - } - } - } - } else { - throw new IllegalStateException("Illegal class found: " + node.getClass().getName()); - } - EffRow gridUnits = buildGridRow(this.currentRow, rowFO); - if (firstInTablePart) { - gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_PART, true); - } - if (firstInTable && (tablePart == HEADER || table.getTableHeader() == null) - && tablePart != FOOTER) { - gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_TABLE, true); - } - log.debug(gridUnits); - fetchedRows.add(gridUnits); - return true; - } - - /** - * Places the given object at the given position in the list, first extending it if - * necessary with null objects to reach the position. - * - * @param list the list in which to place the object - * @param position index at which the object must be placed (0-based) - * @param obj the object to place - */ - private void safelySetListItem(List list, int position, Object obj) { - while (position >= list.size()) { - list.add(null); - } - list.set(position, obj); - } - - private Object safelyGetListItem(List list, int position) { - if (position >= list.size()) { + EffRow[] getNextRowGroup() { + if (!rowGroupsIter.hasNext()) { return null; - } else { - return list.get(position); - } - } - - /** - * Builds the list of grid units corresponding to the given table row. - * - * @param cells list of cells starting at the current row - * @param rowFO the fo:table-row object containing the row, possibly null - * @return the list of grid units - */ - private EffRow buildGridRow(List cells, TableRow rowFO) { - EffRow row = new EffRow(this.fetchIndex, tablePart); - List gridUnits = row.getGridUnits(); - - TableBody bodyFO = null; - - //Create all row-spanned grid units based on information from the previous row - int colnum = 1; - GridUnit[] horzSpan = null; // Grid units horizontally spanned by a single cell - if (pendingRowSpans > 0) { - ListIterator spanIter = previousRowsSpanningCells.listIterator(); - while (spanIter.hasNext()) { - GridUnit gu = (GridUnit)spanIter.next(); - if (gu != null) { - if (gu.getColSpanIndex() == 0) { - horzSpan = new GridUnit[gu.getCell().getNumberColumnsSpanned()]; - } - GridUnit newGU = gu.createNextRowSpanningGridUnit(); - newGU.setRow(rowFO); - safelySetListItem(gridUnits, colnum - 1, newGU); - horzSpan[newGU.getColSpanIndex()] = newGU; - if (newGU.isLastGridUnitColSpan()) { - //Add the array of row-spanned grid units to the primary grid unit - newGU.getPrimary().addRow(horzSpan); - horzSpan = null; - } - if (newGU.isLastGridUnitRowSpan()) { - spanIter.set(null); - pendingRowSpans--; - } else { - spanIter.set(newGU); - } - } - colnum++; - } } - if (pendingRowSpans < 0) { - throw new IllegalStateException("pendingRowSpans must not become negative!"); - } - - //Transfer available cells to their slots - colnum = 1; - ListIterator iter = cells.listIterator(); - while (iter.hasNext()) { - TableCell cell = (TableCell)iter.next(); - - colnum = cell.getColumnNumber(); - - //TODO: remove the check below??? - //shouldn't happen here, since - //overlapping cells already caught in - //fo.flow.TableCell.bind()... - GridUnit other = (GridUnit)safelyGetListItem(gridUnits, colnum - 1); - if (other != null) { - String err = "A table-cell (" - + cell.getContextInfo() - + ") is overlapping with another (" - + other.getCell().getContextInfo() - + ") in column " + colnum; - throw new IllegalStateException(err - + " (this should have been catched by FO tree validation)"); - } - TableColumn col = columns.getColumn(colnum); - - //Add grid unit for primary grid unit - PrimaryGridUnit gu = new PrimaryGridUnit(cell, col, colnum - 1, this.fetchIndex); - safelySetListItem(gridUnits, colnum - 1, gu); - boolean hasRowSpanningLeft = !gu.isLastGridUnitRowSpan(); - if (hasRowSpanningLeft) { - pendingRowSpans++; - safelySetListItem(previousRowsSpanningCells, colnum - 1, gu); - } - - if (gu.hasSpanning()) { - //Add grid units on spanned slots if any - horzSpan = new GridUnit[cell.getNumberColumnsSpanned()]; - horzSpan[0] = gu; - for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) { - colnum++; - GridUnit guSpan = new GridUnit(gu, columns.getColumn(colnum), colnum - 1, j); - //TODO: remove the check below??? - other = (GridUnit)safelyGetListItem(gridUnits, colnum - 1); - if (other != null) { - String err = "A table-cell (" - + cell.getContextInfo() - + ") is overlapping with another (" - + other.getCell().getContextInfo() - + ") in column " + colnum; - throw new IllegalStateException(err - + " (this should have been catched by FO tree validation)"); - } - safelySetListItem(gridUnits, colnum - 1, guSpan); - if (hasRowSpanningLeft) { - pendingRowSpans++; - safelySetListItem(previousRowsSpanningCells, colnum - 1, guSpan); - } - horzSpan[j] = guSpan; - } - gu.addRow(horzSpan); - } - - //Gather info for empty grid units (used later) - if (bodyFO == null) { - bodyFO = gu.getBody(); - } - - colnum++; - } - - //Post-processing the list (looking for gaps and resolve start and end borders) - fillEmptyGridUnits(gridUnits, rowFO, bodyFO); - resolveStartEndBorders(gridUnits); - - return row; - } - - private void fillEmptyGridUnits(List gridUnits, TableRow row, TableBody body) { - for (int pos = 1; pos <= gridUnits.size(); pos++) { - GridUnit gu = (GridUnit)gridUnits.get(pos - 1); - - //Empty grid units - if (gu == null) { - //Add grid unit - gu = new EmptyGridUnit(row, columns.getColumn(pos), body, - pos - 1); - gridUnits.set(pos - 1, gu); - } - - //Set flags - gu.setFlag(GridUnit.IN_FIRST_COLUMN, (pos == 1)); - gu.setFlag(GridUnit.IN_LAST_COLUMN, (pos == gridUnits.size())); - } - } - - private void resolveStartEndBorders(List gridUnits) { - for (int pos = 1; pos <= gridUnits.size(); pos++) { - GridUnit starting = (GridUnit)gridUnits.get(pos - 1); - - //Border resolution - if (table.isSeparateBorderModel()) { - starting.assignBorderForSeparateBorderModel(); - } else { - //Neighbouring grid unit at start edge - GridUnit start = null; - int find = pos - 1; - while (find >= 1) { - GridUnit candidate = (GridUnit)gridUnits.get(find - 1); - if (candidate.isLastGridUnitColSpan()) { - start = candidate; - break; - } - find--; - } - - //Ending grid unit for current cell - GridUnit ending = null; - if (starting.getCell() != null) { - pos += starting.getCell().getNumberColumnsSpanned() - 1; - } - ending = (GridUnit)gridUnits.get(pos - 1); - - //Neighbouring grid unit at end edge - GridUnit end = null; - find = pos + 1; - while (find <= gridUnits.size()) { - GridUnit candidate = (GridUnit)gridUnits.get(find - 1); - if (candidate.isPrimary()) { - end = candidate; - break; - } - find++; - } - starting.resolveBorder(start, - CommonBorderPaddingBackground.START); - ending.resolveBorder(end, - CommonBorderPaddingBackground.END); - //Only start and end borders here, before and after during layout - } + List rowGroup = (List) rowGroupsIter.next(); + EffRow[] effRowGroup = new EffRow[rowGroup.size()]; + int i = 0; + for (Iterator rowIter = rowGroup.iterator(); rowIter.hasNext();) { + List gridUnits = (List) rowIter.next(); + effRowGroup[i++] = new EffRow(rowIndex++, tablePart, gridUnits); } + return effRowGroup; } } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java index 92c62cff7..98b07778f 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java @@ -27,6 +27,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; +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.TableRow; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.KnuthBox; @@ -153,15 +156,15 @@ public class TableStepper { boolean signalKeepWithNext = false; int laststep = 0; int step; - int addedBoxLen = 0; + int cumulateLength = 0; // Length of the content accumulated before the break TableContentPosition lastTCPos = null; LinkedList returnList = new LinkedList(); while ((step = getNextStep()) >= 0) { int normalRow = activeRowIndex; int increase = step - laststep; int penaltyOrGlueLen = step + getMaxRemainingHeight() - totalHeight; - int boxLen = step - addedBoxLen - Math.max(0, penaltyOrGlueLen); - addedBoxLen += boxLen; + int boxLen = step - cumulateLength - Math.max(0, penaltyOrGlueLen)/* the penalty, if any */; + cumulateLength += boxLen + Math.max(0, -penaltyOrGlueLen)/* the glue, if any */; boolean forcedBreak = false; int breakClass = -1; diff --git a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java index 1e485735b..670881643 100644 --- a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java +++ b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java @@ -53,14 +53,6 @@ public abstract class AbstractRendererConfigurator { * @return the requested configuration subtree, null if there's no configuration */ protected Configuration getRendererConfig(Renderer renderer) { - Configuration cfg = userAgent.getFactory().getUserConfig(); - if (cfg == null) { - if (log.isDebugEnabled()) { - log.debug("userconfig is null"); - } - return null; - } - String mimeType = renderer.getMimeType(); if (mimeType == null) { if (log.isInfoEnabled()) { @@ -69,6 +61,24 @@ public abstract class AbstractRendererConfigurator { return null; } + return getRendererConfig(userAgent, mimeType); + } + + /** + * Returns the configuration subtree for a specific renderer. + * @param userAgent the user agent containing the user configuration + * @param mimeType the MIME type of the renderer + * @return the requested configuration subtree, null if there's no configuration + */ + public static Configuration getRendererConfig(FOUserAgent userAgent, String mimeType) { + Configuration cfg = userAgent.getFactory().getUserConfig(); + if (cfg == null) { + if (log.isDebugEnabled()) { + log.debug("userconfig is null"); + } + return null; + } + Configuration userRendererConfig = null; Configuration[] cfgs diff --git a/src/java/org/apache/fop/render/PrintRendererConfigurator.java b/src/java/org/apache/fop/render/PrintRendererConfigurator.java index 23bc0a022..318e1b1dc 100644 --- a/src/java/org/apache/fop/render/PrintRendererConfigurator.java +++ b/src/java/org/apache/fop/render/PrintRendererConfigurator.java @@ -27,12 +27,15 @@ import java.util.Iterator; import java.util.List; import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; @@ -222,7 +225,15 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator } } } - + + private static void closeSource(Source src) { + if (src instanceof StreamSource) { + StreamSource streamSource = (StreamSource)src; + IOUtils.closeQuietly(streamSource.getInputStream()); + IOUtils.closeQuietly(streamSource.getReader()); + } + } + /** * Returns a font info from a font node Configuration definition * @@ -243,23 +254,27 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator LogUtil.handleError(log, "Font configuration without metric-url or embed-url", strict); return null; } - if (embedUrl != null) { - Source source = fontResolver.resolve(embedUrl); - if (source == null) { - LogUtil.handleError(log, - "Failed to resolve font with embed-url '" + embedUrl + "'", strict); - return null; + if (strict) { + //This section just checks early whether the URIs can be resolved + //Stream are immediately closed again since they will never be used anyway + if (embedUrl != null) { + Source source = fontResolver.resolve(embedUrl); + closeSource(source); + if (source == null) { + LogUtil.handleError(log, + "Failed to resolve font with embed-url '" + embedUrl + "'", strict); + return null; + } } - embedUrl = source.getSystemId(); // absolute path/url - } - if (metricsUrl != null) { - Source source = fontResolver.resolve(metricsUrl); - if (source == null) { - LogUtil.handleError(log, - "Failed to resolve font with metric-url '" + metricsUrl + "'", strict); - return null; + if (metricsUrl != null) { + Source source = fontResolver.resolve(metricsUrl); + closeSource(source); + if (source == null) { + LogUtil.handleError(log, + "Failed to resolve font with metric-url '" + metricsUrl + "'", strict); + return null; + } } - metricsUrl = source.getSystemId(); // absolute path/url } boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true); diff --git a/src/java/org/apache/fop/render/java2d/FontSetup.java b/src/java/org/apache/fop/render/java2d/FontSetup.java index 5637bdee2..bd53c20d7 100644 --- a/src/java/org/apache/fop/render/java2d/FontSetup.java +++ b/src/java/org/apache/fop/render/java2d/FontSetup.java @@ -218,7 +218,7 @@ public class FontSetup { java.awt.Font[] fonts = env.getAllFonts(); for (int i = 0; i < fonts.length; i++) { java.awt.Font f = fonts[i]; - if (HARDCODED_FONT_NAMES.contains(f.getFontName())) { + if (HARDCODED_FONT_NAMES.contains(f.getName())) { continue; //skip } @@ -231,20 +231,20 @@ public class FontSetup { + ", Style: " + f.getStyle()); } - String searchName = FontUtil.stripWhiteSpace(f.getFontName()).toLowerCase(); + String searchName = FontUtil.stripWhiteSpace(f.getName()).toLowerCase(); String guessedStyle = FontUtil.guessStyle(searchName); int guessedWeight = FontUtil.guessWeight(searchName); num++; String fontKey = "F" + num; int style = convertToAWTFontStyle(guessedStyle, guessedWeight); - addFontMetricsMapper(fontInfo, f.getFontName(), fontKey, graphics, style); + addFontMetricsMapper(fontInfo, f.getName(), fontKey, graphics, style); //Register appropriate font triplets matching the font. Two different strategies: //Example: "Arial Bold", normal, normal - addFontTriplet(fontInfo, f.getFontName(), + addFontTriplet(fontInfo, f.getName(), Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, fontKey); - if (!f.getFontName().equals(f.getFamily())) { + if (!f.getName().equals(f.getFamily())) { //Example: "Arial", bold, normal addFontTriplet(fontInfo, f.getFamily(), guessedStyle, guessedWeight, fontKey); diff --git a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java index e228b16bc..e6a855b83 100644 --- a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java +++ b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java @@ -21,7 +21,12 @@ package org.apache.fop.render.ps; import java.awt.Color; +import java.io.BufferedOutputStream; import java.io.IOException; +import java.io.OutputStream; + +import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGLength; import org.apache.avalon.framework.configuration.Configuration; import org.apache.batik.bridge.BridgeContext; @@ -29,13 +34,12 @@ import org.apache.batik.bridge.UnitProcessor; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.image.ImageTranscoder; +import org.apache.xmlgraphics.java2d.ps.AbstractPSDocumentGraphics2D; +import org.apache.xmlgraphics.java2d.ps.TextHandler; + import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; import org.apache.fop.svg.AbstractFOPTranscoder; -import org.apache.xmlgraphics.java2d.ps.AbstractPSDocumentGraphics2D; -import org.apache.xmlgraphics.java2d.ps.TextHandler; -import org.w3c.dom.Document; -import org.w3c.dom.svg.SVGLength; /** * This class enables to transcode an input to a PostScript document. @@ -114,7 +118,11 @@ public abstract class AbstractPSTranscoder extends AbstractFOPTranscoder { getLogger().trace("document size: " + w + "pt x " + h + "pt"); try { - graphics.setupDocument(output.getOutputStream(), w, h); + OutputStream out = output.getOutputStream(); + if (!(out instanceof BufferedOutputStream)) { + out = new BufferedOutputStream(out); + } + graphics.setupDocument(out, w, h); graphics.setViewportDimension(width, height); if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) { diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index c568fe826..8fb29d302 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -100,8 +100,11 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (fm instanceof LazyFont && ((LazyFont)fm).getRealFont() == null) { continue; } else if (null == fm.getEncoding()) { - //ignore (ZapfDingbats and Symbol run through here - //TODO: ZapfDingbats and Symbol should get getEncoding() fixed! + //ignore (ZapfDingbats and Symbol used to run through here, kept for safety reasons) + } else if ("SymbolEncoding".equals(fm.getEncoding())) { + //ignore (no encoding redefinition) + } else if ("ZapfDingbatsEncoding".equals(fm.getEncoding())) { + //ignore (no encoding redefinition) } else if ("WinAnsiEncoding".equals(fm.getEncoding())) { redefineFontEncoding(gen, fm.getFontName(), fm.getEncoding()); } else { diff --git a/src/java/org/apache/fop/svg/PDFTranscoder.java b/src/java/org/apache/fop/svg/PDFTranscoder.java index f0d40b574..417b82097 100644 --- a/src/java/org/apache/fop/svg/PDFTranscoder.java +++ b/src/java/org/apache/fop/svg/PDFTranscoder.java @@ -20,7 +20,12 @@ package org.apache.fop.svg; import java.awt.Color; +import java.io.BufferedOutputStream; import java.io.IOException; +import java.io.OutputStream; + +import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGLength; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; @@ -36,10 +41,9 @@ import org.apache.batik.transcoder.TranscodingHints; import org.apache.batik.transcoder.image.ImageTranscoder; import org.apache.batik.transcoder.keys.BooleanKey; import org.apache.batik.transcoder.keys.FloatKey; + import org.apache.fop.Version; import org.apache.fop.fonts.FontInfo; -import org.w3c.dom.Document; -import org.w3c.dom.svg.SVGLength; /** * This class enables to transcode an input to a pdf document. @@ -195,7 +199,11 @@ public class PDFTranscoder extends AbstractFOPTranscoder if (hints.containsKey(KEY_DEVICE_RESOLUTION)) { graphics.setDeviceDPI(((Float)hints.get(KEY_DEVICE_RESOLUTION)).floatValue()); } - graphics.setupDocument(output.getOutputStream(), w, h); + OutputStream out = output.getOutputStream(); + if (!(out instanceof BufferedOutputStream)) { + out = new BufferedOutputStream(out); + } + graphics.setupDocument(out, w, h); graphics.setSVGDimension(width, height); if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) { |