aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache')
-rw-r--r--src/java/org/apache/fop/area/AreaTreeHandler.java12
-rw-r--r--src/java/org/apache/fop/area/DestinationData.java131
-rw-r--r--src/java/org/apache/fop/fo/ElementMappingRegistry.java1
-rw-r--r--src/java/org/apache/fop/fo/FONode.java1
-rw-r--r--src/java/org/apache/fop/fo/FOTreeBuilder.java9
-rw-r--r--src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java10
-rw-r--r--src/java/org/apache/fop/fo/extensions/destination/Destination.java102
-rw-r--r--src/java/org/apache/fop/fo/extensions/destination/package.html23
-rw-r--r--src/java/org/apache/fop/fo/flow/Block.java36
-rw-r--r--src/java/org/apache/fop/fo/pagination/Root.java24
-rw-r--r--src/java/org/apache/fop/image/JpegImage.java11
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java10
-rw-r--r--src/java/org/apache/fop/layoutmgr/KnuthPossPosIter.java4
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java11
-rw-r--r--src/java/org/apache/fop/layoutmgr/SpaceResolver.java6
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java10
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/GridUnit.java13
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/RowPainter.java272
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java185
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java51
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java6
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java2
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableStepper.java163
-rw-r--r--src/java/org/apache/fop/pdf/DestinationComparator.java41
-rw-r--r--src/java/org/apache/fop/pdf/PDFDestination.java138
-rw-r--r--src/java/org/apache/fop/pdf/PDFDests.java79
-rw-r--r--src/java/org/apache/fop/pdf/PDFDocument.java119
-rw-r--r--src/java/org/apache/fop/pdf/PDFFactory.java71
-rw-r--r--src/java/org/apache/fop/pdf/PDFLimits.java93
-rw-r--r--src/java/org/apache/fop/pdf/PDFRoot.java19
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFRenderer.java16
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderer.java19
32 files changed, 1311 insertions, 377 deletions
diff --git a/src/java/org/apache/fop/area/AreaTreeHandler.java b/src/java/org/apache/fop/area/AreaTreeHandler.java
index 91a5d603d..e7f6effe0 100644
--- a/src/java/org/apache/fop/area/AreaTreeHandler.java
+++ b/src/java/org/apache/fop/area/AreaTreeHandler.java
@@ -48,6 +48,9 @@ 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;
+
/**
* Area tree handler for formatting objects.
*
@@ -412,6 +415,15 @@ public class AreaTreeHandler extends FOEventHandler {
public void endDocument() throws SAXException {
finishPrevPageSequence(null);
+ // process fox:destination elements
+ ArrayList 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) {
diff --git a/src/java/org/apache/fop/area/DestinationData.java b/src/java/org/apache/fop/area/DestinationData.java
new file mode 100644
index 000000000..7e59210e0
--- /dev/null
+++ b/src/java/org/apache/fop/area/DestinationData.java
@@ -0,0 +1,131 @@
+/*
+ * 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.area;
+
+import java.util.List;
+
+import org.apache.fop.fo.extensions.destination.Destination;
+import org.apache.fop.area.PageViewport;
+/**
+ * An instance of this class is named destination from fox:destination
+ */
+public class DestinationData extends AbstractOffDocumentItem implements Resolvable {
+
+ // PDFReference (object reference) for this destination
+ private String goToReference;
+
+ // ID Reference for this bookmark
+ private String idRef;
+
+ // String Array to satisfy getIDRefs method
+ private String[] idRefs;
+
+ // PageViewport that the idRef item refers to
+ private PageViewport pageRef = null;
+
+ /**
+ * Create a new pdf destination data object.
+ * This is used by the destination to create a data object
+ * with a idref. During processing, this idref will be
+ * subsequently resolved to a particular PageViewport.
+ *
+ * @param destination the fo:bookmark object
+ */
+ public DestinationData(Destination destination) {
+ idRef = destination.getInternalDestination();
+ idRefs = new String[] {idRef};
+ }
+
+ /**
+ * Get the idref for this destination
+ *
+ * @return the idref for the destination
+ */
+ public String getIDRef() {
+ return idRef;
+ }
+
+ /**
+ * @see org.apache.fop.area.Resolvable#getIDRefs()
+ */
+ public String[] getIDRefs() {
+ return idRefs;
+ }
+
+ /**
+ * Get the PageViewport object that this destination refers to
+ *
+ * @return the PageViewport that this destination points to
+ */
+ public PageViewport getPageViewport() {
+ return pageRef;
+ }
+
+ /**
+ * Set the GoToReference for this destination
+ *
+ * @param goToReference the GoToReference to associate with this destination
+ */
+ public void setGoToReference(String goToReference) {
+ this.goToReference = goToReference;
+ }
+
+ /**
+ * Get the GoToReference for this destination
+ *
+ * @return the GoToReference associated with this destination
+ */
+ public String getGoToReference() {
+ return goToReference;
+ }
+
+ /**
+ * Check if this resolvable object has been resolved.
+ * For now, just return true.
+ * To do: Find a way to determine whether the destination has been resolved.
+ *
+ * @return true if this object has been resolved
+ */
+ public boolean isResolved() {
+ return true;
+ }
+
+ /**
+ * Resolves the idref of this object by getting the PageViewport
+ * object that corresponds to the IDRef
+ *
+ * @see org.apache.fop.area.Resolvable#resolveIDRef(String, List)
+ * @todo check to make sure it works if multiple bookmark-items
+ * have the same idref
+ */
+ public void resolveIDRef(String id, List pages) {
+ pageRef = (PageViewport) pages.get(0);
+ // TODO get rect area of id on page
+ }
+
+ /**
+ * @see org.apache.fop.area.OffDocumentItem#getName()
+ */
+ public String getName() {
+ return "Destination";
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/fo/ElementMappingRegistry.java b/src/java/org/apache/fop/fo/ElementMappingRegistry.java
index 105a956a2..887fe8b55 100644
--- a/src/java/org/apache/fop/fo/ElementMappingRegistry.java
+++ b/src/java/org/apache/fop/fo/ElementMappingRegistry.java
@@ -90,7 +90,6 @@ public class ElementMappingRegistry {
*/
public void addElementMapping(String mappingClassName)
throws IllegalArgumentException {
-
try {
ElementMapping mapping
= (ElementMapping)Class.forName(mappingClassName).newInstance();
diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java
index 91817b87f..baf964935 100644
--- a/src/java/org/apache/fop/fo/FONode.java
+++ b/src/java/org/apache/fop/fo/FONode.java
@@ -45,6 +45,7 @@ public abstract class FONode implements Cloneable {
/** the XSL-FO namespace URI */
protected static final String FO_URI = FOElementMapping.URI;
+ protected static final String FOX_URI = ExtensionElementMapping.URI;
/** Parent FO node */
protected FONode parent;
diff --git a/src/java/org/apache/fop/fo/FOTreeBuilder.java b/src/java/org/apache/fop/fo/FOTreeBuilder.java
index 4c754520d..2f1b53f1d 100644
--- a/src/java/org/apache/fop/fo/FOTreeBuilder.java
+++ b/src/java/org/apache/fop/fo/FOTreeBuilder.java
@@ -23,6 +23,7 @@ import java.io.OutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FormattingResults;
@@ -296,9 +297,8 @@ public class FOTreeBuilder extends DefaultHandler {
+ " Please make sure you're producing a valid XSL-FO document.");
}
} else { // check that incoming node is valid for currentFObj
- if (namespaceURI.equals(FOElementMapping.URI)) {
- // currently no fox: elements to validate
- // || namespaceURI.equals(ExtensionElementMapping.URI) */) {
+ if (namespaceURI.equals(FOElementMapping.URI)
+ || namespaceURI.equals(ExtensionElementMapping.URI)) {
try {
currentFObj.validateChildNode(locator, namespaceURI, localName);
} catch (ValidationException e) {
@@ -368,7 +368,8 @@ public class FOTreeBuilder extends DefaultHandler {
throw new IllegalStateException(
"endElement() called for " + rawName
+ " where there is no current element.");
- } else if (!currentFObj.getLocalName().equals(localName)
+ } else
+ if (!currentFObj.getLocalName().equals(localName)
|| !currentFObj.getNamespaceURI().equals(uri)) {
log.warn("Mismatch: " + currentFObj.getLocalName()
+ " (" + currentFObj.getNamespaceURI()
diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
index 0b5ae827b..b5ed3e61c 100644
--- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
+++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
@@ -20,7 +20,9 @@
package org.apache.fop.fo.extensions;
import org.apache.fop.fo.ElementMapping;
+import org.apache.fop.fo.FONode;
import org.apache.fop.fo.UnknownXMLObj;
+import org.apache.fop.fo.extensions.destination.Destination;
import org.apache.fop.util.QName;
import java.util.HashMap;
@@ -41,6 +43,7 @@ public class ExtensionElementMapping extends ElementMapping {
propertyAttributes.add("block-progression-unit");
propertyAttributes.add("widow-content-limit");
propertyAttributes.add("orphan-content-limit");
+ propertyAttributes.add("internal-destination");
}
/**
@@ -58,9 +61,16 @@ public class ExtensionElementMapping extends ElementMapping {
foObjs = new HashMap();
foObjs.put("outline", new UnknownXMLObj.Maker(URI));
foObjs.put("label", new UnknownXMLObj.Maker(URI));
+ foObjs.put("destination", new DestinationMaker());
}
}
+ static class DestinationMaker extends ElementMapping.Maker {
+ public FONode make(FONode parent) {
+ return new Destination(parent);
+ }
+ }
+
/** @see org.apache.fop.fo.ElementMapping#getStandardPrefix() */
public String getStandardPrefix() {
return "fox";
diff --git a/src/java/org/apache/fop/fo/extensions/destination/Destination.java b/src/java/org/apache/fop/fo/extensions/destination/Destination.java
new file mode 100644
index 000000000..b4611661e
--- /dev/null
+++ b/src/java/org/apache/fop/fo/extensions/destination/Destination.java
@@ -0,0 +1,102 @@
+/*
+ * 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.extensions.destination;
+
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.pagination.Root;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
+/**
+ * Class for named destinations in PDF.
+ */
+public class Destination extends FONode {
+
+ private String internalDestination;
+ private Root root;
+
+ /**
+ * Constructs a Destination object (called by Maker).
+ *
+ * @param parent the parent formatting object
+ */
+ public Destination(FONode parent) {
+ super(parent);
+ root = parent.getRoot();
+ }
+
+ /**
+ * @see org.apache.fop.fo.FONode#processNode(java.lang.String, org.xml.sax.Locator,
+ * org.xml.sax.Attributes, org.apache.fop.fo.PropertyList)
+ */
+ public void processNode(String elementName, Locator locator,
+ Attributes attlist, PropertyList pList) throws FOPException {
+ internalDestination = attlist.getValue("internal-destination");
+ if (internalDestination == null || internalDestination.length() == 0) {
+ attributeError("Missing attribute: internal-destination must be specified.");
+ }
+ }
+
+ /**
+ * @see org.apache.fop.fo.FONode#endOfNode
+ */
+ protected void endOfNode() throws FOPException {
+ root.addDestination(this);
+ }
+
+ /**
+ * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
+ XSL/FOP: empty
+ */
+ protected void validateChildNode(Locator loc, String nsURI, String localName)
+ throws ValidationException {
+ invalidChildError(loc, nsURI, localName);
+ }
+
+ /**
+ * Returns the internal destination (an reference of the id property of any FO).
+ * @return the internal destination
+ */
+ public String getInternalDestination() {
+ return internalDestination;
+ }
+
+ /** @see org.apache.fop.fo.FONode#getNamespaceURI() */
+ public String getNamespaceURI() {
+ return ExtensionElementMapping.URI;
+ }
+
+ /** @see org.apache.fop.fo.FONode#getNormalNamespacePrefix() */
+ public String getNormalNamespacePrefix() {
+ return "fox";
+ }
+
+ /** @see org.apache.fop.fo.FONode#getLocalName() */
+ public String getLocalName() {
+ return "destination";
+ }
+
+}
+
diff --git a/src/java/org/apache/fop/fo/extensions/destination/package.html b/src/java/org/apache/fop/fo/extensions/destination/package.html
new file mode 100644
index 000000000..59cbb493d
--- /dev/null
+++ b/src/java/org/apache/fop/fo/extensions/destination/package.html
@@ -0,0 +1,23 @@
+<!--
+ 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$ -->
+<HTML>
+<TITLE>org.apache.fop.destination Package</TITLE>
+<BODY>
+<P>Classes to support named destinations (only relevant for PDF output)</P>
+</BODY>
+</HTML>
diff --git a/src/java/org/apache/fop/fo/flow/Block.java b/src/java/org/apache/fop/fo/flow/Block.java
index 48a8d3bdf..6beffdfe5 100644
--- a/src/java/org/apache/fop/fo/flow/Block.java
+++ b/src/java/org/apache/fop/fo/flow/Block.java
@@ -296,25 +296,27 @@ public class Block extends FObjMixed {
* fo:inline-container."
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
- throws ValidationException {
- if (FO_URI.equals(nsURI) && localName.equals("marker")) {
- if (blockOrInlineItemFound || initialPropertySetFound) {
- nodesOutOfOrderError(loc, "fo:marker",
- "initial-property-set? (#PCDATA|%inline;|%block;)");
- }
- } else if (FO_URI.equals(nsURI) && localName.equals("initial-property-set")) {
- if (initialPropertySetFound) {
- tooManyNodesError(loc, "fo:initial-property-set");
- } else if (blockOrInlineItemFound) {
- nodesOutOfOrderError(loc, "fo:initial-property-set",
- "(#PCDATA|%inline;|%block;)");
+ throws ValidationException {
+ if (FO_URI.equals(nsURI)) {
+ if (localName.equals("marker")) {
+ if (blockOrInlineItemFound || initialPropertySetFound) {
+ nodesOutOfOrderError(loc, "fo:marker",
+ "initial-property-set? (#PCDATA|%inline;|%block;)");
+ }
+ } else if (localName.equals("initial-property-set")) {
+ if (initialPropertySetFound) {
+ tooManyNodesError(loc, "fo:initial-property-set");
+ } else if (blockOrInlineItemFound) {
+ nodesOutOfOrderError(loc, "fo:initial-property-set",
+ "(#PCDATA|%inline;|%block;)");
+ } else {
+ initialPropertySetFound = true;
+ }
+ } else if (isBlockOrInlineItem(nsURI, localName)) {
+ blockOrInlineItemFound = true;
} else {
- initialPropertySetFound = true;
+ invalidChildError(loc, nsURI, localName);
}
- } else if (isBlockOrInlineItem(nsURI, localName)) {
- blockOrInlineItemFound = true;
- } else {
- invalidChildError(loc, nsURI, localName);
}
}
diff --git a/src/java/org/apache/fop/fo/pagination/Root.java b/src/java/org/apache/fop/fo/pagination/Root.java
index 47ee3096a..23f9cd391 100644
--- a/src/java/org/apache/fop/fo/pagination/Root.java
+++ b/src/java/org/apache/fop/fo/pagination/Root.java
@@ -21,6 +21,7 @@ package org.apache.fop.fo.pagination;
// java
import java.util.List;
+import java.util.ArrayList;
import org.xml.sax.Locator;
@@ -31,6 +32,7 @@ import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.pagination.bookmarks.BookmarkTree;
+import org.apache.fop.fo.extensions.destination.Destination;
/**
* The fo:root formatting object. Contains page masters, page-sequences.
@@ -43,6 +45,7 @@ public class Root extends FObj {
private LayoutMasterSet layoutMasterSet;
private Declarations declarations;
private BookmarkTree bookmarkTree = null;
+ private ArrayList destinationList;
private List pageSequences;
// temporary until above list populated
@@ -64,7 +67,7 @@ public class Root extends FObj {
*/
public Root(FONode parent) {
super(parent);
- pageSequences = new java.util.ArrayList();
+ pageSequences = new ArrayList();
if (parent != null) {
//throw new FOPException("root must be root element");
}
@@ -252,6 +255,25 @@ public class Root extends FObj {
}
/**
+ * Add a Destination object to this FO
+ * @param destination the Destination object to add
+ */
+ public void addDestination(Destination destination) {
+ if (destinationList == null) {
+ destinationList = new ArrayList();
+ }
+ destinationList.add(destination);
+ }
+
+ /**
+ * Public accessor for the list of Destination objects for this FO
+ * @return the Destination object
+ */
+ public ArrayList getDestinationList() {
+ return destinationList;
+ }
+
+ /**
* Public accessor for the BookmarkTree object for this FO
* @return the BookmarkTree object
*/
diff --git a/src/java/org/apache/fop/image/JpegImage.java b/src/java/org/apache/fop/image/JpegImage.java
index 820a728f9..3ad745281 100644
--- a/src/java/org/apache/fop/image/JpegImage.java
+++ b/src/java/org/apache/fop/image/JpegImage.java
@@ -189,15 +189,20 @@ public class JpegImage extends AbstractFopImage {
}
try {
iccProfile = ICC_Profile.getInstance(iccStream.toByteArray());
- } catch (Exception e) {
- log.error("Invalid ICC profile: " + e, e);
- return false;
+ } catch (IllegalArgumentException iae) {
+ log.warn("An ICC profile is present but it is invalid ("
+ + iae.getMessage() + "). The color profile will be ignored. ("
+ + this.getOriginalURI() + ")");
}
} else if (this.colorSpace == null) {
log.error("ColorSpace not specified for JPEG image");
return false;
}
if (hasAPPEMarker && this.colorSpace.getType() == ColorSpace.TYPE_CMYK) {
+ if (log.isDebugEnabled()) {
+ log.debug("JPEG has an Adobe APPE marker. Note: CMYK Image will be inverted. ("
+ + this.getOriginalURI() + ")");
+ }
this.invertImage = true;
}
return true;
diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
index e63345f77..117893304 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
@@ -34,6 +34,7 @@ import org.apache.fop.area.Trait;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
+import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
import org.apache.fop.area.CTM;
import org.apache.fop.datatypes.FODimension;
import org.apache.fop.datatypes.Length;
@@ -989,9 +990,12 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
*/
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
- return ((BlockLevelLayoutManager)getParent()).mustKeepTogether()
- || !getBlockContainerFO().getKeepTogether().getWithinPage().isAuto()
- || !getBlockContainerFO().getKeepTogether().getWithinColumn().isAuto();
+ return (!getBlockContainerFO().getKeepTogether().getWithinPage().isAuto()
+ || !getBlockContainerFO().getKeepTogether().getWithinColumn().isAuto()
+ || (getParent() instanceof BlockLevelLayoutManager
+ && ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
+ || (getParent() instanceof InlineLayoutManager
+ && ((InlineLayoutManager) getParent()).mustKeepTogether()));
}
/**
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthPossPosIter.java b/src/java/org/apache/fop/layoutmgr/KnuthPossPosIter.java
index a3b48c26a..9553959b0 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthPossPosIter.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthPossPosIter.java
@@ -28,8 +28,8 @@ public class KnuthPossPosIter extends PositionIterator {
/**
* Main constructor
* @param elementList List of Knuth elements
- * @param startPos starting position
- * @param endPos ending position
+ * @param startPos starting position, inclusive
+ * @param endPos ending position, exclusive
*/
public KnuthPossPosIter(List elementList, int startPos, int endPos) {
super(elementList.listIterator(startPos));
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
index db4663df6..de779b011 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
@@ -28,6 +28,7 @@ import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.FOElementMapping;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FObjMixed;
@@ -85,6 +86,8 @@ import org.apache.fop.layoutmgr.list.ListItemLayoutManager;
import org.apache.fop.layoutmgr.table.TableLayoutManager;
import org.apache.fop.util.CharUtilities;
+import org.apache.fop.fo.extensions.destination.Destination;
+
/**
* The default LayoutManager maker class
*/
@@ -146,7 +149,13 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
public void makeLayoutManagers(FONode node, List lms) {
Maker maker = (Maker) makers.get(node.getClass());
if (maker == null) {
- log.error("No LayoutManager maker for class " + node.getClass());
+ if (FOElementMapping.URI.equals(node.getNamespaceURI())) {
+ log.error("No LayoutManager maker for class " + node.getClass());
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Skipping the creation of a layout manager for " + node.getClass());
+ }
+ }
} else {
maker.make(node, lms);
}
diff --git a/src/java/org/apache/fop/layoutmgr/SpaceResolver.java b/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
index 9fd7c9f21..c59911bf1 100644
--- a/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
+++ b/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
@@ -57,7 +57,7 @@ public class SpaceResolver {
* @param isFirst Resolution at the beginning of a (full) element list
* @param isLast Resolution at the end of a (full) element list
*/
- public SpaceResolver(List first, BreakElement breakPoss, List second,
+ private SpaceResolver(List first, BreakElement breakPoss, List second,
boolean isFirst, boolean isLast) {
this.isFirst = isFirst;
this.isLast = isLast;
@@ -494,7 +494,7 @@ public class SpaceResolver {
* Position class for break possibilities. It is used to notify layout manager about the
* effective spaces and conditional lengths.
*/
- public class SpaceHandlingBreakPosition extends Position {
+ public static class SpaceHandlingBreakPosition extends Position {
private SpaceResolver resolver;
private Position originalPosition;
@@ -566,7 +566,7 @@ public class SpaceResolver {
* Position class for no-break situations. It is used to notify layout manager about the
* effective spaces and conditional lengths.
*/
- public class SpaceHandlingPosition extends Position {
+ public static class SpaceHandlingPosition extends Position {
private SpaceResolver resolver;
diff --git a/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java b/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java
index b7f29a744..eb91f7175 100644
--- a/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java
+++ b/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java
@@ -221,8 +221,14 @@ public class ColumnSetup {
public int getXOffset(int col, PercentBaseContext context) {
int xoffset = 0;
for (int i = col; --i >= 0;) {
- if (colWidths.get(i) != null) {
- xoffset += ((Length) colWidths.get(i)).getValue(context);
+ int effCol;
+ if (i < colWidths.size()) {
+ effCol = i;
+ } else {
+ effCol = colWidths.size() - 1;
+ }
+ if (colWidths.get(effCol) != null) {
+ xoffset += ((Length) colWidths.get(effCol)).getValue(context);
}
}
return xoffset;
diff --git a/src/java/org/apache/fop/layoutmgr/table/GridUnit.java b/src/java/org/apache/fop/layoutmgr/table/GridUnit.java
index b472acf49..beb41f35b 100644
--- a/src/java/org/apache/fop/layoutmgr/table/GridUnit.java
+++ b/src/java/org/apache/fop/layoutmgr/table/GridUnit.java
@@ -345,11 +345,24 @@ public class GridUnit {
buffer.append("GridUnit:");
if (colSpanIndex > 0) {
buffer.append(" colSpan=").append(colSpanIndex);
+ if (isLastGridUnitColSpan()) {
+ buffer.append("(last)");
+ }
}
if (rowSpanIndex > 0) {
buffer.append(" rowSpan=").append(rowSpanIndex);
+ if (isLastGridUnitRowSpan()) {
+ buffer.append("(last)");
+ }
}
buffer.append(" startCol=").append(startCol);
+ if (!isPrimary() && getPrimary() != null) {
+ buffer.append(" primary=").append(getPrimary().getStartRow());
+ buffer.append("/").append(getPrimary().getStartCol());
+ if (getPrimary().getCell() != null) {
+ buffer.append(" id=" + getPrimary().getCell().getId());
+ }
+ }
buffer.append(" flags=").append(Integer.toBinaryString(flags));
return buffer.toString();
}
diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
index d8c294a07..4eac98953 100644
--- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
+++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
@@ -42,12 +42,16 @@ class RowPainter {
/** Currently handled row (= last encountered row). */
private EffRow lastRow = null;
private LayoutContext layoutContext;
- private int lastRowHeight = 0;
/**
* For each part of the table (header, footer, body), index of the first row of that
* part present on the current page.
*/
private int[] firstRow = new int[3];
+ /**
+ * Keeps track of the y-offsets of each row on a page (for body, header and footer separately).
+ * This is particularly needed for spanned cells where you need to know the y-offset
+ * of the starting row when the area is generated at the time the cell is closed.
+ */
private Map[] rowOffsets = new Map[] {new java.util.HashMap(),
new java.util.HashMap(), new java.util.HashMap()};
@@ -66,9 +70,9 @@ class RowPainter {
private int[] end;
/**
* Length, for each column, of the elements from the current cell put on the
- * current page.
+ * current page. This is the corresponding area's bpd.
*/
- private int[] partLength;
+ private int[] partBPD;
private TableContentLayoutManager tclm;
public RowPainter(TableContentLayoutManager tclm, LayoutContext layoutContext) {
@@ -78,7 +82,7 @@ class RowPainter {
this.primaryGridUnits = new PrimaryGridUnit[colCount];
this.start = new int[colCount];
this.end = new int[colCount];
- this.partLength = new int[colCount];
+ this.partBPD = new int[colCount];
Arrays.fill(firstRow, -1);
Arrays.fill(end, -1);
}
@@ -87,12 +91,9 @@ class RowPainter {
return this.accumulatedBPD;
}
- public void notifyEndOfSequence() {
- this.accumulatedBPD += lastRowHeight; //for last row
- }
-
public void notifyNestedPenaltyArea(int length) {
- this.lastRowHeight += length;
+ yoffset += length;
+ accumulatedBPD += length;
}
/**
@@ -104,8 +105,6 @@ class RowPainter {
public void handleTableContentPosition(TableContentPosition tcpos) {
if (lastRow != tcpos.row && lastRow != null) {
addAreasAndFlushRow(false);
- yoffset += lastRowHeight;
- this.accumulatedBPD += lastRowHeight;
}
if (log.isDebugEnabled()) {
log.debug("===handleTableContentPosition(" + tcpos);
@@ -144,12 +143,12 @@ class RowPainter {
* lying on the current page must be drawn.
*
* @param forcedFlush true if the elements must be drawn even if the row isn't
- * finished yet (last row on the page)
+ * finished yet (last row on the page), or if the row is the last of the current table
+ * part
* @return the height of the (grid) row
*/
public int addAreasAndFlushRow(boolean forcedFlush) {
int actualRowHeight = 0;
- int readyCount = 0;
int bt = lastRow.getBodyType();
if (log.isDebugEnabled()) {
@@ -160,117 +159,142 @@ class RowPainter {
for (int i = 0; i < primaryGridUnits.length; i++) {
if ((primaryGridUnits[i] != null)
&& (forcedFlush || (end[i] == primaryGridUnits[i].getElements().size() - 1))) {
- if (log.isTraceEnabled()) {
- log.trace("getting len for " + i + " "
- + start[i] + "-" + end[i]);
- }
- readyCount++;
- int len = ElementListUtils.calcContentLength(
- primaryGridUnits[i].getElements(), start[i], end[i]);
- partLength[i] = len;
- if (log.isTraceEnabled()) {
- log.trace("len of part: " + len);
- }
-
- if (start[i] == 0) {
- LengthRangeProperty bpd = primaryGridUnits[i].getCell()
- .getBlockProgressionDimension();
- if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
- int min = bpd.getMinimum(tclm.getTableLM())
- .getLength().getValue(tclm.getTableLM());
- if (min > 0) {
- len = Math.max(len, min);
- }
- }
- if (!bpd.getOptimum(tclm.getTableLM()).isAuto()) {
- int opt = bpd.getOptimum(tclm.getTableLM())
- .getLength().getValue(tclm.getTableLM());
- if (opt > 0) {
- len = Math.max(len, opt);
- }
- }
- if (primaryGridUnits[i].getRow() != null) {
- bpd = primaryGridUnits[i].getRow().getBlockProgressionDimension();
- if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
- int min = bpd.getMinimum(tclm.getTableLM()).getLength()
- .getValue(tclm.getTableLM());
- if (min > 0) {
- len = Math.max(len, min);
- }
- }
- }
- }
-
- // Add the padding if any
- len += primaryGridUnits[i].getBorders()
- .getPaddingBefore(false, primaryGridUnits[i].getCellLM());
- len += primaryGridUnits[i].getBorders()
- .getPaddingAfter(false, primaryGridUnits[i].getCellLM());
-
- //Now add the borders to the contentLength
- if (tclm.isSeparateBorderModel()) {
- len += primaryGridUnits[i].getBorders().getBorderBeforeWidth(false);
- len += primaryGridUnits[i].getBorders().getBorderAfterWidth(false);
- } else {
- len += primaryGridUnits[i].getHalfMaxBeforeBorderWidth();
- len += primaryGridUnits[i].getHalfMaxAfterBorderWidth();
- }
- int startRow = Math.max(primaryGridUnits[i].getStartRow(), firstRow[bt]);
- Integer storedOffset = (Integer)rowOffsets[bt].get(new Integer(startRow));
- int effYOffset;
- if (storedOffset != null) {
- effYOffset = storedOffset.intValue();
- } else {
- effYOffset = yoffset;
- }
- len -= yoffset - effYOffset;
- actualRowHeight = Math.max(actualRowHeight, len);
+ actualRowHeight = Math.max(actualRowHeight, computeSpanHeight(
+ primaryGridUnits[i], start[i], end[i], i, bt));
}
}
- if (readyCount == 0) {
- return 0;
- }
actualRowHeight += 2 * tclm.getTableLM().getHalfBorderSeparationBPD();
- lastRowHeight = actualRowHeight;
//Add areas for row
tclm.addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(), yoffset);
for (int i = 0; i < primaryGridUnits.length; i++) {
GridUnit currentGU = lastRow.safelyGetGridUnit(i);
- if ((primaryGridUnits[i] != null)
- && (forcedFlush || (end[i] == primaryGridUnits[i].getElements().size() - 1)
- && (currentGU == null || currentGU.isLastGridUnitRowSpan()))
- || (primaryGridUnits[i] == null && currentGU != null)) {
- //the last line in the "if" above is to avoid a premature end of an
- //row-spanned cell because no GridUnitParts are generated after a cell is
- //finished with its content. currentGU can be null if there's no grid unit
- //at this place in the current row (empty cell and no borders to process)
- if (log.isDebugEnabled()) {
- log.debug((forcedFlush ? "FORCED " : "") + "flushing..." + i + " "
- + start[i] + "-" + end[i]);
- }
- PrimaryGridUnit gu = primaryGridUnits[i];
- if (gu == null
- && !currentGU.isEmpty()
- && currentGU.getColSpanIndex() == 0
- && currentGU.isLastGridUnitColSpan()
- && (forcedFlush || currentGU.isLastGridUnitRowSpan())) {
- gu = currentGU.getPrimary();
- }
- if (gu != null) {
- addAreasForCell(gu, start[i], end[i],
- lastRow,
- partLength[i], actualRowHeight);
+ //currentGU can be null if there's no grid unit
+ //at this place in the current row (empty cell and no borders to process)
+
+ if (primaryGridUnits[i] != null) {
+ if (forcedFlush || ((end[i] == primaryGridUnits[i].getElements().size() - 1)
+ && (currentGU == null || currentGU.isLastGridUnitRowSpan()))) {
+ //the last line in the "if" above is to avoid a premature end of a
+ //row-spanned cell because no GridUnitParts are generated after a cell is
+ //finished with its content.
+ //See table-cell_number-rows-spanned_bug38397.xml
+ addAreasForCell(primaryGridUnits[i], start[i], end[i], lastRow, partBPD[i],
+ actualRowHeight);
primaryGridUnits[i] = null;
start[i] = 0;
end[i] = -1;
- partLength[i] = 0;
+ partBPD[i] = 0;
}
+ } else if (currentGU != null && !currentGU.isEmpty()
+ && currentGU.getColSpanIndex() == 0
+ && (forcedFlush || currentGU.isLastGridUnitRowSpan())) {
+ //A row-spanned cell has finished contributing content on the previous page
+ //and now still has to cause grid units to be painted.
+ //See table-cell_page-break_span.xml
+ addAreasForCell(currentGU.getPrimary(), start[i], end[i], lastRow, partBPD[i],
+ actualRowHeight);
+ start[i] = 0;
+ end[i] = -1;
+ partBPD[i] = 0;
}
}
+ yoffset += actualRowHeight;
+ accumulatedBPD += actualRowHeight;
+ if (forcedFlush) {
+ // Either the end of the page is reached, then this was the last call of this
+ // method and we no longer care about lastRow; or the end of a table-part
+ // (header, footer, body) has been reached, and the next row will anyway be
+ // different from the current one, and this is unnecessary to recall this
+ // method in the first lines of handleTableContentPosition, so we may reset
+ // lastRow
+ lastRow = null;
+ }
return actualRowHeight;
}
+ /**
+ * Computes the total height of the part of the given cell spanning on the current
+ * active row, including borders and paddings. The bpd is also stored in partBPD, and
+ * it is ensured that the cell's or row's explicit height is respected. yoffset is
+ * updated accordingly.
+ *
+ * @param pgu primary grid unit corresponding to the cell
+ * @param start index of the first element of the cell occuring on the current page
+ * @param end index of the last element of the cell occuring on the current page
+ * @param columnIndex column index of the cell
+ * @param bodyType {@link TableRowIterator#HEADER}, {@link TableRowIterator#FOOTER}, or
+ * {@link TableRowIterator#BODY}
+ * @return the cell's height
+ */
+ private int computeSpanHeight(PrimaryGridUnit pgu, int start, int end, int columnIndex,
+ int bodyType) {
+ if (log.isTraceEnabled()) {
+ log.trace("getting len for " + columnIndex + " "
+ + start + "-" + end);
+ }
+ int len = ElementListUtils.calcContentLength(
+ pgu.getElements(), start, end);
+ partBPD[columnIndex] = len;
+ if (log.isTraceEnabled()) {
+ log.trace("len of part: " + len);
+ }
+
+ if (start == 0) {
+ LengthRangeProperty bpd = pgu.getCell()
+ .getBlockProgressionDimension();
+ if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
+ int min = bpd.getMinimum(tclm.getTableLM())
+ .getLength().getValue(tclm.getTableLM());
+ if (min > 0) {
+ len = Math.max(len, min);
+ }
+ }
+ if (!bpd.getOptimum(tclm.getTableLM()).isAuto()) {
+ int opt = bpd.getOptimum(tclm.getTableLM())
+ .getLength().getValue(tclm.getTableLM());
+ if (opt > 0) {
+ len = Math.max(len, opt);
+ }
+ }
+ if (pgu.getRow() != null) {
+ bpd = pgu.getRow().getBlockProgressionDimension();
+ if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
+ int min = bpd.getMinimum(tclm.getTableLM()).getLength()
+ .getValue(tclm.getTableLM());
+ if (min > 0) {
+ len = Math.max(len, min);
+ }
+ }
+ }
+ }
+
+ // Add the padding if any
+ len += pgu.getBorders()
+ .getPaddingBefore(false, pgu.getCellLM());
+ len += pgu.getBorders()
+ .getPaddingAfter(false, pgu.getCellLM());
+
+ //Now add the borders to the contentLength
+ if (tclm.isSeparateBorderModel()) {
+ len += pgu.getBorders().getBorderBeforeWidth(false);
+ len += pgu.getBorders().getBorderAfterWidth(false);
+ } else {
+ len += pgu.getHalfMaxBeforeBorderWidth();
+ len += pgu.getHalfMaxAfterBorderWidth();
+ }
+ int startRow = Math.max(pgu.getStartRow(), firstRow[bodyType]);
+ Integer storedOffset = (Integer)rowOffsets[bodyType].get(new Integer(startRow));
+ int effYOffset;
+ if (storedOffset != null) {
+ effYOffset = storedOffset.intValue();
+ } else {
+ effYOffset = yoffset;
+ }
+ len -= yoffset - effYOffset;
+ return len;
+ }
+
private void addAreasForCell(PrimaryGridUnit pgu, int startPos, int endPos,
EffRow row, int contentHeight, int rowHeight) {
int bt = row.getBodyType();
@@ -278,12 +302,33 @@ class RowPainter {
firstRow[bt] = row.getIndex();
}
//Determine the first row in this sequence
- int startRow = Math.max(pgu.getStartRow(), firstRow[bt]);
+ int startRowIndex = Math.max(pgu.getStartRow(), firstRow[bt]);
+ int lastRowIndex = lastRow.getIndex();
+
+ // In collapsing-border model, if the cell spans over several columns/rows then
+ // dedicated areas will be created for each grid unit to hold the corresponding
+ // borders. For that we need to know the height of each grid unit, that is of each
+ // grid row spanned over by the cell
+ int[] spannedGridRowHeights = null;
+ if (!tclm.getTableLM().getTable().isSeparateBorderModel() && pgu.hasSpanning()) {
+ spannedGridRowHeights = new int[lastRowIndex - startRowIndex + 1];
+ int prevOffset = ((Integer)rowOffsets[bt].get(new Integer(startRowIndex))).intValue();
+ for (int i = 0; i < lastRowIndex - startRowIndex; i++) {
+ int newOffset = ((Integer) rowOffsets[bt].get(new Integer(startRowIndex + i + 1)))
+ .intValue();
+ spannedGridRowHeights[i] = newOffset - prevOffset;
+ prevOffset = newOffset;
+ }
+ spannedGridRowHeights[lastRowIndex - startRowIndex] = rowHeight;
+ }
+
//Determine y offset for the cell
- Integer offset = (Integer)rowOffsets[bt].get(new Integer(startRow));
+ Integer offset = (Integer)rowOffsets[bt].get(new Integer(startRowIndex));
while (offset == null) {
- startRow--;
- offset = (Integer)rowOffsets[bt].get(new Integer(startRow));
+ //TODO Figure out what this does and when it's triggered
+ //This block is probably never used, at least it's not triggered by any of our tests
+ startRowIndex--;
+ offset = (Integer)rowOffsets[bt].get(new Integer(startRowIndex));
}
int effYOffset = offset.intValue();
int effCellHeight = rowHeight;
@@ -306,7 +351,8 @@ class RowPainter {
SpaceResolver.performConditionalsNotification(pgu.getElements(),
startPos, endPos, prevBreak);
}
- cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(),
- startPos, endPos + 1), layoutContext);
+ cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(), startPos, endPos + 1),
+ layoutContext, spannedGridRowHeights, startRowIndex - pgu.getStartRow(),
+ lastRowIndex - pgu.getStartRow() + 1);
}
}
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
index 223d80a7f..2f17a6a25 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
@@ -16,13 +16,14 @@
*/
/* $Id$ */
-
+
package org.apache.fop.layoutmgr.table;
import java.util.LinkedList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableCell;
@@ -48,20 +49,20 @@ import org.apache.fop.traits.MinOptMax;
* LayoutManager for a table-cell FO.
* A cell contains blocks. These blocks fill the cell.
*/
-public class TableCellLayoutManager extends BlockStackingLayoutManager
+public class TableCellLayoutManager extends BlockStackingLayoutManager
implements BlockLevelLayoutManager {
/**
* logging instance
*/
private static Log log = LogFactory.getLog(TableCellLayoutManager.class);
-
- private PrimaryGridUnit gridUnit;
-
+
+ private PrimaryGridUnit primaryGridUnit;
+
private Block curBlockArea;
private int inRowIPDOffset;
-
+
private int xoffset;
private int yoffset;
private int cellIPD;
@@ -75,23 +76,23 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
/**
* Create a new Cell layout manager.
* @param node table-cell FO for which to create the LM
- * @param pgu primary grid unit for the cell
+ * @param pgu primary grid unit for the cell
*/
public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) {
super(node);
fobj = node;
- this.gridUnit = pgu;
+ this.primaryGridUnit = pgu;
}
/** @return the table-cell FO */
public TableCell getTableCell() {
return (TableCell)this.fobj;
}
-
+
private boolean isSeparateBorderModel() {
return getTable().isSeparateBorderModel();
}
-
+
/** @see org.apache.fop.layoutmgr.LayoutManager#initialize() */
public void initialize() {
borderAndPaddingBPD = 0;
@@ -107,7 +108,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
borderAndPaddingBPD += getTableCell().getCommonBorderPaddingBackground()
.getPaddingAfter(false, this);
}
-
+
/**
* @return the table owning this cell
*/
@@ -118,12 +119,12 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
return (Table)node;
}
-
+
/** @see org.apache.fop.layoutmgr.BlockStackingLayoutManager#getIPIndents() */
protected int getIPIndents() {
int iIndents = 0;
- int[] startEndBorderWidths = gridUnit.getStartEndBorderWidths();
+ int[] startEndBorderWidths = primaryGridUnit.getStartEndBorderWidths();
startBorderWidth += startEndBorderWidths[0];
endBorderWidth += startEndBorderWidths[1];
iIndents += startBorderWidth;
@@ -135,14 +136,14 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
iIndents += getTableCell().getCommonBorderPaddingBackground().getPaddingEnd(false, this);
return iIndents;
}
-
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager
*/
public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
MinOptMax stackLimit = new MinOptMax(context.getStackLimit());
- referenceIPD = context.getRefIPD();
+ referenceIPD = context.getRefIPD();
cellIPD = referenceIPD;
cellIPD -= getIPIndents();
if (isSeparateBorderModel()) {
@@ -173,7 +174,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false);
}
-
+
if (returnedList.size() == 1
&& ((ListElement)returnedList.getFirst()).isForcedBreak()) {
// a descendant of this block has break-before
@@ -193,13 +194,13 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
//Space resolution
SpaceResolver.resolveElementList(returnList);
-
+
return returnList;
} else {
if (prevLM != null) {
// there is a block handled by prevLM
// before the one handled by curLM
- if (mustKeepTogether()
+ if (mustKeepTogether()
|| context.isKeepWithNextPending()
|| childLC.isKeepWithPreviousPending()) {
//Clear keep pending flag
@@ -242,7 +243,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
//Space resolution
SpaceResolver.resolveElementList(returnList);
-
+
return returnList;
}
}
@@ -256,16 +257,16 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
returnedList = new LinkedList();
wrapPositionElements(contentList, returnList);
-
+
//Space resolution
SpaceResolver.resolveElementList(returnList);
-
+
getPSLM().notifyEndOfLayout(((TableCell)getFObj()).getId());
-
+
setFinished(true);
return returnList;
}
-
+
/**
* Set the y offset of this cell.
* This offset is used to set the absolute position of the cell.
@@ -294,7 +295,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
public void setInRowIPDOffset(int off) {
this.inRowIPDOffset = off;
}
-
+
/**
* Set the content height for this cell. This method is used during
* addAreas() stage.
@@ -304,7 +305,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
public void setContentHeight(int h) {
usedBPD = h;
}
-
+
/**
* Set the row height that contains this cell. This method is used during
* addAreas() stage.
@@ -328,96 +329,107 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
} else {
bpd -= gu.getPrimary().getHalfMaxBorderWidth();
}
- CommonBorderPaddingBackground cbpb
- = gu.getCell().getCommonBorderPaddingBackground();
+ CommonBorderPaddingBackground cbpb
+ = gu.getCell().getCommonBorderPaddingBackground();
bpd -= cbpb.getPaddingBefore(false, this);
bpd -= cbpb.getPaddingAfter(false, this);
bpd -= 2 * ((TableLayoutManager)getParent()).getHalfBorderSeparationBPD();
return bpd;
}
-
+
/**
- * Add the areas for the break points.
- * The cell contains block stacking layout managers
- * that add block areas.
- *
+ * Add the areas for the break points. The cell contains block stacking layout
+ * managers that add block areas.
+ *
+ * <p>In the collapsing-border model, the borders of a cell that spans over several
+ * rows or columns are drawn separately for each grid unit. Therefore we must know the
+ * height of each grid row spanned over by the cell. Also, if the cell is broken over
+ * two pages we must know which spanned grid rows are present on the current page.</p>
+ *
* @param parentIter the iterator of the break positions
* @param layoutContext the layout context for adding the areas
+ * @param spannedGridRowHeights in collapsing-border model for a spanning cell, height
+ * of each spanned grid row
+ * @param startRow first grid row on the current page spanned over by the cell,
+ * inclusive
+ * @param endRow last grid row on the current page spanned over by the cell, exclusive
*/
public void addAreas(PositionIterator parentIter,
- LayoutContext layoutContext) {
+ LayoutContext layoutContext,
+ int[] spannedGridRowHeights,
+ int startRow,
+ int endRow) {
getParentArea(null);
getPSLM().addIDToPage(getTableCell().getId());
if (isSeparateBorderModel()) {
if (!emptyCell || getTableCell().showEmptyCells()) {
- TraitSetter.addBorders(curBlockArea,
- getTableCell().getCommonBorderPaddingBackground(), this);
+ TraitSetter.addBorders(curBlockArea, getTableCell().getCommonBorderPaddingBackground(),
+ false, false, false, false, this);
+ TraitSetter.addPadding(curBlockArea, getTableCell().getCommonBorderPaddingBackground(),
+ false, false, false, false, this);
}
} else {
- boolean[] outer = new boolean[] {
- gridUnit.getFlag(GridUnit.FIRST_IN_TABLE),
- gridUnit.getFlag(GridUnit.LAST_IN_TABLE),
- gridUnit.getFlag(GridUnit.IN_FIRST_COLUMN),
- gridUnit.getFlag(GridUnit.IN_LAST_COLUMN)};
- if (!gridUnit.hasSpanning()) {
+ if (!primaryGridUnit.hasSpanning()) {
//Can set the borders directly if there's no span
- TraitSetter.addCollapsingBorders(curBlockArea,
- gridUnit.getBorders(), outer, this);
+ boolean[] outer = new boolean[] {
+ primaryGridUnit.getFlag(GridUnit.FIRST_IN_TABLE),
+ primaryGridUnit.getFlag(GridUnit.LAST_IN_TABLE),
+ primaryGridUnit.getFlag(GridUnit.IN_FIRST_COLUMN),
+ primaryGridUnit.getFlag(GridUnit.IN_LAST_COLUMN)};
+ TraitSetter.addCollapsingBorders(curBlockArea,
+ primaryGridUnit.getBorders(), outer, this);
} else {
+ boolean[] outer = new boolean[4];
int dy = yoffset;
- for (int y = 0; y < gridUnit.getRows().size(); y++) {
- GridUnit[] gridUnits = (GridUnit[])gridUnit.getRows().get(y);
+ for (int y = startRow; y < endRow; y++) {
+ GridUnit[] gridUnits = (GridUnit[])primaryGridUnit.getRows().get(y);
int dx = xoffset;
- int lastRowHeight = 0;
for (int x = 0; x < gridUnits.length; x++) {
GridUnit gu = gridUnits[x];
if (!gu.hasBorders()) {
continue;
}
-
+
//Blocks for painting grid unit borders
Block block = new Block();
block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
block.setPositioning(Block.ABSOLUTE);
- int bpd = getContentHeight(gu);
- if (isSeparateBorderModel()) {
- bpd += (gu.getBorders().getBorderBeforeWidth(false));
- bpd += (gu.getBorders().getBorderAfterWidth(false));
- } else {
- bpd += gridUnit.getHalfMaxBeforeBorderWidth()
- - (gu.getBorders().getBorderBeforeWidth(false) / 2);
- bpd += gridUnit.getHalfMaxAfterBorderWidth()
- - (gu.getBorders().getBorderAfterWidth(false) / 2);
- }
+ int bpd = spannedGridRowHeights[y - startRow];
+ bpd -= gu.getBorders().getBorderBeforeWidth(false) / 2;
+ bpd -= gu.getBorders().getBorderAfterWidth(false) / 2;
block.setBPD(bpd);
- lastRowHeight = rowHeight;
- int ipd = gu.getColumn().getColumnWidth().getValue(this);
- int borderStartWidth = gu.getBorders().getBorderStartWidth(false) / 2;
+ if (log.isTraceEnabled()) {
+ log.trace("pgu: " + primaryGridUnit + "; gu: " + gu + "; yoffset: "
+ + (dy - gu.getBorders().getBorderBeforeWidth(false) / 2)
+ + "; bpd: " + bpd);
+ }
+ int ipd = gu.getColumn().getColumnWidth().getValue(
+ (PercentBaseContext) getParent());
+ int borderStartWidth = gu.getBorders().getBorderStartWidth(false) / 2;
ipd -= borderStartWidth;
ipd -= gu.getBorders().getBorderEndWidth(false) / 2;
block.setIPD(ipd);
block.setXOffset(dx + borderStartWidth);
- int halfCollapsingBorderHeight = 0;
- if (!isSeparateBorderModel()) {
- halfCollapsingBorderHeight
- += gu.getBorders().getBorderBeforeWidth(false) / 2;
- }
- block.setYOffset(dy - halfCollapsingBorderHeight);
+ block.setYOffset(dy - gu.getBorders().getBorderBeforeWidth(false) / 2);
+ outer[0] = gu.getFlag(GridUnit.FIRST_IN_TABLE);
+ outer[1] = gu.getFlag(GridUnit.LAST_IN_TABLE);
+ outer[2] = gu.getFlag(GridUnit.IN_FIRST_COLUMN);
+ outer[3] = gu.getFlag(GridUnit.IN_LAST_COLUMN);
TraitSetter.addCollapsingBorders(block, gu.getBorders(), outer, this);
parentLM.addChildArea(block);
- dx += gu.getColumn().getColumnWidth().getValue(this);
+ dx += gu.getColumn().getColumnWidth().getValue(
+ (PercentBaseContext) getParent());
}
- dy += lastRowHeight;
+ dy += spannedGridRowHeights[y - startRow];
}
- log.warn("TODO Add collapsed border painting for spanned cells");
}
}
//Handle display-align
- int contentBPD = getContentHeight(gridUnit);
+ int contentBPD = getContentHeight(primaryGridUnit);
if (usedBPD < contentBPD) {
if (getTableCell().getDisplayAlign() == EN_CENTER) {
Block space = new Block();
@@ -431,7 +443,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
-
+
curBlockArea.setBPD(contentBPD);
// Add background after we know the BPD
@@ -446,7 +458,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
getTableCell().getCommonBorderPaddingBackground(),
this);
}
-
+
flush();
curBlockArea = null;
@@ -471,8 +483,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
TraitSetter.setProducerID(curBlockArea, getTableCell().getId());
curBlockArea.setPositioning(Block.ABSOLUTE);
- int indent = 0;
- indent += startBorderWidth;
+ int indent = startBorderWidth;
if (!isSeparateBorderModel()) {
indent /= 2;
}
@@ -481,18 +492,18 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
// set position
int borderAdjust = 0;
if (!isSeparateBorderModel()) {
- if (gridUnit.hasSpanning()) {
- borderAdjust -= gridUnit.getHalfMaxBeforeBorderWidth();
+ if (primaryGridUnit.hasSpanning()) {
+ borderAdjust -= primaryGridUnit.getHalfMaxBeforeBorderWidth();
} else {
- borderAdjust += gridUnit.getHalfMaxBeforeBorderWidth();
+ borderAdjust += primaryGridUnit.getHalfMaxBeforeBorderWidth();
}
} else {
- //borderAdjust += gridUnit.getBorders().getBorderBeforeWidth(false);
+ //borderAdjust += primaryGridUnit.getBorders().getBorderBeforeWidth(false);
}
TableLayoutManager tableLM = (TableLayoutManager)getParent();
- curBlockArea.setXOffset(xoffset + inRowIPDOffset
+ curBlockArea.setXOffset(xoffset + inRowIPDOffset
+ tableLM.getHalfBorderSeparationIPD() + indent);
- curBlockArea.setYOffset(yoffset - borderAdjust
+ curBlockArea.setYOffset(yoffset - borderAdjust
+ tableLM.getHalfBorderSeparationBPD());
curBlockArea.setIPD(cellIPD);
//curBlockArea.setHeight();
@@ -548,8 +559,8 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
boolean keep = ((BlockLevelLayoutManager)getParent()).mustKeepTogether();
- if (gridUnit.getRow() != null) {
- keep |= gridUnit.getRow().mustKeepTogether();
+ if (primaryGridUnit.getRow() != null) {
+ keep |= primaryGridUnit.getRow().mustKeepTogether();
}
return keep;
}
@@ -575,9 +586,9 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
|| !fobj.getKeepWithNext().getWithinColumn().isAuto();
*/
}
-
+
// --------- Property Resolution related functions --------- //
-
+
/**
* Returns the IPD of the content area
* @return the IPD of the content area
@@ -585,7 +596,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
public int getContentAreaIPD() {
return cellIPD;
}
-
+
/**
* Returns the BPD of the content area
* @return the BPD of the content area
@@ -598,14 +609,14 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
return -1;
}
}
-
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesReferenceArea
*/
public boolean getGeneratesReferenceArea() {
return true;
}
-
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getGeneratesBlockArea
*/
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
index f9d7c6397..c3e1a41da 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
@@ -235,6 +235,12 @@ public class TableContentLayoutManager implements PercentBaseContext {
if (!isSeparateBorderModel()) {
resolveNormalBeforeAfterBordersForRowGroup(rowGroup, iter);
}
+
+ //Reset keep-with-next when remaining inside the table.
+ //The context flag is only used to propagate keep-with-next to the outside.
+ //The clearing is ok here because createElementsForRowGroup already handles
+ //the keep when inside a table.
+ context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false);
//Element list creation
createElementsForRowGroup(context, alignment, bodyType,
@@ -691,7 +697,6 @@ public class TableContentLayoutManager implements PercentBaseContext {
iterateAndPaintPositions(nestedIter, painter);
}
- painter.notifyEndOfSequence();
this.usedBPD += painter.getAccumulatedBPD();
if (markers != null) {
@@ -701,15 +706,16 @@ public class TableContentLayoutManager implements PercentBaseContext {
}
/**
- * Iterates over a part of the table and paints the related elements.
+ * Iterates over a part of the table (header, footer, body) and paints the related
+ * elements.
*
- * @param iterator iterator over the table's header, body or footer elements
+ * @param iterator iterator over Position elements. Those positions correspond to the
+ * elements of the table present on the current page
* @param painter
*/
private void iterateAndPaintPositions(Iterator iterator, RowPainter painter) {
List lst = new java.util.ArrayList();
boolean firstPos = false;
- boolean lastPos = false;
TableBody body = null;
while (iterator.hasNext()) {
Position pos = (Position)iterator.next();
@@ -728,18 +734,9 @@ public class TableContentLayoutManager implements PercentBaseContext {
if (tcpos.getFlag(TableContentPosition.LAST_IN_ROWGROUP)
&& tcpos.row.getFlag(EffRow.LAST_IN_PART)) {
log.trace("LAST_IN_ROWGROUP + LAST_IN_PART");
- lastPos = true;
- getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
- true, firstPos, lastPos);
- int size = lst.size();
- for (int i = 0; i < size; i++) {
- painter.handleTableContentPosition((TableContentPosition)lst.get(i));
- }
- getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
- false, firstPos, lastPos);
+ handleMarkersAndPositions(lst, body, firstPos, true, painter);
//reset
firstPos = false;
- lastPos = false;
body = null;
lst.clear();
}
@@ -750,18 +747,26 @@ public class TableContentLayoutManager implements PercentBaseContext {
}
}
if (body != null) {
- getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
- true, firstPos, lastPos);
- int size = lst.size();
- for (int i = 0; i < size; i++) {
- painter.handleTableContentPosition((TableContentPosition)lst.get(i));
- }
- getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
- false, firstPos, lastPos);
+ // Entering this block means that the end of the current table-part hasn't
+ // been reached (otherwise it would have been caught by the test above). So
+ // lastPos is necessarily false
+ handleMarkersAndPositions(lst, body, firstPos, false, painter);
}
painter.addAreasAndFlushRow(true);
}
-
+
+ private void handleMarkersAndPositions(List positions, TableBody body, boolean firstPos,
+ boolean lastPos, RowPainter painter) {
+ getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
+ true, firstPos, lastPos);
+ int size = positions.size();
+ for (int i = 0; i < size; i++) {
+ painter.handleTableContentPosition((TableContentPosition)positions.get(i));
+ }
+ getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
+ false, firstPos, lastPos);
+ }
+
/**
* Get the area for a row for background.
* @param row the table-row object or null
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
index 1707ad422..00ecb01d2 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
@@ -215,10 +215,12 @@ public class TableLayoutManager extends BlockStackingLayoutManager
if (getTable().isSeparateBorderModel()) {
addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
firstVisibleMarkServed = true;
+ // Border and padding to be repeated at each break
+ // This must be done only in the separate-border model, as in collapsing
+ // tables have no padding and borders are determined at the cell level
+ addPendingMarks(context);
}
- //Spaces, border and padding to be repeated at each break
- addPendingMarks(context);
// Elements for the table-header/footer/body
LinkedList contentKnuthElements = null;
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java
index 63d153584..f8cedd7de 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java
@@ -477,7 +477,7 @@ public class TableRowIterator {
safelySetListItem(gridUnits, colnum - 1, guSpan);
if (hasRowSpanningLeft) {
pendingRowSpans++;
- safelySetListItem(previousRowsSpanningCells, colnum - 1, gu);
+ safelySetListItem(previousRowsSpanningCells, colnum - 1, guSpan);
}
horzSpan[j] = guSpan;
}
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
index 4459f9a3b..20b80c1bd 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
@@ -46,6 +46,8 @@ public class TableStepper {
private TableContentLayoutManager tclm;
private EffRow[] rowGroup;
+ /** Number of columns in the row group. */
+ private int columnCount;
private int totalHeight;
private int activeRowIndex;
/**
@@ -83,7 +85,7 @@ public class TableStepper {
private boolean rowBacktrackForLastStep;
private boolean skippedStep;
private boolean[] keepWithNextSignals;
- private boolean[] forcedBreaks;
+ private boolean forcedBreak;
private int lastMaxPenaltyLength;
/**
@@ -100,6 +102,7 @@ public class TableStepper {
* @param columnCount number of columns the row group has
*/
private void setup(int columnCount) {
+ this.columnCount = columnCount;
this.activeRowIndex = 0;
elementLists = new List[columnCount];
startRow = new int[columnCount];
@@ -112,21 +115,15 @@ public class TableStepper {
borderAfter = new int[columnCount];
paddingAfter = new int[columnCount];
keepWithNextSignals = new boolean[columnCount];
- forcedBreaks = new boolean[columnCount];
Arrays.fill(end, -1);
}
private void clearBreakCondition() {
- Arrays.fill(forcedBreaks, false);
+ forcedBreak = false;
}
private boolean isBreakCondition() {
- for (int i = 0; i < forcedBreaks.length; i++) {
- if (forcedBreaks[i]) {
- return true;
- }
- }
- return false;
+ return forcedBreak;
}
/**
@@ -171,7 +168,7 @@ public class TableStepper {
private int getMaxRemainingHeight() {
int maxW = 0;
if (!rowBacktrackForLastStep) {
- for (int i = 0; i < widths.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
if (elementLists[i] == null) {
continue;
}
@@ -217,7 +214,6 @@ public class TableStepper {
widths[column] = 0;
startRow[column] = activeRowIndex;
keepWithNextSignals[column] = false;
- forcedBreaks[column] = false;
} else if (gu.isPrimary()) {
PrimaryGridUnit pgu = (PrimaryGridUnit)gu;
boolean makeBoxForWholeRow = false;
@@ -263,9 +259,6 @@ public class TableStepper {
widths[column] = 0;
startRow[column] = activeRowIndex;
keepWithNextSignals[column] = false;
- forcedBreaks[column] = false;
- } else {
- log.trace("TableStepper.setupElementList: not empty nor primary grid unit");
}
}
@@ -302,7 +295,7 @@ public class TableStepper {
int addedBoxLen = 0;
TableContentPosition lastTCPos = null;
LinkedList returnList = new LinkedList();
- while ((step = getNextStep(laststep)) >= 0) {
+ while ((step = getNextStep()) >= 0) {
int normalRow = activeRowIndex;
if (rowBacktrackForLastStep) {
//Even though we've already switched to the next row, we have to
@@ -316,7 +309,7 @@ public class TableStepper {
//Put all involved grid units into a list
List gridUnitParts = new java.util.ArrayList(maxColumnCount);
- for (int i = 0; i < start.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
if (end[i] >= start[i]) {
PrimaryGridUnit pgu = rowGroup[startRow[i]].getGridUnit(i).getPrimary();
if (start[i] == 0 && end[i] == 0
@@ -395,7 +388,7 @@ public class TableStepper {
int p = 0;
boolean allCellsHaveContributed = true;
signalKeepWithNext = false;
- for (int i = 0; i < start.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
if (start[i] == 0 && end[i] < 0 && elementLists[i] != null) {
allCellsHaveContributed = false;
}
@@ -455,10 +448,9 @@ public class TableStepper {
/**
* Finds the smallest increment leading to the next legal break inside the row-group.
*
- * @param lastStep used for log only
* @return the size of the increment, -1 if no next step is available (end of row-group reached)
*/
- private int getNextStep(int lastStep) {
+ private int getNextStep() {
log.trace("Entering getNextStep");
this.lastMaxPenaltyLength = 0;
//Check for forced break conditions
@@ -467,65 +459,15 @@ public class TableStepper {
return -1;
}*/
- int[] backupWidths = new int[start.length];
- System.arraycopy(widths, 0, backupWidths, 0, backupWidths.length);
+ int[] backupWidths = new int[columnCount];
+ System.arraycopy(widths, 0, backupWidths, 0, columnCount);
//set starting points
- // We assume that the current grid row is finished. If this is not the case this
- // boolean will be reset (see below)
- boolean currentGridRowFinished = true;
- for (int i = 0; i < start.length; i++) {
- // null element lists probably correspond to empty cells
- if (elementLists[i] == null) {
- continue;
- }
- if (end[i] < elementLists[i].size()) {
- start[i] = end[i] + 1;
- if (end[i] + 1 < elementLists[i].size()
- && getActiveGridUnit(i).isLastGridUnitRowSpan()) {
- // Ok, so this grid unit is the last in the row-spanning direction and
- // there are still unhandled Knuth elements. They /will/ have to be
- // put on the current grid row, which means that this row isn't
- // finished yet
- currentGridRowFinished = false;
- }
- } else {
- throw new IllegalStateException("end[i] overflows elementList[i].size()");
-// start[i] = -1; //end of list reached
-// end[i] = -1;
- }
- }
-
- if (currentGridRowFinished) {
- if (activeRowIndex < rowGroup.length - 1) {
- TableRow rowFO = getActiveRow().getTableRow();
- if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
- log.warn(FONode.decorateWithContextInfo(
- "break-after ignored on table-row because of row spanning "
- + "in progress (See XSL 1.0, 7.19.1)", rowFO));
- }
- activeRowIndex++;
- if (log.isDebugEnabled()) {
- log.debug("===> new row: " + activeRowIndex);
- }
- initializeElementLists();
- for (int i = 0; i < backupWidths.length; i++) {
- if (end[i] < 0) {
- backupWidths[i] = 0;
- }
- }
- rowFO = getActiveRow().getTableRow();
- if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
- log.warn(FONode.decorateWithContextInfo(
- "break-before ignored on table-row because of row spanning "
- + "in progress (See XSL 1.0, 7.19.2)", rowFO));
- }
- }
- }
+ goToNextRowIfCurrentFinished(backupWidths);
//Get next possible sequence for each cell
- int seqCount = 0;
- for (int i = 0; i < start.length; i++) {
+ boolean stepFound = false;
+ for (int i = 0; i < columnCount; i++) {
if (elementLists[i] == null) {
continue;
}
@@ -536,7 +478,7 @@ public class TableStepper {
this.lastMaxPenaltyLength = Math.max(this.lastMaxPenaltyLength, el.getW());
if (el.getP() <= -KnuthElement.INFINITE) {
log.debug("FORCED break encountered!");
- forcedBreaks[i] = true;
+ forcedBreak = true;
break;
} else if (el.getP() < KnuthElement.INFINITE) {
//First legal break point
@@ -562,7 +504,7 @@ public class TableStepper {
}
widths[i] = backupWidths[i];
} else {
- seqCount++;
+ stepFound = true;
}
//log.debug("part " + start[i] + "-" + end[i] + " " + widths[i]);
if (end[i] + 1 >= elementLists[i].size()) {
@@ -588,14 +530,14 @@ public class TableStepper {
log.trace("column " + (i+1) + ": padding before=" + paddingBefore[i] + " after=" + paddingAfter[i]);
}
}
- if (seqCount == 0) {
+ if (!stepFound) {
return -1;
}
//Determine smallest possible step
int minStep = Integer.MAX_VALUE;
StringBuffer sb = new StringBuffer();
- for (int i = 0; i < widths.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
baseWidth[i] = 0;
for (int prevRow = 0; prevRow < startRow[i]; prevRow++) {
baseWidth[i] += rowGroup[prevRow].getHeight().opt;
@@ -610,12 +552,12 @@ public class TableStepper {
}
}
if (log.isDebugEnabled()) {
- log.debug("candidate steps: " + sb + " lastStep=" + lastStep);
+ log.debug("candidate steps: " + sb);
}
//Check for constellations that would result in overlapping borders
/*
- for (int i = 0; i < widths.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
}*/
@@ -623,7 +565,7 @@ public class TableStepper {
//See http://people.apache.org/~jeremias/fop/NextStepAlgoNotes.pdf
rowBacktrackForLastStep = false;
skippedStep = false;
- for (int i = 0; i < widths.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
int len = baseWidth[i] + widths[i];
if (len > minStep) {
widths[i] = backupWidths[i];
@@ -651,7 +593,7 @@ public class TableStepper {
}
if (log.isDebugEnabled()) {
/*StringBuffer*/ sb = new StringBuffer("[col nb: start-end(width)] ");
- for (int i = 0; i < widths.length; i++) {
+ for (int i = 0; i < columnCount; i++) {
if (end[i] >= start[i]) {
sb.append(i + ": " + start[i] + "-" + end[i] + "(" + widths[i] + "), ");
} else {
@@ -663,8 +605,61 @@ public class TableStepper {
return minStep;
}
-
-
+
+ private void goToNextRowIfCurrentFinished(int[] backupWidths) {
+ // We assume that the current grid row is finished. If this is not the case this
+ // boolean will be reset (see below)
+ boolean currentGridRowFinished = true;
+ for (int i = 0; i < columnCount; i++) {
+ // null element lists probably correspond to empty cells
+ if (elementLists[i] == null) {
+ continue;
+ }
+ if (end[i] < elementLists[i].size()) {
+ start[i] = end[i] + 1;
+ if (end[i] + 1 < elementLists[i].size()
+ && getActiveGridUnit(i).isLastGridUnitRowSpan()) {
+ // Ok, so this grid unit is the last in the row-spanning direction and
+ // there are still unhandled Knuth elements. They /will/ have to be
+ // put on the current grid row, which means that this row isn't
+ // finished yet
+ currentGridRowFinished = false;
+ }
+ } else {
+ throw new IllegalStateException("end[i] overflows elementList[i].size()");
+// start[i] = -1; //end of list reached
+// end[i] = -1;
+ }
+ }
+
+ if (currentGridRowFinished) {
+ if (activeRowIndex < rowGroup.length - 1) {
+ TableRow rowFO = getActiveRow().getTableRow();
+ if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
+ log.warn(FONode.decorateWithContextInfo(
+ "break-after ignored on table-row because of row spanning "
+ + "in progress (See XSL 1.0, 7.19.1)", rowFO));
+ }
+ activeRowIndex++;
+ if (log.isDebugEnabled()) {
+ log.debug("===> new row: " + activeRowIndex);
+ }
+ initializeElementLists();
+ for (int i = 0; i < columnCount; i++) {
+ if (end[i] < 0) {
+ backupWidths[i] = 0;
+ }
+ }
+ rowFO = getActiveRow().getTableRow();
+ if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
+ log.warn(FONode.decorateWithContextInfo(
+ "break-before ignored on table-row because of row spanning "
+ + "in progress (See XSL 1.0, 7.19.2)", rowFO));
+ }
+ }
+ }
+ }
+
/** @return true if the table uses the separate border model. */
private boolean isSeparateBorderModel() {
return getTableLM().getTable().isSeparateBorderModel();
diff --git a/src/java/org/apache/fop/pdf/DestinationComparator.java b/src/java/org/apache/fop/pdf/DestinationComparator.java
new file mode 100644
index 000000000..87d6a00ff
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/DestinationComparator.java
@@ -0,0 +1,41 @@
+/*
+ * 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.pdf;
+
+import org.apache.fop.pdf.PDFDestination;
+
+/**
+ * Comparator class to enable comparing (and
+ * hence sorting) of PDFDestination objects.
+ */
+public class DestinationComparator implements java.util.Comparator {
+/* public int compare (PDFDestination dest1, PDFDestination dest2) {
+ return dest1.getIDRef().compareTo(dest2.getIDRef());
+ }*/
+
+ public int compare (Object obj1, Object obj2) {
+ if (obj1 instanceof PDFDestination && obj2 instanceof PDFDestination) {
+ PDFDestination dest1 = (PDFDestination)obj1;
+ PDFDestination dest2 = (PDFDestination)obj2;
+ return dest1.getIDRef().compareTo(dest2.getIDRef());
+ }
+ return 0;
+ }
+}
diff --git a/src/java/org/apache/fop/pdf/PDFDestination.java b/src/java/org/apache/fop/pdf/PDFDestination.java
new file mode 100644
index 000000000..97923e935
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFDestination.java
@@ -0,0 +1,138 @@
+/*
+ * 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.pdf;
+
+import org.apache.fop.area.DestinationData;
+import org.apache.fop.area.PageViewport;
+
+/**
+ * class representing a named destination
+ */
+public class PDFDestination extends PDFObject {
+
+ /**
+ * PDFReference (object reference) for this destination
+ */
+ private String goToReference;
+
+ /**
+ * ID Reference for this destination
+ */
+ private String idRef;
+
+ /**
+ * PageViewport to which the idRef item refers
+ */
+ private PageViewport pageViewport = null;
+
+ /**
+ * create a named destination
+ */
+ public PDFDestination(DestinationData destinationData) {
+ /* generic creation of PDF object */
+ super();
+ this.goToReference = destinationData.getGoToReference();
+ this.idRef = destinationData.getIDRef();
+ this.pageViewport = destinationData.getPageViewport();
+ }
+
+ /**
+ * @see org.apache.fop.pdf.PDFObject#toPDFString()
+ */
+ public String toPDFString() {
+ String s = getObjectID()
+ + "<<"
+ + "/Limits [(" + idRef + ") (" + idRef + ")]\n"
+ + "/Names [(" + idRef + ") " + goToReference + "]"
+ + "\n>>\nendobj\n";
+ return s;
+ }
+
+ /*
+ * example:
+ *
+ * 249 0 obj
+ * <<
+ * /Limits [(drivervariables) (drivervariables)]
+ * /Names [(drivervariables) 73 0 R]
+ * >>
+ * endobj
+ */
+
+ /**
+ * Sets the GoToReference in the associated DestinationData object.
+ *
+ * @param goToReference the reference to set in the associated DestinationData object.
+ */
+ public void setGoToReference(String goToReference) {
+ this.goToReference = goToReference;
+ }
+
+ /**
+ * Returns the GoToReference from the associated DestinationData object.
+ *
+ * @return the GoToReference from the associated DestinationData object.
+ */
+ public String getGoToReference() {
+ return this.goToReference;
+ }
+
+ /**
+ * Get the PageViewport object that this destination refers to
+ *
+ * @return the PageViewport that this destination points to
+ */
+ public PageViewport getPageViewport() {
+ return this.pageViewport;
+ }
+
+ /**
+ * Returns the RefID from the associated DestinationData object.
+ *
+ * @return the RefID from the associated DestinationData object.
+ */
+ public String getIDRef() {
+ return this.idRef;
+ }
+
+ /**
+ * Check if this equals another object.
+ *
+ * @param obj the object to compare
+ * @return true if this equals other object
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || !(obj instanceof PDFDestination)) {
+ return false;
+ }
+
+ PDFDestination dest = (PDFDestination)obj;
+ if (dest.getIDRef() == this.getIDRef()) {
+ return true;
+ }
+
+ return true;
+ }
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFDests.java b/src/java/org/apache/fop/pdf/PDFDests.java
new file mode 100644
index 000000000..96172c8e2
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFDests.java
@@ -0,0 +1,79 @@
+/*
+ * 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.pdf;
+
+import org.apache.fop.area.DestinationData;
+
+/**
+ * class representing an /Dests object (part of a name dictionary)
+ */
+public class PDFDests extends PDFObject {
+
+ private String limitsRef;
+
+ /**
+ * create a named destination
+ */
+ public PDFDests(String limitsRef) {
+ /* generic creation of PDF object */
+ super();
+ this.limitsRef = limitsRef;
+ }
+
+ /**
+ * @see org.apache.fop.pdf.PDFObject#toPDFString()
+ */
+ public String toPDFString() {
+ String s = getObjectID()
+ + "<<\n"
+ + "/Dests " + limitsRef
+ + "\n>>\nendobj\n";
+ return s;
+ }
+
+ /*
+ * example:
+ *
+ * 262 0 obj
+ * <<
+ * /Dests 260 0 R
+ * >>
+ * endobj
+ */
+
+ /**
+ * Check if this equals another object.
+ *
+ * @param obj the object to compare
+ * @return true if this equals other object
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || !(obj instanceof PDFDests)) {
+ return false;
+ }
+
+ return true;
+ }
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java
index 4ce82fab9..29cb88731 100644
--- a/src/java/org/apache/fop/pdf/PDFDocument.java
+++ b/src/java/org/apache/fop/pdf/PDFDocument.java
@@ -5,9 +5,9 @@
* 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.
@@ -19,7 +19,7 @@
package org.apache.fop.pdf;
-// Java
+/// Java
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -32,10 +32,14 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collections;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.pdf.DestinationComparator;
+
/* image support modified from work of BoBoGi */
/* font support based on work by Takayuki Takeuchi */
@@ -63,13 +67,13 @@ import org.apache.commons.logging.LogFactory;
public class PDFDocument {
private static final Integer LOCATION_PLACEHOLDER = new Integer(0);
-
+
/** Integer constant to represent PDF 1.3 */
public static final int PDF_VERSION_1_3 = 3;
/** Integer constant to represent PDF 1.4 */
public static final int PDF_VERSION_1_4 = 4;
-
+
/**
* the encoding to use when converting strings to PDF commandos.
*/
@@ -85,7 +89,7 @@ public class PDFDocument {
/**
* the character position of each object
*/
- protected List location = new java.util.ArrayList();
+ protected List location = new ArrayList();
/** List of objects to write in the trailer */
private List trailerObjects = new java.util.ArrayList();
@@ -107,12 +111,12 @@ public class PDFDocument {
/** Indicates what PDF version is active */
protected int pdfVersion = PDF_VERSION_1_4;
-
+
/**
* Indicates which PDF profiles are active (PDF/A, PDF/X etc.)
*/
protected PDFProfile pdfProfile = new PDFProfile(this);
-
+
/**
* the /Root object
*/
@@ -202,6 +206,11 @@ public class PDFDocument {
protected List links = new java.util.ArrayList();
/**
+ * List of Destinations.
+ */
+ protected List destinations = new java.util.ArrayList();
+
+ /**
* List of FileSpecs.
*/
protected List filespecs = new java.util.ArrayList();
@@ -216,6 +225,25 @@ public class PDFDocument {
*/
protected List gotos = new java.util.ArrayList();
+ /**
+ * The PDFDests object for the name dictionary.
+ * Note: This object is not a list.
+ */
+ private PDFDests dests;
+
+ /**
+ * The PDFLimits object for the name dictionary.
+ * Note: This object is not a list.
+ */
+ private PDFLimits limits;
+
+ /**
+ * Whether this PDFDocument has named destinations
+ * (and thus needs PDFDestinations, PDFLimits, and
+ * PDFDests)
+ */
+ private boolean hasDestinations = false;
+
private PDFFactory factory;
private boolean encodingOnTheFly = true;
@@ -255,7 +283,7 @@ public class PDFDocument {
public int getPDFVersion() {
return this.pdfVersion;
}
-
+
/** @return the String representing the active PDF version */
public String getPDFVersionString() {
switch (getPDFVersion()) {
@@ -272,7 +300,7 @@ public class PDFDocument {
public PDFProfile getProfile() {
return this.pdfProfile;
}
-
+
/**
* Returns the factory for PDF objects.
* @return PDFFactory the factory
@@ -315,7 +343,7 @@ public class PDFDocument {
/**
* Set the creation date of the document.
- *
+ *
* @param date Date to be stored as creation date in the PDF.
*/
public void setCreationDate(Date date) {
@@ -460,6 +488,9 @@ public class PDFDocument {
if (obj instanceof PDFLink) {
this.links.add(obj);
}
+ if (obj instanceof PDFDestination) {
+ this.destinations.add(obj);
+ }
if (obj instanceof PDFFileSpec) {
this.filespecs.add(obj);
}
@@ -578,6 +609,15 @@ public class PDFDocument {
}
/**
+ * Finds a named destination.
+ * @param compare reference object to use as search template
+ * @return the link if found, null otherwise
+ */
+ protected PDFDestination findDestination(PDFDestination compare) {
+ return (PDFDestination)findPDFObject(destinations, compare);
+ }
+
+ /**
* Finds a link.
* @param compare reference object to use as search template
* @return the link if found, null otherwise
@@ -702,6 +742,51 @@ public class PDFDocument {
}
/**
+ * Gets the PDFDests object (which represents the /Dests entry).
+ *
+ * @return the PDFDests object (which represents the /Dests entry).
+ */
+ public PDFDests getDests() {
+ return dests;
+ }
+
+ /**
+ * Gets the list of named destinations.
+ *
+ * @return the list of named destinations.
+ */
+ public ArrayList getDestinationList() {
+ return (ArrayList)destinations;
+ }
+
+ /**
+ * Sets whether the document has named destinations.
+ *
+ * @param hasDestinations whether the document has named destinations.
+ */
+ public void setHasDestinations(boolean hasDestinations) {
+ this.hasDestinations = hasDestinations;
+ }
+
+ /**
+ * Gets whether the document has named destinations.
+ *
+ * @return whether the document has named destinations.
+ */
+ public boolean getHasDestinations() {
+ return this.hasDestinations;
+ }
+
+ /**
+ * Gets the PDFLimits object (part of the name dictionary).
+ *
+ * @return the PDFLimits object (part of the name dictionary).
+ */
+ public PDFLimits getLimits() {
+ return limits;
+ }
+
+ /**
* Add an image to the PDF document.
* This adds an image to the PDF objects.
* If an image with the same key already exists it will return the
@@ -848,7 +933,7 @@ public class PDFDocument {
this.position = 0;
getProfile().verifyPDFVersion();
-
+
byte[] pdf = ("%PDF-" + getPDFVersionString() + "\n").getBytes();
stream.write(pdf);
this.position += pdf.length;
@@ -885,7 +970,7 @@ public class PDFDocument {
}
}
}
-
+
/**
* write the trailer
*
@@ -893,6 +978,12 @@ public class PDFDocument {
* @throws IOException if there is an exception writing to the output stream
*/
public void outputTrailer(OutputStream stream) throws IOException {
+ if (hasDestinations) {
+ Collections.sort((ArrayList)destinations, new DestinationComparator());
+ limits = getFactory().makeLimits((ArrayList)destinations);
+ dests = getFactory().makeDests(limits.referencePDF());
+ this.root.setNames(dests.referencePDF());
+ }
output(stream);
for (int count = 0; count < trailerObjects.size(); count++) {
PDFObject o = (PDFObject)trailerObjects.get(count);
@@ -970,4 +1061,4 @@ public class PDFDocument {
return pdfBytes.length;
}
-}
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java
index 4ab6ebd7b..3005f2018 100644
--- a/src/java/org/apache/fop/pdf/PDFFactory.java
+++ b/src/java/org/apache/fop/pdf/PDFFactory.java
@@ -5,9 +5,9 @@
* 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.
@@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
+import java.util.ArrayList;
// Apache libs
import org.apache.commons.io.IOUtils;
@@ -52,6 +53,8 @@ import org.apache.fop.fonts.truetype.TTFSubSetFile;
import org.apache.fop.fonts.type1.PFBData;
import org.apache.fop.fonts.type1.PFBParser;
import org.apache.xmlgraphics.xmp.Metadata;
+import org.apache.fop.area.PageViewport;
+import org.apache.fop.area.DestinationData;
/**
* This class provides method to create and register PDF objects.
@@ -731,7 +734,7 @@ public class PDFFactory {
PDFPattern myPattern;
//PDFColorSpace theColorSpace;
double interpolation = (double)1.000;
- List theFunctions = new java.util.ArrayList();
+ List theFunctions = new ArrayList();
int currentPosition;
int lastPosition = theColors.size() - 1;
@@ -782,7 +785,7 @@ public class PDFFactory {
} else { // if the center x, center y, and radius specifiy
// the gradient, then assume the same center x, center y,
// and radius of zero for the other necessary component
- List newCoords = new java.util.ArrayList();
+ List newCoords = new ArrayList();
newCoords.add(theCoords.get(0));
newCoords.add(theCoords.get(1));
newCoords.add(theCoords.get(2));
@@ -809,6 +812,56 @@ public class PDFFactory {
return (myPattern);
}
+ /* ============= named destinations and the name dictionary ============ */
+
+ /**
+ * Make a named destination.
+ *
+ * @param destinationData the DestinationData object that holds the info about this named destination
+ * @return the new PDF named destination object
+ */
+ public PDFDestination makeDestination(DestinationData destinationData) {
+ PageViewport pv = destinationData.getPageViewport();
+ if (pv == null) {
+ log.warn("Unresolved destination item received: " + destinationData.getIDRef());
+ }
+ PDFDestination destination = new PDFDestination(destinationData);
+
+ PDFDestination oldDestination = getDocument().findDestination(destination);
+ if (destination == oldDestination) {
+ destination = oldDestination;
+ } else {
+ getDocument().registerObject(destination);
+ getDocument().setHasDestinations(true);
+ }
+
+ return destination;
+ }
+
+ /**
+ * Make a the head object of the name dictionary (the /Dests object).
+ *
+ * @return the new PDFDests object
+ */
+ public PDFDests makeDests(String limitsRef) {
+ PDFDests dests = new PDFDests(limitsRef);
+ getDocument().registerObject(dests);
+
+ return dests;
+ }
+
+ /**
+ * Make a the limits object of the name dictionary (the /Limits object).
+ *
+ * @return the new PDFLimits object
+ */
+ public PDFLimits makeLimits(ArrayList destinationList) {
+ PDFLimits limits = new PDFLimits(destinationList);
+ getDocument().registerObject(limits);
+
+ return limits;
+ }
+
/* ========================= links ===================================== */
/**
@@ -888,7 +941,7 @@ public class PDFFactory {
return link;
}
- private String getGoToReference(String destination, float yoffset) {
+ public String getGoToReference(String destination, float yoffset) {
getDocument().getProfile().verifyActionAllowed();
String goToReference = null;
PDFGoTo gt = new PDFGoTo(destination);
@@ -1153,9 +1206,9 @@ public class PDFFactory {
int value = 0;
for (int i = 0, c = cidSubset.length(); i < c; i++) {
int shift = i % 8;
- boolean b = cidSubset.get(i);
+ boolean b = cidSubset.get(i);
if (b) {
- value |= 1 << 7 - shift;
+ value |= 1 << 7 - shift;
}
if (shift == 7) {
baout.write(value);
@@ -1335,7 +1388,7 @@ public class PDFFactory {
public PDFICCBasedColorSpace makeICCBasedColorSpace(PDFResourceContext res,
String explicitName, PDFICCStream iccStream) {
PDFICCBasedColorSpace cs = new PDFICCBasedColorSpace(explicitName, iccStream);
-
+
getDocument().registerObject(cs);
if (res != null) {
@@ -1343,7 +1396,7 @@ public class PDFFactory {
} else {
getDocument().getResources().addColorSpace(cs);
}
-
+
return cs;
}
diff --git a/src/java/org/apache/fop/pdf/PDFLimits.java b/src/java/org/apache/fop/pdf/PDFLimits.java
new file mode 100644
index 000000000..97c097463
--- /dev/null
+++ b/src/java/org/apache/fop/pdf/PDFLimits.java
@@ -0,0 +1,93 @@
+/*
+ * 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.pdf;
+
+import java.util.ArrayList;
+
+import org.apache.fop.pdf.PDFDestination;
+
+/**
+ * class representing a Limits object (part of the names dictionary for named destinations)
+ */
+public class PDFLimits extends PDFObject {
+
+ private ArrayList destinationList;
+
+ /**
+ * create a named destination
+ */
+ public PDFLimits(ArrayList destinationList) {
+ /* generic creation of PDF object */
+ super();
+ this.destinationList = destinationList;
+ }
+
+ /**
+ * @see org.apache.fop.pdf.PDFObject#toPDFString()
+ */
+ public String toPDFString() {
+ String[] idRefs = new String[destinationList.size()];
+ String kidsString = "";
+ for (int i = 0; i < destinationList.size(); i++) {
+ PDFDestination dest = (PDFDestination)destinationList.get(i);
+ idRefs[i] = dest.getIDRef();
+ kidsString += dest.referencePDF();
+ if (!(i == destinationList.size() - 1)) {
+ kidsString += " ";
+ }
+ }
+ String s = getObjectID()
+ + "<<\n"
+ + "/Limits [(" + idRefs[0] + ") (" + idRefs[destinationList.size() - 1] + ")]\n"
+ + "/Kids [" + kidsString + "]"
+ + "\n>>\nendobj\n";
+ return s;
+ }
+
+ /*
+ * example:
+ *
+ * 260 0 obj
+ * <<
+ * /Limits [(Annotate) (thumbnails)]
+ * /Kids [248 0 R 253 0 R 254 0 R 259 0 R]
+ * >>
+ * endobj
+ */
+
+ /**
+ * Check if this equals another object.
+ *
+ * @param obj the object to compare
+ * @return true if this equals other object
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null || !(obj instanceof PDFLimits)) {
+ return false;
+ }
+
+ return true;
+ }
+}
+
diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java
index ffe9611ba..60fe6b390 100644
--- a/src/java/org/apache/fop/pdf/PDFRoot.java
+++ b/src/java/org/apache/fop/pdf/PDFRoot.java
@@ -20,6 +20,7 @@
package org.apache.fop.pdf;
import java.util.List;
+import java.util.ArrayList;
/**
* class representing a Root (/Catalog) object
@@ -62,6 +63,12 @@ public class PDFRoot extends PDFObject {
/** The array of OutputIntents */
private List outputIntents;
+ /**
+ * The referencePDF value of the /Dests object,
+ * if this PDF has a Name Dictionary
+ */
+ private String namesReferencePDF = null;
+
private int pageMode = PAGEMODE_USENONE;
/**
@@ -130,6 +137,15 @@ public class PDFRoot extends PDFObject {
* @param meta the Metadata object
* @since PDF 1.4
*/
+ public void setNames(String referencePDF) {
+ this.namesReferencePDF = referencePDF;
+ }
+
+ /**
+ * Set the optional Metadata object.
+ * @param meta the Metadata object
+ * @since PDF 1.4
+ */
public void setMetadata(PDFMetadata meta) {
this.metadata = meta;
}
@@ -181,6 +197,9 @@ public class PDFRoot extends PDFObject {
break;
}
}
+ if (getDocumentSafely().getHasDestinations() && namesReferencePDF != null) {
+ p.append(" /Names " + namesReferencePDF + "\n");
+ }
if (getMetadata() != null
&& getDocumentSafely().getPDFVersion() >= PDFDocument.PDF_VERSION_1_4) {
p.append("/Metadata " + getMetadata().referencePDF() + "\n");
diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
index 481ce844c..f64fa75aa 100644
--- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java
@@ -73,6 +73,7 @@ import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.pdf.PDFColor;
import org.apache.fop.pdf.PDFConformanceException;
+import org.apache.fop.pdf.PDFDestination;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
@@ -105,6 +106,8 @@ import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
+import org.apache.fop.area.DestinationData;
+
/**
* Renderer that renders areas to PDF.
*/
@@ -509,8 +512,19 @@ public class PDFRenderer extends AbstractPathOrientedRenderer {
* @see org.apache.fop.render.Renderer#processOffDocumentItem(OffDocumentItem)
*/
public void processOffDocumentItem(OffDocumentItem odi) {
+ // render Destinations
+ if (odi instanceof DestinationData) {
+ PDFDestination destination = pdfDoc.getFactory().makeDestination((DestinationData) odi);
+ PageViewport pv = destination.getPageViewport();
+ String dest = (String)pageReferences.get(pv.getKey());
+ Rectangle2D bounds = pv.getViewArea();
+ double h = bounds.getHeight();
+ float yoffset = (float)h / 1000f;
+ String gtRef = pdfDoc.getFactory().getGoToReference(dest, yoffset);
+ destination.setGoToReference(gtRef);
+ }
// render Bookmark-Tree
- if (odi instanceof BookmarkData) {
+ else if (odi instanceof BookmarkData) {
renderBookmarkTree((BookmarkData) odi);
} else if (odi instanceof OffDocumentExtensionAttachment) {
ExtensionAttachment attachment = ((OffDocumentExtensionAttachment)odi).getAttachment();
diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java
index 24595368f..68c6cc86c 100644
--- a/src/java/org/apache/fop/render/ps/PSRenderer.java
+++ b/src/java/org/apache/fop/render/ps/PSRenderer.java
@@ -953,15 +953,22 @@ public class PSRenderer extends AbstractPathOrientedRenderer implements ImageAda
}
if (rotate) {
+ gen.writeln("<<");
+ gen.writeln("/PageSize ["
+ + Math.round(pspageheight) + " "
+ + Math.round(pspagewidth) + "]");
+ gen.writeln("/ImagingBBox null");
+ gen.writeln(">> setpagedevice");
gen.writeln(Math.round(pspageheight) + " 0 translate");
gen.writeln("90 rotate");
+ } else {
+ gen.writeln("<<");
+ gen.writeln("/PageSize ["
+ + Math.round(pspagewidth) + " "
+ + Math.round(pspageheight) + "]");
+ gen.writeln("/ImagingBBox null");
+ gen.writeln(">> setpagedevice");
}
- gen.writeln("<<");
- gen.writeln("/PageSize ["
- + Math.round(pspagewidth) + " "
- + Math.round(pspageheight) + "]");
- gen.writeln("/ImagingBBox null");
- gen.writeln(">> setpagedevice");
concatMatrix(1, 0, 0, -1, 0, pageheight / 1000f);
gen.writeDSCComment(DSCConstants.END_PAGE_SETUP);