git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1391502 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.fo.flow.Marker; | import org.apache.fop.fo.flow.Marker; | ||||
import org.apache.fop.fo.Constants; | |||||
import org.apache.fop.fo.flow.AbstractRetrieveMarker; | |||||
import org.apache.fop.fo.flow.Marker; | |||||
import org.apache.fop.fo.flow.Markers; | |||||
import org.apache.fop.fo.pagination.SimplePageMaster; | import org.apache.fop.fo.pagination.SimplePageMaster; | ||||
import org.apache.fop.traits.WritingModeTraitsGetter; | import org.apache.fop.traits.WritingModeTraitsGetter; | ||||
private Map<String, List<PageViewport>> pendingResolved = null; | private Map<String, List<PageViewport>> pendingResolved = null; | ||||
// hashmap of markers for this page | |||||
// start and end are added by the fo that contains the markers | |||||
private Map<String, Marker> markerFirstStart = null; | |||||
private Map<String, Marker> markerLastStart = null; | |||||
private Map<String, Marker> markerFirstAny = null; | |||||
private Map<String, Marker> markerLastEnd = null; | |||||
private Map<String, Marker> markerLastAny = null; | |||||
private Markers pageMarkers; | |||||
/** | /** | ||||
* logging instance | * logging instance | ||||
} | } | ||||
/** | /** | ||||
* Add the markers for this page. | |||||
* Only the required markers are kept. | |||||
* For "first-starting-within-page" it adds the markers | |||||
* that are starting only if the marker class name is not | |||||
* already added. | |||||
* For "first-including-carryover" it adds any starting marker | |||||
* if the marker class name is not already added. | |||||
* For "last-starting-within-page" it adds all marks that | |||||
* are starting, replacing earlier markers. | |||||
* For "last-ending-within-page" it adds all markers that | |||||
* are ending, replacing earlier markers. | |||||
* | |||||
* Should this logic be placed in the Page layout manager. | |||||
* Register the markers for this page. | |||||
* | * | ||||
* @param marks the map of markers to add | * @param marks the map of markers to add | ||||
* @param starting if the area being added is starting or ending | * @param starting if the area being added is starting or ending | ||||
* @param isfirst if the area being added has is-first trait | * @param isfirst if the area being added has is-first trait | ||||
* @param islast if the area being added has is-last trait | * @param islast if the area being added has is-last trait | ||||
*/ | */ | ||||
public void addMarkers(Map<String, Marker> marks, boolean starting, | |||||
boolean isfirst, boolean islast) { | |||||
if (marks == null) { | |||||
return; | |||||
} | |||||
if (log.isDebugEnabled()) { | |||||
log.debug("--" + marks.keySet() + ": " | |||||
+ (starting ? "starting" : "ending") | |||||
+ (isfirst ? ", first" : "") | |||||
+ (islast ? ", last" : "")); | |||||
} | |||||
// at the start of the area, register is-first and any areas | |||||
if (starting) { | |||||
if (isfirst) { | |||||
if (markerFirstStart == null) { | |||||
markerFirstStart = new HashMap<String, Marker>(); | |||||
} | |||||
if (markerFirstAny == null) { | |||||
markerFirstAny = new HashMap<String, Marker>(); | |||||
} | |||||
// first on page: only put in new values, leave current | |||||
for (String key : marks.keySet()) { | |||||
if (!markerFirstStart.containsKey(key)) { | |||||
markerFirstStart.put(key, marks.get(key)); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " | |||||
+ "Adding marker " + key + " to FirstStart"); | |||||
} | |||||
} | |||||
if (!markerFirstAny.containsKey(key)) { | |||||
markerFirstAny.put(key, marks.get(key)); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " | |||||
+ "Adding marker " + key + " to FirstAny"); | |||||
} | |||||
} | |||||
} | |||||
if (markerLastStart == null) { | |||||
markerLastStart = new HashMap<String, Marker>(); | |||||
} | |||||
// last on page: replace all | |||||
markerLastStart.putAll(marks); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " | |||||
+ "Adding all markers to LastStart"); | |||||
} | |||||
} else { | |||||
if (markerFirstAny == null) { | |||||
markerFirstAny = new HashMap<String, Marker>(); | |||||
} | |||||
// first on page: only put in new values, leave current | |||||
for (String key : marks.keySet()) { | |||||
if (!markerFirstAny.containsKey(key)) { | |||||
markerFirstAny.put(key, marks.get(key)); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " | |||||
+ "Adding marker " + key + " to FirstAny"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
// at the end of the area, register is-last and any areas | |||||
if (islast) { | |||||
if (markerLastEnd == null) { | |||||
markerLastEnd = new HashMap<String, Marker>(); | |||||
} | |||||
// last on page: replace all | |||||
markerLastEnd.putAll(marks); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " | |||||
+ "Adding all markers to LastEnd"); | |||||
} | |||||
} | |||||
if (markerLastAny == null) { | |||||
markerLastAny = new HashMap<String, Marker>(); | |||||
} | |||||
// last on page: replace all | |||||
markerLastAny.putAll(marks); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " | |||||
+ "Adding all markers to LastAny"); | |||||
} | |||||
public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { | |||||
if (pageMarkers == null) { | |||||
pageMarkers = new Markers(); | |||||
} | } | ||||
pageMarkers.register(marks, starting, isfirst, islast); | |||||
} | } | ||||
/** | /** | ||||
* Get a marker from this page. | |||||
* Resolve a marker from this page. | |||||
* This will retrieve a marker with the class name | * This will retrieve a marker with the class name | ||||
* and position. | * and position. | ||||
* | * | ||||
* @param pos the position to retrieve | * @param pos the position to retrieve | ||||
* @return Object the marker found or null | * @return Object the marker found or null | ||||
*/ | */ | ||||
public Marker getMarker(String name, int pos) { | |||||
Marker mark = null; | |||||
String posName = null; | |||||
switch (pos) { | |||||
case EN_FSWP: | |||||
if (markerFirstStart != null) { | |||||
mark = markerFirstStart.get(name); | |||||
posName = "FSWP"; | |||||
} | |||||
if (mark == null && markerFirstAny != null) { | |||||
mark = markerFirstAny.get(name); | |||||
posName = "FirstAny after " + posName; | |||||
} | |||||
break; | |||||
case EN_FIC: | |||||
if (markerFirstAny != null) { | |||||
mark = markerFirstAny.get(name); | |||||
posName = "FIC"; | |||||
} | |||||
break; | |||||
case EN_LSWP: | |||||
if (markerLastStart != null) { | |||||
mark = markerLastStart.get(name); | |||||
posName = "LSWP"; | |||||
} | |||||
if (mark == null && markerLastAny != null) { | |||||
mark = markerLastAny.get(name); | |||||
posName = "LastAny after " + posName; | |||||
} | |||||
break; | |||||
case EN_LEWP: | |||||
if (markerLastEnd != null) { | |||||
mark = markerLastEnd.get(name); | |||||
posName = "LEWP"; | |||||
} | |||||
if (mark == null && markerLastAny != null) { | |||||
mark = markerLastAny.get(name); | |||||
posName = "LastAny after " + posName; | |||||
} | |||||
break; | |||||
default: | |||||
assert false; | |||||
} | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name | |||||
+ " at position " + posName); | |||||
public Marker resolveMarker(AbstractRetrieveMarker rm) { | |||||
if (pageMarkers == null) { | |||||
return null; | |||||
} | } | ||||
return mark; | |||||
return pageMarkers.resolve(rm); | |||||
} | } | ||||
/** Dumps the current marker data to the logger. */ | /** Dumps the current marker data to the logger. */ | ||||
public void dumpMarkers() { | public void dumpMarkers() { | ||||
if (log.isTraceEnabled()) { | |||||
log.trace("FirstAny: " + this.markerFirstAny); | |||||
log.trace("FirstStart: " + this.markerFirstStart); | |||||
log.trace("LastAny: " + this.markerLastAny); | |||||
log.trace("LastEnd: " + this.markerLastEnd); | |||||
log.trace("LastStart: " + this.markerLastStart); | |||||
if (pageMarkers != null) { | |||||
pageMarkers.dump(); | |||||
} | } | ||||
} | } | ||||
int EN_BT = 204; // bottom to top | int EN_BT = 204; // bottom to top | ||||
/** Enumeration constant */ | /** Enumeration constant */ | ||||
int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode | int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode | ||||
/** Enumeration constant -- for fo:retrieve-table-marker */ | |||||
int EN_FIRST_INCLUDING_CARRYOVER = 206; | |||||
/** Number of enumeration constants defined */ | /** Number of enumeration constants defined */ | ||||
int ENUM_COUNT = 205; | |||||
int ENUM_COUNT = 206; | |||||
} | } |
getFOValidationEventProducer().invalidChild(this, parentName, qn, ruleViolated, loc); | getFOValidationEventProducer().invalidChild(this, parentName, qn, ruleViolated, loc); | ||||
} | } | ||||
/** | |||||
* Helper function to return "not supported child" exceptions. Note that the child is valid, just not | |||||
* supported yet by FOP. | |||||
* | |||||
* @param loc org.xml.sax.Locator object of the error (*not* parent node) | |||||
* @param nsURI namespace URI of incoming invalid node | |||||
* @param lName local name (i.e., no prefix) of incoming node | |||||
* @throws ValidationException the validation error provoked by the method call | |||||
*/ | |||||
protected void notSupportedChildError(Locator loc, String nsURI, String lName) throws ValidationException { | |||||
getFOValidationEventProducer().notSupportedChild(this, getName(), new QName(nsURI, lName), loc); | |||||
} | |||||
/** | /** | ||||
* Helper function to throw an error caused by missing mandatory child elements. | * Helper function to throw an error caused by missing mandatory child elements. | ||||
* (e.g., <code>fo:layout-master-set</code> not having any <code>fo:page-master</code> | * (e.g., <code>fo:layout-master-set</code> not having any <code>fo:page-master</code> |
m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE); | m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE); | ||||
m.setInherited(false); | m.setInherited(false); | ||||
m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING")); | m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING")); | ||||
m.addEnum("first-including-carryover", getEnumProperty(EN_FIC, "FIC")); | |||||
m.addEnum("first-including-carryover", | |||||
getEnumProperty(EN_FIRST_INCLUDING_CARRYOVER, "FIRST_INCLUDING_CARRYOVER")); | |||||
m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING")); | m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING")); | ||||
m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING")); | m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING")); | ||||
m.setDefault("first-starting"); | m.setDefault("first-starting"); | ||||
m.setInherited(false); | m.setInherited(false); | ||||
m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE")); | m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE")); | ||||
m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT")); | m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT")); | ||||
m.addEnum("page", getEnumProperty(EN_DOCUMENT, "PAGE")); | |||||
m.addEnum("page", getEnumProperty(EN_PAGE, "PAGE")); | |||||
m.setDefault("table"); | m.setDefault("table"); | ||||
addPropertyMaker("retrieve-boundary-within-table", m); | addPropertyMaker("retrieve-boundary-within-table", m); | ||||
} | } |
void invalidChild(Object source, String elementName, QName offendingNode, String ruleViolated, | void invalidChild(Object source, String elementName, QName offendingNode, String ruleViolated, | ||||
Locator loc) throws ValidationException; | Locator loc) throws ValidationException; | ||||
/** | |||||
* A valid but not yet supported child was encountered. | |||||
* | |||||
* @param source the event source | |||||
* @param elementName the name of the context node | |||||
* @param offendingNode the offending node | |||||
* @param loc the location of the error or null | |||||
* @throws ValidationException the validation error provoked by the method call | |||||
*/ | |||||
void notSupportedChild(Object source, String elementName, QName offendingNode, Locator loc) | |||||
throws ValidationException; | |||||
/** | /** | ||||
* A required child element is missing. | * A required child element is missing. | ||||
* @param source the event source | * @param source the event source |
<message key="tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message> | <message key="tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message> | ||||
<message key="nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message> | <message key="nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message> | ||||
<message key="invalidChild">"{offendingNode}" is not a valid child of "{elementName}"![ {ruleViolated,lookup}]{{locator}}</message> | <message key="invalidChild">"{offendingNode}" is not a valid child of "{elementName}"![ {ruleViolated,lookup}]{{locator}}</message> | ||||
<message key="notSupportedChild">"{offendingNode}" as a child of "{elementName}" is not supported yet!{{locator}}</message> | |||||
<message key="missingChildElement">"{elementName}" is missing child elements.[ Required content model: {contentModel}]{{locator}}</message> | <message key="missingChildElement">"{elementName}" is missing child elements.[ Required content model: {contentModel}]{{locator}}</message> | ||||
<message key="missingProperty">Element "{elementName}" is missing required property "{propertyName}"!{{locator}}</message> | <message key="missingProperty">Element "{elementName}" is missing required property "{propertyName}"!{{locator}}</message> | ||||
<message key="idNotUnique">Property ID "{id}" (found on "{elementName}") previously used; ID values must be unique within a document!{severity,equals,EventSeverity:FATAL,, Any reference to it will be considered a reference to the first occurrence in the document.}{{locator}}</message> | <message key="idNotUnique">Property ID "{id}" (found on "{elementName}") previously used; ID values must be unique within a document!{severity,equals,EventSeverity:FATAL,, Any reference to it will be considered a reference to the first occurrence in the document.}{{locator}}</message> |
package org.apache.fop.fo; | package org.apache.fop.fo; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.HashMap; | |||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.ListIterator; | import java.util.ListIterator; | ||||
import org.apache.fop.apps.FOPException; | import org.apache.fop.apps.FOPException; | ||||
import org.apache.fop.fo.extensions.ExtensionAttachment; | import org.apache.fop.fo.extensions.ExtensionAttachment; | ||||
import org.apache.fop.fo.flow.Marker; | import org.apache.fop.fo.flow.Marker; | ||||
import org.apache.fop.fo.flow.table.TableCell; | |||||
import org.apache.fop.fo.properties.PropertyMaker; | import org.apache.fop.fo.properties.PropertyMaker; | ||||
/** | /** | ||||
private boolean isOutOfLineFODescendant = false; | private boolean isOutOfLineFODescendant = false; | ||||
/** Markers added to this element. */ | /** Markers added to this element. */ | ||||
private Map markers = null; | |||||
private Map<String, Marker> markers; | |||||
private int bidiLevel = -1; | private int bidiLevel = -1; | ||||
} | } | ||||
} | } | ||||
if (markers == null) { | if (markers == null) { | ||||
markers = new java.util.HashMap(); | |||||
markers = new HashMap<String, Marker>(); | |||||
} | } | ||||
if (!markers.containsKey(mcname)) { | if (!markers.containsKey(mcname)) { | ||||
markers.put(mcname, marker); | markers.put(mcname, marker); | ||||
/** | /** | ||||
* @return the collection of Markers attached to this object | * @return the collection of Markers attached to this object | ||||
*/ | */ | ||||
public Map getMarkers() { | |||||
public Map<String, Marker> getMarkers() { | |||||
return markers; | return markers; | ||||
} | } | ||||
int found = 1; | int found = 1; | ||||
FONode temp = getParent(); | FONode temp = getParent(); | ||||
while (temp != null) { | while (temp != null) { | ||||
if (temp instanceof TableCell && (ancestorID == FO_TABLE_HEADER || ancestorID == FO_TABLE_FOOTER)) { | |||||
// note that if the retrieve-table-marker is not in a table-header/footer an exception is | |||||
// thrown, so no need to reset this flag in that case | |||||
((TableCell) temp).flagAsHavingRetrieveTableMarker(); | |||||
} | |||||
if (temp.getNameId() == ancestorID) { | if (temp.getNameId() == ancestorID) { | ||||
return found; | return found; | ||||
} | } |
private String retrieveClassName; | private String retrieveClassName; | ||||
private int position; | |||||
private String positionLabel; | |||||
private int boundary; | |||||
private String boundaryLabel; | |||||
/** | /** | ||||
* Create a new AbstractRetrieveMarker instance that | * Create a new AbstractRetrieveMarker instance that | ||||
* is a child of the given {@link FONode} | * is a child of the given {@link FONode} | ||||
return this.retrieveClassName; | return this.retrieveClassName; | ||||
} | } | ||||
protected void setBoundaryLabel(String label) { | |||||
this.boundaryLabel = label; | |||||
} | |||||
protected void setPositionLabel(String label) { | |||||
this.positionLabel = label; | |||||
} | |||||
public String getBoundaryLabel() { | |||||
return this.boundaryLabel; | |||||
} | |||||
public String getPositionLabel() { | |||||
return this.positionLabel; | |||||
} | |||||
protected void setPosition(int position) { | |||||
this.position = position; | |||||
} | |||||
protected void setBoundary(int boundary) { | |||||
this.boundary = boundary; | |||||
} | |||||
public int getPosition() { | |||||
return this.position; | |||||
} | |||||
public int getBoundary() { | |||||
return this.boundary; | |||||
} | |||||
public abstract String getLocalName(); | |||||
public abstract int getNameId(); | |||||
public void changePositionTo(int position) { | |||||
this.position = position; | |||||
} | |||||
} | } |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.fo.flow; | |||||
import java.util.HashMap; | |||||
import java.util.Iterator; | |||||
import java.util.Map; | |||||
import org.apache.commons.logging.Log; | |||||
import org.apache.commons.logging.LogFactory; | |||||
import org.apache.fop.fo.Constants; | |||||
/** | |||||
* A class to register and resolve markers. | |||||
*/ | |||||
public final class Markers { | |||||
// IsAny means either IsFirst or IsLast | |||||
private Map<String, Marker> firstQualifyingIsFirst; | |||||
private Map<String, Marker> firstQualifyingIsAny; | |||||
private Map<String, Marker> lastQualifyingIsFirst; | |||||
private Map<String, Marker> lastQualifyingIsLast; | |||||
private Map<String, Marker> lastQualifyingIsAny; | |||||
private static Log log = LogFactory.getLog(Markers.class); | |||||
/** | |||||
* Registers a marker with the position traits set. | |||||
* Only the required markers are kept. | |||||
* For "first-starting-within-page" it adds the markers | |||||
* that are starting only if the marker class name is not | |||||
* already added. | |||||
* For "first-including-carryover" it adds any starting marker | |||||
* if the marker class name is not already added. | |||||
* For "last-starting-within-page" it adds all marks that | |||||
* are starting, replacing earlier markers. | |||||
* For "last-ending-within-page" it adds all markers that | |||||
* are ending, replacing earlier markers. | |||||
* | |||||
* @param marks a map of markers to register | |||||
* @param starting whether the registration happens at the start (true) or end (false) the the area | |||||
* @param isfirst whether it is the first area of the parent LM | |||||
* @param islast whether it is the last area of the parent LM | |||||
*/ | |||||
public void register(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { | |||||
// TODO: find way to put the page number in the log tracing | |||||
if (marks == null) { | |||||
return; | |||||
} | |||||
if (log.isDebugEnabled()) { | |||||
log.debug("--" + marks.keySet() + ": " + (starting ? "starting" : "ending") | |||||
+ (isfirst ? ", first" : "") + (islast ? ", last" : "")); | |||||
} | |||||
if (starting) { | |||||
// at the start of the area, register is-first and any areas | |||||
if (firstQualifyingIsAny == null) { | |||||
firstQualifyingIsAny = new HashMap<String, Marker>(); | |||||
} | |||||
if (isfirst) { | |||||
if (firstQualifyingIsFirst == null) { | |||||
firstQualifyingIsFirst = new HashMap<String, Marker>(); | |||||
} | |||||
// first on scope: only put in new values, leave current | |||||
for (Iterator<String> iter = marks.keySet().iterator(); iter.hasNext();) { | |||||
String key = iter.next(); | |||||
if (!firstQualifyingIsFirst.containsKey(key)) { | |||||
firstQualifyingIsFirst.put(key, marks.get(key)); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("Adding marker " + key + " to firstQualifyingIsFirst"); | |||||
} | |||||
} | |||||
if (!firstQualifyingIsAny.containsKey(key)) { | |||||
firstQualifyingIsAny.put(key, marks.get(key)); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("Adding marker " + key + " to firstQualifyingIsAny"); | |||||
} | |||||
} | |||||
} | |||||
if (lastQualifyingIsFirst == null) { | |||||
lastQualifyingIsFirst = new HashMap<String, Marker>(); | |||||
} | |||||
// last on scope: replace all | |||||
lastQualifyingIsFirst.putAll(marks); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("Adding all markers to LastStart"); | |||||
} | |||||
} else { | |||||
// first on scope: only put in new values, leave current | |||||
for (Iterator<String> iter = marks.keySet().iterator(); iter.hasNext();) { | |||||
String key = iter.next(); | |||||
if (!firstQualifyingIsAny.containsKey(key)) { | |||||
firstQualifyingIsAny.put(key, marks.get(key)); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("Adding marker " + key + " to firstQualifyingIsAny"); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
// at the end of the area, register is-last and any areas | |||||
if (islast) { | |||||
if (lastQualifyingIsLast == null) { | |||||
lastQualifyingIsLast = new HashMap<String, Marker>(); | |||||
} | |||||
// last on page: replace all | |||||
lastQualifyingIsLast.putAll(marks); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("Adding all markers to lastQualifyingIsLast"); | |||||
} | |||||
} | |||||
if (lastQualifyingIsAny == null) { | |||||
lastQualifyingIsAny = new HashMap<String, Marker>(); | |||||
} | |||||
// last on page: replace all | |||||
lastQualifyingIsAny.putAll(marks); | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("Adding all markers to lastQualifyingIsAny"); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Retrieves the best candidate marker for the given position. | |||||
* @param name the key used to register the marker | |||||
* @param pos the retrieval scope position | |||||
* @return a Marker instance | |||||
*/ | |||||
public Marker resolve(AbstractRetrieveMarker arm) { | |||||
Marker mark = null; | |||||
int pos = arm.getPosition(); | |||||
String name = arm.getRetrieveClassName(); | |||||
String posName = arm.getPositionLabel(); | |||||
String localName = arm.getLocalName(); | |||||
switch (pos) { | |||||
case Constants.EN_FSWP: // retrieve-marker | |||||
case Constants.EN_FIRST_STARTING: // retrieve-table-marker | |||||
if (firstQualifyingIsFirst != null) { | |||||
mark = firstQualifyingIsFirst.get(name); | |||||
} | |||||
if (mark == null && firstQualifyingIsAny != null) { | |||||
mark = firstQualifyingIsAny.get(name); | |||||
posName = "FirstAny after " + posName; | |||||
} | |||||
break; | |||||
case Constants.EN_FIC: // retrieve-marker | |||||
case Constants.EN_FIRST_INCLUDING_CARRYOVER: // retrieve-table-marker | |||||
if (firstQualifyingIsAny != null) { | |||||
mark = firstQualifyingIsAny.get(name); | |||||
} | |||||
break; | |||||
case Constants.EN_LSWP: // retrieve-marker | |||||
case Constants.EN_LAST_STARTING: // retrieve-table-marker | |||||
if (lastQualifyingIsFirst != null) { | |||||
mark = lastQualifyingIsFirst.get(name); | |||||
} | |||||
if (mark == null && lastQualifyingIsAny != null) { | |||||
mark = lastQualifyingIsAny.get(name); | |||||
posName = "LastAny after " + posName; | |||||
} | |||||
break; | |||||
case Constants.EN_LEWP: // retrieve-marker | |||||
case Constants.EN_LAST_ENDING: // retrieve-table-marker | |||||
if (lastQualifyingIsLast != null) { | |||||
mark = lastQualifyingIsLast.get(name); | |||||
} | |||||
if (mark == null && lastQualifyingIsAny != null) { | |||||
mark = lastQualifyingIsAny.get(name); | |||||
posName = "LastAny after " + posName; | |||||
} | |||||
break; | |||||
default: | |||||
throw new RuntimeException("Invalid position attribute in " + localName + "."); | |||||
} | |||||
if (log.isTraceEnabled()) { | |||||
// TODO: find way to put the page number here | |||||
log.trace(localName + ": name[" + name + "]; position [" + posName + "]"); | |||||
} | |||||
return mark; | |||||
} | |||||
/** Dumps the current marker data to the logger. */ | |||||
public void dump() { | |||||
if (log.isTraceEnabled()) { | |||||
log.trace("FirstAny: " + this.firstQualifyingIsAny); | |||||
log.trace("FirstStart: " + this.firstQualifyingIsFirst); | |||||
log.trace("LastAny: " + this.lastQualifyingIsAny); | |||||
log.trace("LastEnd: " + this.lastQualifyingIsLast); | |||||
log.trace("LastStart: " + this.lastQualifyingIsFirst); | |||||
} | |||||
} | |||||
} |
*/ | */ | ||||
public class RetrieveMarker extends AbstractRetrieveMarker { | public class RetrieveMarker extends AbstractRetrieveMarker { | ||||
// The value of properties relevant for fo:retrieve-marker. | |||||
private int retrievePosition; | |||||
private int retrieveBoundary; | |||||
// End of property values | |||||
/** | /** | ||||
* Create a new RetrieveMarker instance that is a | * Create a new RetrieveMarker instance that is a | ||||
* child of the given {@link FONode}. | * child of the given {@link FONode}. | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void bind(PropertyList pList) throws FOPException { | public void bind(PropertyList pList) throws FOPException { | ||||
super.bind(pList); | super.bind(pList); | ||||
this.retrievePosition = pList.get(PR_RETRIEVE_POSITION).getEnum(); | |||||
this.retrieveBoundary = pList.get(PR_RETRIEVE_BOUNDARY).getEnum(); | |||||
setPosition(pList.get(PR_RETRIEVE_POSITION).getEnum()); | |||||
setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION).getObject()); | |||||
setBoundary(pList.get(PR_RETRIEVE_BOUNDARY).getEnum()); | |||||
setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY).getObject()); | |||||
} | } | ||||
/** | /** | ||||
* {@link org.apache.fop.fo.Constants#EN_LEWP}. | * {@link org.apache.fop.fo.Constants#EN_LEWP}. | ||||
*/ | */ | ||||
public int getRetrievePosition() { | public int getRetrievePosition() { | ||||
return this.retrievePosition; | |||||
return getPosition(); | |||||
} | } | ||||
/** | /** | ||||
* Return the value for the <code>retrieve-boundary</code> | * Return the value for the <code>retrieve-boundary</code> | ||||
* property | * property | ||||
* @return the value for retrieve-boundary-within-table; one of | |||||
* @return the value for retrieve-boundary; one of | |||||
* {@link org.apache.fop.fo.Constants#EN_PAGE}, | * {@link org.apache.fop.fo.Constants#EN_PAGE}, | ||||
* {@link org.apache.fop.fo.Constants#EN_PAGE_SEQUENCE}, | * {@link org.apache.fop.fo.Constants#EN_PAGE_SEQUENCE}, | ||||
* {@link org.apache.fop.fo.Constants#EN_DOCUMENT}. | * {@link org.apache.fop.fo.Constants#EN_DOCUMENT}. | ||||
*/ | */ | ||||
public int getRetrieveBoundary() { | public int getRetrieveBoundary() { | ||||
return this.retrieveBoundary; | |||||
return getBoundary(); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ |
*/ | */ | ||||
public class RetrieveTableMarker extends AbstractRetrieveMarker { | public class RetrieveTableMarker extends AbstractRetrieveMarker { | ||||
// The value of properties relevant for fo:retrieve-table-marker. | |||||
private int retrievePositionWithinTable; | |||||
private int retrieveBoundaryWithinTable; | |||||
// end property values | |||||
/** | /** | ||||
* Create a new RetrieveTableMarker instance that is | * Create a new RetrieveTableMarker instance that is | ||||
* a child of the given {@link FONode}. | * a child of the given {@link FONode}. | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public void bind(PropertyList pList) throws FOPException { | public void bind(PropertyList pList) throws FOPException { | ||||
super.bind(pList); | super.bind(pList); | ||||
this.retrievePositionWithinTable | |||||
= pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum(); | |||||
this.retrieveBoundaryWithinTable | |||||
= pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum(); | |||||
setPosition(pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum()); | |||||
setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getObject()); | |||||
setBoundary(pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum()); | |||||
setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getObject()); | |||||
} | } | ||||
/** | /** | ||||
* {@link org.apache.fop.fo.Constants#EN_LAST_ENDING}. | * {@link org.apache.fop.fo.Constants#EN_LAST_ENDING}. | ||||
*/ | */ | ||||
public int getRetrievePositionWithinTable() { | public int getRetrievePositionWithinTable() { | ||||
return this.retrievePositionWithinTable; | |||||
return getPosition(); | |||||
} | } | ||||
/** | /** | ||||
* {@link org.apache.fop.fo.Constants#EN_PAGE}. | * {@link org.apache.fop.fo.Constants#EN_PAGE}. | ||||
*/ | */ | ||||
public int getRetrieveBoundaryWithinTable() { | public int getRetrieveBoundaryWithinTable() { | ||||
return this.retrieveBoundaryWithinTable; | |||||
return getBoundary(); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
public int getNameId() { | public int getNameId() { | ||||
return FO_RETRIEVE_TABLE_MARKER; | return FO_RETRIEVE_TABLE_MARKER; | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
public void clearChildNodes() { | |||||
super.clearChildNodes(); | |||||
this.currentTextNode = null; | |||||
this.lastFOTextProcessed = null; | |||||
} | |||||
} | } |
/** used for FO validation */ | /** used for FO validation */ | ||||
private boolean blockItemFound = false; | private boolean blockItemFound = false; | ||||
private boolean hasRetrieveTableMarker; | |||||
/** | /** | ||||
* Create a TableCell instance with the given {@link FONode} | * Create a TableCell instance with the given {@link FONode} | ||||
* as parent. | * as parent. | ||||
return FO_TABLE_CELL; | return FO_TABLE_CELL; | ||||
} | } | ||||
public void flagAsHavingRetrieveTableMarker() { | |||||
hasRetrieveTableMarker = true; | |||||
} | |||||
public boolean hasRetrieveTableMarker() { | |||||
return hasRetrieveTableMarker; | |||||
} | |||||
} | } |
getUserAgent().getEventBroadcaster()); | getUserAgent().getEventBroadcaster()); | ||||
eventProducer.noMixRowsAndCells(this, getName(), getLocator()); | eventProducer.noMixRowsAndCells(this, getName(), getLocator()); | ||||
} | } | ||||
} else if (localName.equals("retrieve-table-marker")) { | |||||
notSupportedChildError(loc, nsURI, localName); | |||||
} else { | } else { | ||||
invalidChildError(loc, nsURI, localName); | invalidChildError(loc, nsURI, localName); | ||||
} | } |
throw new UnsupportedOperationException("Not implemented"); | throw new UnsupportedOperationException("Not implemented"); | ||||
} | } | ||||
public void preserveChildrenAtEndOfLayout() { | |||||
} | |||||
public void recreateChildrenLMs() { | |||||
} | |||||
} | } |
import org.apache.fop.fo.FObj; | import org.apache.fop.fo.FObj; | ||||
import org.apache.fop.fo.flow.Marker; | import org.apache.fop.fo.flow.Marker; | ||||
import org.apache.fop.fo.flow.RetrieveMarker; | import org.apache.fop.fo.flow.RetrieveMarker; | ||||
import org.apache.fop.layoutmgr.table.TableLayoutManager; | |||||
/** | /** | ||||
* The base class for most LayoutManagers. | * The base class for most LayoutManagers. | ||||
private int lastGeneratedPosition = -1; | private int lastGeneratedPosition = -1; | ||||
private int smallestPosNumberChecked = Integer.MAX_VALUE; | private int smallestPosNumberChecked = Integer.MAX_VALUE; | ||||
private boolean preserveChildrenAtEndOfLayout; | |||||
/** | /** | ||||
* Abstract layout manager. | * Abstract layout manager. | ||||
*/ | */ | ||||
} | } | ||||
/** | /** | ||||
* Registers the FO's markers on the current PageViewport | |||||
* Registers the FO's markers on the current PageViewport, and if applicable on the parent TableLM. | |||||
* | * | ||||
* @param isStarting boolean indicating whether the markers qualify as 'starting' | * @param isStarting boolean indicating whether the markers qualify as 'starting' | ||||
* @param isFirst boolean indicating whether the markers qualify as 'first' | * @param isFirst boolean indicating whether the markers qualify as 'first' | ||||
* @param isLast boolean indicating whether the markers qualify as 'last' | * @param isLast boolean indicating whether the markers qualify as 'last' | ||||
*/ | */ | ||||
protected void addMarkersToPage(boolean isStarting, boolean isFirst, boolean isLast) { | |||||
protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) { | |||||
if (this.markers != null) { | if (this.markers != null) { | ||||
getCurrentPV().addMarkers( | |||||
getCurrentPV().registerMarkers( | |||||
this.markers, | this.markers, | ||||
isStarting, | isStarting, | ||||
isFirst, | isFirst, | ||||
isLast); | isLast); | ||||
possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); | |||||
} | } | ||||
} | } | ||||
notifyEndOfLayout(); | notifyEndOfLayout(); | ||||
/* References to the child LMs are no longer needed | |||||
*/ | |||||
childLMs = null; | |||||
curChildLM = null; | |||||
childLMiter = null; | |||||
if (!preserveChildrenAtEndOfLayout) { | |||||
// References to the child LMs are no longer needed | |||||
childLMs = null; | |||||
curChildLM = null; | |||||
childLMiter = null; | |||||
} | |||||
/* markers that qualify have been transferred to the page | /* markers that qualify have been transferred to the page | ||||
*/ | */ | ||||
|| lm instanceof PageSequenceLayoutManager)) { | || lm instanceof PageSequenceLayoutManager)) { | ||||
lm = lm.getParent(); | lm = lm.getParent(); | ||||
} | } | ||||
if (lm instanceof FlowLayoutManager) { | |||||
if (lm instanceof FlowLayoutManager && !preserveChildrenAtEndOfLayout) { | |||||
fobj.clearChildNodes(); | fobj.clearChildNodes(); | ||||
fobjIter = null; | fobjIter = null; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | |||||
* Preserves the children LMs at the end of layout. This is necessary if the layout is expected to be | |||||
* repeated, as when using retrieve-table-markers. | |||||
*/ | |||||
public void preserveChildrenAtEndOfLayout() { | |||||
preserveChildrenAtEndOfLayout = true; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public String toString() { | public String toString() { | ||||
lastGeneratedPosition = -1; | lastGeneratedPosition = -1; | ||||
} | } | ||||
public void recreateChildrenLMs() { | |||||
childLMs = new ArrayList(); | |||||
isFinished = false; | |||||
if (fobj == null) { | |||||
return; | |||||
} | |||||
fobjIter = fobj.getChildNodes(); | |||||
int position = 0; | |||||
while (createNextChildLMs(position++)) { | |||||
// | |||||
} | |||||
childLMiter = new LMiter(this); | |||||
for (LMiter iter = new LMiter(this); iter.hasNext();) { | |||||
AbstractBaseLayoutManager alm = (AbstractBaseLayoutManager) iter.next(); | |||||
alm.initialize(); | |||||
alm.recreateChildrenLMs(); | |||||
alm.preserveChildrenAtEndOfLayout(); | |||||
} | |||||
curChildLM = getChildLM(); | |||||
} | |||||
protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting, | |||||
boolean isFirst, boolean isLast) { | |||||
LayoutManager lm = this.parentLayoutManager; | |||||
if (lm instanceof FlowLayoutManager || lm instanceof PageSequenceLayoutManager | |||||
|| !(lm instanceof AbstractLayoutManager)) { | |||||
return; | |||||
} | |||||
((AbstractLayoutManager) lm).possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); | |||||
} | |||||
} | } |
public RetrieveMarker resolveRetrieveMarker(RetrieveMarker rm) { | public RetrieveMarker resolveRetrieveMarker(RetrieveMarker rm) { | ||||
AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel(); | AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel(); | ||||
String name = rm.getRetrieveClassName(); | String name = rm.getRetrieveClassName(); | ||||
int pos = rm.getRetrievePosition(); | |||||
int boundary = rm.getRetrieveBoundary(); | int boundary = rm.getRetrieveBoundary(); | ||||
// get marker from the current markers on area tree | // get marker from the current markers on area tree | ||||
Marker mark = (Marker)getCurrentPV().getMarker(name, pos); | |||||
Marker mark = getCurrentPV().resolveMarker(rm); | |||||
if (mark == null && boundary != EN_PAGE) { | if (mark == null && boundary != EN_PAGE) { | ||||
// go back over pages until mark found | // go back over pages until mark found | ||||
// if document boundary then keep going | // if document boundary then keep going | ||||
boolean doc = boundary == EN_DOCUMENT; | |||||
boolean doc = (boundary == EN_DOCUMENT); | |||||
int seq = areaTreeModel.getPageSequenceCount(); | int seq = areaTreeModel.getPageSequenceCount(); | ||||
int page = areaTreeModel.getPageCount(seq) - 1; | int page = areaTreeModel.getPageCount(seq) - 1; | ||||
while (page < 0 && doc && seq > 1) { | while (page < 0 && doc && seq > 1) { | ||||
} | } | ||||
while (page >= 0) { | while (page >= 0) { | ||||
PageViewport pv = areaTreeModel.getPage(seq, page); | PageViewport pv = areaTreeModel.getPage(seq, page); | ||||
mark = (Marker)pv.getMarker(name, Constants.EN_LEWP); | |||||
int originalPosition = rm.getPosition(); | |||||
rm.changePositionTo(Constants.EN_LEWP); | |||||
mark = (Marker) pv.resolveMarker(rm); | |||||
// this is probably not necessary since the RM will not be used again, but to be safe... | |||||
rm.changePositionTo(originalPosition); | |||||
if (mark != null) { | if (mark != null) { | ||||
break; | break; | ||||
} | } |
} | } | ||||
if (bslm != null) { | if (bslm != null) { | ||||
bslm.addMarkersToPage( | |||||
bslm.registerMarkers( | |||||
true, | true, | ||||
bslm.isFirst(firstPos), | bslm.isFirst(firstPos), | ||||
bslm.isLast(lastPos)); | bslm.isLast(lastPos)); | ||||
} | } | ||||
if (bslm != null) { | if (bslm != null) { | ||||
bslm.addMarkersToPage( | |||||
bslm.registerMarkers( | |||||
false, | false, | ||||
bslm.isFirst(firstPos), | bslm.isFirst(firstPos), | ||||
bslm.isLast(lastPos)); | bslm.isLast(lastPos)); | ||||
bslm.checkEndOfLayout(lastPos); | |||||
} | } | ||||
addId(); | addId(); | ||||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||||
if (bcpos == null) { | if (bcpos == null) { | ||||
// the Positions in positionList were inside the elements | // the Positions in positionList were inside the elements | ||||
bcpos.getBreaker().addContainedAreas(layoutContext); | bcpos.getBreaker().addContainedAreas(layoutContext); | ||||
} | } | ||||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||||
TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(), | TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(), | ||||
effSpaceBefore, effSpaceAfter); | effSpaceBefore, effSpaceAfter); |
addId(); | addId(); | ||||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||||
// the Positions in positionList were inside the elements | // the Positions in positionList were inside the elements | ||||
// created by the LineLM | // created by the LineLM | ||||
childLM.addAreas(childPosIter, lc); | childLM.addAreas(childPosIter, lc); | ||||
} | } | ||||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||||
TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), | TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), | ||||
effSpaceBefore, effSpaceAfter); | effSpaceBefore, effSpaceAfter); |
import org.apache.fop.area.AreaTreeHandler; | import org.apache.fop.area.AreaTreeHandler; | ||||
import org.apache.fop.fo.FOElementMapping; | import org.apache.fop.fo.FOElementMapping; | ||||
import org.apache.fop.fo.FONode; | import org.apache.fop.fo.FONode; | ||||
import org.apache.fop.fo.FONode.FONodeIterator; | |||||
import org.apache.fop.fo.FOText; | import org.apache.fop.fo.FOText; | ||||
import org.apache.fop.fo.FObjMixed; | import org.apache.fop.fo.FObjMixed; | ||||
import org.apache.fop.fo.extensions.ExternalDocument; | import org.apache.fop.fo.extensions.ExternalDocument; | ||||
registerMaker(Block.class, new BlockLayoutManagerMaker()); | registerMaker(Block.class, new BlockLayoutManagerMaker()); | ||||
registerMaker(Leader.class, new LeaderLayoutManagerMaker()); | registerMaker(Leader.class, new LeaderLayoutManagerMaker()); | ||||
registerMaker(RetrieveMarker.class, new RetrieveMarkerLayoutManagerMaker()); | registerMaker(RetrieveMarker.class, new RetrieveMarkerLayoutManagerMaker()); | ||||
registerMaker(RetrieveTableMarker.class, new Maker()); | |||||
registerMaker(RetrieveTableMarker.class, new RetrieveTableMarkerLayoutManagerMaker()); | |||||
registerMaker(Character.class, new CharacterLayoutManagerMaker()); | registerMaker(Character.class, new CharacterLayoutManagerMaker()); | ||||
registerMaker(ExternalGraphic.class, | registerMaker(ExternalGraphic.class, | ||||
new ExternalGraphicLayoutManagerMaker()); | new ExternalGraphicLayoutManagerMaker()); | ||||
} | } | ||||
} | } | ||||
public class RetrieveTableMarkerLayoutManagerMaker extends Maker { | |||||
public void make(FONode node, List lms) { | |||||
FONodeIterator baseIter = node.getChildNodes(); | |||||
if (baseIter == null) { | |||||
// this happens when the retrieve-table-marker cannot be resolved yet | |||||
RetrieveTableMarker rtm = (RetrieveTableMarker) node; | |||||
RetrieveTableMarkerLayoutManager rtmlm = new RetrieveTableMarkerLayoutManager(rtm); | |||||
lms.add(rtmlm); | |||||
return; | |||||
} | |||||
while (baseIter.hasNext()) { | |||||
// this happens when the retrieve-table-marker has been resolved | |||||
FONode child = (FONode) baseIter.next(); | |||||
makeLayoutManagers(child, lms); | |||||
} | |||||
} | |||||
} | |||||
/** a layout manager maker */ | /** a layout manager maker */ | ||||
public class WrapperLayoutManagerMaker extends Maker { | public class WrapperLayoutManagerMaker extends Maker { | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.layoutmgr; | |||||
import java.util.LinkedList; | |||||
import java.util.List; | |||||
import org.apache.fop.fo.FObj; | |||||
import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; | |||||
import org.apache.fop.layoutmgr.inline.TextLayoutManager; | |||||
public abstract class LocalBreaker extends AbstractBreaker { | |||||
protected BlockStackingLayoutManager lm; | |||||
private int displayAlign; | |||||
private int ipd; | |||||
private int overflow = 0; | |||||
public LocalBreaker(BlockStackingLayoutManager lm, int ipd, int displayAlign) { | |||||
this.lm = lm; | |||||
this.ipd = ipd; | |||||
this.displayAlign = displayAlign; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
protected boolean isPartOverflowRecoveryActivated() { | |||||
// For side regions, this must be disabled because of wanted overflow. | |||||
return false; | |||||
} | |||||
public boolean isOverflow() { | |||||
return (this.overflow != 0); | |||||
} | |||||
public int getOverflowAmount() { | |||||
return this.overflow; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
protected PageBreakingLayoutListener createLayoutListener() { | |||||
return new PageBreakingLayoutListener() { | |||||
public void notifyOverflow(int part, int amount, FObj obj) { | |||||
if (LocalBreaker.this.overflow == 0) { | |||||
LocalBreaker.this.overflow = amount; | |||||
} | |||||
} | |||||
}; | |||||
} | |||||
protected LayoutManager getTopLevelLM() { | |||||
return lm; | |||||
} | |||||
protected LayoutContext createLayoutContext() { | |||||
LayoutContext lc = super.createLayoutContext(); | |||||
lc.setRefIPD(ipd); | |||||
return lc; | |||||
} | |||||
protected List getNextKnuthElements(LayoutContext context, int alignment) { | |||||
LayoutManager curLM; // currently active LM | |||||
List returnList = new LinkedList(); | |||||
while ((curLM = lm.getChildLM()) != null) { | |||||
LayoutContext childLC = LayoutContext.newInstance(); | |||||
childLC.setStackLimitBP(context.getStackLimitBP()); | |||||
childLC.setRefIPD(context.getRefIPD()); | |||||
childLC.setWritingMode(context.getWritingMode()); | |||||
List returnedList = null; | |||||
// The following is a HACK! Ignore leading and trailing white space | |||||
boolean ignore = curLM instanceof TextLayoutManager; | |||||
if (!curLM.isFinished()) { | |||||
returnedList = curLM.getNextKnuthElements(childLC, alignment); | |||||
} | |||||
if (returnedList != null && !ignore) { | |||||
lm.wrapPositionElements(returnedList, returnList); | |||||
} | |||||
} | |||||
SpaceResolver.resolveElementList(returnList); | |||||
lm.setFinished(true); | |||||
return returnList; | |||||
} | |||||
protected int getCurrentDisplayAlign() { | |||||
return displayAlign; | |||||
} | |||||
protected boolean hasMoreContent() { | |||||
return !lm.isFinished(); | |||||
} | |||||
protected void addAreas(PositionIterator posIter, LayoutContext context) { | |||||
AreaAdditionUtil.addAreas(lm, posIter, context); | |||||
} | |||||
protected void doPhase3(PageBreakingAlgorithm alg, int partCount, BlockSequence originalList, | |||||
BlockSequence effectiveList) { | |||||
if (partCount > 1) { | |||||
PageBreakPosition pos = (PageBreakPosition) alg.getPageBreaks().getFirst(); | |||||
int firstPartLength = ElementListUtils.calcContentLength(effectiveList, | |||||
effectiveList.ignoreAtStart, pos.getLeafPos()); | |||||
overflow += alg.totalWidth - firstPartLength; | |||||
} | |||||
// Rendering all parts (not just the first) at once for the case where the parts that | |||||
// overflow should be visible. | |||||
alg.removeAllPageBreaks(); | |||||
// Directly add areas after finding the breaks | |||||
this.addAreas(alg, 1, originalList, effectiveList); | |||||
} | |||||
protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { | |||||
// nop for static content | |||||
} | |||||
protected LayoutManager getCurrentChildLM() { | |||||
return null; // TODO NYI | |||||
} | |||||
} |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.layoutmgr; | |||||
import java.util.List; | |||||
import org.apache.commons.logging.Log; | |||||
import org.apache.commons.logging.LogFactory; | |||||
import org.apache.fop.fo.FONode; | |||||
import org.apache.fop.fo.flow.RetrieveTableMarker; | |||||
import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager; | |||||
import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager; | |||||
import org.apache.fop.layoutmgr.table.TableLayoutManager; | |||||
public class RetrieveTableMarkerLayoutManager extends LeafNodeLayoutManager { | |||||
private static Log log = LogFactory.getLog(RetrieveTableMarkerLayoutManager.class); | |||||
public RetrieveTableMarkerLayoutManager(RetrieveTableMarker node) { | |||||
super(node); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public List getNextKnuthElements(LayoutContext context, int alignment) { | |||||
setFinished(true); | |||||
FONode foNode = (FONode) getFObj(); | |||||
foNode = getTableLayoutManager().resolveRetrieveTableMarker((RetrieveTableMarker) foNode); | |||||
if (foNode != null) { | |||||
// resolve the RTM and replace current LM by the resolved target LM | |||||
InlineLevelLayoutManager illm = (InlineLevelLayoutManager) getPSLM().getLayoutManagerMaker() | |||||
.makeLayoutManager(foNode); | |||||
if (illm instanceof RetrieveTableMarkerLayoutManager) { | |||||
// happens if the retrieve-marker was empty | |||||
return null; | |||||
} | |||||
illm.setParent(getParent()); | |||||
illm.initialize(); | |||||
return illm.getNextKnuthElements(context, alignment); | |||||
} else { | |||||
return null; | |||||
} | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public void addAreas(PositionIterator posIter, LayoutContext context) { | |||||
} | |||||
private TableLayoutManager getTableLayoutManager() { | |||||
LayoutManager parentLM = getParent(); | |||||
while (!(parentLM instanceof TableLayoutManager)) { | |||||
parentLM = parentLM.getParent(); | |||||
} | |||||
TableLayoutManager tlm = (TableLayoutManager) parentLM; | |||||
return tlm; | |||||
} | |||||
} |
return (StaticContent) fobj; | return (StaticContent) fobj; | ||||
} | } | ||||
private class StaticContentBreaker extends AbstractBreaker { | |||||
private StaticContentLayoutManager lm; | |||||
private int displayAlign; | |||||
private int ipd; | |||||
private int overflow = 0; | |||||
public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, | |||||
int displayAlign) { | |||||
this.lm = lm; | |||||
this.ipd = ipd; | |||||
this.displayAlign = displayAlign; | |||||
private class StaticContentBreaker extends LocalBreaker { | |||||
public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, int displayAlign) { | |||||
super(lm, ipd, displayAlign); | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
protected void observeElementList(List elementList) { | protected void observeElementList(List elementList) { | ||||
String elementListID = getStaticContentFO().getFlowName(); | String elementListID = getStaticContentFO().getFlowName(); | ||||
String pageSequenceID = ((PageSequence)lm.getParent().getFObj()).getId(); | |||||
String pageSequenceID = ((PageSequence) lm.getParent().getFObj()).getId(); | |||||
if (pageSequenceID != null && pageSequenceID.length() > 0) { | if (pageSequenceID != null && pageSequenceID.length() > 0) { | ||||
elementListID += "-" + pageSequenceID; | elementListID += "-" + pageSequenceID; | ||||
} | } | ||||
ElementListObserver.observe(elementList, "static-content", elementListID); | ElementListObserver.observe(elementList, "static-content", elementListID); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
protected boolean isPartOverflowRecoveryActivated() { | |||||
//For side regions, this must be disabled because of wanted overflow. | |||||
return false; | |||||
} | |||||
public boolean isOverflow() { | |||||
return (this.overflow != 0); | |||||
} | |||||
public int getOverflowAmount() { | |||||
return this.overflow; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
protected PageBreakingLayoutListener createLayoutListener() { | |||||
return new PageBreakingLayoutListener() { | |||||
public void notifyOverflow(int part, int amount, FObj obj) { | |||||
if (StaticContentBreaker.this.overflow == 0) { | |||||
StaticContentBreaker.this.overflow = amount; | |||||
} | |||||
} | |||||
}; | |||||
} | |||||
protected LayoutManager getTopLevelLM() { | |||||
return lm; | |||||
} | |||||
protected LayoutContext createLayoutContext() { | |||||
LayoutContext lc = super.createLayoutContext(); | |||||
lc.setRefIPD(ipd); | |||||
return lc; | |||||
} | |||||
protected List getNextKnuthElements(LayoutContext context, int alignment) { | |||||
LayoutManager curLM; // currently active LM | |||||
List returnList = new LinkedList(); | |||||
while ((curLM = getChildLM()) != null) { | |||||
LayoutContext childLC = LayoutContext.newInstance(); | |||||
childLC.setStackLimitBP(context.getStackLimitBP()); | |||||
childLC.setRefIPD(context.getRefIPD()); | |||||
childLC.setWritingMode(context.getWritingMode()); | |||||
List returnedList = null; | |||||
//The following is a HACK! Ignore leading and trailing white space | |||||
boolean ignore = curLM instanceof TextLayoutManager; | |||||
if (!curLM.isFinished()) { | |||||
returnedList = curLM.getNextKnuthElements(childLC, alignment); | |||||
} | |||||
if (returnedList != null && !ignore) { | |||||
lm.wrapPositionElements(returnedList, returnList); | |||||
} | |||||
} | |||||
SpaceResolver.resolveElementList(returnList); | |||||
setFinished(true); | |||||
return returnList; | |||||
} | |||||
protected int getCurrentDisplayAlign() { | |||||
return displayAlign; | |||||
} | |||||
protected boolean hasMoreContent() { | |||||
return !lm.isFinished(); | |||||
} | |||||
protected void addAreas(PositionIterator posIter, LayoutContext context) { | |||||
AreaAdditionUtil.addAreas(lm, posIter, context); | |||||
} | |||||
protected void doPhase3(PageBreakingAlgorithm alg, int partCount, | |||||
BlockSequence originalList, BlockSequence effectiveList) { | |||||
if (partCount > 1) { | |||||
PageBreakPosition pos = (PageBreakPosition)alg.getPageBreaks().getFirst(); | |||||
int firstPartLength = ElementListUtils.calcContentLength(effectiveList, | |||||
effectiveList.ignoreAtStart, pos.getLeafPos()); | |||||
overflow += alg.totalWidth - firstPartLength; | |||||
} | |||||
//Rendering all parts (not just the first) at once for the case where the parts that | |||||
//overflow should be visible. | |||||
alg.removeAllPageBreaks(); | |||||
//Directly add areas after finding the breaks | |||||
this.addAreas(alg, 1, originalList, effectiveList); | |||||
} | |||||
protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { | |||||
//nop for static content | |||||
} | |||||
protected LayoutManager getCurrentChildLM() { | |||||
return null; //TODO NYI | |||||
} | |||||
} | } | ||||
/** | /** |
context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); | context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); | ||||
} | } | ||||
addMarkersToPage( | |||||
registerMarkers( | |||||
true, | true, | ||||
!areaCreated, | !areaCreated, | ||||
lastPos == null || isLast(lastPos)); | lastPos == null || isLast(lastPos)); | ||||
setTraits(areaCreated, lastPos == null || !isLast(lastPos)); | setTraits(areaCreated, lastPos == null || !isLast(lastPos)); | ||||
parentLayoutManager.addChildArea(getCurrentArea()); | parentLayoutManager.addChildArea(getCurrentArea()); | ||||
addMarkersToPage( | |||||
registerMarkers( | |||||
false, | false, | ||||
!areaCreated, | !areaCreated, | ||||
lastPos == null || isLast(lastPos)); | lastPos == null || isLast(lastPos)); |
} | } | ||||
} | } | ||||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||||
PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | ||||
while ((childLM = childPosIter.getNextChildLM()) != null) { | while ((childLM = childPosIter.getNextChildLM()) != null) { | ||||
childLM.addAreas(childPosIter, lc); | childLM.addAreas(childPosIter, lc); | ||||
} | } | ||||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||||
// We are done with this area add the background | // We are done with this area add the background | ||||
TraitSetter.addBackground(curBlockArea, | TraitSetter.addBackground(curBlockArea, |
} | } | ||||
} | } | ||||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||||
PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | ||||
while ((childLM = childPosIter.getNextChildLM()) != null) { | while ((childLM = childPosIter.getNextChildLM()) != null) { | ||||
childLM.addAreas(childPosIter, lc); | childLM.addAreas(childPosIter, lc); | ||||
} | } | ||||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||||
flush(); | flush(); | ||||
} | } | ||||
} | } | ||||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||||
// use the first and the last ListItemPosition to determine the | // use the first and the last ListItemPosition to determine the | ||||
// corresponding indexes in the original labelList and bodyList | // corresponding indexes in the original labelList and bodyList | ||||
} | } | ||||
curBlockArea.setBPD(itemBPD); | curBlockArea.setBPD(itemBPD); | ||||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||||
// We are done with this area add the background | // We are done with this area add the background | ||||
TraitSetter.addBackground(curBlockArea, | TraitSetter.addBackground(curBlockArea, |
borderAfterWhich = ConditionalBorder.REST; | borderAfterWhich = ConditionalBorder.REST; | ||||
} | } | ||||
// when adding the areas for the TableCellLayoutManager this helps with the isLast trait | |||||
// if, say, the first cell of a row has content that fits in the page, but the content of | |||||
// the second cell does not fit this will assure that the isLast trait for the first cell | |||||
// will also be false | |||||
lastCellParts[i].pgu.getCellLM().setLastTrait(lastCellParts[i].isLastPart()); | |||||
addAreasForCell(firstCellParts[i].pgu, | addAreasForCell(firstCellParts[i].pgu, | ||||
firstCellParts[i].start, lastCellParts[i].end, | firstCellParts[i].start, lastCellParts[i].end, | ||||
actualRowHeight, borderBeforeWhich, borderAfterWhich, | actualRowHeight, borderBeforeWhich, borderAfterWhich, | ||||
lastOnPage); | lastOnPage); | ||||
firstCellParts[i] = null; | |||||
firstCellParts[i] = null; // why? what about the lastCellParts[i]? | |||||
Arrays.fill(firstCellOnPage, i, i + currentGU.getCell().getNumberColumnsSpanned(), | Arrays.fill(firstCellOnPage, i, i + currentGU.getCell().getNumberColumnsSpanned(), | ||||
false); | false); | ||||
} | } |
import java.util.LinkedList; | import java.util.LinkedList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.area.Area; | import org.apache.fop.area.Area; | ||||
import org.apache.fop.area.Block; | import org.apache.fop.area.Block; | ||||
import org.apache.fop.area.Trait; | import org.apache.fop.area.Trait; | ||||
import org.apache.fop.fo.flow.Marker; | |||||
import org.apache.fop.fo.flow.table.ConditionalBorder; | import org.apache.fop.fo.flow.table.ConditionalBorder; | ||||
import org.apache.fop.fo.flow.table.GridUnit; | import org.apache.fop.fo.flow.table.GridUnit; | ||||
import org.apache.fop.fo.flow.table.PrimaryGridUnit; | import org.apache.fop.fo.flow.table.PrimaryGridUnit; | ||||
import org.apache.fop.fo.flow.table.Table; | import org.apache.fop.fo.flow.table.Table; | ||||
import org.apache.fop.fo.flow.table.TableCell; | import org.apache.fop.fo.flow.table.TableCell; | ||||
import org.apache.fop.fo.flow.table.TableColumn; | import org.apache.fop.fo.flow.table.TableColumn; | ||||
import org.apache.fop.fo.flow.table.TableFooter; | |||||
import org.apache.fop.fo.flow.table.TableHeader; | |||||
import org.apache.fop.fo.flow.table.TablePart; | import org.apache.fop.fo.flow.table.TablePart; | ||||
import org.apache.fop.fo.flow.table.TableRow; | import org.apache.fop.fo.flow.table.TableRow; | ||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | ||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; | import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; | ||||
import org.apache.fop.layoutmgr.AbstractLayoutManager; | |||||
import org.apache.fop.layoutmgr.AreaAdditionUtil; | import org.apache.fop.layoutmgr.AreaAdditionUtil; | ||||
import org.apache.fop.layoutmgr.BlockLevelLayoutManager; | import org.apache.fop.layoutmgr.BlockLevelLayoutManager; | ||||
import org.apache.fop.layoutmgr.BlockStackingLayoutManager; | import org.apache.fop.layoutmgr.BlockStackingLayoutManager; | ||||
import org.apache.fop.layoutmgr.ElementListObserver; | |||||
import org.apache.fop.layoutmgr.ElementListUtils; | import org.apache.fop.layoutmgr.ElementListUtils; | ||||
import org.apache.fop.layoutmgr.Keep; | import org.apache.fop.layoutmgr.Keep; | ||||
import org.apache.fop.layoutmgr.KnuthBox; | import org.apache.fop.layoutmgr.KnuthBox; | ||||
import org.apache.fop.layoutmgr.KnuthPenalty; | import org.apache.fop.layoutmgr.KnuthPenalty; | ||||
import org.apache.fop.layoutmgr.LayoutContext; | import org.apache.fop.layoutmgr.LayoutContext; | ||||
import org.apache.fop.layoutmgr.LayoutManager; | import org.apache.fop.layoutmgr.LayoutManager; | ||||
import org.apache.fop.layoutmgr.LocalBreaker; | |||||
import org.apache.fop.layoutmgr.Position; | import org.apache.fop.layoutmgr.Position; | ||||
import org.apache.fop.layoutmgr.PositionIterator; | import org.apache.fop.layoutmgr.PositionIterator; | ||||
import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager; | |||||
import org.apache.fop.layoutmgr.SpaceResolver; | import org.apache.fop.layoutmgr.SpaceResolver; | ||||
import org.apache.fop.layoutmgr.TraitSetter; | import org.apache.fop.layoutmgr.TraitSetter; | ||||
import org.apache.fop.traits.BorderProps; | import org.apache.fop.traits.BorderProps; | ||||
private int totalHeight; | private int totalHeight; | ||||
private int usedBPD; | private int usedBPD; | ||||
private boolean emptyCell = true; | private boolean emptyCell = true; | ||||
private boolean isDescendantOfTableFooter; | |||||
private boolean isDescendantOfTableHeader; | |||||
private boolean hasRetrieveTableMarker; | |||||
// place holder for the addAreas arguments | |||||
private boolean savedAddAreasArguments; | |||||
private PositionIterator savedParentIter; | |||||
private LayoutContext savedLayoutContext; | |||||
private int[] savedSpannedGridRowHeights; | |||||
private int savedStartRow; | |||||
private int savedEndRow; | |||||
private int savedBorderBeforeWhich; | |||||
private int savedBorderAfterWhich; | |||||
private boolean savedFirstOnPage; | |||||
private boolean savedLastOnPage; | |||||
private RowPainter savedPainter; | |||||
private int savedFirstRowHeight; | |||||
// this is set to false when the table-cell has a retrieve-table-marker and is in the table-header | |||||
private boolean flushArea = true; | |||||
// this information is set by the RowPainter | |||||
private boolean isLastTrait; | |||||
/** | /** | ||||
* Create a new Cell layout manager. | * Create a new Cell layout manager. | ||||
public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) { | public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) { | ||||
super(node); | super(node); | ||||
this.primaryGridUnit = pgu; | this.primaryGridUnit = pgu; | ||||
this.isDescendantOfTableHeader = node.getParent().getParent() instanceof TableHeader | |||||
|| node.getParent() instanceof TableHeader; | |||||
this.isDescendantOfTableFooter = node.getParent().getParent() instanceof TableFooter | |||||
|| node.getParent() instanceof TableFooter; | |||||
this.hasRetrieveTableMarker = node.hasRetrieveTableMarker(); | |||||
} | } | ||||
/** @return the table-cell FO */ | /** @return the table-cell FO */ | ||||
totalHeight = h; | totalHeight = h; | ||||
} | } | ||||
private void clearRetrieveTableMarkerChildNodes(List<LayoutManager> childrenLMs) { | |||||
if (childrenLMs == null) { | |||||
return; | |||||
} | |||||
int n = childrenLMs.size(); | |||||
for (int j = 0; j < n; j++) { | |||||
LayoutManager lm = (LayoutManager) childrenLMs.get(j); | |||||
if (lm == null) { | |||||
return; | |||||
} else if (lm instanceof RetrieveTableMarkerLayoutManager) { | |||||
((AbstractLayoutManager) lm).getFObj().clearChildNodes(); | |||||
} else { | |||||
List<LayoutManager> lms = lm.getChildLMs(); | |||||
clearRetrieveTableMarkerChildNodes(lms); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Checks whether the associated table cell of this LM is in a table header or footer. | |||||
* @return true if descendant of table header or footer | |||||
*/ | |||||
private boolean isDescendantOfTableHeaderOrFooter() { | |||||
return (isDescendantOfTableFooter || isDescendantOfTableHeader); | |||||
} | |||||
private void saveAddAreasArguments(PositionIterator parentIter, LayoutContext layoutContext, | |||||
int[] spannedGridRowHeights, int startRow, int endRow, int borderBeforeWhich, | |||||
int borderAfterWhich, boolean firstOnPage, boolean lastOnPage, RowPainter painter, | |||||
int firstRowHeight) { | |||||
// checks for savedAddAreasArguments and isDescendantOfTableHeader were already made but repeat them | |||||
if (savedAddAreasArguments) { | |||||
return; | |||||
} | |||||
if (isDescendantOfTableHeader) { | |||||
savedAddAreasArguments = true; | |||||
savedParentIter = null /* parentIter */; | |||||
savedLayoutContext = null /* layoutContext */; | |||||
savedSpannedGridRowHeights = spannedGridRowHeights; | |||||
savedStartRow = startRow; | |||||
savedEndRow = endRow; | |||||
savedBorderBeforeWhich = borderBeforeWhich; | |||||
savedBorderAfterWhich = borderAfterWhich; | |||||
savedFirstOnPage = firstOnPage; | |||||
savedLastOnPage = lastOnPage; | |||||
savedPainter = painter; | |||||
savedFirstRowHeight = firstRowHeight; | |||||
TableLayoutManager parentTableLayoutManager = getTableLayoutManager(); | |||||
parentTableLayoutManager.saveTableHeaderTableCellLayoutManagers(this); | |||||
// this saving is done the first time the addArea() is called; since the retrieve-table-markers | |||||
// cannot be resolved at this time we do not want to flush the area; the area needs nevertheless | |||||
// be built so that space is allocated for it. | |||||
flushArea = false; | |||||
} | |||||
} | |||||
private TableLayoutManager getTableLayoutManager() { | |||||
LayoutManager parentLM = getParent(); | |||||
while (!(parentLM instanceof TableLayoutManager)) { | |||||
parentLM = parentLM.getParent(); | |||||
} | |||||
TableLayoutManager tlm = (TableLayoutManager) parentLM; | |||||
return tlm; | |||||
} | |||||
/** | |||||
* Calls the addAreas() using the original arguments. | |||||
*/ | |||||
protected void repeatAddAreas() { | |||||
if (savedAddAreasArguments) { | |||||
addAreas(savedParentIter, savedLayoutContext, savedSpannedGridRowHeights, savedStartRow, | |||||
savedEndRow, savedBorderBeforeWhich, savedBorderAfterWhich, savedFirstOnPage, | |||||
savedLastOnPage, savedPainter, savedFirstRowHeight); | |||||
// so that the arguments of the next table fragment header can be saved | |||||
savedAddAreasArguments = false; | |||||
} | |||||
} | |||||
/** | /** | ||||
* Add the areas for the break points. The cell contains block stacking layout | * Add the areas for the break points. The cell contains block stacking layout | ||||
* managers that add block areas. | * managers that add block areas. | ||||
} | } | ||||
} | } | ||||
AreaAdditionUtil.addAreas(this, parentIter, layoutContext); | |||||
if (isDescendantOfTableHeaderOrFooter()) { | |||||
if (hasRetrieveTableMarker) { | |||||
if (isDescendantOfTableHeader && !savedAddAreasArguments) { | |||||
saveAddAreasArguments(parentIter, layoutContext, spannedGridRowHeights, startRow, endRow, | |||||
borderBeforeWhich, borderAfterWhich, firstOnPage, lastOnPage, painter, | |||||
firstRowHeight); | |||||
} | |||||
recreateChildrenLMs(); | |||||
int displayAlign = ((TableCell) this.getFObj()).getDisplayAlign(); | |||||
TableCellBreaker breaker = new TableCellBreaker(this, cellIPD, displayAlign); | |||||
breaker.doLayout(usedBPD, false); | |||||
// this is needed so the next time the LMs are recreated they look like the originals; this | |||||
// is due to the fact that during the doLayout() above the FO tree changes when the | |||||
// retrieve-table-markers are resolved | |||||
clearRetrieveTableMarkerChildNodes(getChildLMs()); | |||||
} | |||||
} | |||||
// if hasRetrieveTableMarker == true the areas were already added when the re-layout was done above | |||||
if (!hasRetrieveTableMarker) { | |||||
AreaAdditionUtil.addAreas(this, parentIter, layoutContext); | |||||
} | |||||
// Re-adjust the cell's bpd as it may have been modified by the previous call | // Re-adjust the cell's bpd as it may have been modified by the previous call | ||||
// for some reason (?) | // for some reason (?) | ||||
curBlockArea.setBPD(cellBPD); | curBlockArea.setBPD(cellBPD); | ||||
getTableCell().getCommonBorderPaddingBackground(), this); | getTableCell().getCommonBorderPaddingBackground(), this); | ||||
} | } | ||||
flush(); | |||||
if (flushArea) { | |||||
flush(); | |||||
} else { | |||||
flushArea = true; | |||||
} | |||||
curBlockArea = null; | curBlockArea = null; | ||||
return true; | return true; | ||||
} | } | ||||
private class TableCellBreaker extends LocalBreaker { | |||||
public TableCellBreaker(TableCellLayoutManager lm, int ipd, int displayAlign) { | |||||
super(lm, ipd, displayAlign); | |||||
} | |||||
/** | |||||
* {@inheritDoc} | |||||
*/ | |||||
protected void observeElementList(List elementList) { | |||||
String elementListID = lm.getParent().getFObj().getId() + "-" + lm.getFObj().getId(); | |||||
ElementListObserver.observe(elementList, "table-cell", elementListID); | |||||
} | |||||
} | |||||
/** | |||||
* Registers the FO's markers on the current PageViewport and parent Table. | |||||
* | |||||
* @param isStarting boolean indicating whether the markers qualify as 'starting' | |||||
* @param isFirst boolean indicating whether the markers qualify as 'first' | |||||
* @param isLast boolean indicating whether the markers qualify as 'last' | |||||
*/ | |||||
protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) { | |||||
Map<String, Marker> markers = getTableCell().getMarkers(); | |||||
if (markers != null) { | |||||
getCurrentPV().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait); | |||||
if (!isDescendantOfTableHeaderOrFooter()) { | |||||
getTableLayoutManager().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait); | |||||
} | |||||
} | |||||
} | |||||
void setLastTrait(boolean isLast) { | |||||
isLastTrait = isLast; | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public void setParent(LayoutManager lm) { | |||||
this.parentLayoutManager = lm; | |||||
if (this.hasRetrieveTableMarker) { | |||||
this.getTableLayoutManager().flagAsHavingRetrieveTableMarker(); | |||||
} | |||||
} | |||||
} | } |
import org.apache.fop.datatypes.PercentBaseContext; | import org.apache.fop.datatypes.PercentBaseContext; | ||||
import org.apache.fop.fo.Constants; | import org.apache.fop.fo.Constants; | ||||
import org.apache.fop.fo.FObj; | import org.apache.fop.fo.FObj; | ||||
import org.apache.fop.fo.flow.Marker; | |||||
import org.apache.fop.fo.flow.table.EffRow; | import org.apache.fop.fo.flow.table.EffRow; | ||||
import org.apache.fop.fo.flow.table.PrimaryGridUnit; | import org.apache.fop.fo.flow.table.PrimaryGridUnit; | ||||
import org.apache.fop.fo.flow.table.Table; | import org.apache.fop.fo.flow.table.Table; | ||||
import org.apache.fop.fo.flow.table.TableBody; | |||||
import org.apache.fop.fo.flow.table.TablePart; | import org.apache.fop.fo.flow.table.TablePart; | ||||
import org.apache.fop.layoutmgr.BreakElement; | import org.apache.fop.layoutmgr.BreakElement; | ||||
import org.apache.fop.layoutmgr.ElementListUtils; | import org.apache.fop.layoutmgr.ElementListUtils; | ||||
} | } | ||||
} | } | ||||
Map markers = getTableLM().getTable().getMarkers(); | |||||
// there may be table fragment markers stored; clear them since we are starting a new fragment | |||||
tableLM.clearTableFragmentMarkers(); | |||||
// note: markers at table level are to be retrieved by the page, not by the table itself | |||||
Map<String, Marker> markers = getTableLM().getTable().getMarkers(); | |||||
if (markers != null) { | if (markers != null) { | ||||
getTableLM().getCurrentPV().addMarkers(markers, | |||||
getTableLM().getCurrentPV().registerMarkers(markers, | |||||
true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); | true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); | ||||
} | } | ||||
addBodyAreas(tablePositions.iterator(), painter, footerElements == null); | addBodyAreas(tablePositions.iterator(), painter, footerElements == null); | ||||
} | } | ||||
// if there are TCLMs saved because they have a RetrieveTableMarker, we repeat the header areas now; | |||||
// this can also be done after the areas for the footer are added but should be the same as here | |||||
tableLM.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); | |||||
if (footerElements != null) { | if (footerElements != null) { | ||||
boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); | boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); | ||||
layoutContext.setTreatAsArtifact(treatFooterAsArtifact); | layoutContext.setTreatAsArtifact(treatFooterAsArtifact); | ||||
this.usedBPD += painter.getAccumulatedBPD(); | this.usedBPD += painter.getAccumulatedBPD(); | ||||
if (markers != null) { | if (markers != null) { | ||||
getTableLM().getCurrentPV().addMarkers(markers, | |||||
getTableLM().getCurrentPV().registerMarkers(markers, | |||||
false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); | false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); | ||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
private void addTablePartAreas(List positions, RowPainter painter, TablePart body, | private void addTablePartAreas(List positions, RowPainter painter, TablePart body, | ||||
boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { | boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { | ||||
getTableLM().getCurrentPV().addMarkers(body.getMarkers(), | |||||
getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), | |||||
true, isFirstPos, isLastPos); | true, isFirstPos, isLastPos); | ||||
if (body instanceof TableBody) { | |||||
getTableLM().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); | |||||
} | |||||
painter.startTablePart(body); | painter.startTablePart(body); | ||||
for (Iterator iter = positions.iterator(); iter.hasNext();) { | for (Iterator iter = positions.iterator(); iter.hasNext();) { | ||||
painter.handleTableContentPosition((TableContentPosition) iter.next()); | painter.handleTableContentPosition((TableContentPosition) iter.next()); | ||||
} | } | ||||
getTableLM().getCurrentPV().addMarkers(body.getMarkers(), | |||||
getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), | |||||
false, isFirstPos, isLastPos); | false, isFirstPos, isLastPos); | ||||
if (body instanceof TableBody) { | |||||
getTableLM().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); | |||||
} | |||||
painter.endTablePart(lastInBody, lastOnPage); | painter.endTablePart(lastInBody, lastOnPage); | ||||
} | } | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.LinkedList; | import java.util.LinkedList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||
import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||
import org.apache.fop.fo.Constants; | import org.apache.fop.fo.Constants; | ||||
import org.apache.fop.fo.FONode; | import org.apache.fop.fo.FONode; | ||||
import org.apache.fop.fo.FObj; | import org.apache.fop.fo.FObj; | ||||
import org.apache.fop.fo.flow.Marker; | |||||
import org.apache.fop.fo.flow.Markers; | |||||
import org.apache.fop.fo.flow.RetrieveTableMarker; | |||||
import org.apache.fop.fo.flow.table.Table; | import org.apache.fop.fo.flow.table.Table; | ||||
import org.apache.fop.fo.flow.table.TableColumn; | import org.apache.fop.fo.flow.table.TableColumn; | ||||
import org.apache.fop.fo.properties.KeepProperty; | import org.apache.fop.fo.properties.KeepProperty; | ||||
private Position auxiliaryPosition; | private Position auxiliaryPosition; | ||||
// this holds a possible list of TCLMs that needed to have their addAreas() repeated | |||||
private List<TableCellLayoutManager> savedTCLMs; | |||||
private boolean areAllTCLMsSaved; | |||||
private Markers tableMarkers; | |||||
private Markers tableFragmentMarkers; | |||||
private boolean hasRetrieveTableMarker; | |||||
/** | /** | ||||
* Temporary holder of column background informations for a table-cell's area. | * Temporary holder of column background informations for a table-cell's area. | ||||
* | * | ||||
tableUnit = 0.0; | tableUnit = 0.0; | ||||
} | } | ||||
/** | |||||
* Saves a TableCellLayoutManager for later use. | |||||
* | |||||
* @param tclm a TableCellLayoutManager that has a RetrieveTableMarker | |||||
*/ | |||||
protected void saveTableHeaderTableCellLayoutManagers(TableCellLayoutManager tclm) { | |||||
if (savedTCLMs == null) { | |||||
savedTCLMs = new ArrayList<TableCellLayoutManager>(); | |||||
} | |||||
if (!areAllTCLMsSaved) { | |||||
savedTCLMs.add(tclm); | |||||
} | |||||
} | |||||
/** | |||||
* Calls addAreas() for each of the saved TableCellLayoutManagers. | |||||
*/ | |||||
protected void repeatAddAreasForSavedTableHeaderTableCellLayoutManagers() { | |||||
if (savedTCLMs == null) { | |||||
return; | |||||
} | |||||
// if we get to this stage then we are at the footer of the table fragment; this means that no more | |||||
// different TCLM need to be saved (we already have all); we flag the list as being complete then | |||||
areAllTCLMsSaved = true; | |||||
for (int i = 0; i < savedTCLMs.size(); i++) { | |||||
TableCellLayoutManager tclm = savedTCLMs.get(i); | |||||
tclm.repeatAddAreas(); | |||||
} | |||||
} | |||||
/** | |||||
* Resolves a RetrieveTableMarker by finding a qualifying Marker to which it is bound to. | |||||
* @param rtm the RetrieveTableMarker to be resolved | |||||
* @return a bound RetrieveTableMarker instance or null if no qualifying Marker found | |||||
*/ | |||||
public RetrieveTableMarker resolveRetrieveTableMarker(RetrieveTableMarker rtm) { | |||||
String name = rtm.getRetrieveClassName(); | |||||
int originalPosition = rtm.getPosition(); | |||||
boolean changedPosition = false; | |||||
Marker mark = null; | |||||
// try the primary retrieve scope area, which is the same as table-fragment | |||||
mark = (tableFragmentMarkers == null) ? null : tableFragmentMarkers.resolve(rtm); | |||||
if (mark == null && rtm.getBoundary() != Constants.EN_TABLE_FRAGMENT) { | |||||
rtm.changePositionTo(Constants.EN_LAST_ENDING); | |||||
changedPosition = true; | |||||
// try the page scope area | |||||
mark = getCurrentPV().resolveMarker(rtm); | |||||
if (mark == null && rtm.getBoundary() != Constants.EN_PAGE) { | |||||
// try the table scope area | |||||
mark = (tableMarkers == null) ? null : tableMarkers.resolve(rtm); | |||||
} | |||||
} | |||||
if (changedPosition) { | |||||
// so that the next time it is called looks unchanged | |||||
rtm.changePositionTo(originalPosition); | |||||
} | |||||
if (mark == null) { | |||||
log.debug("found no marker with name: " + name); | |||||
return null; | |||||
} else { | |||||
rtm.bindMarker(mark); | |||||
return rtm; | |||||
} | |||||
} | |||||
/** | |||||
* Register the markers for this table. | |||||
* | |||||
* @param marks the map of markers to add | |||||
* @param starting if the area being added is starting or ending | |||||
* @param isfirst if the area being added has is-first trait | |||||
* @param islast if the area being added has is-last trait | |||||
*/ | |||||
public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, | |||||
boolean islast) { | |||||
if (tableMarkers == null) { | |||||
tableMarkers = new Markers(); | |||||
} | |||||
tableMarkers.register(marks, starting, isfirst, islast); | |||||
if (tableFragmentMarkers == null) { | |||||
tableFragmentMarkers = new Markers(); | |||||
} | |||||
tableFragmentMarkers.register(marks, starting, isfirst, islast); | |||||
} | |||||
/** | |||||
* Clears the list of markers in the current table fragment. Should be called just before starting a new | |||||
* header (that belongs to the next table fragment). | |||||
*/ | |||||
protected void clearTableFragmentMarkers() { | |||||
tableFragmentMarkers = null; | |||||
} | |||||
public void flagAsHavingRetrieveTableMarker() { | |||||
hasRetrieveTableMarker = true; | |||||
} | |||||
protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting, | |||||
boolean isFirst, boolean isLast) { | |||||
// note: if we allow table-footer after a table-body this check should not be made and the markers | |||||
// should be registered regardless because the retrieval may be done only in the footer | |||||
if (hasRetrieveTableMarker) { | |||||
registerMarkers(markers, isStarting, isFirst, isLast); | |||||
} | |||||
super.possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); | |||||
} | |||||
} | } |
documents. Example: the fix of marks layering will be such a case when it's done. | documents. Example: the fix of marks layering will be such a case when it's done. | ||||
--> | --> | ||||
<release version="FOP Trunk" date="TBD"> | <release version="FOP Trunk" date="TBD"> | ||||
<action context="Layout" dev="MH" type="add" fixes-bug="53924" due-to="Luis Bernardo"> | |||||
Support for retrieve-table-markers | |||||
</action> | |||||
<action context="Renderers" dev="VH" type="add" fixes-bug="53902"> | <action context="Renderers" dev="VH" type="add" fixes-bug="53902"> | ||||
Added possibility to define ‘header’ table columns (the same way as fo:table-header allows | Added possibility to define ‘header’ table columns (the same way as fo:table-header allows | ||||
to define header rows). When accessibility is enabled, this allows to set the appropriate | to define header rows). When accessibility is enabled, this allows to set the appropriate |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id:$ */ | |||||
package org.apache.fop.fo.flow; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import org.junit.Test; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.fail; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.fo.Constants; | |||||
import org.apache.fop.fo.flow.Marker; | |||||
import org.apache.fop.fo.flow.Markers; | |||||
import org.apache.fop.fo.flow.RetrieveMarker; | |||||
import org.apache.fop.fo.flow.RetrieveTableMarker; | |||||
public class MarkersTestCase { | |||||
@Test | |||||
public void testRegisterAndResolve() { | |||||
// consider 3 regions, and a boundary; the first region starts before the boundary and ends inside | |||||
// the boundary, the second region is fully inside the boundary, and the third region starts inside | |||||
// the boundary and ends after the boundary. in every region there are 2 markers, A and B. | |||||
// ======== region 1 | |||||
Map<String, Marker> markers_region_1 = new HashMap<String, Marker>(); | |||||
Marker marker_1A = mock(Marker.class); | |||||
Marker marker_1B = mock(Marker.class); | |||||
markers_region_1.put("A", marker_1A); | |||||
markers_region_1.put("B", marker_1B); | |||||
// ======== region 2 | |||||
Map<String, Marker> markers_region_2 = new HashMap<String, Marker>(); | |||||
Marker marker_2A = mock(Marker.class); | |||||
Marker marker_2B = mock(Marker.class); | |||||
markers_region_2.put("A", marker_2A); | |||||
markers_region_2.put("B", marker_2B); | |||||
// ======== region 3 | |||||
Map<String, Marker> markers_region_3 = new HashMap<String, Marker>(); | |||||
Marker marker_3A = mock(Marker.class); | |||||
Marker marker_3B = mock(Marker.class); | |||||
markers_region_3.put("A", marker_3A); | |||||
markers_region_3.put("B", marker_3B); | |||||
// instantiate markers for the boundary | |||||
Markers markers = new Markers(); | |||||
// register the markers for the different regions | |||||
// region 1 | |||||
markers.register(markers_region_1, true, false, true); | |||||
markers.register(markers_region_1, false, false, true); | |||||
// region 2 | |||||
markers.register(markers_region_2, true, true, true); | |||||
markers.register(markers_region_2, false, true, true); | |||||
// region 3 | |||||
markers.register(markers_region_3, true, true, false); | |||||
markers.register(markers_region_3, false, true, false); | |||||
// now prepare a RetrieveMarker | |||||
RetrieveMarker rm = mock(RetrieveMarker.class); | |||||
when(rm.getRetrieveClassName()).thenReturn("A"); | |||||
when(rm.getLocalName()).thenReturn("retrieve-marker"); | |||||
when(rm.getPositionLabel()).thenReturn("position-label"); // not relevant for the test | |||||
// and resolve the marker for different positions | |||||
// EN_FSWP | |||||
when(rm.getPosition()).thenReturn(Constants.EN_FSWP); | |||||
// expect marker_2A | |||||
assertEquals(marker_2A, markers.resolve(rm)); | |||||
// EN_LSWP | |||||
when(rm.getPosition()).thenReturn(Constants.EN_LSWP); | |||||
// expect marker_3A | |||||
assertEquals(marker_3A, markers.resolve(rm)); | |||||
// EN_LEWP | |||||
when(rm.getPosition()).thenReturn(Constants.EN_LEWP); | |||||
// expect marker_2A | |||||
assertEquals(marker_2A, markers.resolve(rm)); | |||||
// EN_FIC | |||||
when(rm.getPosition()).thenReturn(Constants.EN_FIC); | |||||
// expect marker_1A | |||||
assertEquals(marker_1A, markers.resolve(rm)); | |||||
// now prepare a RetrieveTableMarker | |||||
RetrieveTableMarker rtm = mock(RetrieveTableMarker.class); | |||||
when(rtm.getRetrieveClassName()).thenReturn("B"); | |||||
when(rtm.getLocalName()).thenReturn("retrieve-table-marker"); | |||||
when(rtm.getPositionLabel()).thenReturn("position-label"); // not relevant for the test | |||||
// and resolve the marker for different positions | |||||
// EN_FIRST_STARTING | |||||
when(rtm.getPosition()).thenReturn(Constants.EN_FIRST_STARTING); | |||||
// expect marker_2B | |||||
assertEquals(marker_2B, markers.resolve(rtm)); | |||||
// EN_LAST_STARTING | |||||
when(rtm.getPosition()).thenReturn(Constants.EN_LAST_STARTING); | |||||
// expect marker_3B | |||||
assertEquals(marker_3B, markers.resolve(rtm)); | |||||
// EN_LAST_ENDING | |||||
when(rtm.getPosition()).thenReturn(Constants.EN_LAST_ENDING); | |||||
// expect marker_2B | |||||
assertEquals(marker_2B, markers.resolve(rtm)); | |||||
// EN_FIRST_INCLUDING_CARRYOVER | |||||
when(rtm.getPosition()).thenReturn(Constants.EN_FIRST_INCLUDING_CARRYOVER); | |||||
// expect marker_1B | |||||
assertEquals(marker_1B, markers.resolve(rtm)); | |||||
// test also an invalid position | |||||
when(rm.getPosition()).thenReturn(Constants.EN_ABSOLUTE); | |||||
try { | |||||
Marker m = markers.resolve(rm); | |||||
fail("Expected an exception... instead got:" + m.toString()); | |||||
} catch (RuntimeException re) { | |||||
// do nothing | |||||
} | |||||
} | |||||
} |
package org.apache.fop.layoutmgr; | package org.apache.fop.layoutmgr; | ||||
import org.junit.Test; | |||||
import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||
import static org.mockito.Matchers.anyInt; | import static org.mockito.Matchers.anyInt; | ||||
import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||
import org.apache.fop.fo.pagination.Region; | import org.apache.fop.fo.pagination.Region; | ||||
import org.apache.fop.fo.pagination.Root; | import org.apache.fop.fo.pagination.Root; | ||||
import org.apache.fop.fo.pagination.SimplePageMaster; | import org.apache.fop.fo.pagination.SimplePageMaster; | ||||
import org.junit.Test; | |||||
public class PageSequenceLayoutManagerTestCase { | public class PageSequenceLayoutManagerTestCase { | ||||
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.layoutmgr; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import org.junit.Test; | |||||
import static org.junit.Assert.assertTrue; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.apps.FOPException; | |||||
import org.apache.fop.fo.FObj.FObjIterator; | |||||
import org.apache.fop.fo.flow.RetrieveTableMarker; | |||||
import org.apache.fop.layoutmgr.LayoutManagerMapping.RetrieveTableMarkerLayoutManagerMaker; | |||||
public class RetrieveTableMarkerLayoutManagerMakerTestCase { | |||||
@Test | |||||
public void testMake() throws FOPException { | |||||
// mock | |||||
FObjIterator foi = mock(FObjIterator.class); | |||||
when(foi.hasNext()).thenReturn(true).thenReturn(false); | |||||
// mock | |||||
RetrieveTableMarker rtm = mock(RetrieveTableMarker.class); | |||||
// real RTMLMM, not mock | |||||
List l = new ArrayList(); | |||||
LayoutManagerMapping lmm = new LayoutManagerMapping(); | |||||
RetrieveTableMarkerLayoutManagerMaker rtmlmm = lmm.new RetrieveTableMarkerLayoutManagerMaker(); | |||||
// test the case rtm has no child nodes | |||||
when(rtm.getChildNodes()).thenReturn(null); | |||||
rtmlmm.make(rtm, l); | |||||
assertTrue(l.size() == 1); | |||||
assertTrue(l.get(0) instanceof RetrieveTableMarkerLayoutManager); | |||||
} | |||||
} |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.layoutmgr; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import org.junit.Test; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.assertNull; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.verify; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.fo.Constants; | |||||
import org.apache.fop.fo.flow.RetrieveTableMarker; | |||||
import org.apache.fop.fo.flow.table.Table; | |||||
import org.apache.fop.layoutmgr.inline.TextLayoutManager; | |||||
import org.apache.fop.layoutmgr.table.TableLayoutManager; | |||||
public class RetrieveTableMarkerLayoutManagerTestCase { | |||||
@Test | |||||
public void testGetNextKnuthElementsLayoutContextInt() { | |||||
LayoutContext lc = LayoutContext.newInstance(); | |||||
// mock | |||||
Table t = mock(Table.class); | |||||
// mock | |||||
RetrieveTableMarker rtm = mock(RetrieveTableMarker.class); | |||||
when(rtm.getRetrieveClassName()).thenReturn("A"); | |||||
when(rtm.getPosition()).thenReturn(Constants.EN_FIRST_STARTING); | |||||
when(rtm.getBoundary()).thenReturn(Constants.EN_TABLE_FRAGMENT); | |||||
// mock | |||||
TextLayoutManager tlm = mock(TextLayoutManager.class); | |||||
// mock | |||||
LayoutManagerMapping lmm = mock(LayoutManagerMapping.class); | |||||
when(lmm.makeLayoutManager(rtm)).thenReturn(tlm); | |||||
// mock | |||||
PageSequenceLayoutManager pslm = mock(PageSequenceLayoutManager.class); | |||||
when(pslm.getPSLM()).thenReturn(pslm); | |||||
when(pslm.getLayoutManagerMaker()).thenReturn(lmm); | |||||
// mock | |||||
TableLayoutManager tablelm = mock(TableLayoutManager.class); | |||||
when(tablelm.getTable()).thenReturn(t); | |||||
// mock | |||||
BlockLayoutManager blm = mock(BlockLayoutManager.class); | |||||
when(blm.getPSLM()).thenReturn(pslm); | |||||
when(blm.getParent()).thenReturn(tablelm); | |||||
// real RTMLM, not mock | |||||
RetrieveTableMarkerLayoutManager rtmlm = new RetrieveTableMarkerLayoutManager(rtm); | |||||
rtmlm.setParent(blm); | |||||
// test the case where resolution returns null | |||||
when(tablelm.resolveRetrieveTableMarker(rtm)).thenReturn(null); | |||||
assertNull(rtmlm.getNextKnuthElements(lc, 0)); | |||||
// test the case where resolution returns non null | |||||
List l = new ArrayList(); | |||||
when(tablelm.resolveRetrieveTableMarker(rtm)).thenReturn(rtm); | |||||
when(tlm.getNextKnuthElements(lc, 0)).thenReturn(l); | |||||
assertEquals(l, rtmlm.getNextKnuthElements(lc, 0)); | |||||
verify(tlm).setParent(blm); | |||||
verify(tlm).initialize(); | |||||
} | |||||
} |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id:$ */ | |||||
package org.apache.fop.layoutmgr.table; | |||||
import java.awt.Color; | |||||
import org.junit.Test; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.verify; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.fo.flow.table.PrimaryGridUnit; | |||||
import org.apache.fop.fo.flow.table.Table; | |||||
import org.apache.fop.fo.flow.table.TableCell; | |||||
import org.apache.fop.fo.flow.table.TableColumn; | |||||
import org.apache.fop.fo.flow.table.TableHeader; | |||||
import org.apache.fop.fo.flow.table.TableRow; | |||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; | |||||
import org.apache.fop.fo.properties.CondLengthProperty; | |||||
import org.apache.fop.layoutmgr.LayoutContext; | |||||
import org.apache.fop.layoutmgr.PageSequenceLayoutManager; | |||||
import org.apache.fop.layoutmgr.PositionIterator; | |||||
import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager; | |||||
public class TableCellLayoutManagerTestCase { | |||||
// this test aims to check that the first call to addAreas() calls | |||||
// TLM.saveTableHeaderTableCellLayoutManagers() but the second call, through repeatAddAreas() | |||||
// does not call it again; there are a lot of mocks here, but just the necessary so that the | |||||
// addAreas() call can run to completion without NPE; also, the mocking needs to be done so | |||||
// the methods isDecendantOfTableHeaderOrFooter() and hasRetrieveTableMarker() return true. | |||||
@Test | |||||
public void testRepeatAddAreas() { | |||||
LayoutContext lc = LayoutContext.newInstance(); | |||||
// mock background | |||||
CommonBorderPaddingBackground cbpb = mock(CommonBorderPaddingBackground.class); | |||||
// mock conditional length property | |||||
CondLengthProperty clp = mock(CondLengthProperty.class); | |||||
when(clp.getLengthValue()).thenReturn(0); | |||||
// real border info | |||||
BorderInfo bi = BorderInfo.getInstance(0, clp, Color.BLACK); | |||||
// mock column | |||||
TableColumn tcol = mock(TableColumn.class); | |||||
when(tcol.getCommonBorderPaddingBackground()).thenReturn(cbpb); | |||||
// mock table | |||||
Table t = mock(Table.class); | |||||
when(t.getColumn(0)).thenReturn(tcol); | |||||
// mock header | |||||
TableHeader th = mock(TableHeader.class); | |||||
when(th.getCommonBorderPaddingBackground()).thenReturn(cbpb); | |||||
// mock row | |||||
TableRow tr = mock(TableRow.class); | |||||
when(tr.getParent()).thenReturn(th); | |||||
// mock cell | |||||
TableCell tc = mock(TableCell.class); | |||||
when(tc.hasRetrieveTableMarker()).thenReturn(true); | |||||
when(tc.getTable()).thenReturn(t); | |||||
when(tc.getId()).thenReturn("cellId"); | |||||
when(tc.getCommonBorderPaddingBackground()).thenReturn(cbpb); | |||||
when(tc.getParent()).thenReturn(tr); | |||||
// mock PGU | |||||
PrimaryGridUnit pgu = mock(PrimaryGridUnit.class); | |||||
when(pgu.getCell()).thenReturn(tc); | |||||
when(pgu.getColIndex()).thenReturn(0); | |||||
when(pgu.getBorderBefore(0)).thenReturn(bi); | |||||
when(pgu.getBorderAfter(0)).thenReturn(bi); | |||||
when(pgu.getBorderEnd()).thenReturn(bi); | |||||
when(pgu.getBorderStart()).thenReturn(bi); | |||||
when(pgu.getTablePart()).thenReturn(th); | |||||
// mock RTMLM | |||||
RetrieveTableMarkerLayoutManager rtmlm = mock(RetrieveTableMarkerLayoutManager.class); | |||||
when(rtmlm.isFinished()).thenReturn(true); // avoids infinite loop | |||||
// mock PSLM | |||||
PageSequenceLayoutManager pslm = mock(PageSequenceLayoutManager.class); | |||||
// mock TLM | |||||
TableLayoutManager tlm = mock(TableLayoutManager.class); | |||||
when(tlm.getPSLM()).thenReturn(pslm); | |||||
// mock PI | |||||
PositionIterator pi = mock(PositionIterator.class); | |||||
// mock RP | |||||
RowPainter rp = mock(RowPainter.class); | |||||
// real TCLM, not a mock! | |||||
TableCellLayoutManager tclm = new TableCellLayoutManager(tc, pgu); | |||||
tclm.addChildLM(rtmlm); | |||||
tclm.setParent(tlm); | |||||
// lets call addAreas | |||||
int[] n = {}; | |||||
tclm.addAreas(pi, lc, n, 0, 0, 0, 0, true, true, rp, 0); | |||||
// check the TCLM is added to the TLM | |||||
verify(tlm).saveTableHeaderTableCellLayoutManagers(tclm); | |||||
// call the repeat | |||||
tclm.repeatAddAreas(); | |||||
// check the TCLM was not added again | |||||
verify(tlm).saveTableHeaderTableCellLayoutManagers(tclm); | |||||
} | |||||
} |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id$ */ | |||||
package org.apache.fop.layoutmgr.table; | |||||
import org.junit.Test; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.verify; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.fo.FONode.FONodeIterator; | |||||
import org.apache.fop.fo.flow.table.Table; | |||||
import org.apache.fop.layoutmgr.LayoutContext; | |||||
import org.apache.fop.layoutmgr.PositionIterator; | |||||
public class TableContentLayoutManagerTestCase { | |||||
@Test | |||||
public void testAddAreas() { | |||||
LayoutContext lc = LayoutContext.newInstance(); | |||||
// mock | |||||
ColumnSetup cs = mock(ColumnSetup.class); | |||||
when(cs.getColumnCount()).thenReturn(3); | |||||
// mock | |||||
FONodeIterator foni = mock(FONodeIterator.class); | |||||
when(foni.hasNext()).thenReturn(false); | |||||
// mock | |||||
Table t = mock(Table.class); | |||||
when(t.getChildNodes()).thenReturn(foni); | |||||
when(t.getMarkers()).thenReturn(null); | |||||
// mock | |||||
TableLayoutManager tlm = mock(TableLayoutManager.class); | |||||
when(tlm.getTable()).thenReturn(t); | |||||
when(tlm.getColumns()).thenReturn(cs); | |||||
// mock | |||||
PositionIterator pi = mock(PositionIterator.class); | |||||
when(pi.hasNext()).thenReturn(false); | |||||
// real TCLM, not a mock | |||||
TableContentLayoutManager tclm = new TableContentLayoutManager(tlm); | |||||
// check that addAreas() calls the clearTableFragments() on the table and the | |||||
// repeatAddAreasForSavedTableHeaderTableCellLayoutManagers on the TLM | |||||
tclm.addAreas(pi, lc); | |||||
verify(tlm).clearTableFragmentMarkers(); | |||||
verify(tlm).repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); | |||||
} | |||||
} |
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||||
* (the "License"); you may not use this file except in compliance with | |||||
* the License. You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
*/ | |||||
/* $Id:$ */ | |||||
package org.apache.fop.layoutmgr.table; | |||||
import java.util.HashMap; | |||||
import org.junit.Test; | |||||
import static org.junit.Assert.assertEquals; | |||||
import static org.junit.Assert.assertNull; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.never; | |||||
import static org.mockito.Mockito.times; | |||||
import static org.mockito.Mockito.verify; | |||||
import static org.mockito.Mockito.when; | |||||
import org.apache.fop.area.PageViewport; | |||||
import org.apache.fop.fo.Constants; | |||||
import org.apache.fop.fo.flow.Marker; | |||||
import org.apache.fop.fo.flow.RetrieveTableMarker; | |||||
import org.apache.fop.fo.flow.table.Table; | |||||
import org.apache.fop.layoutmgr.BlockLayoutManager; | |||||
import org.apache.fop.layoutmgr.Page; | |||||
import org.apache.fop.layoutmgr.PageSequenceLayoutManager; | |||||
public class TableLayoutManagerTestCase { | |||||
@Test | |||||
public void testSavedTableCellLayoutManagersFunctionality() { | |||||
Table t = mock(Table.class); | |||||
TableCellLayoutManager tclm1 = mock(TableCellLayoutManager.class); | |||||
TableLayoutManager tlm = new TableLayoutManager(t); | |||||
tlm.saveTableHeaderTableCellLayoutManagers(tclm1); | |||||
tlm.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); | |||||
verify(tclm1).repeatAddAreas(); // called once | |||||
// test that after the first repeatAddAreas() call the list closes to new additions | |||||
TableCellLayoutManager tclm2 = mock(TableCellLayoutManager.class); | |||||
tlm.saveTableHeaderTableCellLayoutManagers(tclm2); | |||||
tlm.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); | |||||
verify(tclm1, times(2)).repeatAddAreas(); // called twice | |||||
verify(tclm2, never()).repeatAddAreas(); // never called | |||||
} | |||||
@Test | |||||
public void testResolveRetrieveTableMarker() { | |||||
// mock | |||||
Table t = mock(Table.class); | |||||
// mock | |||||
Marker m = mock(Marker.class); | |||||
// mock | |||||
RetrieveTableMarker rtm = mock(RetrieveTableMarker.class); | |||||
when(rtm.getRetrieveClassName()).thenReturn("A"); | |||||
when(rtm.getPosition()).thenReturn(Constants.EN_FIRST_STARTING); | |||||
// mock | |||||
PageViewport pv = mock(PageViewport.class); | |||||
when(pv.resolveMarker(rtm)).thenReturn(m); | |||||
// mock | |||||
Page p = mock(Page.class); | |||||
when(p.getPageViewport()).thenReturn(pv); | |||||
// mock | |||||
PageSequenceLayoutManager pslm = mock(PageSequenceLayoutManager.class); | |||||
when(pslm.getPSLM()).thenReturn(pslm); | |||||
when(pslm.getCurrentPage()).thenReturn(p); | |||||
// mock | |||||
BlockLayoutManager blm = mock(BlockLayoutManager.class); | |||||
blm.setParent(pslm); | |||||
when(blm.getPSLM()).thenReturn(pslm); | |||||
// real TLM, not mock | |||||
TableLayoutManager tlm = new TableLayoutManager(t); | |||||
tlm.setParent(blm); | |||||
// register a marker | |||||
HashMap<String, Marker> markers1 = new HashMap<String, Marker>(); | |||||
Marker m1 = mock(Marker.class); | |||||
markers1.put("A", m1); | |||||
tlm.registerMarkers(markers1, true, true, true); | |||||
tlm.registerMarkers(markers1, false, true, true); | |||||
// check that if there is a marker at table fragment level the RTM is returned | |||||
assertEquals(rtm, tlm.resolveRetrieveTableMarker(rtm)); | |||||
verify(rtm, never()).getBoundary(); | |||||
// check that if there is no marker at table fragment level and that is the boundary | |||||
// we get a null return value | |||||
when(rtm.getBoundary()).thenReturn(Constants.EN_TABLE_FRAGMENT); | |||||
when(rtm.getRetrieveClassName()).thenReturn("B"); | |||||
assertNull(tlm.resolveRetrieveTableMarker(rtm)); | |||||
verify(rtm).getBoundary(); | |||||
verify(rtm, never()).changePositionTo(Constants.EN_LAST_ENDING); | |||||
// check that if there is no marker at table fragment level and the boundary is page | |||||
// then we try to do the resolution at page level; test the case a marker is found | |||||
when(rtm.getBoundary()).thenReturn(Constants.EN_PAGE); | |||||
assertEquals(rtm, tlm.resolveRetrieveTableMarker(rtm)); | |||||
verify(rtm).changePositionTo(Constants.EN_LAST_ENDING); | |||||
verify(rtm).changePositionTo(Constants.EN_FIRST_STARTING); | |||||
verify(pv).resolveMarker(rtm); | |||||
// test the same situation but in this case the marker is not found | |||||
when(pv.resolveMarker(rtm)).thenReturn(null); | |||||
assertNull(tlm.resolveRetrieveTableMarker(rtm)); | |||||
// test the situation where the marker is not found at page level but the boundary is table | |||||
when(rtm.getBoundary()).thenReturn(Constants.EN_TABLE); | |||||
assertNull(tlm.resolveRetrieveTableMarker(rtm)); | |||||
} | |||||
} |
<?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 on broken tables. | |||||
</p> | |||||
</info> | |||||
<fo> | |||||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"> | |||||
<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-before extent="0.5in"/> | |||||
<fo:region-after extent="0.5in"/> | |||||
</fo:simple-page-master> | |||||
</fo:layout-master-set> | |||||
<fo:page-sequence master-reference="normal" white-space-collapse="true"> | |||||
<fo:static-content flow-name="xsl-region-before"> | |||||
<fo:block background-color="yellow"> | |||||
f-i-c: <fo:retrieve-marker retrieve-class-name="test" retrieve-boundary="page" retrieve-position="first-including-carryover"/> | |||||
</fo:block> | |||||
<fo:block background-color="yellow"> | |||||
f-s-w-p: <fo:retrieve-marker retrieve-class-name="test" retrieve-boundary="page" retrieve-position="first-starting-within-page"/> | |||||
</fo:block> | |||||
</fo:static-content> | |||||
<fo:static-content flow-name="xsl-region-after"> | |||||
<fo:block text-align="end" background-color="yellow"> | |||||
l-s-w-p: <fo:retrieve-marker retrieve-class-name="test" retrieve-boundary="page" retrieve-position="last-starting-within-page"/> | |||||
</fo:block> | |||||
<fo:block text-align="end" background-color="yellow"> | |||||
l-e-w-p: <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 color="black" table-layout="fixed"> | |||||
<fo:table-column number-columns-repeated="2"/> | |||||
<fo:table-body> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row1</fo:marker> | |||||
<fo:block>row1</fo:block> | |||||
<fo:block>row1</fo:block> | |||||
<fo:block>row1</fo:block> | |||||
<fo:block>row1</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row1</fo:marker> | |||||
<fo:block>row1</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row2</fo:marker> | |||||
<fo:block>row2</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row2</fo:marker> | |||||
<fo:block>row2</fo:block> | |||||
<fo:block>row2</fo:block> | |||||
<fo:block>row2</fo:block> | |||||
<fo:block>row2</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row3</fo:marker> | |||||
<fo:block>row3</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row3</fo:marker> | |||||
<fo:block>row3</fo:block> | |||||
<fo:block>row3</fo:block> | |||||
<fo:block>row3</fo:block> | |||||
<fo:block>row3</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row4</fo:marker> | |||||
<fo:block>row4</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row5</fo:marker> | |||||
<fo:block>row5</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell> | |||||
<fo:marker marker-class-name="test">row5</fo:marker> | |||||
<fo:block>row5</fo:block> | |||||
<fo:block>row5</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell column-number="2"> | |||||
<fo:marker marker-class-name="test">row6</fo:marker> | |||||
<fo:block>row6</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
</fo:table-body> | |||||
</fo:table> | |||||
</fo:flow> | |||||
</fo:page-sequence> | |||||
</fo:root> | |||||
</fo> | |||||
<checks> | |||||
<true xpath="starts-with(//pageViewport[@nr=1]//regionBefore/block[1],'f-i-c: row1')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=1]//regionBefore/block[2],'f-s-w-p: row1')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=1]//regionAfter/block[1],'l-s-w-p: row2')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=1]//regionAfter/block[2],'l-e-w-p: row1')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=2]//regionBefore/block[1],'f-i-c: row2')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=2]//regionBefore/block[2],'f-s-w-p: row3')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=2]//regionAfter/block[1],'l-s-w-p: row3')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=2]//regionAfter/block[2],'l-e-w-p: row2')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=3]//regionBefore/block[1],'f-i-c: row3')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=3]//regionBefore/block[2],'f-s-w-p: row4')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=3]//regionAfter/block[1],'l-s-w-p: row5')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=3]//regionAfter/block[2],'l-e-w-p: row5')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=4]//regionBefore/block[1],'f-i-c: row6')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=4]//regionBefore/block[2],'f-s-w-p: row6')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=4]//regionAfter/block[1],'l-s-w-p: row6')"/> | |||||
<true xpath="starts-with(//pageViewport[@nr=4]//regionAfter/block[2],'l-e-w-p: row6')"/> | |||||
</checks> | |||||
</testcase> |
<?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 the retrieve-table-marker implementation. Rather, it serves as a regression test.</p> | |||||
</info> | |||||
<fo> | |||||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-size="10pt" font-family="sans-serif" | |||||
line-height="120%"> | |||||
<fo:layout-master-set> | |||||
<fo:simple-page-master master-name="base-page" page-height="210mm" page-width="297mm"> | |||||
<fo:region-body margin="15mm" column-count="3" /> | |||||
<fo:region-before extent="15mm" /> | |||||
<fo:region-after extent="11.4mm" /> | |||||
</fo:simple-page-master> | |||||
</fo:layout-master-set> | |||||
<fo:page-sequence master-reference="base-page"> | |||||
<fo:flow flow-name="xsl-region-body" font-family="sans-serif"> | |||||
<fo:block>The table has two columns, State and Facts. In the rows corresponding to states in the | |||||
Pacific Time Zone (PST), the State and Facts table | |||||
cells have a marker with the value of the State. That marker is retrieved in the table header and | |||||
footer. All the possible boundary and positions are considered in this example. | |||||
</fo:block> | |||||
<fo:block> rbwt = retrieve-boundary-within-table; rpwt = retrieve-position-within-table; | |||||
f-i-c = first-including-carryover; f-s = first-starting; l-s = last-starting; l-e = last-ending; | |||||
t = table; p = page; p-s = page-sequence; t-f = table-fragment. | |||||
</fo:block> | |||||
<fo:wrapper> | |||||
<fo:table space-before="1em" width="100%" table-layout="fixed"> | |||||
<fo:table-column column-width="proportional-column-width(3)" /> | |||||
<fo:table-column column-width="proportional-column-width(5)" /> | |||||
<fo:table-header> | |||||
<fo:table-row> | |||||
<fo:table-cell padding="4pt" number-columns-spanned="2" | |||||
background-color="yellow"> | |||||
<fo:block> | |||||
[rbwt:t][rpwt:f-i-c]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="first-including-carryover" retrieve-boundary-within-table="table" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:t][rpwt:f-s]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="first-starting" retrieve-boundary-within-table="table" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:p][rpwt:f-i-c]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="first-including-carryover" retrieve-boundary-within-table="page" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:p][rpwt:f-s]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="first-starting" retrieve-boundary-within-table="page" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:t-f][rpwt:f-i-c]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="first-including-carryover" retrieve-boundary-within-table="table-fragment" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:t-f][rpwt:f-s]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="first-starting" retrieve-boundary-within-table="table-fragment" /> | |||||
) | |||||
</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block font-weight="bold">State</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block font-weight="bold">Facts</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
</fo:table-header> | |||||
<fo:table-footer> | |||||
<fo:table-row> | |||||
<fo:table-cell padding="4pt" number-columns-spanned="2" | |||||
background-color="yellow"> | |||||
<fo:block> | |||||
[rbwt:t][rpwt:l-s]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="last-starting" retrieve-boundary-within-table="table" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:t][rpwt:l-e]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="last-ending" retrieve-boundary-within-table="table" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:p][rpwt:l-s]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="last-starting" retrieve-boundary-within-table="page" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:p][rpwt:l-e]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="last-ending" retrieve-boundary-within-table="page" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:t-f][rpwt:l-s]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="last-starting" retrieve-boundary-within-table="table-fragment" /> | |||||
) | |||||
</fo:block> | |||||
<fo:block> | |||||
[rbwt:t-f][rpwt:l-e]( | |||||
<fo:retrieve-table-marker retrieve-class-name="state" | |||||
retrieve-position-within-table="last-ending" retrieve-boundary-within-table="table-fragment" /> | |||||
) | |||||
</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
</fo:table-footer> | |||||
<fo:table-body> | |||||
<!--fo:marker marker-class-name="state">Alabama</fo:marker--> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Alabama</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Montgomery</fo:block> | |||||
<fo:block>Area: 52,423 square miles</fo:block> | |||||
<fo:block>Population: 4,447,100</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Alaska</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Juneau</fo:block> | |||||
<fo:block>Area: 656,425 square miles</fo:block> | |||||
<fo:block>Population: 626,932</fo:block> | |||||
<fo:block>Time Zone: GMT -9:00</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Arizona</fo:marker> | |||||
<fo:block>Arizona</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Arizona</fo:marker> | |||||
<fo:block>Capital: Phoenix</fo:block> | |||||
<fo:block>Area: 114,006 square miles</fo:block> | |||||
<fo:block>Population: 5,130,632</fo:block> | |||||
<fo:block>Time Zone: PST and MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Arkansas</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Little Rock</fo:block> | |||||
<fo:block>Area: 53,182 square miles</fo:block> | |||||
<fo:block>Population: 2,673,400</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">California</fo:marker> | |||||
<fo:block>California</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">California</fo:marker> | |||||
<fo:block>Capital: Sacramento</fo:block> | |||||
<fo:block>Area: 163,707 square miles</fo:block> | |||||
<fo:block>Population: 33,871,648</fo:block> | |||||
<fo:block>Time Zone: PST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Colorado</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Denver</fo:block> | |||||
<fo:block>Area: 104,100 square miles</fo:block> | |||||
<fo:block>Population: 4,301,261</fo:block> | |||||
<fo:block>Time Zone: MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Connecticut</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Hartford</fo:block> | |||||
<fo:block>Area: 5,544 square miles</fo:block> | |||||
<fo:block>Population: 3,405,565</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Delaware</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Dover</fo:block> | |||||
<fo:block>Area: 1,954 square miles</fo:block> | |||||
<fo:block>Population: 783,600</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Florida</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Tallahassee</fo:block> | |||||
<fo:block>Area: 65,758 square miles</fo:block> | |||||
<fo:block>Population: 15,982,378</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Georgia</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Atlanta</fo:block> | |||||
<fo:block>Area: 59,441 square miles</fo:block> | |||||
<fo:block>Population: 8,186,453</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Hawaii</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Honolulu</fo:block> | |||||
<fo:block>Area: 10,932 square miles</fo:block> | |||||
<fo:block>Population: 1,211,537</fo:block> | |||||
<fo:block>Time Zone: GMT -11:00</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Idaho</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Boise</fo:block> | |||||
<fo:block>Area: 83,574 square miles</fo:block> | |||||
<fo:block>Population: 1,293,953</fo:block> | |||||
<fo:block>Time Zone: MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Illinois</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Springfield</fo:block> | |||||
<fo:block>Area: 57,918 square miles</fo:block> | |||||
<fo:block>Population: 12,419,293</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Indiana</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Indianapolis</fo:block> | |||||
<fo:block>Area: 36,420 square miles</fo:block> | |||||
<fo:block>Population: 6,080,485</fo:block> | |||||
<fo:block>Time Zone: EST and CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Iowa</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Des Moines</fo:block> | |||||
<fo:block>Area: 56,276 square miles</fo:block> | |||||
<fo:block>Population: 2,926,324</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Kansas</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Topeka</fo:block> | |||||
<fo:block>Area: 82,282 square miles</fo:block> | |||||
<fo:block>Population: 2,688,418</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Kentucky</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Frankfort</fo:block> | |||||
<fo:block>Area: 40,411 square miles</fo:block> | |||||
<fo:block>Population: 4,041,769</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Louisiana</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Baton Rouge</fo:block> | |||||
<fo:block>Area: 51,843 square miles</fo:block> | |||||
<fo:block>Population: 4,468,976</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Maine</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Augusta</fo:block> | |||||
<fo:block>Area: 35,387 square miles</fo:block> | |||||
<fo:block>Population: 1,274,923</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Maryland</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Annapolis</fo:block> | |||||
<fo:block>Area: 12,407 square miles</fo:block> | |||||
<fo:block>Population: 5,296,486</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Massachusetts</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Boston</fo:block> | |||||
<fo:block>Area: 10,555 square miles</fo:block> | |||||
<fo:block>Population: 6,349,097</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Michigan</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Lansing</fo:block> | |||||
<fo:block>Area: 96,810 square miles</fo:block> | |||||
<fo:block>Population: 9,938,444</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Minnesota</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: St. Paul</fo:block> | |||||
<fo:block>Area: 86,943 square miles</fo:block> | |||||
<fo:block>Population: 4,919,479</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Mississippi</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Jackson</fo:block> | |||||
<fo:block>Area: 48,434 square miles</fo:block> | |||||
<fo:block>Population: 2,844,658</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Missouri</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Jefferson City</fo:block> | |||||
<fo:block>Area: 69,709 square miles</fo:block> | |||||
<fo:block>Population: 5,595,211</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Montana</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Helena</fo:block> | |||||
<fo:block>Area: 147,046 square miles</fo:block> | |||||
<fo:block>Population: 902,195</fo:block> | |||||
<fo:block>Time Zone: MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Nebraska</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Lincoln</fo:block> | |||||
<fo:block>Area: XXXXXX square miles</fo:block> | |||||
<fo:block>Population: 77,358</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Nevada</fo:marker> | |||||
<fo:block>Nevada</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Nevada</fo:marker> | |||||
<fo:block>Capital: Carson City</fo:block> | |||||
<fo:block>Area: 110,567 square miles</fo:block> | |||||
<fo:block>Population: 1,998,257</fo:block> | |||||
<fo:block>Time Zone: PST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>New Hampshire</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Concord</fo:block> | |||||
<fo:block>Area: 9,351 square miles</fo:block> | |||||
<fo:block>Population: 1,235,786</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>New Jersey</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Trenton</fo:block> | |||||
<fo:block>Area: 8,722 square miles</fo:block> | |||||
<fo:block>Population: 8,414,350</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>New Mexico</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Santa Fe</fo:block> | |||||
<fo:block>Area: 121,593 square miles</fo:block> | |||||
<fo:block>Population: 1,819,046</fo:block> | |||||
<fo:block>Time Zone: MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>New York</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Albany</fo:block> | |||||
<fo:block>Area: 54,475 square miles</fo:block> | |||||
<fo:block>Population: 18,976,457</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>North Carolina</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Raleigh</fo:block> | |||||
<fo:block>Area: 53,821 square miles</fo:block> | |||||
<fo:block>Population: 8,049,313</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>North Dakota</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Bismarck</fo:block> | |||||
<fo:block>Area: 70,704 square miles</fo:block> | |||||
<fo:block>Population: 642,200</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Ohio</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Columbus</fo:block> | |||||
<fo:block>Area: 44,828 square miles</fo:block> | |||||
<fo:block>Population: 11,353,140</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Oklahoma</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Oklahoma City</fo:block> | |||||
<fo:block>Area: 69,903 square miles</fo:block> | |||||
<fo:block>Population: 3,450,654</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Oregon</fo:marker> | |||||
<fo:block>Oregon</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Oregon</fo:marker> | |||||
<fo:block>Capital: Salem</fo:block> | |||||
<fo:block>Area: 98,386 square miles</fo:block> | |||||
<fo:block>Population: 3,421,399</fo:block> | |||||
<fo:block>Time Zone: PST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Pennsylvania</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Harrisburg</fo:block> | |||||
<fo:block>Area: 46,058 square miles</fo:block> | |||||
<fo:block>Population: 12,281,054</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Rhode Island</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Providence</fo:block> | |||||
<fo:block>Area: 1,045 square miles</fo:block> | |||||
<fo:block>Population: 1,048,319</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>South Carolina</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Columbia</fo:block> | |||||
<fo:block>Area: 32,007 square miles</fo:block> | |||||
<fo:block>Population: 4,012,012</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>South Dakota</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Pierre</fo:block> | |||||
<fo:block>Area: 77,121 square miles</fo:block> | |||||
<fo:block>Population: 754,844</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Tennessee</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Nashville</fo:block> | |||||
<fo:block>Area: 42,146 square miles</fo:block> | |||||
<fo:block>Population: 5,689,283</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Texas</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Austin</fo:block> | |||||
<fo:block>Area: 268,601 square miles</fo:block> | |||||
<fo:block>Population: 20,851,820</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Utah</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Salt Lake City</fo:block> | |||||
<fo:block>Area: 84,904 square miles</fo:block> | |||||
<fo:block>Population: 2,233,169</fo:block> | |||||
<fo:block>Time Zone: MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Vermont</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Montpelier</fo:block> | |||||
<fo:block>Area: 9,615 square miles</fo:block> | |||||
<fo:block>Population: 608,827</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Virginia</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Richmond</fo:block> | |||||
<fo:block>Area: 42,769 square miles</fo:block> | |||||
<fo:block>Population: 7,078,515</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Washington</fo:marker> | |||||
<fo:block>Washington</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:marker marker-class-name="state">Washington</fo:marker> | |||||
<fo:block>Capital: Olympia</fo:block> | |||||
<fo:block>Area: 71,303 square miles</fo:block> | |||||
<fo:block>Population: 5,894,121</fo:block> | |||||
<fo:block>Time Zone: PST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>West Virginia</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Charleston</fo:block> | |||||
<fo:block>Area: 24,231 square miles</fo:block> | |||||
<fo:block>Population: 1,808,344</fo:block> | |||||
<fo:block>Time Zone: EST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Wisconsin</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Madison</fo:block> | |||||
<fo:block>Area: 65,503 square miles</fo:block> | |||||
<fo:block>Population: 5,363,675</fo:block> | |||||
<fo:block>Time Zone: CST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Wyoming</fo:block> | |||||
</fo:table-cell> | |||||
<fo:table-cell padding-before="4pt" padding-after="4pt"> | |||||
<fo:block>Capital: Cheyenne</fo:block> | |||||
<fo:block>Area: 97,818 square miles</fo:block> | |||||
<fo:block>Population: 493,782</fo:block> | |||||
<fo:block>Time Zone: MST</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
</fo:table-body> | |||||
</fo:table> | |||||
</fo:wrapper> | |||||
</fo:flow> | |||||
</fo:page-sequence> | |||||
</fo:root> | |||||
</fo> | |||||
<checks> | |||||
<eval expected="1" xpath="//lineArea[starts-with(., '[rbwt:t-f][rpwt:f-i-c]( )')]/ancestor::pageViewport/@nr" /> | |||||
<eval expected="2" xpath="//lineArea[starts-with(., '[rbwt:t][rpwt:f-i-c]( Nevada )')]/ancestor::pageViewport/@nr" /> | |||||
<eval expected="2" xpath="//lineArea[starts-with(., '[rbwt:p][rpwt:f-i-c]( Nevada )')]/ancestor::pageViewport/@nr" /> | |||||
<eval expected="3" xpath="//lineArea[starts-with(., '[rbwt:t][rpwt:f-i-c]( Oregon )')]/ancestor::pageViewport/@nr" /> | |||||
<eval expected="[rbwt:t][rpwt:f-i-c]( California )" xpath="//pageViewport[2]/page/regionViewport[3]//flow[1]/block[1]/block[17]/block[1]/lineArea" /> | |||||
<eval expected="[rbwt:t][rpwt:f-i-c]( Oregon )" xpath="//pageViewport[3]/page/regionViewport[3]//flow[1]/block[1]/block[15]/block[1]/lineArea" /> | |||||
<eval expected="[rbwt:t][rpwt:f-i-c]( Washington )" xpath="//pageViewport[4]/page/regionViewport[3]//flow[1]/block[1]/block[5]/block[1]/lineArea" /> | |||||
</checks> | |||||
</testcase> |