git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1391502 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -34,6 +34,10 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.FOPException; | |||
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.traits.WritingModeTraitsGetter; | |||
@@ -81,13 +85,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable { | |||
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 | |||
@@ -352,115 +350,23 @@ public class PageViewport extends AreaTreeObject implements Resolvable { | |||
} | |||
/** | |||
* 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 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 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 | |||
* and position. | |||
* | |||
@@ -468,64 +374,17 @@ public class PageViewport extends AreaTreeObject implements Resolvable { | |||
* @param pos the position to retrieve | |||
* @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. */ | |||
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(); | |||
} | |||
} | |||
@@ -1227,6 +1227,8 @@ public interface Constants { | |||
int EN_BT = 204; // bottom to top | |||
/** Enumeration constant */ | |||
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 */ | |||
int ENUM_COUNT = 205; | |||
int ENUM_COUNT = 206; | |||
} |
@@ -562,6 +562,19 @@ public abstract class FONode implements Cloneable { | |||
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. | |||
* (e.g., <code>fo:layout-master-set</code> not having any <code>fo:page-master</code> |
@@ -2178,7 +2178,8 @@ public final class FOPropertyMapping implements Constants { | |||
m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE); | |||
m.setInherited(false); | |||
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-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING")); | |||
m.setDefault("first-starting"); | |||
@@ -2189,7 +2190,7 @@ public final class FOPropertyMapping implements Constants { | |||
m.setInherited(false); | |||
m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE")); | |||
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"); | |||
addPropertyMaker("retrieve-boundary-within-table", m); | |||
} |
@@ -89,6 +89,18 @@ public interface FOValidationEventProducer extends EventProducer { | |||
void invalidChild(Object source, String elementName, QName offendingNode, String ruleViolated, | |||
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. | |||
* @param source the event source |
@@ -17,6 +17,7 @@ | |||
<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="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="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> |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.fo; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
@@ -35,6 +36,7 @@ import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.apps.FOPException; | |||
import org.apache.fop.fo.extensions.ExtensionAttachment; | |||
import org.apache.fop.fo.flow.Marker; | |||
import org.apache.fop.fo.flow.table.TableCell; | |||
import org.apache.fop.fo.properties.PropertyMaker; | |||
/** | |||
@@ -65,7 +67,7 @@ public abstract class FObj extends FONode implements Constants { | |||
private boolean isOutOfLineFODescendant = false; | |||
/** Markers added to this element. */ | |||
private Map markers = null; | |||
private Map<String, Marker> markers; | |||
private int bidiLevel = -1; | |||
@@ -356,7 +358,7 @@ public abstract class FObj extends FONode implements Constants { | |||
} | |||
} | |||
if (markers == null) { | |||
markers = new java.util.HashMap(); | |||
markers = new HashMap<String, Marker>(); | |||
} | |||
if (!markers.containsKey(mcname)) { | |||
markers.put(mcname, marker); | |||
@@ -376,7 +378,7 @@ public abstract class FObj extends FONode implements Constants { | |||
/** | |||
* @return the collection of Markers attached to this object | |||
*/ | |||
public Map getMarkers() { | |||
public Map<String, Marker> getMarkers() { | |||
return markers; | |||
} | |||
@@ -522,6 +524,11 @@ public abstract class FObj extends FONode implements Constants { | |||
int found = 1; | |||
FONode temp = getParent(); | |||
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) { | |||
return found; | |||
} |
@@ -46,6 +46,11 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { | |||
private String retrieveClassName; | |||
private int position; | |||
private String positionLabel; | |||
private int boundary; | |||
private String boundaryLabel; | |||
/** | |||
* Create a new AbstractRetrieveMarker instance that | |||
* is a child of the given {@link FONode} | |||
@@ -206,4 +211,43 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { | |||
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; | |||
} | |||
} |
@@ -0,0 +1,212 @@ | |||
/* | |||
* 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); | |||
} | |||
} | |||
} |
@@ -34,11 +34,6 @@ import org.apache.fop.fo.PropertyList; | |||
*/ | |||
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 | |||
* child of the given {@link FONode}. | |||
@@ -70,8 +65,10 @@ public class RetrieveMarker extends AbstractRetrieveMarker { | |||
/** {@inheritDoc} */ | |||
public void bind(PropertyList pList) throws FOPException { | |||
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()); | |||
} | |||
/** | |||
@@ -84,19 +81,19 @@ public class RetrieveMarker extends AbstractRetrieveMarker { | |||
* {@link org.apache.fop.fo.Constants#EN_LEWP}. | |||
*/ | |||
public int getRetrievePosition() { | |||
return this.retrievePosition; | |||
return getPosition(); | |||
} | |||
/** | |||
* Return the value for the <code>retrieve-boundary</code> | |||
* 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_SEQUENCE}, | |||
* {@link org.apache.fop.fo.Constants#EN_DOCUMENT}. | |||
*/ | |||
public int getRetrieveBoundary() { | |||
return this.retrieveBoundary; | |||
return getBoundary(); | |||
} | |||
/** {@inheritDoc} */ |
@@ -32,11 +32,6 @@ import org.apache.fop.fo.PropertyList; | |||
*/ | |||
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 | |||
* a child of the given {@link FONode}. | |||
@@ -67,10 +62,10 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { | |||
/** {@inheritDoc} */ | |||
public void bind(PropertyList pList) throws FOPException { | |||
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()); | |||
} | |||
/** | |||
@@ -83,7 +78,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { | |||
* {@link org.apache.fop.fo.Constants#EN_LAST_ENDING}. | |||
*/ | |||
public int getRetrievePositionWithinTable() { | |||
return this.retrievePositionWithinTable; | |||
return getPosition(); | |||
} | |||
/** | |||
@@ -95,7 +90,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { | |||
* {@link org.apache.fop.fo.Constants#EN_PAGE}. | |||
*/ | |||
public int getRetrieveBoundaryWithinTable() { | |||
return this.retrieveBoundaryWithinTable; | |||
return getBoundary(); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -110,4 +105,12 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { | |||
public int getNameId() { | |||
return FO_RETRIEVE_TABLE_MARKER; | |||
} | |||
/** {@inheritDoc} */ | |||
public void clearChildNodes() { | |||
super.clearChildNodes(); | |||
this.currentTextNode = null; | |||
this.lastFOTextProcessed = null; | |||
} | |||
} |
@@ -62,6 +62,8 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder { | |||
/** used for FO validation */ | |||
private boolean blockItemFound = false; | |||
private boolean hasRetrieveTableMarker; | |||
/** | |||
* Create a TableCell instance with the given {@link FONode} | |||
* as parent. | |||
@@ -247,4 +249,11 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder { | |||
return FO_TABLE_CELL; | |||
} | |||
public void flagAsHavingRetrieveTableMarker() { | |||
hasRetrieveTableMarker = true; | |||
} | |||
public boolean hasRetrieveTableMarker() { | |||
return hasRetrieveTableMarker; | |||
} | |||
} |
@@ -169,6 +169,8 @@ public abstract class TablePart extends TableCellContainer { | |||
getUserAgent().getEventBroadcaster()); | |||
eventProducer.noMixRowsAndCells(this, getName(), getLocator()); | |||
} | |||
} else if (localName.equals("retrieve-table-marker")) { | |||
notSupportedChildError(loc, nsURI, localName); | |||
} else { | |||
invalidChildError(loc, nsURI, localName); | |||
} |
@@ -273,4 +273,11 @@ public abstract class AbstractBaseLayoutManager | |||
throw new UnsupportedOperationException("Not implemented"); | |||
} | |||
public void preserveChildrenAtEndOfLayout() { | |||
} | |||
public void recreateChildrenLMs() { | |||
} | |||
} |
@@ -37,6 +37,7 @@ import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.flow.Marker; | |||
import org.apache.fop.fo.flow.RetrieveMarker; | |||
import org.apache.fop.layoutmgr.table.TableLayoutManager; | |||
/** | |||
* The base class for most LayoutManagers. | |||
@@ -67,6 +68,8 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im | |||
private int lastGeneratedPosition = -1; | |||
private int smallestPosNumberChecked = Integer.MAX_VALUE; | |||
private boolean preserveChildrenAtEndOfLayout; | |||
/** | |||
* Abstract layout manager. | |||
*/ | |||
@@ -370,19 +373,20 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im | |||
} | |||
/** | |||
* 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 isFirst boolean indicating whether the markers qualify as 'first' | |||
* @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) { | |||
getCurrentPV().addMarkers( | |||
getCurrentPV().registerMarkers( | |||
this.markers, | |||
isStarting, | |||
isFirst, | |||
isLast); | |||
possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); | |||
} | |||
} | |||
@@ -419,11 +423,12 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im | |||
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 | |||
*/ | |||
@@ -438,13 +443,21 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im | |||
|| lm instanceof PageSequenceLayoutManager)) { | |||
lm = lm.getParent(); | |||
} | |||
if (lm instanceof FlowLayoutManager) { | |||
if (lm instanceof FlowLayoutManager && !preserveChildrenAtEndOfLayout) { | |||
fobj.clearChildNodes(); | |||
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} */ | |||
@Override | |||
public String toString() { | |||
@@ -467,4 +480,34 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im | |||
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); | |||
} | |||
} |
@@ -226,15 +226,14 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa | |||
public RetrieveMarker resolveRetrieveMarker(RetrieveMarker rm) { | |||
AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel(); | |||
String name = rm.getRetrieveClassName(); | |||
int pos = rm.getRetrievePosition(); | |||
int boundary = rm.getRetrieveBoundary(); | |||
// 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) { | |||
// go back over pages until mark found | |||
// if document boundary then keep going | |||
boolean doc = boundary == EN_DOCUMENT; | |||
boolean doc = (boundary == EN_DOCUMENT); | |||
int seq = areaTreeModel.getPageSequenceCount(); | |||
int page = areaTreeModel.getPageCount(seq) - 1; | |||
while (page < 0 && doc && seq > 1) { | |||
@@ -243,7 +242,11 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa | |||
} | |||
while (page >= 0) { | |||
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) { | |||
break; | |||
} |
@@ -87,7 +87,7 @@ public final class AreaAdditionUtil { | |||
} | |||
if (bslm != null) { | |||
bslm.addMarkersToPage( | |||
bslm.registerMarkers( | |||
true, | |||
bslm.isFirst(firstPos), | |||
bslm.isLast(lastPos)); | |||
@@ -114,11 +114,10 @@ public final class AreaAdditionUtil { | |||
} | |||
if (bslm != null) { | |||
bslm.addMarkersToPage( | |||
bslm.registerMarkers( | |||
false, | |||
bslm.isFirst(firstPos), | |||
bslm.isLast(lastPos)); | |||
bslm.checkEndOfLayout(lastPos); | |||
} | |||
@@ -806,7 +806,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl | |||
addId(); | |||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||
if (bcpos == null) { | |||
// the Positions in positionList were inside the elements | |||
@@ -826,7 +826,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl | |||
bcpos.getBreaker().addContainedAreas(layoutContext); | |||
} | |||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||
TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(), | |||
effSpaceBefore, effSpaceAfter); |
@@ -312,7 +312,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co | |||
addId(); | |||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||
// the Positions in positionList were inside the elements | |||
// created by the LineLM | |||
@@ -327,7 +327,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co | |||
childLM.addAreas(childPosIter, lc); | |||
} | |||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||
TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), | |||
effSpaceBefore, effSpaceAfter); |
@@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.area.AreaTreeHandler; | |||
import org.apache.fop.fo.FOElementMapping; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.FONode.FONodeIterator; | |||
import org.apache.fop.fo.FOText; | |||
import org.apache.fop.fo.FObjMixed; | |||
import org.apache.fop.fo.extensions.ExternalDocument; | |||
@@ -117,7 +118,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker { | |||
registerMaker(Block.class, new BlockLayoutManagerMaker()); | |||
registerMaker(Leader.class, new LeaderLayoutManagerMaker()); | |||
registerMaker(RetrieveMarker.class, new RetrieveMarkerLayoutManagerMaker()); | |||
registerMaker(RetrieveTableMarker.class, new Maker()); | |||
registerMaker(RetrieveTableMarker.class, new RetrieveTableMarkerLayoutManagerMaker()); | |||
registerMaker(Character.class, new CharacterLayoutManagerMaker()); | |||
registerMaker(ExternalGraphic.class, | |||
new ExternalGraphicLayoutManagerMaker()); | |||
@@ -407,6 +408,24 @@ public class LayoutManagerMapping implements LayoutManagerMaker { | |||
} | |||
} | |||
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 */ | |||
public class WrapperLayoutManagerMaker extends Maker { | |||
/** {@inheritDoc} */ |
@@ -0,0 +1,137 @@ | |||
/* | |||
* 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 | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* | |||
* 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; | |||
} | |||
} |
@@ -167,125 +167,22 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager { | |||
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} */ | |||
protected void observeElementList(List elementList) { | |||
String elementListID = getStaticContentFO().getFlowName(); | |||
String pageSequenceID = ((PageSequence)lm.getParent().getFObj()).getId(); | |||
String pageSequenceID = ((PageSequence) lm.getParent().getFObj()).getId(); | |||
if (pageSequenceID != null && pageSequenceID.length() > 0) { | |||
elementListID += "-" + pageSequenceID; | |||
} | |||
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 | |||
} | |||
} | |||
/** |
@@ -480,7 +480,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { | |||
context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); | |||
} | |||
addMarkersToPage( | |||
registerMarkers( | |||
true, | |||
!areaCreated, | |||
lastPos == null || isLast(lastPos)); | |||
@@ -542,7 +542,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { | |||
setTraits(areaCreated, lastPos == null || !isLast(lastPos)); | |||
parentLayoutManager.addChildArea(getCurrentArea()); | |||
addMarkersToPage( | |||
registerMarkers( | |||
false, | |||
!areaCreated, | |||
lastPos == null || isLast(lastPos)); |
@@ -171,7 +171,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager | |||
} | |||
} | |||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||
PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | |||
while ((childLM = childPosIter.getNextChildLM()) != null) { | |||
@@ -184,7 +184,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager | |||
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 | |||
TraitSetter.addBackground(curBlockArea, |
@@ -136,7 +136,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp | |||
} | |||
} | |||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||
PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | |||
while ((childLM = childPosIter.getNextChildLM()) != null) { | |||
@@ -149,7 +149,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp | |||
childLM.addAreas(childPosIter, lc); | |||
} | |||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||
flush(); | |||
@@ -509,7 +509,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements | |||
} | |||
} | |||
addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(true, isFirst(firstPos), isLast(lastPos)); | |||
// use the first and the last ListItemPosition to determine the | |||
// corresponding indexes in the original labelList and bodyList | |||
@@ -563,7 +563,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements | |||
} | |||
curBlockArea.setBPD(itemBPD); | |||
addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); | |||
registerMarkers(false, isFirst(firstPos), isLast(lastPos)); | |||
// We are done with this area add the background | |||
TraitSetter.addBackground(curBlockArea, |
@@ -303,11 +303,16 @@ class RowPainter { | |||
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, | |||
firstCellParts[i].start, lastCellParts[i].end, | |||
actualRowHeight, borderBeforeWhich, borderAfterWhich, | |||
lastOnPage); | |||
firstCellParts[i] = null; | |||
firstCellParts[i] = null; // why? what about the lastCellParts[i]? | |||
Arrays.fill(firstCellOnPage, i, i + currentGU.getCell().getNumberColumnsSpanned(), | |||
false); | |||
} |
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -28,19 +29,24 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.Block; | |||
import org.apache.fop.area.Trait; | |||
import org.apache.fop.fo.flow.Marker; | |||
import org.apache.fop.fo.flow.table.ConditionalBorder; | |||
import org.apache.fop.fo.flow.table.GridUnit; | |||
import org.apache.fop.fo.flow.table.PrimaryGridUnit; | |||
import org.apache.fop.fo.flow.table.Table; | |||
import org.apache.fop.fo.flow.table.TableCell; | |||
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.TableRow; | |||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||
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.BlockLevelLayoutManager; | |||
import org.apache.fop.layoutmgr.BlockStackingLayoutManager; | |||
import org.apache.fop.layoutmgr.ElementListObserver; | |||
import org.apache.fop.layoutmgr.ElementListUtils; | |||
import org.apache.fop.layoutmgr.Keep; | |||
import org.apache.fop.layoutmgr.KnuthBox; | |||
@@ -49,8 +55,10 @@ import org.apache.fop.layoutmgr.KnuthGlue; | |||
import org.apache.fop.layoutmgr.KnuthPenalty; | |||
import org.apache.fop.layoutmgr.LayoutContext; | |||
import org.apache.fop.layoutmgr.LayoutManager; | |||
import org.apache.fop.layoutmgr.LocalBreaker; | |||
import org.apache.fop.layoutmgr.Position; | |||
import org.apache.fop.layoutmgr.PositionIterator; | |||
import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager; | |||
import org.apache.fop.layoutmgr.SpaceResolver; | |||
import org.apache.fop.layoutmgr.TraitSetter; | |||
import org.apache.fop.traits.BorderProps; | |||
@@ -79,6 +87,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
private int totalHeight; | |||
private int usedBPD; | |||
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. | |||
@@ -88,6 +118,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) { | |||
super(node); | |||
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 */ | |||
@@ -248,6 +283,84 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
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 | |||
* managers that add block areas. | |||
@@ -407,7 +520,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
} | |||
} | |||
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 | |||
// for some reason (?) | |||
curBlockArea.setBPD(cellBPD); | |||
@@ -418,7 +552,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
getTableCell().getCommonBorderPaddingBackground(), this); | |||
} | |||
flush(); | |||
if (flushArea) { | |||
flush(); | |||
} else { | |||
flushArea = true; | |||
} | |||
curBlockArea = null; | |||
@@ -604,4 +742,49 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager | |||
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(); | |||
} | |||
} | |||
} |
@@ -31,9 +31,11 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.Constants; | |||
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.PrimaryGridUnit; | |||
import org.apache.fop.fo.flow.table.Table; | |||
import org.apache.fop.fo.flow.table.TableBody; | |||
import org.apache.fop.fo.flow.table.TablePart; | |||
import org.apache.fop.layoutmgr.BreakElement; | |||
import org.apache.fop.layoutmgr.ElementListUtils; | |||
@@ -400,9 +402,13 @@ public class TableContentLayoutManager implements PercentBaseContext { | |||
} | |||
} | |||
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) { | |||
getTableLM().getCurrentPV().addMarkers(markers, | |||
getTableLM().getCurrentPV().registerMarkers(markers, | |||
true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); | |||
} | |||
@@ -430,6 +436,10 @@ public class TableContentLayoutManager implements PercentBaseContext { | |||
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) { | |||
boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); | |||
layoutContext.setTreatAsArtifact(treatFooterAsArtifact); | |||
@@ -442,7 +452,7 @@ public class TableContentLayoutManager implements PercentBaseContext { | |||
this.usedBPD += painter.getAccumulatedBPD(); | |||
if (markers != null) { | |||
getTableLM().getCurrentPV().addMarkers(markers, | |||
getTableLM().getCurrentPV().registerMarkers(markers, | |||
false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); | |||
} | |||
} | |||
@@ -503,14 +513,20 @@ public class TableContentLayoutManager implements PercentBaseContext { | |||
*/ | |||
private void addTablePartAreas(List positions, RowPainter painter, TablePart body, | |||
boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { | |||
getTableLM().getCurrentPV().addMarkers(body.getMarkers(), | |||
getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), | |||
true, isFirstPos, isLastPos); | |||
if (body instanceof TableBody) { | |||
getTableLM().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); | |||
} | |||
painter.startTablePart(body); | |||
for (Iterator iter = positions.iterator(); iter.hasNext();) { | |||
painter.handleTableContentPosition((TableContentPosition) iter.next()); | |||
} | |||
getTableLM().getCurrentPV().addMarkers(body.getMarkers(), | |||
getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), | |||
false, isFirstPos, isLastPos); | |||
if (body instanceof TableBody) { | |||
getTableLM().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); | |||
} | |||
painter.endTablePart(lastInBody, lastOnPage); | |||
} | |||
@@ -23,6 +23,7 @@ import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -33,6 +34,9 @@ import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.FONode; | |||
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.TableColumn; | |||
import org.apache.fop.fo.properties.KeepProperty; | |||
@@ -93,6 +97,15 @@ public class TableLayoutManager extends BlockStackingLayoutManager | |||
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. | |||
* | |||
@@ -560,4 +573,112 @@ public class TableLayoutManager extends BlockStackingLayoutManager | |||
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); | |||
} | |||
} |
@@ -62,6 +62,9 @@ | |||
documents. Example: the fix of marks layering will be such a case when it's done. | |||
--> | |||
<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"> | |||
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 |
@@ -0,0 +1,128 @@ | |||
/* | |||
* 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 | |||
} | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.layoutmgr; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.mockito.Matchers.anyInt; | |||
import static org.mockito.Mockito.mock; | |||
@@ -31,7 +33,6 @@ import org.apache.fop.fo.pagination.PageSequence; | |||
import org.apache.fop.fo.pagination.Region; | |||
import org.apache.fop.fo.pagination.Root; | |||
import org.apache.fop.fo.pagination.SimplePageMaster; | |||
import org.junit.Test; | |||
public class PageSequenceLayoutManagerTestCase { | |||
@@ -0,0 +1,56 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.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); | |||
} | |||
} |
@@ -0,0 +1,82 @@ | |||
/* | |||
* 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(); | |||
} | |||
} |
@@ -0,0 +1,116 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
/* | |||
* 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(); | |||
} | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* 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)); | |||
} | |||
} |
@@ -0,0 +1,144 @@ | |||
<?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> |
@@ -0,0 +1,720 @@ | |||
<?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> |