Selaa lähdekoodia

Rework of the marker/retrieve-marker implementation to cater for correct evaluation of percentages and relative font-sizes, as well as more correct white-space handling.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@429168 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_93
Andreas L. Delmelle 18 vuotta sitten
vanhempi
commit
728532622a
31 muutettua tiedostoa jossa 1472 lisäystä ja 1984 poistoa
  1. 33
    10
      src/java/org/apache/fop/fo/FOEventHandler.java
  2. 35
    2
      src/java/org/apache/fop/fo/FONode.java
  3. 14
    10
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  4. 23
    22
      src/java/org/apache/fop/fo/FOText.java
  5. 51
    24
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  6. 32
    9
      src/java/org/apache/fop/fo/FObj.java
  7. 54
    13
      src/java/org/apache/fop/fo/FObjMixed.java
  8. 103
    52
      src/java/org/apache/fop/fo/PropertyList.java
  9. 0
    1192
      src/java/org/apache/fop/fo/PropertySets.java
  10. 1
    1
      src/java/org/apache/fop/fo/StaticPropertyList.java
  11. 41
    8
      src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
  12. 1
    1
      src/java/org/apache/fop/fo/expr/FromTableColumnFunction.java
  13. 43
    14
      src/java/org/apache/fop/fo/flow/Block.java
  14. 250
    39
      src/java/org/apache/fop/fo/flow/Marker.java
  15. 89
    103
      src/java/org/apache/fop/fo/flow/RetrieveMarker.java
  16. 32
    11
      src/java/org/apache/fop/fo/flow/Table.java
  17. 78
    51
      src/java/org/apache/fop/fo/flow/TableBody.java
  18. 11
    115
      src/java/org/apache/fop/fo/flow/TableCell.java
  19. 1
    11
      src/java/org/apache/fop/fo/flow/TableColumn.java
  20. 208
    9
      src/java/org/apache/fop/fo/flow/TableFObj.java
  21. 0
    1
      src/java/org/apache/fop/fo/flow/TableFooter.java
  22. 0
    1
      src/java/org/apache/fop/fo/flow/TableHeader.java
  23. 24
    31
      src/java/org/apache/fop/fo/flow/TableRow.java
  24. 0
    112
      src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java
  25. 123
    117
      src/java/org/apache/fop/fo/properties/FontShorthandProperty.java
  26. 5
    0
      status.xml
  27. 98
    0
      test/fotree/testcases/table-cell_column-number_rowspan_bug38397.fo
  28. 2
    15
      test/layoutengine/disabled-testcases.xml
  29. 7
    4
      test/layoutengine/standard-testcases/marker_font-size.xml
  30. 106
    0
      test/layoutengine/standard-testcases/marker_percentage-resolution.xml
  31. 7
    6
      test/layoutengine/standard-testcases/marker_white-space-collapse.xml

+ 33
- 10
src/java/org/apache/fop/fo/FOEventHandler.java Näytä tiedosto

@@ -40,9 +40,9 @@ import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.PageNumber;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.fo.flow.TableBody;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.fo.flow.TableRow;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.PageSequence;
@@ -78,7 +78,7 @@ public abstract class FOEventHandler {
*/
private Set idReferences = new HashSet();

/*
/**
* The property list maker.
*/
protected PropertyListMaker propertyListMaker;
@@ -88,6 +88,11 @@ public abstract class FOEventHandler {
*/
protected XMLWhiteSpaceHandler whiteSpaceHandler = new XMLWhiteSpaceHandler();
/**
* Indicates whether processing descendants of a marker
*/
private boolean inMarker = false;
/**
* Main constructor
* @param foUserAgent the apps.FOUserAgent instance for this process
@@ -143,6 +148,23 @@ public abstract class FOEventHandler {
return whiteSpaceHandler;
}

/**
* Switch to or from marker context
* (used by FOTreeBuilder when processing
* a marker)
*
*/
protected void switchMarkerContext(boolean inMarker) {
this.inMarker = inMarker;
}
/**
* Check whether in marker context
*/
protected boolean inMarker() {
return this.inMarker;
}
/**
* This method is called to indicate the start of a new document run.
* @throws SAXException In case of a problem
@@ -185,9 +207,10 @@ public abstract class FOEventHandler {
}

/**
* This method is called to indicate the start of a new fo:flow or fo:static-content.
* This method also handles fo:static-content tags, because the StaticContent class
* is derived from the Flow class.
* This method is called to indicate the start of a new fo:flow
* or fo:static-content.
* This method also handles fo:static-content tags, because the
* StaticContent class is derived from the Flow class.
*
* @param fl Flow that is starting.
*/
@@ -219,15 +242,15 @@ public abstract class FOEventHandler {
*
* @param blc BlockContainer that is starting.
*/
public void startBlockContainer(BlockContainer blc) {
}
public void startBlockContainer(BlockContainer blc) {
}

/**
/**
*
* @param blc BlockContainer that is ending.
*/
public void endBlockContainer(BlockContainer blc) {
}
public void endBlockContainer(BlockContainer blc) {
}

/**
*

+ 35
- 2
src/java/org/apache/fop/fo/FONode.java Näytä tiedosto

@@ -81,7 +81,6 @@ public abstract class FONode implements Cloneable {
throws FOPException {
FONode foNode = (FONode) clone();
foNode.parent = cloneparent;
cloneparent.addChildNode(foNode);
return foNode;
}

@@ -124,6 +123,10 @@ public abstract class FONode implements Cloneable {
public FOEventHandler getFOEventHandler() {
return parent.getFOEventHandler();
}
protected boolean inMarker() {
return getFOEventHandler().inMarker();
}

/**
* Returns the user agent for the node.
@@ -257,7 +260,7 @@ public abstract class FONode implements Cloneable {

/**
* Return an iterator over the object's child nodes starting
* at the pased node.
* at the passed node.
* @param childNode First node in the iterator
* @return A ListIterator or null if child node isn't a child of
* this FObj.
@@ -580,5 +583,35 @@ public abstract class FONode implements Cloneable {
return null;
}
/**
* @return true if markers are valid children
*/
protected boolean canHaveMarkers() {
int foId = getNameId();
switch (foId) {
case Constants.FO_BASIC_LINK:
case Constants.FO_BIDI_OVERRIDE:
case Constants.FO_BLOCK:
case Constants.FO_BLOCK_CONTAINER:
case Constants.FO_FLOW:
case Constants.FO_INLINE:
case Constants.FO_INLINE_CONTAINER:
case Constants.FO_LIST_BLOCK:
case Constants.FO_LIST_ITEM:
case Constants.FO_LIST_ITEM_BODY:
case Constants.FO_LIST_ITEM_LABEL:
case Constants.FO_TABLE:
case Constants.FO_TABLE_BODY:
case Constants.FO_TABLE_HEADER:
case Constants.FO_TABLE_FOOTER:
case Constants.FO_TABLE_CELL:
case Constants.FO_TABLE_AND_CAPTION:
case Constants.FO_TABLE_CAPTION:
case Constants.FO_WRAPPER:
return true;
default:
return false;
}
}
}


+ 14
- 10
src/java/org/apache/fop/fo/FOPropertyMapping.java Näytä tiedosto

@@ -30,7 +30,7 @@ import org.apache.fop.fo.properties.BorderWidthPropertyMaker;
import org.apache.fop.fo.properties.BoxPropShorthandParser;
import org.apache.fop.fo.properties.CharacterProperty;
import org.apache.fop.fo.properties.ColorProperty;
import org.apache.fop.fo.properties.ColumnNumberPropertyMaker;
import org.apache.fop.fo.flow.TableFObj.ColumnNumberPropertyMaker;
import org.apache.fop.fo.properties.CondLengthProperty;
import org.apache.fop.fo.properties.CorrespondingPropertyMaker;
import org.apache.fop.fo.properties.DimensionPropertyMaker;
@@ -326,11 +326,13 @@ public final class FOPropertyMapping implements Constants {
* @return a propId that matches the property name.
*/
public static int getPropertyId(String name) {
Integer i = (Integer) s_htPropNames.get(name);
if (i == null) {
return -1;
if (name != null) {
Integer i = (Integer) s_htPropNames.get(name);
if (i != null) {
return i.intValue();
}
}
return i.intValue();
return -1;
}

/**
@@ -339,11 +341,13 @@ public final class FOPropertyMapping implements Constants {
* @return a subpropId that matches the subproperty name.
*/
public static int getSubPropertyId(String name) {
Integer i = (Integer) s_htSubPropNames.get(name);
if (i == null) {
return -1;
if (name != null) {
Integer i = (Integer) s_htSubPropNames.get(name);
if (i != null) {
return i.intValue();
}
}
return i.intValue();
return -1;
}

// returns a property, compound, or property.compound name
@@ -2263,8 +2267,8 @@ public final class FOPropertyMapping implements Constants {

sub = new LengthProperty.Maker(CP_INLINE_PROGRESSION_DIRECTION);
sub.setDefault("0pt");
m.addSubpropMaker(sub);
sub.setByShorthand(true);
m.addSubpropMaker(sub);
addPropertyMaker("border-separation", m);

// border-start-precedence

+ 23
- 22
src/java/org/apache/fop/fo/FOText.java Näytä tiedosto

@@ -150,6 +150,23 @@ public class FOText extends FONode {
this.ca = nca;
}

/**
* @see org.apache.fop.fo.FONode#clone(FONode, boolean)
*/
public FONode clone(FONode parent, boolean removeChildren)
throws FOPException {
FOText ft = (FOText) super.clone(parent, removeChildren);
if (removeChildren) {
//not really removing, but just make sure the char array
//pointed to is really a different one
if (ca != null) {
ft.ca = new char[ca.length];
System.arraycopy(ca, 0, ft.ca, 0, ca.length);
}
}
return ft;
}

/**
* @see org.apache.fop.fo.FObj#bind(PropertyList)
*/
@@ -171,8 +188,8 @@ public class FOText extends FONode {

/** @see org.apache.fop.fo.FONode#endOfNode() */
protected void endOfNode() throws FOPException {
createBlockPointers();
textTransform();
getFOEventHandler().characters(ca, startIndex, endIndex);
}

/**
@@ -210,28 +227,11 @@ public class FOText extends FONode {
}

/**
* This method is run as part of the Constructor, to create xref pointers to
* This method is run as part of the ancestor Block's flushText(), to create xref pointers to
* the previous FOText objects within the same Block
*/
private void createBlockPointers() {
// build pointers between the FOText objects withing the same Block
//
// find the ancestorBlock of the current node
FONode ancestorFONode = this;
while (this.ancestorBlock == null) {
ancestorFONode = ancestorFONode.parent;
if (ancestorFONode instanceof org.apache.fop.fo.pagination.Title) {
return;
} else if (ancestorFONode instanceof org.apache.fop.fo.flow.Marker) {
return;
} else if (ancestorFONode instanceof Root) {
getLogger().warn("Unexpected: fo:text with no fo:block ancestor. The text is: "
+ new String(ca));
return;
} else if (ancestorFONode instanceof Block) {
this.ancestorBlock = (Block)ancestorFONode;
}
}
protected void createBlockPointers(Block ancestorBlock) {
this.ancestorBlock = ancestorBlock;
// if the last FOText is a sibling, point to it, and have it point here
if (lastFOTextProcessed != null) {
if (lastFOTextProcessed.ancestorBlock == this.ancestorBlock) {
@@ -252,7 +252,8 @@ public class FOText extends FONode {
* text-transform property.
*/
private void textTransform() {
if (textTransform == Constants.EN_NONE) {
if (getFOEventHandler().inMarker()
|| textTransform == Constants.EN_NONE) {
return;
}
for (int i = 0; i < endIndex; i++) {

+ 51
- 24
src/java/org/apache/fop/fo/FOTreeBuilder.java Näytä tiedosto

@@ -246,7 +246,7 @@ public class FOTreeBuilder extends DefaultHandler {
*/
public FormattingResults getResults() {
if (getEventHandler() instanceof AreaTreeHandler) {
return ((AreaTreeHandler)getEventHandler()).getResults();
return ((AreaTreeHandler) getEventHandler()).getResults();
} else {
//No formatting results available for output formats no
//involving the layout engine.
@@ -268,6 +268,11 @@ public class FOTreeBuilder extends DefaultHandler {
* Current propertyList for the node being handled.
*/
protected PropertyList currentPropertyList;
/**
* Current marker nesting-depth
*/
private int nestedMarkerDepth = 0;

/**
* SAX Handler for the start of an element
@@ -278,16 +283,17 @@ public class FOTreeBuilder extends DefaultHandler {

/* the node found in the FO document */
FONode foNode;
PropertyList propertyList;
PropertyList propertyList = null;

// Check to ensure first node encountered is an fo:root
if (rootFObj == null) {
if (!namespaceURI.equals(FOElementMapping.URI)
|| !localName.equals("root")) {
throw new SAXException(new ValidationException(
"Error: First element must be the fo:root formatting object. Found "
+ FONode.getNodeString(namespaceURI, localName) + " instead."
+ " Please make sure you're producing a valid XSL-FO document."));
throw new ValidationException(
"Error: First element must be the fo:root formatting object. "
+ "Found " + FONode.getNodeString(namespaceURI, localName)
+ " instead."
+ " 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)) {
@@ -301,7 +307,8 @@ public class FOTreeBuilder extends DefaultHandler {
}
}
ElementMapping.Maker fobjMaker = findFOMaker(namespaceURI, localName);
ElementMapping.Maker fobjMaker =
findFOMaker(namespaceURI, localName);

try {
foNode = fobjMaker.make(currentFObj);
@@ -309,8 +316,17 @@ public class FOTreeBuilder extends DefaultHandler {
rootFObj = (Root) foNode;
rootFObj.setFOEventHandler(foEventHandler);
}
propertyList = foNode.createPropertyList(currentPropertyList, foEventHandler);
foNode.processNode(localName, getEffectiveLocator(), attlist, propertyList);
propertyList = foNode.createPropertyList(
currentPropertyList, foEventHandler);
foNode.processNode(localName, getEffectiveLocator(),
attlist, propertyList);
if (foNode.getNameId() == Constants.FO_MARKER) {
if (foEventHandler.inMarker()) {
nestedMarkerDepth++;
} else {
foEventHandler.switchMarkerContext(true);
}
}
foNode.startOfNode();
} catch (IllegalArgumentException e) {
throw new SAXException(e);
@@ -321,11 +337,13 @@ public class FOTreeBuilder extends DefaultHandler {
ContentHandler subHandler = chFactory.createContentHandler();
if (subHandler instanceof ObjectSource
&& foNode instanceof ObjectBuiltListener) {
((ObjectSource)subHandler).setObjectBuiltListener((ObjectBuiltListener)foNode);
((ObjectSource) subHandler).setObjectBuiltListener(
(ObjectBuiltListener) foNode);
}
subHandler.startDocument();
subHandler.startElement(namespaceURI, localName, rawName, attlist);
subHandler.startElement(namespaceURI, localName,
rawName, attlist);
depth = 1;
delegate = subHandler;
}
@@ -335,7 +353,7 @@ public class FOTreeBuilder extends DefaultHandler {
}

currentFObj = foNode;
if (propertyList != null) {
if (propertyList != null && !foEventHandler.inMarker()) {
currentPropertyList = propertyList;
}
}
@@ -356,11 +374,24 @@ public class FOTreeBuilder extends DefaultHandler {
+ " (" + currentFObj.getNamespaceURI()
+ ") vs. " + localName + " (" + uri + ")");
}
currentFObj.endOfNode();

if (currentPropertyList.getFObj() == currentFObj) {
currentPropertyList = currentPropertyList.getParentPropertyList();
if (currentPropertyList != null
&& currentPropertyList.getFObj() == currentFObj
&& !foEventHandler.inMarker()) {
currentPropertyList =
currentPropertyList.getParentPropertyList();
}
if (currentFObj.getNameId() == Constants.FO_MARKER) {
if (nestedMarkerDepth == 0) {
foEventHandler.switchMarkerContext(false);
} else {
nestedMarkerDepth--;
}
}
if (currentFObj.getParent() == null) {
log.debug("endElement for top-level " + currentFObj.getName());
}
@@ -373,19 +404,15 @@ public class FOTreeBuilder extends DefaultHandler {
*/
public void characters(char[] data, int start, int length)
throws FOPException {
if (currentFObj != null) {
currentFObj.addCharacters(data, start, start + length,
currentPropertyList, getEffectiveLocator());
}
if (currentFObj != null) {
currentFObj.addCharacters(data, start, start + length,
currentPropertyList, getEffectiveLocator());
}
}

public void endDocument() throws SAXException {
currentFObj = null;
}

}
}
}


+ 32
- 9
src/java/org/apache/fop/fo/FObj.java Näytä tiedosto

@@ -20,7 +20,6 @@
package org.apache.fop.fo;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -119,11 +118,15 @@ public abstract class FObj extends FONode implements Constants {
* @see org.apache.fop.fo.FONode#processNode
*/
public void processNode(String elementName, Locator locator,
Attributes attlist, PropertyList pList) throws FOPException {
Attributes attlist, PropertyList pList)
throws FOPException {
setLocator(locator);
pList.addAttributesToList(attlist);
pList.setWritingMode();
bind(pList);
if (!inMarker()
|| "marker".equals(elementName)) {
pList.setWritingMode();
bind(pList);
}
}

/**
@@ -154,7 +157,7 @@ public abstract class FObj extends FONode implements Constants {
* @throws ValidationException if the ID is already defined elsewhere
*/
protected void checkId(String id) throws ValidationException {
if (!id.equals("")) {
if (!inMarker() && !id.equals("")) {
Set idrefs = getFOEventHandler().getIDReferences();
if (!idrefs.contains(id)) {
idrefs.add(id);
@@ -178,13 +181,15 @@ public abstract class FObj extends FONode implements Constants {
* @see org.apache.fop.fo.FONode#addChildNode(FONode)
*/
protected void addChildNode(FONode child) throws FOPException {
if (PropertySets.canHaveMarkers(getNameId()) && child.getNameId() == FO_MARKER) {
addMarker((Marker)child);
if (canHaveMarkers() && child.getNameId() == FO_MARKER) {
addMarker((Marker) child);
} else {
ExtensionAttachment attachment = child.getExtensionAttachment();
if (attachment != null) {
//This removes the element from the normal children, so no layout manager
//is being created for them as they are only additional information.
/* This removes the element from the normal children,
* so no layout manager is being created for them
* as they are only additional information.
*/
addExtensionAttachment(attachment);
} else {
if (childNodes == null) {
@@ -195,6 +200,10 @@ public abstract class FObj extends FONode implements Constants {
}
}

protected static void addChildTo(FONode child, FObj parent) throws FOPException {
parent.addChildNode(child);
}
/** @see org.apache.fop.fo.FONode#removeChild(org.apache.fop.fo.FONode) */
public void removeChild(FONode child) {
if (childNodes != null) {
@@ -250,6 +259,20 @@ public abstract class FObj extends FONode implements Constants {
return null;
}

/**
* Return a FONode based on the index in the list of childNodes.
* @param nodeIndex index of the node to return
* @return the node or null if the index is invalid
*/
public FONode getChildNodeAt(int nodeIndex) {
if (childNodes != null) {
if (nodeIndex >= 0 && nodeIndex < childNodes.size()) {
return (FONode) childNodes.get(nodeIndex);
}
}
return null;
}

/**
* Notifies a FObj that one of it's children is removed.
* This method is subclassed by Block to clear the firstInlineChild variable.

+ 54
- 13
src/java/org/apache/fop/fo/FObjMixed.java Näytä tiedosto

@@ -42,7 +42,7 @@ public abstract class FObjMixed extends FObj {
protected FObjMixed(FONode parent) {
super(parent);
}
/** @see org.apache.fop.fo.FONode */
protected void addCharacters(char[] data, int start, int end,
PropertyList pList,
@@ -50,7 +50,9 @@ public abstract class FObjMixed extends FObj {
if (ft == null) {
ft = new FOText(this);
ft.setLocator(locator);
ft.bind(pList);
if (!inMarker()) {
ft.bind(pList);
}
}
ft.addCharacters(data, start, end, null, null);
}
@@ -58,11 +60,26 @@ public abstract class FObjMixed extends FObj {
/** @see org.apache.fop.fo.FONode#endOfNode() */
protected void endOfNode() throws FOPException {
flushText();
getFOEventHandler().whiteSpaceHandler
.handleWhiteSpace(this, currentTextNode);
if (!inMarker()
|| getNameId() == FO_MARKER) {
getFOEventHandler().whiteSpaceHandler
.handleWhiteSpace(this, currentTextNode);
}
super.endOfNode();
}

/**
* Handles white-space for the node that is passed in,
* starting at its current text-node
* (used by RetrieveMarker to trigger 'end-of-node' white-space
* handling)
* @param fobj the node for which to handle white-space
*/
protected static void handleWhiteSpaceFor(FObjMixed fobj) {
fobj.getFOEventHandler().getXMLWhiteSpaceHandler()
.handleWhiteSpace(fobj, fobj.currentTextNode);
}
/**
* Adds accumulated text as one FOText instance.
* Makes sure that nested calls to itself do nothing.
@@ -72,8 +89,29 @@ public abstract class FObjMixed extends FObj {
if (ft != null) {
FOText lft = ft;
ft = null;
if (getNameId() == FO_BLOCK) {
lft.createBlockPointers((org.apache.fop.fo.flow.Block) this);
} else if (getNameId() != FO_MARKER
&& getNameId() != FO_TITLE
&& getNameId() != FO_BOOKMARK_TITLE) {
FONode fo = parent;
int foNameId = fo.getNameId();
while (foNameId != FO_BLOCK
&& foNameId != FO_MARKER
&& foNameId != FO_TITLE
&& foNameId != FO_BOOKMARK_TITLE
&& foNameId != FO_PAGE_SEQUENCE) {
fo = fo.getParent();
foNameId = fo.getNameId();
}
if (foNameId == FO_BLOCK) {
lft.createBlockPointers((org.apache.fop.fo.flow.Block) fo);
} else if (foNameId == FO_PAGE_SEQUENCE) {
log.error("Could not create block pointers."
+ " FOText w/o Block ancestor.");
}
}
lft.endOfNode();
getFOEventHandler().characters(lft.ca, lft.startIndex, lft.endIndex);
addChildNode(lft);
}
}
@@ -83,15 +121,18 @@ public abstract class FObjMixed extends FObj {
*/
protected void addChildNode(FONode child) throws FOPException {
flushText();
if (child instanceof FOText || child.getNameId() == FO_CHARACTER) {
if (currentTextNode == null) {
currentTextNode = child;
if (!inMarker()
|| getNameId() == FO_MARKER) {
if (child instanceof FOText || child.getNameId() == FO_CHARACTER) {
if (currentTextNode == null) {
currentTextNode = child;
}
} else {
// handle white-space for all text up to here
getFOEventHandler().whiteSpaceHandler
.handleWhiteSpace(this, currentTextNode, child);
currentTextNode = null;
}
} else {
// handle white-space for all text up to here
getFOEventHandler().whiteSpaceHandler
.handleWhiteSpace(this, currentTextNode, child);
currentTextNode = null;
}
super.addChildNode(child);
}

+ 103
- 52
src/java/org/apache/fop/fo/PropertyList.java Näytä tiedosto

@@ -169,8 +169,11 @@ public abstract class PropertyList {
boolean bTryDefault) throws PropertyException {

PropertyMaker propertyMaker = findMaker(propId & Constants.PROPERTY_MASK);
return propertyMaker.get(propId & Constants.COMPOUND_MASK, this,
bTryInherit, bTryDefault);
if (propertyMaker != null) {
return propertyMaker.get(propId & Constants.COMPOUND_MASK, this,
bTryInherit, bTryDefault);
}
return null;
}

/**
@@ -260,8 +263,11 @@ public abstract class PropertyList {
* Adds the attributes, passed in by the parser to the PropertyList
*
* @param attributes Collection of attributes passed to us from the parser.
* @throws ValidationException if there is an attribute that does not
* map to a property id (strict validation only)
*/
public void addAttributesToList(Attributes attributes) {
public void addAttributesToList(Attributes attributes)
throws ValidationException {
/*
* If column-number/number-columns-spanned are specified, then we
* need them before all others (possible from-table-column() on any
@@ -308,69 +314,104 @@ public abstract class PropertyList {
if (factory.getElementMappingRegistry().isKnownNamespace(attributeNS)) {
getFObj().addForeignAttribute(attributeNS, attributeName, attributeValue);
} else {
handleInvalidProperty(attributeName);
handleInvalidProperty(
"Error processing foreign attribute: "
+ attributeNS + "/@" + attributeName, attributeName);
}
}
}
}
/**
* Validates a property name.
* @param propertyName the property name to check
* @return true if the base property name and the subproperty name (if any)
* can be correctly mapped to an id
* @throws ValidationException in case the property name
* is invalid for the FO namespace
*/
protected boolean isValidPropertyName(String propertyName)
throws ValidationException {

int propId = FOPropertyMapping.getPropertyId(
findBasePropertyName(propertyName));
int subpropId = FOPropertyMapping.getSubPropertyId(
findSubPropertyName(propertyName));
if (propId == -1
|| (subpropId == -1
&& findSubPropertyName(propertyName) != null)) {
StringBuffer errorMessage = new StringBuffer().append(
"Invalid property name \'").append(propertyName);
handleInvalidProperty(errorMessage.toString(), propertyName);
return false;
}
return true;
}

/**
*
* @param attributes Collection of attributes
* @param attributeName Attribute name to convert
* @param attributeValue Attribute value to assign to property
* @throws ValidationException in case the property name is invalid
* for the FO namespace
*/
private void convertAttributeToProperty(Attributes attributes,
String attributeName,
String attributeValue) {
PropertyMaker propertyMaker = null;
FObj parentFO = fobj.findNearestAncestorFObj();
String attributeValue)
throws ValidationException {
/* Handle "compound" properties, ex. space-before.minimum */
String basePropertyName = findBasePropertyName(attributeName);
String subPropertyName = findSubPropertyName(attributeName);
if (attributeValue != null) {

if (!isValidPropertyName(attributeName)) {
//will log an error or throw an exception
return;
}
FObj parentFO = fobj.findNearestAncestorFObj();
/* Handle "compound" properties, ex. space-before.minimum */
String basePropertyName = findBasePropertyName(attributeName);
String subPropertyName = findSubPropertyName(attributeName);

int propId = FOPropertyMapping.getPropertyId(basePropertyName);
int propId = FOPropertyMapping.getPropertyId(basePropertyName);
int subpropId = FOPropertyMapping.getSubPropertyId(subPropertyName);
PropertyMaker propertyMaker = findMaker(propId);
if (propertyMaker == null) {
log.warn("No PropertyMaker registered for " + attributeName
+ ". Ignoring property.");
return;
}

propertyMaker = findMaker(propId);
if (propertyMaker == null) {
handleInvalidProperty(attributeName);
return;
}
if (attributeValue == null) {
return;
}
try {
Property prop = null;
if (subPropertyName == null) { // base attribute only found
/* Do nothing if the base property has already been created.
* This is e.g. the case when a compound attribute was
* specified before the base attribute; in these cases
* the base attribute was already created in
* findBaseProperty()
*/
if (getExplicit(propId) != null) {
return;
try {
Property prop = null;
if (subPropertyName == null) { // base attribute only found
/* Do nothing if the base property has already been created.
* This is e.g. the case when a compound attribute was
* specified before the base attribute; in these cases
* the base attribute was already created in
* findBaseProperty()
*/
if (getExplicit(propId) != null) {
return;
}
prop = propertyMaker.make(this, attributeValue, parentFO);
} else { // e.g. "leader-length.maximum"
Property baseProperty =
findBaseProperty(attributes, parentFO, propId,
basePropertyName, propertyMaker);
prop = propertyMaker.make(baseProperty, subpropId,
this, attributeValue, parentFO);
}
prop = propertyMaker.make(this, attributeValue, parentFO);
} else { // e.g. "leader-length.maximum"
Property baseProperty = findBaseProperty(attributes,
parentFO, propId, basePropertyName, propertyMaker);
int subpropertyId = FOPropertyMapping.getSubPropertyId(subPropertyName);
if (subpropertyId == -1) {
handleInvalidProperty(attributeName);
return;
if (prop != null) {
putExplicit(propId, prop);
}
prop = propertyMaker.make(baseProperty, subpropertyId,
this, attributeValue, parentFO);
}
if (prop != null) {
putExplicit(propId, prop);
} catch (PropertyException e) {
log.error("Ignoring property: "
+ attributeName + "=\"" + attributeValue + "\"");
}
} catch (PropertyException e) {
// TODO: Add strict validation.
log.error(e.getMessage());
}
}

@@ -405,9 +446,19 @@ public abstract class PropertyList {
return null; // could not find base property
}

private void handleInvalidProperty(String attributeName) {
if (!attributeName.startsWith("xmlns")) {
log.error("property '" + attributeName + "' ignored");
/**
* @param message ...
* @param propName ...
* @throws ValidationException ...
*/
protected void handleInvalidProperty(String message, String propName)
throws ValidationException {
if (!propName.startsWith("xmlns")) {
if (fobj.getUserAgent().validateStrictly()) {
fobj.attributeError(message);
} else {
log.error(message + " Property ignored.");
}
}
}

@@ -418,7 +469,7 @@ public abstract class PropertyList {
* @param attributeName String to be atomized
* @return the base portion of the attribute
*/
private static String findBasePropertyName(String attributeName) {
protected static String findBasePropertyName(String attributeName) {
int separatorCharIndex = attributeName.indexOf('.');
String basePropertyName = attributeName;
if (separatorCharIndex > -1) {
@@ -434,7 +485,7 @@ public abstract class PropertyList {
* @param attributeName String to be atomized
* @return the sub portion of the attribute
*/
private static String findSubPropertyName(String attributeName) {
protected static String findSubPropertyName(String attributeName) {
int separatorCharIndex = attributeName.indexOf('.');
String subpropertyName = null;
if (separatorCharIndex > -1) {

+ 0
- 1192
src/java/org/apache/fop/fo/PropertySets.java
File diff suppressed because it is too large
Näytä tiedosto


+ 1
- 1
src/java/org/apache/fop/fo/StaticPropertyList.java Näytä tiedosto

@@ -21,7 +21,7 @@ import org.apache.fop.fo.properties.Property;

/**
* A very fast implementation of PropertyList that uses arrays to store
* the explit set properties and another array to store cached values.
* the explicit set properties and another array to store cached values.
*/
public class StaticPropertyList extends PropertyList {
private Property[] explicit;

+ 41
- 8
src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java Näytä tiedosto

@@ -72,11 +72,34 @@ public class XMLWhiteSpaceHandler {
* @param firstTextNode the node at which to start
*/
public void handleWhiteSpace(FObjMixed fo, FONode firstTextNode) {
if (fo.getNameId() == Constants.FO_BLOCK) {
this.currentBlock = (Block) fo;
this.linefeedTreatment = currentBlock.getLinefeedTreatment();
this.whiteSpaceCollapse = currentBlock.getWhitespaceCollapse();
this.whiteSpaceTreatment = currentBlock.getWhitespaceTreatment();
if (fo.getNameId() == Constants.FO_BLOCK
|| fo.getNameId() == Constants.FO_RETRIEVE_MARKER) {
if (fo.getNameId() == Constants.FO_BLOCK) {
this.currentBlock = (Block) fo;
} else {
FONode ancestor = fo.parent;
while (ancestor.getNameId() != Constants.FO_BLOCK
&& ancestor.getNameId() != Constants.FO_STATIC_CONTENT) {
ancestor = ancestor.getParent();
}
if (ancestor.getNameId() == Constants.FO_BLOCK) {
this.currentBlock = (Block) ancestor;
}
}
if (currentBlock != null) {
this.linefeedTreatment = currentBlock.getLinefeedTreatment();
this.whiteSpaceCollapse = currentBlock.getWhitespaceCollapse();
this.whiteSpaceTreatment =
currentBlock.getWhitespaceTreatment();
} else {
/* fo:retrieve-marker as direct child of static-content
* set properties to their initial values
*/
this.linefeedTreatment = Constants.EN_TREAT_AS_SPACE;
this.whiteSpaceCollapse = Constants.EN_TRUE;
this.whiteSpaceTreatment =
Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED;
}
} else if (fo.getNameId() == Constants.FO_TITLE
|| fo.getNameId() == Constants.FO_BOOKMARK_TITLE) {
/* Two special types of FO that can contain #PCDATA
@@ -84,7 +107,8 @@ public class XMLWhiteSpaceHandler {
*/
this.linefeedTreatment = Constants.EN_TREAT_AS_SPACE;
this.whiteSpaceCollapse = Constants.EN_TRUE;
this.whiteSpaceTreatment = Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED;
this.whiteSpaceTreatment =
Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED;
}
currentFO = fo;
if (firstTextNode == null) {
@@ -94,7 +118,10 @@ public class XMLWhiteSpaceHandler {
charIter = new RecursiveCharIterator(fo, firstTextNode);
inWhiteSpace = false;
int textNodeIndex = -1;
if (currentFO == currentBlock) {
if (currentFO == currentBlock
|| currentBlock == null
|| (currentFO.getNameId() == Constants.FO_RETRIEVE_MARKER
&& currentFO.getParent() == currentBlock)) {
textNodeIndex = fo.childNodes.indexOf(firstTextNode);
afterLinefeed = ((textNodeIndex == 0)
|| (textNodeIndex > 0
@@ -104,7 +131,8 @@ public class XMLWhiteSpaceHandler {
endOfBlock = (nextChild == null && currentFO == currentBlock);
if (nextChild != null) {
int nextChildId = nextChild.getNameId();
nextChildIsBlockLevel = (nextChildId == Constants.FO_BLOCK
nextChildIsBlockLevel = (
nextChildId == Constants.FO_BLOCK
|| nextChildId == Constants.FO_TABLE_AND_CAPTION
|| nextChildId == Constants.FO_TABLE
|| nextChildId == Constants.FO_LIST_BLOCK
@@ -149,6 +177,11 @@ public class XMLWhiteSpaceHandler {
addPendingInline(fo);
}
}
if (currentFO == currentBlock && nextChild == null) {
/* end of block: clear the reference */
currentBlock = null;
}
}
/**

+ 1
- 1
src/java/org/apache/fop/fo/expr/FromTableColumnFunction.java Näytä tiedosto

@@ -24,9 +24,9 @@ import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.FOPropertyMapping;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableFObj;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.fo.flow.TableFObj;
import org.apache.fop.fo.properties.Property;

/**

+ 43
- 14
src/java/org/apache/fop/fo/flow/Block.java Näytä tiedosto

@@ -42,20 +42,6 @@ import org.apache.fop.fo.properties.CommonRelativePosition;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.SpaceProperty;

/*
Modified by Mark Lillywhite mark-fop@inomial.com. The changes
here are based on memory profiling and do not change functionality.
Essentially, the Block object had a pointer to a BlockArea object
that it created. The BlockArea was not referenced after the Block
was finished except to determine the size of the BlockArea, however
a reference to the BlockArea was maintained and this caused a lot of
GC problems, and was a major reason for FOP memory leaks. So,
the reference to BlockArea was made local, the required information
is now stored (instead of a reference to the complex BlockArea object)
and it appears that there are a lot of changes in this file, in fact
there are only a few sematic changes; mostly I just got rid of
"this." from blockArea since BlockArea is now local.
*/
/**
* Class modelling the fo:block object.
*/
@@ -361,6 +347,48 @@ public class Block extends FObjMixed {
return whiteSpaceCollapse;
}
/**
* @return Returns the commonAccessibility.
*/
public CommonAccessibility getCommonAccessibility() {
return this.commonAccessibility;
}

/**
* @return Returns the commonAural.
*/
public CommonAural getCommonAural() {
return this.commonAural;
}

/**
* @return Returns the commonRelativePosition.
*/
public CommonRelativePosition getCommonRelativePosition() {
return this.commonRelativePosition;
}

/**
* @return Returns the hyphenationKeep.
*/
public int getHyphenationKeep() {
return this.hyphenationKeep;
}

/**
* @return Returns the intrusionDisplace.
*/
public int getIntrusionDisplace() {
return this.intrusionDisplace;
}

/**
* @return Returns the lineHeightShiftAdjustment.
*/
public int getLineHeightShiftAdjustment() {
return this.lineHeightShiftAdjustment;
}

/** @see org.apache.fop.fo.FONode#charIterator() */
public CharIterator charIterator() {
return NullCharIterator.getInstance();
@@ -377,4 +405,5 @@ public class Block extends FObjMixed {
public int getNameId() {
return FO_BLOCK;
}
}

+ 250
- 39
src/java/org/apache/fop/fo/flow/Marker.java Näytä tiedosto

@@ -20,9 +20,8 @@
package org.apache.fop.fo.flow;

import java.util.HashMap;
import java.util.Iterator;


import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
@@ -30,6 +29,7 @@ import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.FOPropertyMapping;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.PropertyListMaker;
import org.apache.fop.fo.ValidationException;
@@ -44,7 +44,7 @@ public class Marker extends FObjMixed {
// End of property values

private PropertyListMaker savePropertyListMaker;
private HashMap descPLists = new HashMap();
private HashMap descendantPropertyLists = new HashMap();

/**
* Create a marker fo.
@@ -76,14 +76,11 @@ public class Marker extends FObjMixed {
* @param foNode the FO node whose property list is requested
* @return the MarkerPropertyList of foNode
*/
protected MarkerPropertyList getPList(FONode foNode) {
return (MarkerPropertyList) descPLists.get(foNode);
}

protected PropertyList createPropertyList(PropertyList parent, FOEventHandler foEventHandler) throws FOPException {
return new MarkerPropertyList(this, parent);
protected MarkerPropertyList getPropertyListFor(FONode foNode) {
return (MarkerPropertyList)
descendantPropertyLists.get(foNode);
}
/** @see org.apache.fop.fo.FONode#startOfNode() */
protected void startOfNode() {
FOEventHandler foEventHandler = getFOEventHandler();
@@ -92,30 +89,18 @@ public class Marker extends FObjMixed {
foEventHandler.setPropertyListMaker(new PropertyListMaker() {
public PropertyList make(FObj fobj, PropertyList parentPropertyList) {
PropertyList pList = new MarkerPropertyList(fobj, parentPropertyList);
descPLists.put(fobj, pList);
descendantPropertyLists.put(fobj, pList);
return pList;
}
});
}
/** @see org.apache.fop.fo.FONode#endOfNode() */
protected void endOfNode() throws FOPException {
super.endOfNode();
// Pop the MarkerPropertyList maker.
getFOEventHandler().setPropertyListMaker(savePropertyListMaker);
savePropertyListMaker = null;
// unparent the child property lists
Iterator iter = getChildNodes();
if (iter != null) {
while (iter.hasNext()) {
FONode child = (FONode) iter.next();
MarkerPropertyList pList
= (MarkerPropertyList) descPLists.get(child);
if (pList != null) {
pList.setParentPropertyList(null);
}
}
}
}

/**
@@ -132,7 +117,11 @@ public class Marker extends FObjMixed {
invalidChildError(loc, nsURI, localName);
}
}

protected boolean inMarker() {
return true;
}
/**
* Return the "marker-class-name" property.
*/
@@ -160,30 +149,252 @@ public class Marker extends FObjMixed {
}
/**
* An implementation of PropertyList which only stores the explicit
* assigned properties. It is memory efficient but slow.
* An implementation of PropertyList which only stores the explicitly
* specified properties/attributes as bundles of name-value-namespace
* strings
*/
public class MarkerPropertyList extends PropertyList {
HashMap explicit = new HashMap();
public MarkerPropertyList(FObj fobj, PropertyList parentPropertyList) {
super(fobj, parentPropertyList);
protected class MarkerPropertyList extends PropertyList
implements Attributes {
protected class MarkerAttribute {
protected String namespace;
protected String qname;
protected String name;
protected String value;
/**
* Main constructor
* @param namespace the namespace URI
* @param qname the qualified name
* @param name the name
* @param value the value
*/
public MarkerAttribute(String namespace, String qname,
String name, String value) {
this.namespace = namespace;
this.qname = qname;
this.name = (name == null ? qname : name);
this.value = value;
}
/**
* Convenience constructor for FO attributes
* @param name the attribute name
* @param value the attribute value
*/
public MarkerAttribute(String name, String value) {
this.namespace = null;
this.qname = name;
this.name = name;
this.value = value;
}
}
/** the array of attributes **/
private MarkerAttribute[] attribs;
/**
* Set the parent property list. Used to assign a new parent
* before re-binding all the child elements.
* Overriding default constructor
*
* @param fobj the FObj to attach
* @param parentPropertyList ignored
*/
public void setParentPropertyList(PropertyList parentPropertyList) {
this.parentPropertyList = parentPropertyList;
public MarkerPropertyList(FObj fobj, PropertyList parentPropertyList) {
/* ignore parentPropertyList
* won't be used because the attributes will be stored
* without resolving
*/
super(fobj, null);
}
/**
* Override that doesn't convert the attributes to Property instances,
* but simply stores the attributes for later processing;
*
* @see org.apache.fop.fo.PropertyList#addAttributesToList(Attributes)
*/
public void addAttributesToList(Attributes attributes)
throws ValidationException {
this.attribs = new MarkerAttribute[attributes.getLength()];

String name;
String value;
String namespace;
String qname;
for (int i = attributes.getLength(); --i >= 0;) {
namespace = attributes.getURI(i);
qname = attributes.getQName(i);
name = attributes.getLocalName(i);
value = attributes.getValue(i);
this.attribs[i] =
new MarkerAttribute(namespace, qname, name, value);
}
}
/**
* Null implementation; not used by this type of PropertyList
* @see org.apache.fop.fo.PropertyList#putExplicit(int, Property)
*/
public void putExplicit(int propId, Property value) {
explicit.put(new Integer(propId), value);
//nop
}

/**
* Null implementation; not used by this type of PropertyList
* @see org.apache.fop.fo.PropertyList#getExplicit(int)
*/
public Property getExplicit(int propId) {
return (Property) explicit.get(new Integer(propId));
return null;
}

/**
* @see org.xml.sax.Attributes#getLength()
*/
public int getLength() {
if (attribs == null) {
return 0;
} else {
return attribs.length;
}
}

/**
* @see org.xml.sax.Attributes#getURI()
*/
public String getURI(int index) {
if (attribs != null
&& index < attribs.length
&& index >= 0
&& attribs[index] != null) {
return attribs[index].namespace;
} else {
return null;
}
}

/**
* @see org.xml.sax.Attributes#getLocalName()
*/
public String getLocalName(int index) {
if (attribs != null
&& index < attribs.length
&& index >= 0
&& attribs[index] != null) {
return attribs[index].name;
} else {
return null;
}
}

/**
* @see org.xml.sax.Attributes#getQName()
*/
public String getQName(int index) {
if (attribs != null
&& index < attribs.length
&& index >= 0
&& attribs[index] != null) {
return attribs[index].qname;
} else {
return null;
}
}
}

}
/**
* Default implementation; not used
* @see org.xml.sax.Attributes#getType()
*/
public String getType(int index) {
return "CDATA";
}

/**
* @see org.xml.sax.Attributes#getValue()
*/
public String getValue(int index) {
if (attribs != null
&& index < attribs.length
&& index >= 0
&& attribs[index] != null) {
return attribs[index].value;
} else {
return null;
}
}

/**
* @see org.xml.sax.Attributes#getIndex()
*/
public int getIndex(String name, String namespace) {
int index = -1;
if (attribs != null && name != null && namespace != null) {
for (int i = attribs.length; --i >= 0;) {
if (attribs[i] != null
&& namespace.equals(attribs[i].namespace)
&& name.equals(attribs[i].name)) {
break;
}
}
}
return index;
}

/**
* @see org.xml.sax.Attributes#getIndex()
*/
public int getIndex(String qname) {
int index = -1;
if (attribs != null && qname != null) {
for (int i = attribs.length; --i >= 0;) {
if (attribs[i] != null
&& qname.equals(attribs[i].qname)) {
break;
}
}
}
return index;
}

/**
* Default implementation; not used
* @see org.xml.sax.Attributes#getType()
*/
public String getType(String name, String namespace) {
return "CDATA";
}

/**
* Default implementation; not used
* @see org.xml.sax.Attributes#getType()
*/
public String getType(String qname) {
return "CDATA";
}

/**
* @see org.xml.sax.Attributes#getValue()
*/
public String getValue(String name, String namespace) {
int index = getIndex(name, namespace);
if (index > 0) {
return getValue(index);
}
return null;
}

/**
* @see org.xml.sax.Attributes#getValue()
*/
public String getValue(String qname) {
int index = getIndex(qname);
if (index > 0) {
return getValue(index);
}
return null;
}
}
}

+ 89
- 103
src/java/org/apache/fop/fo/flow/RetrieveMarker.java Näytä tiedosto

@@ -19,24 +19,24 @@

package org.apache.fop.fo.flow;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;

import org.xml.sax.Locator;

import org.apache.commons.logging.Log;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FOPropertyMapping;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.StaticPropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.PropertyMaker;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;



/**
@@ -44,7 +44,7 @@ import org.apache.fop.fo.ValidationException;
* This will create a layout manager that will retrieve
* a marker based on the information.
*/
public class RetrieveMarker extends FObj {
public class RetrieveMarker extends FObjMixed {
// The value of properties relevant for fo:retrieve-marker.
private String retrieveClassName;
private int retrievePosition;
@@ -78,7 +78,9 @@ public class RetrieveMarker extends FObj {
if (retrieveClassName == null || retrieveClassName.equals("")) {
missingPropertyError("retrieve-class-name");
}
}
propertyList = pList.getParentPropertyList();
}
/**
@@ -90,40 +92,70 @@ public class RetrieveMarker extends FObj {
invalidChildError(loc, nsURI, localName);
}

protected PropertyList createPropertyList(PropertyList parent,
FOEventHandler foEventHandler) throws FOPException {
// TODO: A special RetrieveMarkerPropertyList would be more memory
// efficient. Storing a StaticPropertyList like this will keep all
// the parent PropertyLists alive.
propertyList = new StaticPropertyList(this, parent);
return propertyList;
}

public PropertyList getPropertyList() {
return propertyList;
}

/**
* Return the "retrieve-class-name" property.
* @return the "retrieve-class-name" property.
*/
public String getRetrieveClassName() {
return retrieveClassName;
}

/**
* Return the "retrieve-position" property.
* @return the "retrieve-position" property (enum value).
*/
public int getRetrievePosition() {
return retrievePosition;
}

/**
* Return the "retrieve-boundry" property.
* @return the "retrieve-boundary" property (enum value).
*/
public int getRetrieveBoundary() {
return retrieveBoundary;
}
private PropertyList createPropertyListFor(FObj fo, PropertyList parent) {
return getFOEventHandler().getPropertyListMaker().make(fo, parent);
}

private void cloneSingleNode(FONode child, FONode newParent,
Marker marker, PropertyList parentPropertyList)
throws FOPException {

if (child != null) {
FONode newChild = child.clone(newParent, true);
if (child instanceof FObj) {
Marker.MarkerPropertyList pList;
PropertyList newPropertyList = createPropertyListFor(
(FObj) newChild, parentPropertyList);
pList = marker.getPropertyListFor(child);
newChild.processNode(
child.getLocalName(),
getLocator(),
pList,
newPropertyList);
if (newChild.getNameId() == FO_TABLE) {
Table t = (Table) child;
cloneSubtree(t.getColumns().listIterator(),
newChild, marker, newPropertyList);
cloneSingleNode(t.getTableHeader(),
newChild, marker, newPropertyList);
cloneSingleNode(t.getTableFooter(),
newChild, marker, newPropertyList);
}
cloneSubtree(child.getChildNodes(), newChild,
marker, newPropertyList);
if (newChild instanceof FObjMixed) {
handleWhiteSpaceFor((FObjMixed) newChild);
}
} else if (child instanceof FOText) {
FOText ft = (FOText) newChild;
ft.bind(parentPropertyList);
}
addChildTo(newChild, (FObj) newParent);
}
}
/**
* Clone the FO nodes in the parent iterator,
* attach the new nodes to the new parent,
@@ -136,94 +168,48 @@ public class RetrieveMarker extends FObj {
* @param descPLists the map of the new nodes to property lists
*/
private void cloneSubtree(Iterator parentIter, FONode newParent,
Marker marker, Map descPLists)
throws FOPException {
if (parentIter == null) return;
while (parentIter.hasNext()) {
FONode child = (FONode) parentIter.next();
FONode newChild = child.clone(newParent, true);
descPLists.put(newChild, marker.getPList(child));
cloneSubtree(child.getChildNodes(), newChild, marker, descPLists);
}
}

/**
* Clone the subtree of marker,
* and attach the new subtree to this node.
* The property lists are not cloned;
* the existing property lists of the direct children
* are reparented to the property list of this node.
* @param marker the marker that is to be cloned
* @param descPLists the map of the new nodes to property lists
*/
private void cloneFromMarker(Marker marker, Map descPLists)
Marker marker, PropertyList parentPropertyList)
throws FOPException {
// release child nodes from a possible earlier layout
childNodes = new ArrayList();
Iterator markerIter = marker.getChildNodes();
cloneSubtree(markerIter, this, marker, descPLists);
// reparent the property lists of the direct children
for (Iterator iter = getChildNodes(); iter.hasNext(); ) {
FONode child = (FONode) iter.next();
Marker.MarkerPropertyList pList
= (Marker.MarkerPropertyList) descPLists.get(child);
if (pList != null) {
pList.setParentPropertyList(propertyList);
if (parentIter != null) {
FONode child;
while (parentIter.hasNext()) {
child = (FONode) parentIter.next();
cloneSingleNode(child, newParent,
marker, parentPropertyList);
}
}
}

/**
* Bind the new nodes to the property values in this context
* @param descPLists the map of the new nodes to property lists
*/
private void bindChildren(Map descPLists) throws FOPException {
for (Iterator i = descPLists.keySet().iterator(); i.hasNext(); ) {
FONode desc = (FONode) i.next();
PropertyList descPList;
if (desc instanceof FObj) {
descPList = (PropertyList) descPLists.get(desc);
((FObj) desc).bind(descPList);
} else if (desc instanceof FOText) {
descPList = (PropertyList) descPLists.get(desc.getParent());
if (descPList == null) {
descPList = propertyList;
}
((FOText) desc).bind(descPList);
}
private void cloneFromMarker(Marker marker)
throws FOPException {
// clean up remnants from a possible earlier layout
if (childNodes != null) {
currentTextNode = null;
childNodes.removeAll(childNodes);
}
cloneSubtree(marker.getChildNodes(), this,
marker, propertyList);
}

/**
* Clone the subtree of marker
* and bind the nodes to the property values in this context.
* The property lists are not cloned,
* but the subtree is attached to the property list of this node.
* This is only needed for the binding of the FO nodes.
* After that a subsequent retrieve-marker
* may reparent the property lists.
* Clone the subtree of the given marker
*
* @param marker the marker that is to be cloned
*/
public void bindMarker(Marker marker) {
// assert(marker != null);
// catch empty marker
if (marker.getChildNodes() == null) {
return;
}
HashMap descPLists = new HashMap();
try {
cloneFromMarker(marker, descPLists);
} catch (FOPException exc) {
Log log = getLogger();
log.error("fo:retrieve-marker unable to clone subtree of fo:marker", exc);
return;
}
try {
bindChildren(descPLists);
} catch (FOPException exc) {
Log log = getLogger();
log.error("fo:retrieve-marker unable to rebind property values", exc);
if (marker.getChildNodes() != null) {
try {
cloneFromMarker(marker);
} catch (FOPException exc) {
log.error("fo:retrieve-marker unable to clone "
+ "subtree of fo:marker (marker-class-name="
+ marker.getMarkerClassName() + ")", exc);
return;
}
} else if (log.isInfoEnabled()) {
log.info("Empty marker retrieved...");
}
return;
}

/** @see org.apache.fop.fo.FONode#getLocalName() */
@@ -236,5 +222,5 @@ public class RetrieveMarker extends FObj {
*/
public int getNameId() {
return FO_RETRIEVE_MARKER;
}
}
}
}

+ 32
- 11
src/java/org/apache/fop/fo/flow/Table.java Näytä tiedosto

@@ -27,6 +27,7 @@ import org.xml.sax.Locator;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.ValidationPercentBaseContext;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.StaticPropertyList;
import org.apache.fop.fo.ValidationException;
@@ -209,15 +210,19 @@ public class Table extends TableFObj {
* @see org.apache.fop.fo.FONode#endOfNode
*/
protected void endOfNode() throws FOPException {
if (!tableBodyFound) {
missingChildElementError(
"(marker*,table-column*,table-header?,table-footer?"
+ ",table-body+)");
}
if (columns != null && !columns.isEmpty()) {
for (int i = columns.size(); --i >= 0;) {
if (isColumnNumberUsed(i + 1)) {
((TableColumn) columns.get(i)).releasePropertyList();
if (!inMarker()) {
if (columns != null && !columns.isEmpty()) {
for (int i = columns.size(); --i >= 0;) {
TableColumn col = (TableColumn) columns.get(i);
if (col != null) {
col.releasePropertyList();
}
}
}
}
@@ -229,7 +234,14 @@ public class Table extends TableFObj {
*/
protected void addChildNode(FONode child) throws FOPException {
if ("fo:table-column".equals(child.getName())) {
addColumnNode((TableColumn) child);
if (columns == null) {
columns = new java.util.ArrayList();
}
if (!inMarker()) {
addColumnNode((TableColumn) child);
} else {
columns.add((TableColumn) child);
}
} else {
if ("fo:table-footer".equals(child.getName())) {
tableFooter = (TableBody) child;
@@ -252,9 +264,6 @@ public class Table extends TableFObj {
private void addColumnNode(TableColumn col) {
int colNumber = col.getColumnNumber();
int colRepeat = col.getNumberColumnsRepeated();
if (columns == null) {
columns = new java.util.ArrayList();
}
if (columns.size() < colNumber) {
//add nulls for non-occupied indices between
//the last column up to and including the current one
@@ -273,6 +282,10 @@ public class Table extends TableFObj {
columns.add(col);
}
}
//flag column indices used by this column
int startIndex = columnIndex - 1;
int endIndex = startIndex + colRepeat;
flagColumnIndices(startIndex, endIndex);
}

/** @return true of table-layout="auto" */
@@ -458,9 +471,17 @@ public class Table extends TableFObj {
}
/**
* @see org.apache.fop.fo.flow.TableFObj#existsUsedColumnIndices()
* @see org.apache.fop.fo.FONode#clone(FONode, boolean)
*/
protected boolean existsUsedColumnIndices() {
return (usedColumnIndices != null);
public FONode clone(FONode parent, boolean removeChildren)
throws FOPException {
FObj fobj = (FObj) super.clone(parent, removeChildren);
if (removeChildren) {
Table t = (Table) fobj;
t.columns = null;
t.tableHeader = null;
t.tableFooter = null;
}
return fobj;
}
}

+ 78
- 51
src/java/org/apache/fop/fo/flow/TableBody.java Näytä tiedosto

@@ -25,6 +25,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
@@ -33,6 +34,7 @@ import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.StaticPropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.flow.TableFObj.PendingSpan;
import org.apache.fop.fo.properties.CommonAccessibility;
import org.apache.fop.fo.properties.CommonAural;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
@@ -62,7 +64,7 @@ public class TableBody extends TableFObj {
* used for initial values of column-number property
*/
protected List pendingSpans;
protected BitSet usedColumnIndices = new BitSet();
protected BitSet usedColumnIndices;
private int columnIndex = 1;
protected boolean firstRow = true;
@@ -87,11 +89,30 @@ public class TableBody extends TableFObj {
savedPropertyList = pList;
}
/**
* @see org.apache.fop.fo.FONode#processNode()
*/
public void processNode(String elementName, Locator locator,
Attributes attlist, PropertyList pList)
throws FOPException {
if (!inMarker()) {
if (getTable().columns != null) {
int cap = getTable().columns.size();
pendingSpans = new java.util.ArrayList(cap);
usedColumnIndices = new java.util.BitSet(cap);
} else {
pendingSpans = new java.util.ArrayList();
usedColumnIndices = new java.util.BitSet();
}
setNextColumnIndex();
}
super.processNode(elementName, locator, attlist, pList);
}

/**
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
initPendingSpans();
getFOEventHandler().startBody(this);
}

@@ -99,7 +120,16 @@ public class TableBody extends TableFObj {
* @see org.apache.fop.fo.FONode#endOfNode
*/
protected void endOfNode() throws FOPException {
if (!inMarker()) {
// clean up
savedPropertyList = null;
pendingSpans = null;
usedColumnIndices = null;
}
getFOEventHandler().endBody(this);
if (!(tableRowsFound || tableCellsFound)) {
if (getUserAgent().validateStrictly()) {
missingChildElementError("marker* (table-row+|table-cell+)");
@@ -110,18 +140,11 @@ public class TableBody extends TableFObj {
}
}
/*
if (tableCellsFound) {
convertCellsToRows();
}
//reset column index (so that it would be
//correct if the table is cloned during
//marker retrieval)
resetColumnIndex();
//release references
savedPropertyList = null;
pendingSpans = null;
usedColumnIndices = null;
*/
}

/**
@@ -158,6 +181,18 @@ public class TableBody extends TableFObj {
}
}
/**
* @see org.apache.fop.fo.FONode#addChildNode(FONode)
*/
protected void addChildNode(FONode child) throws FOPException {
if (!inMarker()) {
if (firstRow && child.getNameId() == FO_TABLE_ROW) {
firstRow = false;
}
}
super.addChildNode(child);
}
/**
* If table-cells are used as direct children of a table-body|header|footer
* they are replaced in this method by proper table-rows.
@@ -243,15 +278,17 @@ public class TableBody extends TableFObj {
* column-number of 2, since the first column is already
* occupied...)
*/
protected void initPendingSpans() {
if (getTable().columns != null) {
List tableCols = getTable().columns;
pendingSpans = new java.util.ArrayList(tableCols.size());
for (int i = tableCols.size(); --i >= 0;) {
pendingSpans.add(null);
}
} else {
if (firstRow && pendingSpans == null) {
protected void initPendingSpans(FONode child) {
if (child.getNameId() == FO_TABLE_ROW) {
pendingSpans = ((TableRow) child).pendingSpans;
} else if (pendingSpans == null) {
if (getTable().columns != null) {
List tableCols = getTable().columns;
pendingSpans = new java.util.ArrayList(tableCols.size());
for (int i = tableCols.size(); --i >= 0;) {
pendingSpans.add(null);
}
} else {
pendingSpans = new java.util.ArrayList();
}
}
@@ -262,7 +299,7 @@ public class TableBody extends TableFObj {
*
* @return the next column number to use
*/
public int getCurrentColumnIndex() {
protected int getCurrentColumnIndex() {
return columnIndex;
}

@@ -273,7 +310,7 @@ public class TableBody extends TableFObj {
*
* @param newIndex the new column index
*/
public void setCurrentColumnIndex(int newIndex) {
protected void setCurrentColumnIndex(int newIndex) {
columnIndex = newIndex;
}

@@ -281,11 +318,12 @@ public class TableBody extends TableFObj {
* Resets the current column index for the TableBody
*
*/
public void resetColumnIndex() {
protected void resetColumnIndex() {
columnIndex = 1;
for (int i = 0; i < usedColumnIndices.size(); i++) {
for (int i = usedColumnIndices.length(); --i >= 0;) {
usedColumnIndices.clear(i);
}
PendingSpan pSpan;
for (int i = pendingSpans.size(); --i >= 0;) {
pSpan = (PendingSpan) pendingSpans.get(i);
@@ -293,13 +331,10 @@ public class TableBody extends TableFObj {
pSpan.rowsLeft--;
if (pSpan.rowsLeft == 0) {
pendingSpans.set(i, null);
} else {
usedColumnIndices.set(i);
}
}
if (pendingSpans.get(i) != null) {
usedColumnIndices.set(i);
} else {
usedColumnIndices.clear(i);
}
}
if (!firstRow) {
setNextColumnIndex();
@@ -310,19 +345,19 @@ public class TableBody extends TableFObj {
* Increases columnIndex to the next available value
*
*/
private void setNextColumnIndex() {
protected void setNextColumnIndex() {
while (usedColumnIndices.get(columnIndex - 1)) {
//increment columnIndex
columnIndex++;
//if the table has explicit columns, and
//the updated index is not assigned to any
//column, increment further until the next
//index occupied by a column...
if (getTable().columns != null) {
while (columnIndex <= getTable().columns.size()
&& !getTable().isColumnNumberUsed(columnIndex) ) {
columnIndex++;
}
}
//if the table has explicit columns, and
//the index is not assigned to any
//column, increment further until the next
//index occupied by a column...
if (getTable().columns != null) {
while (columnIndex <= getTable().columns.size()
&& !getTable().isColumnNumberUsed(columnIndex) ) {
columnIndex++;
}
}
}
@@ -337,11 +372,10 @@ public class TableBody extends TableFObj {
* b) there is no previous cell (implicit
* start of row)
*/
protected boolean lastCellEndedRow(TableCell currentCell) {
if (childNodes != null && childNodes.indexOf(currentCell) > 0) {
FONode prevNode = (FONode) childNodes.get(
childNodes.indexOf(currentCell) - 1);
if (prevNode != null && prevNode.getNameId() == FO_TABLE_CELL) {
protected boolean previousCellEndedRow() {
if (childNodes != null) {
FONode prevNode = (FONode) childNodes.get(childNodes.size() - 1);
if (prevNode.getNameId() == FO_TABLE_CELL) {
return ((TableCell) prevNode).endsRow();
}
}
@@ -368,11 +402,4 @@ public class TableBody extends TableFObj {
}
setNextColumnIndex();
}
/**
* @see org.apache.fop.fo.flow.TableFObj#existsUsedColumnIndices()
*/
protected boolean existsUsedColumnIndices() {
return (usedColumnIndices != null);
}
}

+ 11
- 115
src/java/org/apache/fop/fo/flow/TableCell.java Näytä tiedosto

@@ -22,6 +22,7 @@ package org.apache.fop.fo.flow;
import java.util.BitSet;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
@@ -30,10 +31,12 @@ import org.apache.fop.datatypes.Numeric;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.properties.CommonAccessibility;
import org.apache.fop.fo.properties.CommonAural;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonRelativePosition;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.LengthRangeProperty;

/**
@@ -59,6 +62,9 @@ public class TableCell extends TableFObj {
private Numeric numberRowsSpanned;
private int startsRow;
private Length width;
private KeepProperty keepTogether;
private KeepProperty keepWithNext;
private KeepProperty keepWithPrevious;
// End of property values

/** used for FO validation */
@@ -94,11 +100,6 @@ public class TableCell extends TableFObj {
/** Ypos of cell ??? */
protected int top;

/**
* Set to true if all content completely laid out.
*/
private boolean bDone = false;
/**
* @param parent FONode that is the parent of this object
*/
@@ -122,16 +123,14 @@ public class TableCell extends TableFObj {
height = pList.get(PR_HEIGHT).getLength();
id = pList.get(PR_ID).getString();
inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange();
columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric();
numberColumnsSpanned = pList.get(PR_NUMBER_COLUMNS_SPANNED).getNumeric();
numberRowsSpanned = pList.get(PR_NUMBER_ROWS_SPANNED).getNumeric();
startsRow = pList.get(PR_STARTS_ROW).getEnum();
width = pList.get(PR_WIDTH).getLength();
//Check to make sure we're not in retrieve-marker context
//TODO: Can this be generalized/extended to other FOs/Properties?
if (((TableFObj) parent).existsUsedColumnIndices()) {
columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric();
}
keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep();
keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep();
keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep();
super.bind(pList);
}
@@ -163,112 +162,9 @@ public class TableCell extends TableFObj {
getLogger().warn("starts-row/ends-row for fo:table-cells "
+ "non-applicable for children of an fo:table-row.");
}
updateParentColumnIndex();
getFOEventHandler().endCell(this);
}

private void updateParentColumnIndex() {
int rowSpan = getNumberRowsSpanned();
int colSpan = getNumberColumnsSpanned();
int columnIndex = ((TableFObj) parent).getCurrentColumnIndex();
int i = -1;
while (++i < colSpan) {
//if table has explicit columns and the column-number isn't
//assigned to any column, increment further until the next
//column is encountered
if (getTable().getColumns() != null) {
while (columnIndex <= getTable().getColumns().size()
&& !getTable().isColumnNumberUsed(columnIndex)) {
columnIndex++;
}
}
//if column-number is already in use by another cell
//in the current row => error!
if (((TableFObj) parent).isColumnNumberUsed(columnIndex + i)) {
log.error("fo:table-cell overlaps in column "
+ (columnIndex + i));
}
}

if (parent.getNameId() == FO_TABLE_ROW) {
/* parent is a fo:table-row */
TableRow row = (TableRow) parent;
TableBody body = (TableBody) parent.getParent();
if (body.isFirst(row) && getTable().columns == null ) {
row.pendingSpans.add(null);
if (row.usedColumnIndices == null) {
row.usedColumnIndices = new BitSet();
}
}
//if the current cell spans more than one row,
//update pending span list for the next row
if (rowSpan > 1) {
for (i = colSpan; --i >= 0;) {
row.pendingSpans.set(columnIndex - 1 + i,
new PendingSpan(rowSpan));
}
}
} else {
/* parent is (should be) a fo:table-body/-header/-footer */
TableBody body = (TableBody) parent;
/* if body.firstRow is still true, and :
* a) the cell starts a row,
* b) there was a previous cell
* c) that previous cell didn't explicitly end the previous row
* => set firstRow flag to false
*/
if (startsRow() && body.firstRow) {
if (!body.lastCellEndedRow(this)) {
body.firstRow = false;
}
}
/* if there were no explicit columns, pendingSpans
* will not be properly initialized for the first row...
*/
if (body.firstRow && getTable().columns == null) {
for (i = colSpan; --i >= 0;) {
body.pendingSpans.add(null);
}
}
/* if the current cell spans more than one row,
* update pending span list for the next row
*/
if (rowSpan > 1) {
for (i = colSpan; --i >= 0;) {
body.pendingSpans.set(columnIndex - 1 + i,
new PendingSpan(rowSpan));
}
}
}
//flag column indices used by this cell,
//take into account that possibly not all column-numbers
//are used by columns in the parent table (if any),
//so a cell spanning three columns, might actually
//take up more than three columnIndices...
int startIndex = columnIndex - 1;
int endIndex = startIndex + colSpan;
if (getTable().columns != null) {
List cols = getTable().columns;
int tmpIndex = endIndex;
for (i = startIndex; i <= tmpIndex; ++i) {
if (i < cols.size() && cols.get(i) == null) {
endIndex++;
}
}
}
((TableFObj) parent).flagColumnIndices(startIndex, endIndex);
if (endsRow() && parent.getNameId() != FO_TABLE_ROW) {
((TableBody) parent).firstRow = false;
((TableBody) parent).resetColumnIndex();
}
}
/**
* @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
* XSL Content Model: marker* (%block;)+
@@ -304,7 +200,7 @@ public class TableCell extends TableFObj {
* @return the Common Border, Padding, and Background Properties.
*/
public CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
return commonBorderPaddingBackground;
return this.commonBorderPaddingBackground;
}

/**

+ 1
- 11
src/java/org/apache/fop/fo/flow/TableColumn.java Näytä tiedosto

@@ -78,10 +78,6 @@ public class TableColumn extends TableFObj {
visibility = pList.get(PR_VISIBILITY).getEnum();
super.bind(pList);
if (getTable().isColumnNumberUsed(columnNumber.getValue())) {
throw new PropertyException("column-number \"" + columnNumber
+ "\" has already been assigned to a previous column");
}
if (numberColumnsRepeated.getValue() <= 0) {
throw new PropertyException("number-columns-repeated must be 1 or bigger, "
+ "but got " + numberColumnsRepeated.getValue());
@@ -104,10 +100,6 @@ public class TableColumn extends TableFObj {
* @see org.apache.fop.fo.FONode#endOfNode
*/
protected void endOfNode() throws FOPException {
//flag column indices used by this column
int startIndex = getColumnNumber() - 1;
int endIndex = startIndex + getNumberColumnsRepeated();
getTable().flagColumnIndices(startIndex, endIndex);
getFOEventHandler().endColumn(this);
}

@@ -211,6 +203,4 @@ public class TableColumn extends TableFObj {
protected void releasePropertyList() {
this.pList = null;
}

}

}

+ 208
- 9
src/java/org/apache/fop/fo/flow/TableFObj.java Näytä tiedosto

@@ -19,13 +19,23 @@

package org.apache.fop.fo.flow;

import java.util.BitSet;
import java.util.Iterator;
import java.util.List;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Numeric;
import org.apache.fop.datatypes.ValidationPercentBaseContext;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.NumberProperty;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.PropertyMaker;

/**
* Superclass for table-related FOs
@@ -89,12 +99,128 @@ public abstract class TableFObj extends FObj {
if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java
&& getNameId() != FO_TABLE_CELL
&& getCommonBorderPaddingBackground().hasPadding(
ValidationPercentBaseContext.getPseudoContextForValidationPurposes())) {
attributeWarning("padding-* properties are not applicable to " + getName()
ValidationPercentBaseContext
.getPseudoContextForValidationPurposes())) {
attributeWarning(
"padding-* properties are not applicable to " + getName()
+ ", but a non-zero value for padding was found.");
}
}
/**
* @see org.apache.fop.fo.FONode#addChildNode(FONode)
*/
protected void addChildNode(FONode child) throws FOPException {
if (!inMarker()
&& child.getNameId() == FO_TABLE_CELL) {
/* update current column index for the table-body/table-row */
updateColumnIndex((TableCell) child);
}
super.addChildNode(child);
}
private void updateColumnIndex(TableCell cell)
throws ValidationException {
int rowSpan = cell.getNumberRowsSpanned();
int colSpan = cell.getNumberColumnsSpanned();
int columnIndex = getCurrentColumnIndex();
int i = -1;
while (++i < colSpan) {
if (isColumnNumberUsed(columnIndex + i)) {
/* if column-number is already in use by another cell
* in the current row => error!
*/
StringBuffer errorMessage = new StringBuffer();
errorMessage.append("fo:table-cell overlaps in column ")
.append(columnIndex + i);
if (locator.getLineNumber() != -1) {
errorMessage.append(" (line #")
.append(locator.getLineNumber()).append(", column #")
.append(locator.getColumnNumber()).append(")");
}
throw new ValidationException(errorMessage.toString());
}
}

if (getNameId() == FO_TABLE_ROW) {
TableRow row = (TableRow) this;
TableBody body = (TableBody) parent;
for (i = colSpan; --i >= 0;) {
row.pendingSpans.add(null);
}
/* if the current cell spans more than one row,
* update pending span list for the next row
*/
if (rowSpan > 1) {
for (i = colSpan; --i >= 0;) {
row.pendingSpans.set(columnIndex - 1 + i,
new PendingSpan(rowSpan));
}
}
} else {
TableBody body = (TableBody) this;
/* if body.firstRow is still true, and :
* a) the cell starts a row,
* b) there was a previous cell
* c) that previous cell didn't explicitly end the previous row
* => set firstRow flag to false
*/
if (body.firstRow && cell.startsRow()) {
if (!body.previousCellEndedRow()) {
body.firstRow = false;
}
}
/* pendingSpans not initialized for the first row...
*/
if (body.firstRow) {
for (i = colSpan; --i >= 0;) {
body.pendingSpans.add(null);
}
}
/* if the current cell spans more than one row,
* update pending span list for the next row
*/
if (rowSpan > 1) {
for (i = colSpan; --i >= 0;) {
body.pendingSpans.set(columnIndex - 1 + i,
new PendingSpan(rowSpan));
}
}
}

/* flag column indices used by this cell,
* take into account that possibly not all column-numbers
* are used by columns in the parent table (if any),
* so a cell spanning three columns, might actually
* take up more than three columnIndices...
*/
int startIndex = columnIndex - 1;
int endIndex = startIndex + colSpan;
if (getTable().columns != null) {
List cols = getTable().columns;
int tmpIndex = endIndex;
for (i = startIndex; i <= tmpIndex; ++i) {
if (i < cols.size() && cols.get(i) == null) {
endIndex++;
}
}
}
flagColumnIndices(startIndex, endIndex);
if (getNameId() != FO_TABLE_ROW && cell.endsRow()) {
((TableBody) this).firstRow = false;
((TableBody) this).resetColumnIndex();
}
}
/**
*
* @param side the side for which to return the border precedence
@@ -121,7 +247,7 @@ public abstract class TableFObj extends FObj {
*
* @return the next column number to use
*/
public int getCurrentColumnIndex() {
protected int getCurrentColumnIndex() {
return 0;
}
@@ -133,10 +259,10 @@ public abstract class TableFObj extends FObj {
*
* @param newIndex new value for column index
*/
public void setCurrentColumnIndex(int newIndex) {
protected void setCurrentColumnIndex(int newIndex) {
//do nothing by default
}
/**
* Checks if a certain column-number is already occupied
* (overridden for Table, TableBody, TableRow)
@@ -184,10 +310,83 @@ public abstract class TableFObj extends FObj {
}
/**
* Overridden for Table, TableBody, TableRow
* @return true if the usedColumnIndices BitSet exists, and is initialized
* PropertyMaker subclass for the column-number property
*
*/
protected boolean existsUsedColumnIndices() {
return false;
public static class ColumnNumberPropertyMaker extends NumberProperty.Maker {

/**
* Constructor
* @param propId the id of the property for which the maker should
* be created
*/
public ColumnNumberPropertyMaker(int propId) {
super(propId);
}

/**
* @see PropertyMaker#make(PropertyList)
*/
public Property make(PropertyList propertyList)
throws PropertyException {
FObj fo = propertyList.getFObj();

if (fo.getNameId() == Constants.FO_TABLE_CELL
|| fo.getNameId() == Constants.FO_TABLE_COLUMN) {
if (fo.getNameId() == Constants.FO_TABLE_CELL
&& fo.getParent().getNameId() != Constants.FO_TABLE_ROW
&& (propertyList.get(Constants.PR_STARTS_ROW).getEnum()
== Constants.EN_TRUE)) {
TableBody parent = (TableBody) fo.getParent();
if (!parent.previousCellEndedRow()) {
parent.resetColumnIndex();
}
}
return new NumberProperty(((TableFObj) fo.getParent())
.getCurrentColumnIndex());
} else {
throw new PropertyException(
"column-number property is only allowed"
+ " on fo:table-cell or fo:table-column, not on "
+ fo.getName());
}
}
/**
* Check the value of the column-number property.
* Return the parent's column index (initial value) in case
* of a negative or zero value
*
* @see org.apache.fop.fo.properties.PropertyMaker#get(
* int, PropertyList, boolean, boolean)
*/
public Property get(int subpropId, PropertyList propertyList,
boolean tryInherit, boolean tryDefault)
throws PropertyException {
Property p = super.get(0, propertyList, tryInherit, tryDefault);
TableFObj fo = (TableFObj) propertyList.getFObj();
TableFObj parent = (TableFObj) propertyList.getParentFObj();
int columnIndex = p.getNumeric().getValue();
if (columnIndex <= 0) {
fo.getLogger().warn("Specified negative or zero value for "
+ "column-number on " + fo.getName() + ": "
+ columnIndex + " forced to "
+ parent.getCurrentColumnIndex());
return new NumberProperty(parent.getCurrentColumnIndex());
}
//TODO: check for non-integer value and round
/* if column-number was explicitly specified, force the
* parent's current column index to the specified value,
* so that the updated index will be the correct initial
* value for the next cell/column (see Rec 7.26.8)
*/
if (propertyList.getExplicit(Constants.PR_COLUMN_NUMBER) != null) {
parent.setCurrentColumnIndex(p.getNumeric().getValue());
}
return p;
}
}
}

+ 0
- 1
src/java/org/apache/fop/fo/flow/TableFooter.java Näytä tiedosto

@@ -40,7 +40,6 @@ public class TableFooter extends TableBody {
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
initPendingSpans();
//getFOEventHandler().startBody(this);
}


+ 0
- 1
src/java/org/apache/fop/fo/flow/TableHeader.java Näytä tiedosto

@@ -40,7 +40,6 @@ public class TableHeader extends TableBody {
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
initPendingSpans();
//getFOEventHandler().startHeader(this);
}


+ 24
- 31
src/java/org/apache/fop/fo/flow/TableRow.java Näytä tiedosto

@@ -22,6 +22,7 @@ package org.apache.fop.fo.flow;
import java.util.BitSet;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
@@ -104,24 +105,30 @@ public class TableRow extends TableFObj {
childNodes.add(cell);
}
/**
* @see org.apache.fop.fo.FONode#processNode(String, Locator,
* Attributes, PropertyList)
*/
public void processNode(String elementName, Locator locator,
Attributes attlist, PropertyList pList) throws FOPException {
if (!inMarker()) {
TableBody body = (TableBody) parent;
body.resetColumnIndex();
pendingSpans = body.pendingSpans;
usedColumnIndices = body.usedColumnIndices;
while (usedColumnIndices.get(columnIndex - 1)) {
columnIndex++;
}
}
super.processNode(elementName, locator, attlist, pList);
}

/**
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
pendingSpans = ((TableBody) parent).pendingSpans;
usedColumnIndices = ((TableBody) parent).usedColumnIndices;
while (usedColumnIndices.get(columnIndex - 1)) {
columnIndex++;
}
checkId(id);
getFOEventHandler().startRow(this);
if (((TableBody) parent).isFirst(this)
&& getTable().columns == null ) {
if (pendingSpans == null) {
pendingSpans = new java.util.ArrayList();
}
}
}

/**
@@ -131,17 +138,10 @@ public class TableRow extends TableFObj {
if (childNodes == null) {
missingChildElementError("(table-cell+)");
}
if (((TableBody) parent).isFirst(this)
&& getTable().columns == null ) {
//force parent body's pendingSpans
//to the one accumulated after processing this row
((TableBody) parent).pendingSpans = pendingSpans;
if (!inMarker()) {
pendingSpans = null;
usedColumnIndices = null;
}
((TableBody) parent).resetColumnIndex();
columnIndex = 1;
//release references
pendingSpans = null;
usedColumnIndices = null;
getFOEventHandler().endRow(this);
}

@@ -155,7 +155,7 @@ public class TableRow extends TableFObj {
if (!(FO_URI.equals(nsURI) && localName.equals("table-cell"))) {
invalidChildError(loc, nsURI, localName);
}
}
}
/**
* @return the "id" property.
@@ -292,12 +292,5 @@ public class TableRow extends TableFObj {
while (usedColumnIndices.get(columnIndex - 1)) {
columnIndex++;
}
}
/**
* @see org.apache.fop.fo.flow.TableFObj#existsUsedColumnIndices()
*/
protected boolean existsUsedColumnIndices() {
return (usedColumnIndices != null);
}
}
}

+ 0
- 112
src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java Näytä tiedosto

@@ -1,112 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.fo.properties;

import java.util.Iterator;

import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.flow.TableBody;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableFObj;

/**
* Maker class for the column-number property on table-cells and
* table-columns
*
*/
public class ColumnNumberPropertyMaker extends NumberProperty.Maker {

/**
* Constructor
* @param propId the id of the property for which the maker should be created
*/
public ColumnNumberPropertyMaker(int propId) {
super(propId);
}

/**
* @see PropertyMaker#make(PropertyList)
*/
public Property make(PropertyList propertyList) throws PropertyException {
FObj fo = propertyList.getFObj();

if (fo.getNameId() == Constants.FO_TABLE_CELL
|| fo.getNameId() == Constants.FO_TABLE_COLUMN) {
if (fo.getNameId() == Constants.FO_TABLE_CELL
&& fo.getParent().getNameId() != Constants.FO_TABLE_ROW
&& (propertyList.get(Constants.PR_STARTS_ROW).getEnum()
== Constants.EN_TRUE)) {
TableBody parent = (TableBody) fo.getParent();
TableCell prevCell = null;
for (Iterator i = parent.getChildNodes();
(i != null && i.hasNext());) {
prevCell = (TableCell) i.next();
}
if (prevCell != null && !prevCell.endsRow()) {
parent.resetColumnIndex();
}
}
return new NumberProperty(((TableFObj) fo.getParent())
.getCurrentColumnIndex());
} else {
throw new PropertyException("column-number property is only allowed"
+ " on fo:table-cell or fo:table-column, not on "
+ fo.getName());
}
}
/**
* Check the value of the column-number property.
* Return the parent's column index (initial value) in case
* of a negative or zero value
*
* @see org.apache.fop.fo.properties.PropertyMaker#get(
* int, PropertyList, boolean, boolean)
*/
public Property get(int subpropId, PropertyList propertyList,
boolean tryInherit, boolean tryDefault)
throws PropertyException {
Property p = super.get(0, propertyList, tryInherit, tryDefault);
TableFObj fo = (TableFObj) propertyList.getFObj();
TableFObj parent = (TableFObj) propertyList.getParentFObj();
int columnIndex = p.getNumeric().getValue();
if (columnIndex <= 0) {
fo.getLogger().warn("Specified negative or zero value for "
+ "column-number on " + fo.getName() + ": "
+ columnIndex + " forced to "
+ parent.getCurrentColumnIndex());
return new NumberProperty(parent.getCurrentColumnIndex());
}
//TODO: check for non-integer value and round
//if column-number was explicitly specified, force the parent's current
//column index to the specified value, so that the updated index will
//be the correct initial value for the next cell/column (see Rec 7.26.8)
if (propertyList.getExplicit(Constants.PR_COLUMN_NUMBER) != null) {
parent.setCurrentColumnIndex(p.getNumeric().getValue());
}
return p;
}
}

+ 123
- 117
src/java/org/apache/fop/fo/properties/FontShorthandProperty.java Näytä tiedosto

@@ -53,136 +53,142 @@ public class FontShorthandProperty extends ListProperty {
public Property make(PropertyList propertyList,
String value, FObj fo) throws PropertyException {
FontShorthandProperty newProp = new FontShorthandProperty();
newProp.setSpecifiedValue(value);
String specVal = value;
Property prop = null;
if ("inherit".equals(specVal)) {
for (int i = PROP_IDS.length; --i >= 0;) {
prop = propertyList.getFromParent(PROP_IDS[i]);
newProp.addProperty(prop, i);
}
} else {
/* initialize list with nulls */
for (int pos = 6; --pos >= 0;) {
newProp.addProperty(null, pos);
}
prop = checkEnumValues(specVal);
if (prop == null) {
/* not an enum:
* value should consist at least of font-size and font-family
* separated by a space
* mind the possible spaces from quoted font-family names
*/
int spaceIndex = value.indexOf(' ');
int quoteIndex = (value.indexOf('\'') == -1)
? value.indexOf('\"') : value.indexOf('\'');
if (spaceIndex == -1
|| (quoteIndex != -1 && spaceIndex > quoteIndex)) {
/* no spaces or first space appears after the first
* single/double quote, so malformed value string
try {
FontShorthandProperty newProp = new FontShorthandProperty();
newProp.setSpecifiedValue(value);
String specVal = value;
Property prop = null;
if ("inherit".equals(specVal)) {
/* fill the list with the individual properties from the parent */
for (int i = PROP_IDS.length; --i >= 0;) {
prop = propertyList.getFromParent(PROP_IDS[i]);
newProp.addProperty(prop, i);
}
} else {
/* initialize list with nulls */
for (int pos = PROP_IDS.length; --pos >= 0;) {
newProp.addProperty(null, pos);
}
prop = checkEnumValues(specVal);
if (prop == null) {
/* not an enum:
* value should consist at least of font-size and font-family
* separated by a space
* mind the possible spaces from quoted font-family names
*/
throw new PropertyException("Invalid property value: "
+ "font=\"" + value + "\"");
}
PropertyMaker m = null;
int fromIndex = spaceIndex + 1;
int toIndex = specVal.length();
/* at least one space that appears before the first
* single/double quote, so extract the individual properties
*/
boolean fontFamilyParsed = false;
int commaIndex = value.indexOf(',');
while (!fontFamilyParsed) {
/* value contains a (list of) possibly quoted
* font-family name(s)
int spaceIndex = value.indexOf(' ');
int quoteIndex = (value.indexOf('\'') == -1)
? value.indexOf('\"') : value.indexOf('\'');
if (spaceIndex == -1
|| (quoteIndex != -1 && spaceIndex > quoteIndex)) {
/* no spaces or first space appears after the first
* single/double quote, so malformed value string
*/
throw new PropertyException("Invalid property value: "
+ "font=\"" + value + "\"");
}
PropertyMaker m = null;
int fromIndex = spaceIndex + 1;
int toIndex = specVal.length();
/* at least one space that appears before the first
* single/double quote, so extract the individual properties
*/
if (commaIndex == -1) {
/* no list, just a single name
* (or first name in the list)
boolean fontFamilyParsed = false;
int commaIndex = value.indexOf(',');
while (!fontFamilyParsed) {
/* value contains a (list of) possibly quoted
* font-family name(s)
*/
if (quoteIndex != -1) {
/* a single name, quoted
if (commaIndex == -1) {
/* no list, just a single name
* (or first name in the list)
*/
fromIndex = quoteIndex;
}
m = FObj.getPropertyMakerFor(PROP_IDS[1]);
prop = m.make(propertyList, specVal.substring(fromIndex), fo);
newProp.addProperty(prop, 1);
fontFamilyParsed = true;
} else {
if (quoteIndex != -1 && quoteIndex < commaIndex) {
/* a quoted font-family name as first name
* in the comma-separated list
* fromIndex = index of the first quote
*/
fromIndex = quoteIndex;
quoteIndex = -1;
if (quoteIndex != -1) {
/* a single name, quoted
*/
fromIndex = quoteIndex;
}
m = FObj.getPropertyMakerFor(PROP_IDS[1]);
prop = m.make(propertyList, specVal.substring(fromIndex), fo);
newProp.addProperty(prop, 1);
fontFamilyParsed = true;
} else {
fromIndex = value.lastIndexOf(' ', commaIndex) + 1;
if (quoteIndex != -1 && quoteIndex < commaIndex) {
/* a quoted font-family name as first name
* in the comma-separated list
* fromIndex = index of the first quote
*/
fromIndex = quoteIndex;
quoteIndex = -1;
} else {
fromIndex = value.lastIndexOf(' ', commaIndex) + 1;
}
commaIndex = -1;
}
commaIndex = -1;
}
}
toIndex = fromIndex - 1;
fromIndex = value.lastIndexOf(' ', toIndex - 1) + 1;
value = specVal.substring(fromIndex, toIndex);
int slashIndex = value.indexOf('/');
String fontSize = value.substring(0,
(slashIndex == -1) ? value.length() : slashIndex);
m = FObj.getPropertyMakerFor(PROP_IDS[0]);
prop = m.make(propertyList, fontSize, fo);
/* need to make sure subsequent call to LineHeightPropertyMaker.make()
* doesn't generate the default font-size property...
*/
propertyList.putExplicit(PROP_IDS[0], prop);
newProp.addProperty(prop, 0);
if (slashIndex != -1) {
/* line-height */
String lineHeight = value.substring(slashIndex + 1);
m = FObj.getPropertyMakerFor(PROP_IDS[2]);
prop = m.make(propertyList, lineHeight, fo);
newProp.addProperty(prop, 2);
}
if (fromIndex != 0) {
toIndex = fromIndex - 1;
value = specVal.substring(0, toIndex);
fromIndex = 0;
spaceIndex = value.indexOf(' ');
do {
toIndex = (spaceIndex == -1) ? value.length() : spaceIndex;
String val = value.substring(fromIndex, toIndex);
for (int i = 6; --i >= 3;) {
if (newProp.list.get(i) == null) {
/* not set */
m = FObj.getPropertyMakerFor(PROP_IDS[i]);
val = m.checkValueKeywords(val);
prop = m.checkEnumValues(val);
if (prop != null) {
newProp.addProperty(prop, i);
fromIndex = value.lastIndexOf(' ', toIndex - 1) + 1;
value = specVal.substring(fromIndex, toIndex);
int slashIndex = value.indexOf('/');
String fontSize = value.substring(0,
(slashIndex == -1) ? value.length() : slashIndex);
m = FObj.getPropertyMakerFor(PROP_IDS[0]);
prop = m.make(propertyList, fontSize, fo);
/* need to make sure subsequent call to LineHeightPropertyMaker.make()
* doesn't generate the default font-size property...
*/
propertyList.putExplicit(PROP_IDS[0], prop);
newProp.addProperty(prop, 0);
if (slashIndex != -1) {
/* line-height */
String lineHeight = value.substring(slashIndex + 1);
m = FObj.getPropertyMakerFor(PROP_IDS[2]);
prop = m.make(propertyList, lineHeight, fo);
newProp.addProperty(prop, 2);
}
if (fromIndex != 0) {
toIndex = fromIndex - 1;
value = specVal.substring(0, toIndex);
fromIndex = 0;
spaceIndex = value.indexOf(' ');
do {
toIndex = (spaceIndex == -1) ? value.length() : spaceIndex;
String val = value.substring(fromIndex, toIndex);
for (int i = 6; --i >= 3;) {
if (newProp.list.get(i) == null) {
/* not set */
m = FObj.getPropertyMakerFor(PROP_IDS[i]);
val = m.checkValueKeywords(val);
prop = m.checkEnumValues(val);
if (prop != null) {
newProp.addProperty(prop, i);
}
}
}
}
fromIndex = toIndex + 1;
spaceIndex = value.indexOf(' ', fromIndex);
} while (toIndex != value.length());
fromIndex = toIndex + 1;
spaceIndex = value.indexOf(' ', fromIndex);
} while (toIndex != value.length());
}
} else {
//TODO: implement enum values
log.warn("Enum values other than \"inherit\""
+ " not yet supported for the font shorthand.");
return null;
}
} else {
//TODO: implement enum values
log.warn("Enum values other than \"inherit\""
+ " not yet supported for the font shorthand.");
return null;
}
}
if (newProp.list.get(0) == null || newProp.list.get(1) == null) {
throw new PropertyException("Invalid property value: "
+ "font-size and font-family are required for the font shorthand"
+ "\nfont=" + value);
}
return newProp;
if (newProp.list.get(0) == null || newProp.list.get(1) == null) {
throw new PropertyException("Invalid property value: "
+ "font-size and font-family are required for the font shorthand"
+ "\nfont=\"" + value + "\"");
}
return newProp;
} catch (PropertyException pe) {
pe.setLocator(propertyList.getFObj().getLocator());
pe.setPropertyName(getName());
throw pe;
}
}

}
private void addProperty(Property prop, int pos) {

+ 5
- 0
status.xml Näytä tiedosto

@@ -28,6 +28,11 @@

<changes>
<release version="FOP Trunk">
<action context="Code" dev="AD" type="fix">
Deferred property resolution for markers until they are actually retrieved,
which leads to percentages and relative font-sizes now getting the correct
values. Also deferred white-space-handling for markers.
</action>
<action context="Code" dev="JM" type="update">
Changed the way overflowing pages are handled. The overflow property on region-body
is now used to define the behaviour.

+ 98
- 0
test/fotree/testcases/table-cell_column-number_rowspan_bug38397.fo Näytä tiedosto

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"
xmlns:test="http://xmlgraphics.apache.org/fop/test">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%" border-collapse="separate">
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-column column-width="proportional-column-width(2)"/>
<fo:table-column column-width="proportional-column-width(2)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell number-rows-spanned="3" number-columns-spanned="2" display-align="center" border="solid 0.5pt">
<test:assert property="column-number" expected="1" />
<fo:block>cell1</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="2" display-align="center" border="solid 0.5pt">
<test:assert property="column-number" expected="3" />
<fo:block>cell2</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 0.5pt">
<test:assert property="column-number" expected="4" />
<fo:block>cell3</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row background-color="yellow">
<fo:table-cell border="solid 0.5pt">
<test:assert property="column-number" expected="4" />
<fo:block>cell4</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell number-rows-spanned="2" display-align="center" border="solid 0.5pt">
<test:assert property="column-number" expected="3" />
<fo:block>cell5</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 0.5pt">
<test:assert property="column-number" expected="4" />
<fo:block>cell6</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row background-color="yellow">
<fo:table-cell number-rows-spanned="3" display-align="center" border="solid 0.5pt">
<test:assert property="column-number" expected="1" />
<fo:block>cell7</fo:block>
</fo:table-cell>
<fo:table-cell number-rows-spanned="3" display-align="center" border="solid 0.5pt">
<test:assert property="column-number" expected="2" />
<fo:block>cell8</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 0.5pt">
<test:assert property="column-number" expected="4" />
<fo:block>cell9</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell number-rows-spanned="2" display-align="center" border="solid 0.5pt">
<test:assert property="column-number" expected="3" />
<fo:block>cell10</fo:block>
</fo:table-cell>
<fo:table-cell border="solid 0.5pt">
<test:assert property="column-number" expected="4" />
<fo:block>cell11</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row background-color="yellow">
<fo:table-cell border="solid 0.5pt">
<test:assert property="column-number" expected="4" />
<fo:block>cell12</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 2
- 15
test/layoutengine/disabled-testcases.xml Näytä tiedosto

@@ -194,20 +194,6 @@
<description>Keep-with-previous doesn't work inside tables and
lists, yet.</description>
</testcase>
<testcase>
<name>Whitespace around markers is not handled correctly</name>
<file>marker_white-space-collapse.xml</file>
<description>Whitespace within markers is handled according to the value of
the white-space-collapse property in the context of the fo:marker and not according to
the value of the property in the fo:retrieve-marker context.</description>
</testcase>
<testcase>
<name>Relative font sizes within markers are not handled correctly</name>
<file>marker_font-size.xml</file>
<description>Relative font sizes within markers are evaluated according to the
font size in the fo:marker context and not the font size in the fo:retrieve-marker
context.</description>
</testcase>
<testcase>
<name>Page breaking doesn't deal with IPD changes</name>
<file>page-breaking_4.xml</file>
@@ -334,7 +320,8 @@
<testcase>
<name>table-cell empty area with marker.xml</name>
<file>table-cell_empty_area_with_marker.xml</file>
<description>A table-cell producing an empty area does currently not add any markers to a page. See TODO entry in AreaAdditionUtil.</description>
<description>A table-cell producing an empty area does currently not add any markers to a page.
See TODO entry in AreaAdditionUtil.</description>
</testcase>
<testcase>
<name>Border conditionality on table</name>

+ 7
- 4
test/layoutengine/standard-testcases/marker_font-size.xml Näytä tiedosto

@@ -37,7 +37,9 @@
<fo:page-sequence master-reference="normal">
<fo:static-content flow-name="xsl-region-before">
<fo:block background-color="yellow" font-size="16pt">
1. Marker <fo:retrieve-marker retrieve-class-name="m1" />
1. Marker <fo:retrieve-marker retrieve-class-name="m1"
retrieve-boundary="page"
retrieve-position="first-starting-within-page" />
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
@@ -46,7 +48,7 @@
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block background-color="red" white-space-collapse="false">
<fo:block background-color="red">
<fo:marker marker-class-name="m1">
<fo:block font-size=".5em">
First marker with small font
@@ -65,8 +67,9 @@
</fo:root>
</fo>
<checks>
<!-- font-size relative to the retrieve-marker context? -->
<eval expected="8000" xpath="//regionBefore/block[1]/block/lineArea/text/@font-size"/>
<eval expected="20000" xpath="//regionBefore/block[1]/block/lineArea/text/@font-size"/>
<eval expected="20000" xpath="//regionAfter/block[1]/block/lineArea/text/@font-size"/>
</checks>
</testcase>

+ 106
- 0
test/layoutengine/standard-testcases/marker_percentage-resolution.xml Näytä tiedosto

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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$ -->
<testcase>
<info>
<p>
This test checks markers and percentage resolution:
Percentages should be evaluated in the context in which the marker is
retrieved.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="2in">
<fo:region-body margin="0.5in 0"/>
<fo:region-after extent="0.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="end" background-color="yellow">
<fo:retrieve-marker retrieve-class-name="test"
retrieve-boundary="page"
retrieve-position="last-ending-within-page"/>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:table table-layout="fixed" width="100%">
<fo:table-column number-columns-repeated="2"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:marker marker-class-name="test">
<fo:table table-layout="fixed" width="100%">
<fo:table-column number-columns-repeated="2"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Subtotal</fo:block>
</fo:table-cell>
<fo:table-cell text-align="end">
<fo:block>29.95</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:marker>
<fo:block>MemoryStick 32MB</fo:block>
</fo:table-cell>
<fo:table-cell text-align="end">
<fo:block>29.95</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:marker marker-class-name="test">
<fo:block-container inline-progression-dimension="75%">
<fo:block>Test</fo:block>
</fo:block-container>
<fo:table table-layout="fixed" width="100%">
<fo:table-column number-columns-repeated="2"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Subtotal</fo:block>
</fo:table-cell>
<fo:table-cell text-align="end">
<fo:block>49.95</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:marker>
<fo:block>Geek-Tool</fo:block>
</fo:table-cell>
<fo:table-cell text-align="end">
<fo:block>20.00</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="270000" xpath="//regionAfter/block[1]/block[1]/@ipd"/>
<eval expected="360000" xpath="//regionAfter/block[1]/block[2]/@ipd"/>
</checks>
</testcase>

+ 7
- 6
test/layoutengine/standard-testcases/marker_white-space-collapse.xml Näytä tiedosto

@@ -52,7 +52,7 @@
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block background-color="red" white-space-collapse="false">
<fo:block background-color="red">
<fo:marker marker-class-name="m1">
<fo:block>
First marker with whitespace around
@@ -71,11 +71,12 @@
</fo:root>
</fo>
<checks>
<!-- These checks do not have the correct values -->
<eval expected="1" xpath="count(//regionBefore/block[1]/block/lineArea/text/space)"/>
<eval expected="4" xpath="count(//regionBefore/block[2]/block/lineArea/text/space)"/>
<!-- preserve inter-word whitespace in the first block,
collapse them in the second -->
<eval expected="9" xpath="count(//regionBefore/block[1]/block[1]/lineArea[1]/text/space)"/>
<eval expected="4" xpath="count(//regionBefore/block[2]/block[1]/lineArea[1]/text/space)"/>

<eval expected="1" xpath="count(//regionAfter/block[1]/block/lineArea/text/space)"/>
<eval expected="4" xpath="count(//regionAfter/block[2]/block/lineArea/text/space)"/>
<eval expected="8" xpath="count(//regionAfter/block[1]/block[1]/lineArea[1]/text/space)"/>
<eval expected="4" xpath="count(//regionAfter/block[2]/block[1]/lineArea[1]/text/space)"/>
</checks>
</testcase>

Loading…
Peruuta
Tallenna