git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1376923 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -72,8 +72,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { | |||
private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>(); | |||
private final Stack<FOEventRecorder> tableFooterRecorders = new Stack<FOEventRecorder>(); | |||
private final FOEventHandler structureTreeEventTrigger; | |||
/** The descendants of some elements like fo:leader must be ignored. */ | |||
@@ -165,6 +163,20 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { | |||
super.endPageNumberCitationLast(pageLast); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
handleStartArtifact(staticContent); | |||
converter.startStatic(staticContent); | |||
super.startStatic(staticContent); | |||
} | |||
@Override | |||
public void endStatic(StaticContent staticContent) { | |||
converter.endStatic(staticContent); | |||
handleEndArtifact(staticContent); | |||
super.endStatic(staticContent); | |||
} | |||
@Override | |||
public void startFlow(Flow fl) { | |||
converter.startFlow(fl); | |||
@@ -216,16 +228,11 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { | |||
@Override | |||
public void startTable(Table tbl) { | |||
converter.startTable(tbl); | |||
tableFooterRecorders.push(null); | |||
super.startTable(tbl); | |||
} | |||
@Override | |||
public void endTable(Table tbl) { | |||
FOEventRecorder tableFooterRecorder = tableFooterRecorders.pop(); | |||
if (tableFooterRecorder != null) { | |||
tableFooterRecorder.replay(converter); | |||
} | |||
converter.endTable(tbl); | |||
super.endTable(tbl); | |||
} | |||
@@ -256,8 +263,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { | |||
@Override | |||
public void startFooter(TableFooter footer) { | |||
converters.push(converter); | |||
converter = new FOEventRecorder(); | |||
converter.startFooter(footer); | |||
super.startFooter(footer); | |||
} | |||
@@ -265,10 +270,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { | |||
@Override | |||
public void endFooter(TableFooter footer) { | |||
converter.endFooter(footer); | |||
/* Replace the dummy table footer with the real one. */ | |||
tableFooterRecorders.pop(); | |||
tableFooterRecorders.push((FOEventRecorder) converter); | |||
converter = converters.pop(); | |||
super.endFooter(footer); | |||
} | |||
@@ -356,20 +357,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { | |||
super.endListBody(listItemBody); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
handleStartArtifact(staticContent); | |||
converter.startStatic(staticContent); | |||
super.startStatic(staticContent); | |||
} | |||
@Override | |||
public void endStatic(StaticContent statisContent) { | |||
converter.endStatic(statisContent); | |||
handleEndArtifact(statisContent); | |||
super.endStatic(statisContent); | |||
} | |||
@Override | |||
public void startMarkup() { | |||
converter.startMarkup(); |
@@ -1,508 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.accessibility.fo; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.fo.FOText; | |||
import org.apache.fop.fo.flow.BasicLink; | |||
import org.apache.fop.fo.flow.Block; | |||
import org.apache.fop.fo.flow.BlockContainer; | |||
import org.apache.fop.fo.flow.Character; | |||
import org.apache.fop.fo.flow.ExternalGraphic; | |||
import org.apache.fop.fo.flow.Footnote; | |||
import org.apache.fop.fo.flow.FootnoteBody; | |||
import org.apache.fop.fo.flow.Inline; | |||
import org.apache.fop.fo.flow.InstreamForeignObject; | |||
import org.apache.fop.fo.flow.Leader; | |||
import org.apache.fop.fo.flow.ListBlock; | |||
import org.apache.fop.fo.flow.ListItem; | |||
import org.apache.fop.fo.flow.ListItemBody; | |||
import org.apache.fop.fo.flow.ListItemLabel; | |||
import org.apache.fop.fo.flow.PageNumber; | |||
import org.apache.fop.fo.flow.PageNumberCitation; | |||
import org.apache.fop.fo.flow.PageNumberCitationLast; | |||
import org.apache.fop.fo.flow.Wrapper; | |||
import org.apache.fop.fo.flow.table.Table; | |||
import org.apache.fop.fo.flow.table.TableBody; | |||
import org.apache.fop.fo.flow.table.TableCell; | |||
import org.apache.fop.fo.flow.table.TableColumn; | |||
import org.apache.fop.fo.flow.table.TableFooter; | |||
import org.apache.fop.fo.flow.table.TableHeader; | |||
import org.apache.fop.fo.flow.table.TableRow; | |||
final class FOEventRecorder extends FOEventHandler { | |||
private interface Event { | |||
void replay(FOEventHandler target); | |||
} | |||
private final List<Event> events = new ArrayList<Event>(); | |||
public void replay(FOEventHandler target) { | |||
for (Event event : events) { | |||
event.replay(target); | |||
} | |||
} | |||
@Override | |||
public void startPageNumber(final PageNumber pagenum) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startPageNumber(pagenum); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endPageNumber(final PageNumber pagenum) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endPageNumber(pagenum); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startPageNumberCitation(final PageNumberCitation pageCite) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startPageNumberCitation(pageCite); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endPageNumberCitation(final PageNumberCitation pageCite) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endPageNumberCitation(pageCite); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startPageNumberCitationLast(final PageNumberCitationLast pageLast) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startPageNumberCitationLast(pageLast); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endPageNumberCitationLast(final PageNumberCitationLast pageLast) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endPageNumberCitationLast(pageLast); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startBlock(final Block bl) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startBlock(bl); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endBlock(final Block bl) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endBlock(bl); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startBlockContainer(final BlockContainer blc) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startBlockContainer(blc); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endBlockContainer(final BlockContainer blc) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endBlockContainer(blc); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startInline(final Inline inl) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startInline(inl); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endInline(final Inline inl) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endInline(inl); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startTable(final Table tbl) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startTable(tbl); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endTable(final Table tbl) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endTable(tbl); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startColumn(final TableColumn tc) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startColumn(tc); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endColumn(final TableColumn tc) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endColumn(tc); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startHeader(final TableHeader header) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startHeader(header); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endHeader(final TableHeader header) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endHeader(header); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startFooter(final TableFooter footer) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startFooter(footer); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endFooter(final TableFooter footer) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endFooter(footer); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startBody(final TableBody body) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startBody(body); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endBody(final TableBody body) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endBody(body); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startRow(final TableRow tr) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startRow(tr); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endRow(final TableRow tr) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endRow(tr); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startCell(final TableCell tc) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startCell(tc); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endCell(final TableCell tc) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endCell(tc); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startList(final ListBlock lb) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startList(lb); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endList(final ListBlock lb) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endList(lb); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startListItem(final ListItem li) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startListItem(li); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endListItem(final ListItem li) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endListItem(li); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startListLabel(final ListItemLabel listItemLabel) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startListLabel(listItemLabel); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endListLabel(final ListItemLabel listItemLabel) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endListLabel(listItemLabel); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startListBody(final ListItemBody listItemBody) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startListBody(listItemBody); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endListBody(final ListItemBody listItemBody) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endListBody(listItemBody); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startLink(final BasicLink basicLink) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startLink(basicLink); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endLink(final BasicLink basicLink) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endLink(basicLink); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void image(final ExternalGraphic eg) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.image(eg); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startInstreamForeignObject(final InstreamForeignObject ifo) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startInstreamForeignObject(ifo); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endInstreamForeignObject(final InstreamForeignObject ifo) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endInstreamForeignObject(ifo); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startFootnote(final Footnote footnote) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startFootnote(footnote); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endFootnote(final Footnote footnote) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endFootnote(footnote); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startFootnoteBody(final FootnoteBody body) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startFootnoteBody(body); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endFootnoteBody(final FootnoteBody body) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endFootnoteBody(body); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startLeader(final Leader l) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startLeader(l); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endLeader(final Leader l) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endLeader(l); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void startWrapper(final Wrapper wrapper) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.startWrapper(wrapper); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void endWrapper(final Wrapper wrapper) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.endWrapper(wrapper); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void character(final Character c) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.character(c); | |||
} | |||
}); | |||
} | |||
@Override | |||
public void characters(final FOText foText) { | |||
events.add(new Event() { | |||
public void replay(FOEventHandler target) { | |||
target.characters(foText); | |||
} | |||
}); | |||
} | |||
} |
@@ -55,6 +55,7 @@ import org.apache.fop.fo.flow.table.TableFooter; | |||
import org.apache.fop.fo.flow.table.TableHeader; | |||
import org.apache.fop.fo.flow.table.TableRow; | |||
import org.apache.fop.fo.pagination.Flow; | |||
import org.apache.fop.fo.pagination.LayoutMasterSet; | |||
import org.apache.fop.fo.pagination.PageSequence; | |||
import org.apache.fop.fo.pagination.StaticContent; | |||
import org.apache.fop.fo.properties.CommonAccessibilityHolder; | |||
@@ -67,6 +68,8 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
private StructureTreeEventHandler structureTreeEventHandler; | |||
private LayoutMasterSet layoutMasterSet; | |||
public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { | |||
this.structureTreeEventHandler = structureTreeEventHandler; | |||
} | |||
@@ -81,6 +84,9 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
@Override | |||
public void startPageSequence(PageSequence pageSeq) { | |||
if (layoutMasterSet == null) { | |||
layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet(); | |||
} | |||
Locale locale = null; | |||
if (pageSeq.getLanguage() != null) { | |||
if (pageSeq.getCountry() != null) { | |||
@@ -128,9 +134,28 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
endElement(pageLast); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
AttributesImpl flowName = createFlowNameAttribute(staticContent.getFlowName()); | |||
startElement(staticContent, flowName); | |||
} | |||
private AttributesImpl createFlowNameAttribute(String flowName) { | |||
String regionName = layoutMasterSet.getDefaultRegionNameFor(flowName); | |||
AttributesImpl attribute = new AttributesImpl(); | |||
addNoNamespaceAttribute(attribute, Flow.FLOW_NAME, regionName); | |||
return attribute; | |||
} | |||
@Override | |||
public void endStatic(StaticContent staticContent) { | |||
endElement(staticContent); | |||
} | |||
@Override | |||
public void startFlow(Flow fl) { | |||
startElement(fl); | |||
AttributesImpl flowName = createFlowNameAttribute(fl.getFlowName()); | |||
startElement(fl, flowName); | |||
} | |||
@Override | |||
@@ -277,16 +302,6 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
endElement(listItemBody); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
startElement(staticContent); | |||
} | |||
@Override | |||
public void endStatic(StaticContent statisContent) { | |||
endElement(statisContent); | |||
} | |||
@Override | |||
public void startLink(BasicLink basicLink) { | |||
startElementWithID(basicLink); |
@@ -142,6 +142,16 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler { | |||
delegate.endPageNumberCitationLast(pageLast); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
delegate.startStatic(staticContent); | |||
} | |||
@Override | |||
public void endStatic(StaticContent statisContent) { | |||
delegate.endStatic(statisContent); | |||
} | |||
@Override | |||
public void startFlow(Flow fl) { | |||
delegate.startFlow(fl); | |||
@@ -292,16 +302,6 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler { | |||
delegate.endListBody(listItemBody); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
delegate.startStatic(staticContent); | |||
} | |||
@Override | |||
public void endStatic(StaticContent statisContent) { | |||
delegate.endStatic(statisContent); | |||
} | |||
@Override | |||
public void startMarkup() { | |||
delegate.startMarkup(); |
@@ -192,6 +192,20 @@ public abstract class FOEventHandler { | |||
public void endPageNumberCitationLast(PageNumberCitationLast pageLast) { | |||
} | |||
/** | |||
* Process start of a Static. | |||
* @param staticContent StaticContent that is starting | |||
*/ | |||
public void startStatic(StaticContent staticContent) { | |||
} | |||
/** | |||
* Process end of a Static. | |||
* @param staticContent StaticContent that is ending | |||
*/ | |||
public void endStatic(StaticContent staticContent) { | |||
} | |||
/** | |||
* This method is called to indicate the start of a new fo:flow | |||
* or fo:static-content. | |||
@@ -409,22 +423,6 @@ public abstract class FOEventHandler { | |||
public void endListBody(ListItemBody listItemBody) { | |||
} | |||
// Static Regions | |||
/** | |||
* Process start of a Static. | |||
* @param staticContent StaticContent that is starting | |||
*/ | |||
public void startStatic(StaticContent staticContent) { | |||
} | |||
/** | |||
* Process end of a Static. | |||
* @param staticContent StaticContent that is ending | |||
*/ | |||
public void endStatic(StaticContent staticContent) { | |||
} | |||
/** | |||
* Process start of a Markup. | |||
*/ |
@@ -26,6 +26,7 @@ import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.fo.expr.PropertyException; | |||
import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker; | |||
import org.apache.fop.fo.pagination.Flow; | |||
import org.apache.fop.fo.properties.BackgroundPositionShorthand; | |||
import org.apache.fop.fo.properties.BorderSpacingShorthandParser; | |||
import org.apache.fop.fo.properties.BorderWidthPropertyMaker; | |||
@@ -2267,7 +2268,7 @@ public final class FOPropertyMapping implements Constants { | |||
m = new StringProperty.Maker(PR_FLOW_NAME); | |||
m.setInherited(false); | |||
m.setDefault(""); | |||
addPropertyMaker("flow-name", m); | |||
addPropertyMaker(Flow.FLOW_NAME, m); | |||
// force-page-count | |||
m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT); |
@@ -36,6 +36,9 @@ import org.apache.fop.fo.properties.CommonAccessibilityHolder; | |||
*/ | |||
public class Flow extends FObj implements CommonAccessibilityHolder { | |||
/** The "flow-name" property name. */ | |||
public static final String FLOW_NAME = "flow-name"; | |||
private String flowName; | |||
private CommonAccessibility commonAccessibility; | |||
@@ -61,7 +64,7 @@ public class Flow extends FObj implements CommonAccessibilityHolder { | |||
/** {@inheritDoc} */ | |||
protected void startOfNode() throws FOPException { | |||
if (flowName == null || flowName.equals("")) { | |||
missingPropertyError("flow-name"); | |||
missingPropertyError(FLOW_NAME); | |||
} | |||
// according to communication from Paul Grosso (XSL-List, |
@@ -217,5 +217,24 @@ public class LayoutMasterSet extends FObj { | |||
public int getNameId() { | |||
return FO_LAYOUT_MASTER_SET; | |||
} | |||
/** | |||
* Returns the default name of the region to which the flow or static-content having | |||
* the given flow-name is assigned. | |||
* | |||
* @param flowName the value of the flow-name property | |||
* @return the default region name ("xsl-region-body", "xsl-region-before", etc.) | |||
*/ | |||
public String getDefaultRegionNameFor(String flowName) { | |||
for (SimplePageMaster spm : simplePageMasters.values()) { | |||
for (Region region : spm.getRegions().values()) { | |||
if (region.getRegionName().equals(flowName)) { | |||
return region.getDefaultRegionName(); | |||
} | |||
} | |||
} | |||
assert flowName.equals("xsl-before-float-separator") || flowName.equals("xsl-footnote-separator"); | |||
return flowName; | |||
} | |||
} | |||
@@ -42,7 +42,7 @@ public class StaticContent extends Flow { | |||
/** {@inheritDoc} */ | |||
protected void startOfNode() throws FOPException { | |||
if (getFlowName() == null || getFlowName().equals("")) { | |||
missingPropertyError("flow-name"); | |||
missingPropertyError(FLOW_NAME); | |||
} | |||
getFOEventHandler().startStatic(this); | |||
} |
@@ -355,36 +355,20 @@ public class PDFDocument { | |||
} | |||
/** | |||
* Creates and returns a structure element. | |||
* | |||
* @param structureType the structure type of the new element (value for the | |||
* S entry) | |||
* @param parent the parent of the new structure element in the structure | |||
* hierarchy | |||
* @return a dictionary of type StructElem | |||
* Adds the given element to the structure tree. | |||
*/ | |||
public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent) { | |||
PDFStructElem structElem = new PDFStructElem(parent, structureType); | |||
public void registerStructureElement(PDFStructElem structElem) { | |||
assignObjectNumber(structElem); | |||
structureTreeElements.add(structElem); | |||
return structElem; | |||
} | |||
/** | |||
* Creates and returns a structure element. | |||
* | |||
* @param structureType the structure type of the new element (value for the | |||
* S entry) | |||
* @param parent the parent of the new structure element in the structure | |||
* hierarchy | |||
* @param scope the scope of the given table header element | |||
* @return a dictionary of type StructElem | |||
* Assigns the given scope to the given element and adds it to the structure tree. The | |||
* scope may not be added if it's not compatible with this document's PDF version. | |||
*/ | |||
public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent, | |||
Scope scope) { | |||
PDFStructElem structElem = makeStructureElement(structureType, parent); | |||
public void registerStructureElement(PDFStructElem structElem, Scope scope) { | |||
registerStructureElement(structElem); | |||
versionController.addTableHeaderScopeAttribute(structElem, scope); | |||
return structElem; | |||
} | |||
/** |
@@ -32,7 +32,8 @@ import org.apache.fop.util.LanguageTags; | |||
/** | |||
* Class representing a PDF Structure Element. | |||
*/ | |||
public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject { | |||
public class PDFStructElem extends StructureHierarchyMember | |||
implements StructureTreeElement, CompressedObject { | |||
private StructureType structureType; | |||
@@ -51,7 +52,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement | |||
* @param parent parent of this element | |||
* @param structureType the structure type of this element | |||
*/ | |||
PDFStructElem(PDFObject parent, StructureType structureType) { | |||
public PDFStructElem(PDFObject parent, StructureType structureType) { | |||
this(parent); | |||
this.structureType = structureType; | |||
put("S", structureType.getName()); | |||
@@ -86,6 +87,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement | |||
* | |||
* @param kid element to be added | |||
*/ | |||
@Override | |||
public void addKid(PDFObject kid) { | |||
if (kids == null) { | |||
kids = new ArrayList<PDFObject>(); |
@@ -22,7 +22,7 @@ package org.apache.fop.pdf; | |||
/** | |||
* Class representing a PDF /StructTreeRoot dictionary. | |||
*/ | |||
public class PDFStructTreeRoot extends PDFDictionary { | |||
public class PDFStructTreeRoot extends StructureHierarchyMember { | |||
/** | |||
* Creates a new /StructTreeRoot dictionary. | |||
@@ -49,6 +49,7 @@ public class PDFStructTreeRoot extends PDFDictionary { | |||
* | |||
* @param kid an object to be added to the K entry | |||
*/ | |||
@Override | |||
public void addKid(PDFObject kid) { | |||
getKids().add(kid); | |||
} |
@@ -111,6 +111,11 @@ public final class StandardStructureTypes { | |||
return name; | |||
} | |||
@Override | |||
public String toString() { | |||
return name.toString().substring(1); | |||
} | |||
} | |||
private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>(); |
@@ -0,0 +1,37 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.pdf; | |||
/** | |||
* An element in the document's structure tree. This can be either the structure tree root | |||
* or a structure element. | |||
* | |||
* @see "Section 10.6, <q>Logical Structure</q> of the PDF Reference, 4th edition (PDF 1.5)" | |||
*/ | |||
public abstract class StructureHierarchyMember extends PDFDictionary { | |||
/** | |||
* Adds the given object to the array of kids. | |||
* | |||
* @param kid an object to be added to the K entry | |||
*/ | |||
public abstract void addKid(PDFObject kid); | |||
} |
@@ -1,162 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.render.pdf; | |||
import java.util.Map; | |||
import org.apache.fop.events.EventBroadcaster; | |||
import org.apache.fop.pdf.PDFObject; | |||
import org.apache.fop.pdf.PDFStructElem; | |||
import org.apache.fop.pdf.StandardStructureTypes; | |||
import org.apache.fop.pdf.StructureType; | |||
/** | |||
* This class provides the standard mappings from Formatting Objects to PDF structure types. | |||
*/ | |||
final class FOToPDFRoleMap { | |||
private static final Map<String, Mapper> DEFAULT_MAPPINGS = new java.util.HashMap<String, Mapper>(); | |||
static { | |||
// Create the standard mappings | |||
// Declarations and Pagination and Layout Formatting Objects | |||
addMapping("root", StandardStructureTypes.Grouping.DOCUMENT); | |||
addMapping("page-sequence", StandardStructureTypes.Grouping.PART); | |||
addMapping("flow", StandardStructureTypes.Grouping.SECT); | |||
addMapping("static-content", StandardStructureTypes.Grouping.SECT); | |||
// Block-level Formatting Objects | |||
addMapping("block", StandardStructureTypes.Paragraphlike.P); | |||
addMapping("block-container", StandardStructureTypes.Grouping.DIV); | |||
// Inline-level Formatting Objects | |||
addMapping("character", StandardStructureTypes.InlineLevelStructure.SPAN); | |||
addMapping("external-graphic", StandardStructureTypes.Illustration.FIGURE); | |||
addMapping("instream-foreign-object", StandardStructureTypes.Illustration.FIGURE); | |||
addMapping("inline", StandardStructureTypes.InlineLevelStructure.SPAN); | |||
addMapping("inline-container", StandardStructureTypes.Grouping.DIV); | |||
addMapping("page-number", StandardStructureTypes.InlineLevelStructure.QUOTE); | |||
addMapping("page-number-citation", StandardStructureTypes.InlineLevelStructure.QUOTE); | |||
addMapping("page-number-citation-last", StandardStructureTypes.InlineLevelStructure.QUOTE); | |||
// Formatting Objects for Tables | |||
addMapping("table-and-caption", StandardStructureTypes.Grouping.DIV); | |||
addMapping("table", StandardStructureTypes.Table.TABLE); | |||
addMapping("table-caption", StandardStructureTypes.Grouping.CAPTION); | |||
addMapping("table-header", StandardStructureTypes.Table.THEAD); | |||
addMapping("table-footer", StandardStructureTypes.Table.TFOOT); | |||
addMapping("table-body", StandardStructureTypes.Table.TBODY); | |||
addMapping("table-row", StandardStructureTypes.Table.TR); | |||
addMapping("table-cell", new TableCellMapper()); | |||
// Formatting Objects for Lists | |||
addMapping("list-block", StandardStructureTypes.List.L); | |||
addMapping("list-item", StandardStructureTypes.List.LI); | |||
addMapping("list-item-body", StandardStructureTypes.List.LBODY); | |||
addMapping("list-item-label", StandardStructureTypes.List.LBL); | |||
// Dynamic Effects: Link and Multi Formatting Objects | |||
addMapping("basic-link", StandardStructureTypes.InlineLevelStructure.LINK); | |||
// Out-of-Line Formatting Objects | |||
addMapping("float", StandardStructureTypes.Grouping.DIV); | |||
addMapping("footnote", StandardStructureTypes.InlineLevelStructure.NOTE); | |||
addMapping("footnote-body", StandardStructureTypes.Grouping.SECT); | |||
addMapping("wrapper", StandardStructureTypes.InlineLevelStructure.SPAN); | |||
addMapping("marker", StandardStructureTypes.Grouping.PRIVATE); | |||
} | |||
private static void addMapping(String fo, StructureType structureType) { | |||
addMapping(fo, new SimpleMapper(structureType)); | |||
} | |||
private static void addMapping(String fo, Mapper mapper) { | |||
DEFAULT_MAPPINGS.put(fo, mapper); | |||
} | |||
/** | |||
* Maps a Formatting Object to a PDFName representing the associated structure type. | |||
* @param fo the formatting object's local name | |||
* @param role the value of the formatting object's role property | |||
* @param parent the parent of the structure element to be mapped | |||
* @param eventBroadcaster the event broadcaster | |||
* @return the structure type or null if no match could be found | |||
*/ | |||
public static StructureType mapFormattingObject(String fo, String role, | |||
PDFObject parent, EventBroadcaster eventBroadcaster) { | |||
StructureType type = null; | |||
if (role == null) { | |||
type = getDefaultMappingFor(fo, parent); | |||
} else { | |||
type = StandardStructureTypes.get(role); | |||
if (type == null) { | |||
type = getDefaultMappingFor(fo, parent); | |||
PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(fo, | |||
fo, role, type.toString().substring(1)); | |||
} | |||
} | |||
assert type != null; | |||
return type; | |||
} | |||
/** | |||
* Maps a Formatting Object to a PDFName representing the associated structure type. | |||
* @param fo the formatting object's local name | |||
* @param parent the parent of the structure element to be mapped | |||
* @return the structure type or NonStruct if no match could be found | |||
*/ | |||
private static StructureType getDefaultMappingFor(String fo, PDFObject parent) { | |||
Mapper mapper = DEFAULT_MAPPINGS.get(fo); | |||
if (mapper != null) { | |||
return mapper.getStructureType(parent); | |||
} else { | |||
return StandardStructureTypes.Grouping.NON_STRUCT; | |||
} | |||
} | |||
private interface Mapper { | |||
StructureType getStructureType(PDFObject parent); | |||
} | |||
private static class SimpleMapper implements Mapper { | |||
private StructureType structureType; | |||
public SimpleMapper(StructureType structureType) { | |||
this.structureType = structureType; | |||
} | |||
public StructureType getStructureType(PDFObject parent) { | |||
return structureType; | |||
} | |||
} | |||
private static class TableCellMapper implements Mapper { | |||
public StructureType getStructureType(PDFObject parent) { | |||
PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem(); | |||
//TODO What to do with cells from table-footer? Currently they are mapped on TD. | |||
if (grandParent.getStructureType() == StandardStructureTypes.Table.THEAD) { | |||
return StandardStructureTypes.Table.TH; | |||
} else { | |||
return StandardStructureTypes.Table.TD; | |||
} | |||
} | |||
} | |||
private FOToPDFRoleMap() { } | |||
} |
@@ -59,12 +59,11 @@ public interface PDFEventProducer extends EventProducer { | |||
* Custom structure type is not standard as per the PDF reference. | |||
* | |||
* @param source the event source | |||
* @param fo the local name of the formatting object having the custom type | |||
* @param type custom structure type | |||
* @param fallback default structure type used as a fallback | |||
* @event.severity WARN | |||
*/ | |||
void nonStandardStructureType(Object source, String fo, String type, String fallback); | |||
void nonStandardStructureType(Object source, String type, String fallback); | |||
/** | |||
* The encryption length must be a multiple of 8 between 40 and 128. |
@@ -21,24 +21,271 @@ package org.apache.fop.render.pdf; | |||
import java.util.LinkedList; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.fop.accessibility.StructureTreeElement; | |||
import org.apache.fop.accessibility.StructureTreeEventHandler; | |||
import org.apache.fop.events.EventBroadcaster; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
import org.apache.fop.fo.pagination.Flow; | |||
import org.apache.fop.pdf.PDFFactory; | |||
import org.apache.fop.pdf.PDFObject; | |||
import org.apache.fop.pdf.PDFParentTree; | |||
import org.apache.fop.pdf.PDFStructElem; | |||
import org.apache.fop.pdf.PDFStructTreeRoot; | |||
import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope; | |||
import org.apache.fop.pdf.StandardStructureTypes; | |||
import org.apache.fop.pdf.StandardStructureTypes.Grouping; | |||
import org.apache.fop.pdf.StandardStructureTypes.Table; | |||
import org.apache.fop.pdf.StructureHierarchyMember; | |||
import org.apache.fop.pdf.StructureType; | |||
import org.apache.fop.util.XMLUtil; | |||
class PDFStructureTreeBuilder implements StructureTreeEventHandler { | |||
private static final String ROLE = "role"; | |||
private static final Map<String, StructureElementBuilder> BUILDERS | |||
= new java.util.HashMap<String, StructureElementBuilder>(); | |||
private static final StructureElementBuilder DEFAULT_BUILDER | |||
= new DefaultStructureElementBuilder(Grouping.NON_STRUCT); | |||
static { | |||
// Declarations and Pagination and Layout Formatting Objects | |||
StructureElementBuilder regionBuilder = new RegionBuilder(); | |||
addBuilder("root", StandardStructureTypes.Grouping.DOCUMENT); | |||
addBuilder("page-sequence", new PageSequenceBuilder()); | |||
addBuilder("static-content", regionBuilder); | |||
addBuilder("flow", regionBuilder); | |||
// Block-level Formatting Objects | |||
addBuilder("block", StandardStructureTypes.Paragraphlike.P); | |||
addBuilder("block-container", StandardStructureTypes.Grouping.DIV); | |||
// Inline-level Formatting Objects | |||
addBuilder("character", StandardStructureTypes.InlineLevelStructure.SPAN); | |||
addBuilder("external-graphic", new ImageBuilder()); | |||
addBuilder("instream-foreign-object", new ImageBuilder()); | |||
addBuilder("inline", StandardStructureTypes.InlineLevelStructure.SPAN); | |||
addBuilder("inline-container", StandardStructureTypes.Grouping.DIV); | |||
addBuilder("page-number", StandardStructureTypes.InlineLevelStructure.QUOTE); | |||
addBuilder("page-number-citation", StandardStructureTypes.InlineLevelStructure.QUOTE); | |||
addBuilder("page-number-citation-last", StandardStructureTypes.InlineLevelStructure.QUOTE); | |||
// Formatting Objects for Tables | |||
addBuilder("table-and-caption", StandardStructureTypes.Grouping.DIV); | |||
addBuilder("table", new TableBuilder()); | |||
addBuilder("table-caption", StandardStructureTypes.Grouping.CAPTION); | |||
addBuilder("table-header", StandardStructureTypes.Table.THEAD); | |||
addBuilder("table-footer", new TableFooterBuilder()); | |||
addBuilder("table-body", StandardStructureTypes.Table.TBODY); | |||
addBuilder("table-row", StandardStructureTypes.Table.TR); | |||
addBuilder("table-cell", new TableCellBuilder()); | |||
// Formatting Objects for Lists | |||
addBuilder("list-block", StandardStructureTypes.List.L); | |||
addBuilder("list-item", StandardStructureTypes.List.LI); | |||
addBuilder("list-item-body", StandardStructureTypes.List.LBODY); | |||
addBuilder("list-item-label", StandardStructureTypes.List.LBL); | |||
// Dynamic Effects: Link and Multi Formatting Objects | |||
addBuilder("basic-link", StandardStructureTypes.InlineLevelStructure.LINK); | |||
// Out-of-Line Formatting Objects | |||
addBuilder("float", StandardStructureTypes.Grouping.DIV); | |||
addBuilder("footnote", StandardStructureTypes.InlineLevelStructure.NOTE); | |||
addBuilder("footnote-body", StandardStructureTypes.Grouping.SECT); | |||
addBuilder("wrapper", StandardStructureTypes.InlineLevelStructure.SPAN); | |||
addBuilder("marker", StandardStructureTypes.Grouping.PRIVATE); | |||
addBuilder("#PCDATA", new PlaceholderBuilder()); | |||
} | |||
private static void addBuilder(String fo, StructureType structureType) { | |||
addBuilder(fo, new DefaultStructureElementBuilder(structureType)); | |||
} | |||
private static void addBuilder(String fo, StructureElementBuilder mapper) { | |||
BUILDERS.put(fo, mapper); | |||
} | |||
private interface StructureElementBuilder { | |||
PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, PDFFactory pdfFactory, | |||
EventBroadcaster eventBroadcaster); | |||
} | |||
private static class DefaultStructureElementBuilder implements StructureElementBuilder { | |||
private final StructureType defaultStructureType; | |||
DefaultStructureElementBuilder(StructureType structureType) { | |||
this.defaultStructureType = structureType; | |||
} | |||
public final PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, | |||
PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) { | |||
String role = attributes.getValue(ROLE); | |||
StructureType structureType; | |||
if (role == null) { | |||
structureType = defaultStructureType; | |||
} else { | |||
structureType = StandardStructureTypes.get(role); | |||
if (structureType == null) { | |||
structureType = defaultStructureType; | |||
PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(role, role, | |||
structureType.toString()); | |||
} | |||
} | |||
PDFStructElem structElem = createStructureElement(parent, structureType); | |||
setAttributes(structElem, attributes); | |||
addKidToParent(structElem, parent, attributes); | |||
registerStructureElement(structElem, pdfFactory); | |||
return structElem; | |||
} | |||
protected PDFStructElem createStructureElement(StructureHierarchyMember parent, | |||
StructureType structureType) { | |||
return new PDFStructElem(parent, structureType); | |||
} | |||
protected void setAttributes(PDFStructElem structElem, Attributes attributes) { | |||
} | |||
protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent, | |||
Attributes attributes) { | |||
parent.addKid(kid); | |||
} | |||
protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) { | |||
pdfFactory.getDocument().registerStructureElement(structureElement); | |||
} | |||
} | |||
private static class PageSequenceBuilder extends DefaultStructureElementBuilder { | |||
PageSequenceBuilder() { | |||
super(StandardStructureTypes.Grouping.PART); | |||
} | |||
@Override | |||
protected PDFStructElem createStructureElement(StructureHierarchyMember parent, | |||
StructureType structureType) { | |||
return new PageSequenceStructElem(parent, structureType); | |||
} | |||
} | |||
private static class RegionBuilder extends DefaultStructureElementBuilder { | |||
RegionBuilder() { | |||
super(StandardStructureTypes.Grouping.SECT); | |||
} | |||
@Override | |||
protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent, | |||
Attributes attributes) { | |||
String flowName = attributes.getValue(Flow.FLOW_NAME); | |||
((PageSequenceStructElem) parent).addContent(flowName, kid); | |||
} | |||
} | |||
private static class ImageBuilder extends DefaultStructureElementBuilder { | |||
ImageBuilder() { | |||
super(StandardStructureTypes.Illustration.FIGURE); | |||
} | |||
@Override | |||
protected void setAttributes(PDFStructElem structElem, Attributes attributes) { | |||
String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text"); | |||
if (altTextNode == null) { | |||
altTextNode = "No alternate text specified"; | |||
} | |||
structElem.put("Alt", altTextNode); | |||
} | |||
} | |||
private static class TableBuilder extends DefaultStructureElementBuilder { | |||
TableBuilder() { | |||
super(StandardStructureTypes.Table.TABLE); | |||
} | |||
@Override | |||
protected PDFStructElem createStructureElement(StructureHierarchyMember parent, | |||
StructureType structureType) { | |||
return new TableStructElem(parent, structureType); | |||
} | |||
} | |||
private static class TableFooterBuilder extends DefaultStructureElementBuilder { | |||
public TableFooterBuilder() { | |||
super(StandardStructureTypes.Table.TFOOT); | |||
} | |||
@Override | |||
protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent, | |||
Attributes attributes) { | |||
((TableStructElem) parent).addTableFooter(kid); | |||
} | |||
} | |||
private static class TableCellBuilder extends DefaultStructureElementBuilder { | |||
TableCellBuilder() { | |||
super(StandardStructureTypes.Table.TD); | |||
} | |||
@Override | |||
protected PDFStructElem createStructureElement(StructureHierarchyMember parent, | |||
StructureType structureType) { | |||
PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem(); | |||
//TODO What to do with cells from table-footer? Currently they are mapped on TD. | |||
if (grandParent.getStructureType() == StandardStructureTypes.Table.THEAD) { | |||
structureType = StandardStructureTypes.Table.TH; | |||
} else { | |||
structureType = StandardStructureTypes.Table.TD; | |||
} | |||
return super.createStructureElement(parent, structureType); | |||
} | |||
@Override | |||
protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) { | |||
if (structureElement.getStructureType() == Table.TH) { | |||
pdfFactory.getDocument().registerStructureElement(structureElement, Scope.COLUMN); | |||
} else { | |||
pdfFactory.getDocument().registerStructureElement(structureElement); | |||
} | |||
} | |||
@Override | |||
protected void setAttributes(PDFStructElem structElem, Attributes attributes) { | |||
String columnSpan = attributes.getValue("number-columns-spanned"); | |||
if (columnSpan != null) { | |||
structElem.setTableAttributeColSpan(Integer.parseInt(columnSpan)); | |||
} | |||
String rowSpan = attributes.getValue("number-rows-spanned"); | |||
if (rowSpan != null) { | |||
structElem.setTableAttributeRowSpan(Integer.parseInt(rowSpan)); | |||
} | |||
} | |||
} | |||
private static class PlaceholderBuilder implements StructureElementBuilder { | |||
public PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, | |||
PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) { | |||
PDFStructElem elem = new PDFStructElem.Placeholder(parent); | |||
parent.addKid(elem); | |||
return elem; | |||
} | |||
} | |||
private PDFFactory pdfFactory; | |||
private EventBroadcaster eventBroadcaster; | |||
@@ -51,6 +298,10 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { | |||
this.pdfFactory = pdfFactory; | |||
} | |||
void setEventBroadcaster(EventBroadcaster eventBroadcaster) { | |||
this.eventBroadcaster = eventBroadcaster; | |||
} | |||
void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) { | |||
createRootStructureElement(logicalStructureHandler); | |||
} | |||
@@ -59,93 +310,53 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { | |||
assert rootStructureElement == null; | |||
PDFParentTree parentTree = logicalStructureHandler.getParentTree(); | |||
PDFStructTreeRoot structTreeRoot = pdfFactory.getDocument().makeStructTreeRoot(parentTree); | |||
rootStructureElement = createStructureElement("root", structTreeRoot, null); | |||
structTreeRoot.addKid(rootStructureElement); | |||
rootStructureElement = createStructureElement("root", structTreeRoot, | |||
new AttributesImpl(), pdfFactory, eventBroadcaster); | |||
} | |||
void setEventBroadcaster(EventBroadcaster eventBroadcaster) { | |||
this.eventBroadcaster = eventBroadcaster; | |||
} | |||
private static PDFStructElem createStructureElement(String name, StructureHierarchyMember parent, | |||
Attributes attributes, PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) { | |||
StructureElementBuilder builder = BUILDERS.get(name); | |||
if (builder == null) { | |||
// TODO is a fallback really necessary? | |||
builder = DEFAULT_BUILDER; | |||
} | |||
return builder.build(parent, attributes, pdfFactory, eventBroadcaster); | |||
} | |||
public void startPageSequence(Locale language, String role) { | |||
ancestors = new LinkedList<PDFStructElem>(); | |||
PDFStructElem structElem = createStructureElement("page-sequence", rootStructureElement, role); | |||
AttributesImpl attributes = new AttributesImpl(); | |||
attributes.addAttribute("", ROLE, ROLE, XMLUtil.CDATA, role); | |||
PDFStructElem structElem = createStructureElement("page-sequence", | |||
rootStructureElement, attributes, pdfFactory, eventBroadcaster); | |||
if (language != null) { | |||
structElem.setLanguage(language); | |||
} | |||
rootStructureElement.addKid(structElem); | |||
ancestors.add(structElem); | |||
} | |||
private PDFStructElem createStructureElement(String name, PDFObject parent, String role) { | |||
StructureType structureType = FOToPDFRoleMap.mapFormattingObject(name, role, parent, | |||
eventBroadcaster); | |||
if (structureType == Table.TH) { | |||
return pdfFactory.getDocument().makeStructureElement(structureType, parent, Scope.COLUMN); | |||
} else { | |||
return pdfFactory.getDocument().makeStructureElement(structureType, parent); | |||
} | |||
} | |||
public void endPageSequence() { | |||
} | |||
public StructureTreeElement startNode(String name, Attributes attributes) { | |||
PDFStructElem parent = ancestors.getFirst(); | |||
String role = attributes.getValue("role"); | |||
PDFStructElem structElem = createStructureElement(name, parent, role); | |||
setSpanAttributes(structElem, attributes); | |||
parent.addKid(structElem); | |||
PDFStructElem structElem = createStructureElement(name, parent, attributes, | |||
pdfFactory, eventBroadcaster); | |||
ancestors.addFirst(structElem); | |||
return structElem; | |||
} | |||
private void setSpanAttributes(PDFStructElem structElem, Attributes attributes) { | |||
String columnSpan = attributes.getValue("number-columns-spanned"); | |||
if (columnSpan != null) { | |||
structElem.setTableAttributeColSpan(Integer.parseInt(columnSpan)); | |||
} | |||
String rowSpan = attributes.getValue("number-rows-spanned"); | |||
if (rowSpan != null) { | |||
structElem.setTableAttributeRowSpan(Integer.parseInt(rowSpan)); | |||
} | |||
} | |||
public void endNode(String name) { | |||
removeFirstAncestor(); | |||
} | |||
private void removeFirstAncestor() { | |||
ancestors.removeFirst(); | |||
} | |||
public StructureTreeElement startImageNode(String name, Attributes attributes) { | |||
PDFStructElem parent = ancestors.getFirst(); | |||
String role = attributes.getValue("role"); | |||
PDFStructElem structElem = createStructureElement(name, parent, role); | |||
parent.addKid(structElem); | |||
String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text"); | |||
if (altTextNode != null) { | |||
structElem.put("Alt", altTextNode); | |||
} else { | |||
structElem.put("Alt", "No alternate text specified"); | |||
} | |||
ancestors.addFirst(structElem); | |||
return structElem; | |||
return startNode(name, attributes); | |||
} | |||
public StructureTreeElement startReferencedNode(String name, Attributes attributes) { | |||
PDFStructElem parent = ancestors.getFirst(); | |||
String role = attributes.getValue("role"); | |||
PDFStructElem structElem; | |||
if ("#PCDATA".equals(name)) { | |||
structElem = new PDFStructElem.Placeholder(parent); | |||
} else { | |||
structElem = createStructureElement(name, parent, role); | |||
} | |||
parent.addKid(structElem); | |||
ancestors.addFirst(structElem); | |||
return structElem; | |||
return startNode(name, attributes); | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.render.pdf; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.fop.pdf.PDFArray; | |||
import org.apache.fop.pdf.PDFObject; | |||
import org.apache.fop.pdf.PDFStructElem; | |||
import org.apache.fop.pdf.StructureType; | |||
class PageSequenceStructElem extends PDFStructElem { | |||
private List<PDFStructElem> regionBefores = new ArrayList<PDFStructElem>(); | |||
private List<PDFStructElem> regionAfters = new ArrayList<PDFStructElem>(); | |||
private List<PDFStructElem> regionStarts = new ArrayList<PDFStructElem>(); | |||
private List<PDFStructElem> regionEnds = new ArrayList<PDFStructElem>(); | |||
PageSequenceStructElem(PDFObject parent, StructureType structureType) { | |||
super(parent, structureType); | |||
} | |||
void addContent(String flowName, PDFStructElem content) { | |||
if (flowName.equals("xsl-region-before")) { | |||
regionBefores.add(content); | |||
} else if (flowName.equals("xsl-region-after")) { | |||
regionAfters.add(content); | |||
} else if (flowName.equals("xsl-region-start")) { | |||
regionStarts.add(content); | |||
} else if (flowName.equals("xsl-region-end")) { | |||
regionEnds.add(content); | |||
} else { | |||
addKid(content); | |||
} | |||
} | |||
@Override | |||
protected boolean attachKids() { | |||
assert !kids.isEmpty(); | |||
PDFArray k = new PDFArray(); | |||
addRegions(k, regionBefores); | |||
addRegions(k, regionStarts); | |||
addRegions(k, kids); | |||
addRegions(k, regionEnds); | |||
addRegions(k, regionAfters); | |||
put("K", k); | |||
return true; | |||
} | |||
private void addRegions(PDFArray k, List<? extends PDFObject> regions) { | |||
if (!regions.isEmpty()) { | |||
for (PDFObject kid : regions) { | |||
k.add(kid); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
/* | |||
* 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.render.pdf; | |||
import org.apache.fop.pdf.PDFObject; | |||
import org.apache.fop.pdf.PDFStructElem; | |||
import org.apache.fop.pdf.StructureType; | |||
class TableStructElem extends PDFStructElem { | |||
private PDFStructElem tableFooter; | |||
public TableStructElem(PDFObject parent, StructureType structureType) { | |||
super(parent, structureType); | |||
} | |||
void addTableFooter(PDFStructElem footer) { | |||
assert tableFooter == null; | |||
tableFooter = footer; | |||
} | |||
@Override | |||
protected boolean attachKids() { | |||
assert !kids.isEmpty(); | |||
if (tableFooter != null) { | |||
kids.add(tableFooter); | |||
} | |||
return super.attachKids(); | |||
} | |||
} |
@@ -62,6 +62,10 @@ | |||
documents. Example: the fix of marks layering will be such a case when it's done. | |||
--> | |||
<release version="FOP Trunk" date="TBD"> | |||
<action context="Renderers" dev="VH" type="fix" fixes-bug="53778"> | |||
When PDF accessibility is enabled, the contents for the different regions must appear in the | |||
proper order in the structure tree. | |||
</action> | |||
<action context="Renderers" dev="MH" type="fix" fixes-bug="53766" due-to="Robert Meyer"> | |||
Remove StandardEncoding as the encoding type from fonts used in the PDF renderer | |||
</action> |
@@ -19,8 +19,6 @@ | |||
package org.apache.fop.accessibility.fo; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
@@ -34,7 +32,6 @@ import javax.xml.transform.TransformerFactoryConfigurationError; | |||
import javax.xml.transform.dom.DOMResult; | |||
import javax.xml.transform.sax.SAXTransformerFactory; | |||
import javax.xml.transform.sax.TransformerHandler; | |||
import javax.xml.transform.stream.StreamResult; | |||
import javax.xml.transform.stream.StreamSource; | |||
import org.custommonkey.xmlunit.Diff; | |||
@@ -57,9 +54,17 @@ import org.apache.fop.fotreetest.DummyFOEventHandler; | |||
public class FO2StructureTreeConverterTestCase { | |||
private interface FOLoader { | |||
private static class FOLoader { | |||
InputStream getFoInputStream(); | |||
private final String resourceName; | |||
FOLoader(String resourceName) { | |||
this.resourceName = resourceName; | |||
} | |||
public InputStream getFoInputStream() { | |||
return getResource(resourceName); | |||
} | |||
} | |||
private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence"; | |||
@@ -68,62 +73,30 @@ public class FO2StructureTreeConverterTestCase { | |||
@Test | |||
public void testCompleteDocument() throws Exception { | |||
foLoader = new FOLoader() { | |||
public InputStream getFoInputStream() { | |||
return getResource("/org/apache/fop/fo/complete_document.fo"); | |||
} | |||
}; | |||
testConverter(); | |||
testConverter("/org/apache/fop/fo/complete_document.fo"); | |||
} | |||
@Test | |||
public void testTableFooters() throws Exception { | |||
foLoader = new FOLoader() { | |||
public InputStream getFoInputStream() { | |||
return getResource("table-footers.fo"); | |||
} | |||
}; | |||
testConverter(); | |||
} | |||
@Test | |||
public void testCompleteContentWrappedInTableFooter() throws Exception { | |||
Source xslt = new StreamSource(getResource("wrapCompleteDocumentInTableFooter.xsl")); | |||
Transformer transformer = createTransformer(xslt); | |||
InputStream originalFO = getResource("/org/apache/fop/fo/complete_document.fo"); | |||
ByteArrayOutputStream transformedFoOutput = new ByteArrayOutputStream(); | |||
transformer.transform(new StreamSource(originalFO), new StreamResult(transformedFoOutput)); | |||
final byte[] transformedFoOutputBytes = transformedFoOutput.toByteArray(); | |||
foLoader = new FOLoader() { | |||
public InputStream getFoInputStream() { | |||
return new ByteArrayInputStream(transformedFoOutputBytes); | |||
} | |||
}; | |||
testConverter(); | |||
testConverter("table-footers.fo"); | |||
} | |||
@Test | |||
public void testArtifact() throws Exception { | |||
foLoader = new FOLoader() { | |||
public InputStream getFoInputStream() { | |||
return getResource("artifact.fo"); | |||
} | |||
}; | |||
testConverter(); | |||
testConverter("artifact.fo"); | |||
} | |||
private Transformer createTransformer(Source xslt) throws TransformerFactoryConfigurationError, | |||
TransformerConfigurationException { | |||
TransformerFactory transformerFactory = TransformerFactory.newInstance(); | |||
return transformerFactory.newTransformer(xslt); | |||
@Test | |||
public void testSideRegions() throws Exception { | |||
testConverter("/org/apache/fop/fo/pagination/side-regions.fo"); | |||
} | |||
private static InputStream getResource(String name) { | |||
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name); | |||
} | |||
private void testConverter() throws Exception { | |||
private void testConverter(String foResourceName) throws Exception { | |||
foLoader = new FOLoader(foResourceName); | |||
DOMResult expectedStructureTree = loadExpectedStructureTree(); | |||
DOMResult actualStructureTree = buildActualStructureTree(); | |||
final Diff diff = createDiff(expectedStructureTree, actualStructureTree); |
@@ -50,6 +50,25 @@ | |||
<xsl:call-template name="copy"/> | |||
</xsl:template> | |||
<xsl:template match="fo:static-content/@flow-name|fo:flow/@flow-name"> | |||
<xsl:choose> | |||
<xsl:when test=". = 'xsl-region-body' or | |||
. = 'xsl-region-before' or | |||
. = 'xsl-region-after' or | |||
. = 'xsl-region-start' or | |||
. = 'xsl-region-end' or | |||
. = 'xsl-before-float-separator' or | |||
. = 'xsl-footnote-separator'"> | |||
<xsl:copy/> | |||
</xsl:when> | |||
<xsl:otherwise> | |||
<xsl:attribute name="{local-name()}"> | |||
<xsl:value-of select="concat('xsl-', local-name(//*[@region-name = current()]))"/> | |||
</xsl:attribute> | |||
</xsl:otherwise> | |||
</xsl:choose> | |||
</xsl:template> | |||
<!-- Block-level Formatting Objects --> | |||
<xsl:template match="fo:block|fo:block-container"> | |||
<xsl:call-template name="copy"/> | |||
@@ -73,15 +92,7 @@ | |||
<xsl:call-template name="copy"/> | |||
</xsl:template> | |||
<xsl:template match="fo:table"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*"/> | |||
<xsl:apply-templates select="*[name() != 'fo:table-footer']"/> | |||
<xsl:apply-templates select="fo:table-footer"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<xsl:template match="fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell"> | |||
<xsl:template match="fo:table|fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell"> | |||
<xsl:call-template name="copy"/> | |||
</xsl:template> | |||
@@ -1,66 +0,0 @@ | |||
<?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$ --> | |||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | |||
xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<xsl:template match="@*|node()" name="copy"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*|node()"/> | |||
</xsl:copy> | |||
</xsl:template> | |||
<xsl:template match="/"> | |||
<fo:root> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="page" | |||
page-height="500pt" page-width="300pt" margin="20pt"> | |||
<fo:region-body margin-top="20pt"/> | |||
</fo:simple-page-master> | |||
</fo:layout-master-set> | |||
<xsl:apply-templates select="//fo:page-sequence"/> | |||
</fo:root> | |||
</xsl:template> | |||
<xsl:template match="fo:page-sequence"> | |||
<fo:page-sequence master-reference="page"> | |||
<xsl:apply-templates select="fo:flow"/> | |||
</fo:page-sequence> | |||
</xsl:template> | |||
<xsl:template match="fo:flow"> | |||
<xsl:copy> | |||
<xsl:apply-templates select="@*[not(starts-with(name(), 'space-before'))]"/> | |||
<fo:table width="100%" table-layout="fixed"> | |||
<fo:table-footer> | |||
<fo:table-cell background-color="#F0F0F0"> | |||
<xsl:apply-templates select="@*[starts-with(name(), 'space-before')]"/> | |||
<xsl:apply-templates select="*"/> | |||
</fo:table-cell> | |||
</fo:table-footer> | |||
<fo:table-body> | |||
<fo:table-cell> | |||
<fo:block>The content below is in the table footer.</fo:block> | |||
</fo:table-cell> | |||
</fo:table-body> | |||
</fo:table> | |||
</xsl:copy> | |||
</xsl:template> | |||
</xsl:stylesheet> |
@@ -0,0 +1,95 @@ | |||
/* | |||
* 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.pagination; | |||
import org.junit.Test; | |||
import static org.junit.Assert.assertEquals; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fo.FODocumentParser; | |||
import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory; | |||
import org.apache.fop.fo.FOEventHandler; | |||
public class LayoutMasterSetTestCase { | |||
private static class FlowMappingTester extends FOEventHandler { | |||
private static final String[][] FLOW_MAPPINGS = { | |||
{"first-page-before", "xsl-region-before"}, | |||
{"first-page-after", "xsl-region-after"}, | |||
{"first-page-start", "xsl-region-start"}, | |||
{"first-page-end", "xsl-region-end"}, | |||
{"odd-page-before", "xsl-region-before"}, | |||
{"odd-page-after", "xsl-region-after"}, | |||
{"odd-page-start", "xsl-region-start"}, | |||
{"odd-page-end", "xsl-region-end"}, | |||
{"odd-page-before", "xsl-region-before"}, | |||
{"odd-page-after", "xsl-region-after"}, | |||
{"odd-page-start", "xsl-region-start"}, | |||
{"odd-page-end", "xsl-region-end"}, | |||
{"blank-page-before", "xsl-region-before"}, | |||
{"blank-page-after", "xsl-region-after"}, | |||
{"blank-page-start", "xsl-region-start"}, | |||
{"blank-page-end", "xsl-region-end"}, | |||
{"last-page-before", "xsl-region-before"}, | |||
{"last-page-after", "xsl-region-after"}, | |||
{"last-page-start", "xsl-region-start"}, | |||
{"last-page-end", "xsl-region-end"}, | |||
{"xsl-footnote-separator", "xsl-footnote-separator"} | |||
}; | |||
FlowMappingTester(FOUserAgent userAgent) { | |||
super(userAgent); | |||
} | |||
@Override | |||
public void startPageSequence(PageSequence pageSeq) { | |||
super.startPageSequence(pageSeq); | |||
LayoutMasterSet layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet(); | |||
for (String[] mapping : FLOW_MAPPINGS) { | |||
assertEquals(mapping[1], layoutMasterSet.getDefaultRegionNameFor(mapping[0])); | |||
} | |||
} | |||
} | |||
/** | |||
* Tests the {@link LayoutMasterSet#getDefaultRegionNameFor(String)} method. | |||
*/ | |||
@Test | |||
public void testFlowMapping() throws Exception { | |||
FODocumentParser foDocumentParser = FODocumentParser.newInstance(new FOEventHandlerFactory() { | |||
public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) { | |||
return new FlowMappingTester(foUserAgent); | |||
} | |||
}); | |||
foDocumentParser.parse(getClass().getResourceAsStream("side-regions.fo")); | |||
} | |||
} |
@@ -0,0 +1,181 @@ | |||
<?xml version="1.0" standalone="no"?> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="first-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#FFF0F0"/> | |||
<fo:region-before region-name="first-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="first-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="first-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="first-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="odd-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#FFFFF0"/> | |||
<fo:region-before region-name="odd-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="odd-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="odd-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="odd-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="even-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#F0FFF0"/> | |||
<fo:region-before region-name="even-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="even-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="even-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="even-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="blank-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#F0F0F0"/> | |||
<fo:region-before region-name="blank-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="blank-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="blank-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="blank-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="last-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="45pt 12pt" display-align="center" background-color="#F0F0FF"/> | |||
<fo:region-before region-name="last-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="last-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="last-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="last-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:repeatable-page-master-alternatives> | |||
<fo:conditional-page-master-reference page-position="first" master-reference="first-page"/> | |||
<fo:conditional-page-master-reference page-position="last" master-reference="last-page"/> | |||
<fo:conditional-page-master-reference blank-or-not-blank="blank" | |||
master-reference="blank-page"/> | |||
<fo:conditional-page-master-reference odd-or-even="odd" master-reference="odd-page"/> | |||
<fo:conditional-page-master-reference odd-or-even="even" master-reference="even-page"/> | |||
</fo:repeatable-page-master-alternatives> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages" force-page-count="even" font-size="4pt" | |||
text-align="center"> | |||
<fo:static-content flow-name="first-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid red" | |||
padding-bottom="0.5pt">First Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="first-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid red" | |||
padding-top="0.5pt">First Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="first-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red" | |||
padding-bottom="0.5pt">First Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="first-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red" | |||
padding-bottom="0.5pt">First Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid orange" | |||
padding-top="0.5pt">Odd Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange" | |||
padding-bottom="0.5pt">Odd Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange" | |||
padding-bottom="0.5pt">Odd Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid orange" | |||
padding-bottom="0.5pt">Odd Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green" | |||
padding-bottom="0.5pt">Even Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green" | |||
padding-bottom="0.5pt">Even Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid green" | |||
padding-top="0.5pt">Even Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid green" | |||
padding-bottom="0.5pt">Even Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black" | |||
padding-bottom="0.5pt">Blank Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid black" | |||
padding-top="0.5pt">Blank Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid black" | |||
padding-bottom="0.5pt">Blank Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black" | |||
padding-bottom="0.5pt">Blank Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid blue" | |||
padding-bottom="0.5pt">Last Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue" | |||
padding-bottom="0.5pt">Last Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid blue" | |||
padding-top="0.5pt">Last Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue" | |||
padding-bottom="0.5pt">Last Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="xsl-footnote-separator"> | |||
<fo:block> | |||
<fo:leader leader-pattern="rule" leader-length="40%" rule-thickness="0.5pt"/> | |||
</fo:block> | |||
</fo:static-content> | |||
<fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt"> | |||
<fo:block>Apache™ FOP (Formatting Objects Processor) is a print formatter driven by XSL | |||
formatting objects (XSL-FO) and an output independent formatter.</fo:block> | |||
<fo:block break-before="page">It is an application<fo:footnote><fo:inline>*</fo:inline> | |||
<fo:footnote-body><fo:block font-size="80%">* written in | |||
Java</fo:block></fo:footnote-body></fo:footnote> that reads a formatting object (FO) | |||
tree and renders the resulting pages to a specified output.</fo:block> | |||
<fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which | |||
is a wider community of users and developers of open source projects.</fo:block> | |||
<fo:block break-before="page">Apache™ FOP (Formatting Objects Processor) is a print formatter | |||
driven by XSL formatting objects (XSL-FO) and an output independent formatter.</fo:block> | |||
<fo:block break-before="page">It is a Java application that reads a formatting object (FO) | |||
tree and renders the resulting pages to a specified output.</fo:block> | |||
<fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which | |||
is a wider community of users and developers of open source projects.</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> |
@@ -52,7 +52,8 @@ public class TableHeaderScopeTestCase { | |||
VersionController controller = mock(VersionController.class); | |||
PDFDocument document = new PDFDocument("Test", controller); | |||
document.makeStructTreeRoot(null); | |||
document.makeStructureElement(Table.TH, null, scope); | |||
PDFStructElem th = new PDFStructElem(null, Table.TH); | |||
document.registerStructureElement(th, scope); | |||
verify(controller).addTableHeaderScopeAttribute(any(PDFStructElem.class), eq(scope)); | |||
} | |||
@@ -0,0 +1,181 @@ | |||
<?xml version="1.0" standalone="no"?> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="first-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#FFF0F0"/> | |||
<fo:region-before region-name="first-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="first-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="first-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="first-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="odd-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#FFFFF0"/> | |||
<fo:region-before region-name="odd-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="odd-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="odd-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="odd-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="even-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#F0FFF0"/> | |||
<fo:region-before region-name="even-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="even-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="even-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="even-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="blank-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="12pt" display-align="center" background-color="#F0F0F0"/> | |||
<fo:region-before region-name="blank-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="blank-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="blank-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="blank-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="last-page" | |||
page-height="100pt" page-width="150pt"> | |||
<fo:region-body margin="45pt 12pt" display-align="center" background-color="#F0F0FF"/> | |||
<fo:region-before region-name="last-page-before" extent="10pt" precedence="true" | |||
display-align="after"/> | |||
<fo:region-after region-name="last-page-after" extent="10pt" precedence="true"/> | |||
<fo:region-start region-name="last-page-start" extent="10pt" reference-orientation="90" | |||
display-align="after"/> | |||
<fo:region-end region-name="last-page-end" extent="10pt" reference-orientation="-90" | |||
display-align="after"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:repeatable-page-master-alternatives> | |||
<fo:conditional-page-master-reference page-position="first" master-reference="first-page"/> | |||
<fo:conditional-page-master-reference page-position="last" master-reference="last-page"/> | |||
<fo:conditional-page-master-reference blank-or-not-blank="blank" | |||
master-reference="blank-page"/> | |||
<fo:conditional-page-master-reference odd-or-even="odd" master-reference="odd-page"/> | |||
<fo:conditional-page-master-reference odd-or-even="even" master-reference="even-page"/> | |||
</fo:repeatable-page-master-alternatives> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages" force-page-count="even" font-size="4pt" | |||
text-align="center"> | |||
<fo:static-content flow-name="first-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid red" | |||
padding-bottom="0.5pt">First Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="first-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid red" | |||
padding-top="0.5pt">First Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="first-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red" | |||
padding-bottom="0.5pt">First Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="first-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red" | |||
padding-bottom="0.5pt">First Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid orange" | |||
padding-top="0.5pt">Odd Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange" | |||
padding-bottom="0.5pt">Odd Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange" | |||
padding-bottom="0.5pt">Odd Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="odd-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid orange" | |||
padding-bottom="0.5pt">Odd Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green" | |||
padding-bottom="0.5pt">Even Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green" | |||
padding-bottom="0.5pt">Even Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid green" | |||
padding-top="0.5pt">Even Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="even-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid green" | |||
padding-bottom="0.5pt">Even Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black" | |||
padding-bottom="0.5pt">Blank Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid black" | |||
padding-top="0.5pt">Blank Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid black" | |||
padding-bottom="0.5pt">Blank Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="blank-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black" | |||
padding-bottom="0.5pt">Blank Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-before"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid blue" | |||
padding-bottom="0.5pt">Last Page Before.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-end"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue" | |||
padding-bottom="0.5pt">Last Page End.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-after"> | |||
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid blue" | |||
padding-top="0.5pt">Last Page After.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="last-page-start"> | |||
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue" | |||
padding-bottom="0.5pt">Last Page Start.</fo:block> | |||
</fo:static-content> | |||
<fo:static-content flow-name="xsl-footnote-separator"> | |||
<fo:block> | |||
<fo:leader leader-pattern="rule" leader-length="40%" rule-thickness="0.5pt"/> | |||
</fo:block> | |||
</fo:static-content> | |||
<fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt"> | |||
<fo:block>Apache™ FOP (Formatting Objects Processor) is a print formatter driven by XSL | |||
formatting objects (XSL-FO) and an output independent formatter.</fo:block> | |||
<fo:block break-before="page">It is an application<fo:footnote><fo:inline>*</fo:inline> | |||
<fo:footnote-body><fo:block font-size="80%">* written in | |||
Java</fo:block></fo:footnote-body></fo:footnote> that reads a formatting object (FO) | |||
tree and renders the resulting pages to a specified output.</fo:block> | |||
<fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which | |||
is a wider community of users and developers of open source projects.</fo:block> | |||
<fo:block break-before="page">Apache™ FOP (Formatting Objects Processor) is a print formatter | |||
driven by XSL formatting objects (XSL-FO) and an output independent formatter.</fo:block> | |||
<fo:block break-before="page">It is a Java application that reads a formatting object (FO) | |||
tree and renders the resulting pages to a specified output.</fo:block> | |||
<fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which | |||
is a wider community of users and developers of open source projects.</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> |