git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1376923 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>(); | private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>(); | ||||
private final Stack<FOEventRecorder> tableFooterRecorders = new Stack<FOEventRecorder>(); | |||||
private final FOEventHandler structureTreeEventTrigger; | private final FOEventHandler structureTreeEventTrigger; | ||||
/** The descendants of some elements like fo:leader must be ignored. */ | /** The descendants of some elements like fo:leader must be ignored. */ | ||||
super.endPageNumberCitationLast(pageLast); | 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 | @Override | ||||
public void startFlow(Flow fl) { | public void startFlow(Flow fl) { | ||||
converter.startFlow(fl); | converter.startFlow(fl); | ||||
@Override | @Override | ||||
public void startTable(Table tbl) { | public void startTable(Table tbl) { | ||||
converter.startTable(tbl); | converter.startTable(tbl); | ||||
tableFooterRecorders.push(null); | |||||
super.startTable(tbl); | super.startTable(tbl); | ||||
} | } | ||||
@Override | @Override | ||||
public void endTable(Table tbl) { | public void endTable(Table tbl) { | ||||
FOEventRecorder tableFooterRecorder = tableFooterRecorders.pop(); | |||||
if (tableFooterRecorder != null) { | |||||
tableFooterRecorder.replay(converter); | |||||
} | |||||
converter.endTable(tbl); | converter.endTable(tbl); | ||||
super.endTable(tbl); | super.endTable(tbl); | ||||
} | } | ||||
@Override | @Override | ||||
public void startFooter(TableFooter footer) { | public void startFooter(TableFooter footer) { | ||||
converters.push(converter); | |||||
converter = new FOEventRecorder(); | |||||
converter.startFooter(footer); | converter.startFooter(footer); | ||||
super.startFooter(footer); | super.startFooter(footer); | ||||
} | } | ||||
@Override | @Override | ||||
public void endFooter(TableFooter footer) { | public void endFooter(TableFooter footer) { | ||||
converter.endFooter(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); | super.endFooter(footer); | ||||
} | } | ||||
super.endListBody(listItemBody); | 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 | @Override | ||||
public void startMarkup() { | public void startMarkup() { | ||||
converter.startMarkup(); | converter.startMarkup(); |
/* | |||||
* 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); | |||||
} | |||||
}); | |||||
} | |||||
} |
import org.apache.fop.fo.flow.table.TableHeader; | import org.apache.fop.fo.flow.table.TableHeader; | ||||
import org.apache.fop.fo.flow.table.TableRow; | import org.apache.fop.fo.flow.table.TableRow; | ||||
import org.apache.fop.fo.pagination.Flow; | 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.PageSequence; | ||||
import org.apache.fop.fo.pagination.StaticContent; | import org.apache.fop.fo.pagination.StaticContent; | ||||
import org.apache.fop.fo.properties.CommonAccessibilityHolder; | import org.apache.fop.fo.properties.CommonAccessibilityHolder; | ||||
private StructureTreeEventHandler structureTreeEventHandler; | private StructureTreeEventHandler structureTreeEventHandler; | ||||
private LayoutMasterSet layoutMasterSet; | |||||
public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { | public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { | ||||
this.structureTreeEventHandler = structureTreeEventHandler; | this.structureTreeEventHandler = structureTreeEventHandler; | ||||
} | } | ||||
@Override | @Override | ||||
public void startPageSequence(PageSequence pageSeq) { | public void startPageSequence(PageSequence pageSeq) { | ||||
if (layoutMasterSet == null) { | |||||
layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet(); | |||||
} | |||||
Locale locale = null; | Locale locale = null; | ||||
if (pageSeq.getLanguage() != null) { | if (pageSeq.getLanguage() != null) { | ||||
if (pageSeq.getCountry() != null) { | if (pageSeq.getCountry() != null) { | ||||
endElement(pageLast); | 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 | @Override | ||||
public void startFlow(Flow fl) { | public void startFlow(Flow fl) { | ||||
startElement(fl); | |||||
AttributesImpl flowName = createFlowNameAttribute(fl.getFlowName()); | |||||
startElement(fl, flowName); | |||||
} | } | ||||
@Override | @Override | ||||
endElement(listItemBody); | endElement(listItemBody); | ||||
} | } | ||||
@Override | |||||
public void startStatic(StaticContent staticContent) { | |||||
startElement(staticContent); | |||||
} | |||||
@Override | |||||
public void endStatic(StaticContent statisContent) { | |||||
endElement(statisContent); | |||||
} | |||||
@Override | @Override | ||||
public void startLink(BasicLink basicLink) { | public void startLink(BasicLink basicLink) { | ||||
startElementWithID(basicLink); | startElementWithID(basicLink); |
delegate.endPageNumberCitationLast(pageLast); | delegate.endPageNumberCitationLast(pageLast); | ||||
} | } | ||||
@Override | |||||
public void startStatic(StaticContent staticContent) { | |||||
delegate.startStatic(staticContent); | |||||
} | |||||
@Override | |||||
public void endStatic(StaticContent statisContent) { | |||||
delegate.endStatic(statisContent); | |||||
} | |||||
@Override | @Override | ||||
public void startFlow(Flow fl) { | public void startFlow(Flow fl) { | ||||
delegate.startFlow(fl); | delegate.startFlow(fl); | ||||
delegate.endListBody(listItemBody); | delegate.endListBody(listItemBody); | ||||
} | } | ||||
@Override | |||||
public void startStatic(StaticContent staticContent) { | |||||
delegate.startStatic(staticContent); | |||||
} | |||||
@Override | |||||
public void endStatic(StaticContent statisContent) { | |||||
delegate.endStatic(statisContent); | |||||
} | |||||
@Override | @Override | ||||
public void startMarkup() { | public void startMarkup() { | ||||
delegate.startMarkup(); | delegate.startMarkup(); |
public void endPageNumberCitationLast(PageNumberCitationLast pageLast) { | 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 | * This method is called to indicate the start of a new fo:flow | ||||
* or fo:static-content. | * or fo:static-content. | ||||
public void endListBody(ListItemBody listItemBody) { | 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. | * Process start of a Markup. | ||||
*/ | */ |
import org.apache.fop.datatypes.LengthBase; | import org.apache.fop.datatypes.LengthBase; | ||||
import org.apache.fop.fo.expr.PropertyException; | import org.apache.fop.fo.expr.PropertyException; | ||||
import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker; | 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.BackgroundPositionShorthand; | ||||
import org.apache.fop.fo.properties.BorderSpacingShorthandParser; | import org.apache.fop.fo.properties.BorderSpacingShorthandParser; | ||||
import org.apache.fop.fo.properties.BorderWidthPropertyMaker; | import org.apache.fop.fo.properties.BorderWidthPropertyMaker; | ||||
m = new StringProperty.Maker(PR_FLOW_NAME); | m = new StringProperty.Maker(PR_FLOW_NAME); | ||||
m.setInherited(false); | m.setInherited(false); | ||||
m.setDefault(""); | m.setDefault(""); | ||||
addPropertyMaker("flow-name", m); | |||||
addPropertyMaker(Flow.FLOW_NAME, m); | |||||
// force-page-count | // force-page-count | ||||
m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT); | m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT); |
*/ | */ | ||||
public class Flow extends FObj implements 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 String flowName; | ||||
private CommonAccessibility commonAccessibility; | private CommonAccessibility commonAccessibility; | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
protected void startOfNode() throws FOPException { | protected void startOfNode() throws FOPException { | ||||
if (flowName == null || flowName.equals("")) { | if (flowName == null || flowName.equals("")) { | ||||
missingPropertyError("flow-name"); | |||||
missingPropertyError(FLOW_NAME); | |||||
} | } | ||||
// according to communication from Paul Grosso (XSL-List, | // according to communication from Paul Grosso (XSL-List, |
public int getNameId() { | public int getNameId() { | ||||
return FO_LAYOUT_MASTER_SET; | 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; | |||||
} | |||||
} | } | ||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
protected void startOfNode() throws FOPException { | protected void startOfNode() throws FOPException { | ||||
if (getFlowName() == null || getFlowName().equals("")) { | if (getFlowName() == null || getFlowName().equals("")) { | ||||
missingPropertyError("flow-name"); | |||||
missingPropertyError(FLOW_NAME); | |||||
} | } | ||||
getFOEventHandler().startStatic(this); | getFOEventHandler().startStatic(this); | ||||
} | } |
} | } | ||||
/** | /** | ||||
* 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); | assignObjectNumber(structElem); | ||||
structureTreeElements.add(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); | versionController.addTableHeaderScopeAttribute(structElem, scope); | ||||
return structElem; | |||||
} | } | ||||
/** | /** |
/** | /** | ||||
* Class representing a PDF Structure Element. | * 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; | private StructureType structureType; | ||||
* @param parent parent of this element | * @param parent parent of this element | ||||
* @param structureType the structure type 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(parent); | ||||
this.structureType = structureType; | this.structureType = structureType; | ||||
put("S", structureType.getName()); | put("S", structureType.getName()); | ||||
* | * | ||||
* @param kid element to be added | * @param kid element to be added | ||||
*/ | */ | ||||
@Override | |||||
public void addKid(PDFObject kid) { | public void addKid(PDFObject kid) { | ||||
if (kids == null) { | if (kids == null) { | ||||
kids = new ArrayList<PDFObject>(); | kids = new ArrayList<PDFObject>(); |
/** | /** | ||||
* Class representing a PDF /StructTreeRoot dictionary. | * Class representing a PDF /StructTreeRoot dictionary. | ||||
*/ | */ | ||||
public class PDFStructTreeRoot extends PDFDictionary { | |||||
public class PDFStructTreeRoot extends StructureHierarchyMember { | |||||
/** | /** | ||||
* Creates a new /StructTreeRoot dictionary. | * Creates a new /StructTreeRoot dictionary. | ||||
* | * | ||||
* @param kid an object to be added to the K entry | * @param kid an object to be added to the K entry | ||||
*/ | */ | ||||
@Override | |||||
public void addKid(PDFObject kid) { | public void addKid(PDFObject kid) { | ||||
getKids().add(kid); | getKids().add(kid); | ||||
} | } |
return name; | return name; | ||||
} | } | ||||
@Override | |||||
public String toString() { | |||||
return name.toString().substring(1); | |||||
} | |||||
} | } | ||||
private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>(); | private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>(); |
/* | |||||
* 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); | |||||
} |
/* | |||||
* 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() { } | |||||
} |
* Custom structure type is not standard as per the PDF reference. | * Custom structure type is not standard as per the PDF reference. | ||||
* | * | ||||
* @param source the event source | * @param source the event source | ||||
* @param fo the local name of the formatting object having the custom type | |||||
* @param type custom structure type | * @param type custom structure type | ||||
* @param fallback default structure type used as a fallback | * @param fallback default structure type used as a fallback | ||||
* @event.severity WARN | * @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. | * The encryption length must be a multiple of 8 between 40 and 128. |
import java.util.LinkedList; | import java.util.LinkedList; | ||||
import java.util.Locale; | import java.util.Locale; | ||||
import java.util.Map; | |||||
import org.xml.sax.Attributes; | import org.xml.sax.Attributes; | ||||
import org.xml.sax.helpers.AttributesImpl; | |||||
import org.apache.fop.accessibility.StructureTreeElement; | import org.apache.fop.accessibility.StructureTreeElement; | ||||
import org.apache.fop.accessibility.StructureTreeEventHandler; | import org.apache.fop.accessibility.StructureTreeEventHandler; | ||||
import org.apache.fop.events.EventBroadcaster; | import org.apache.fop.events.EventBroadcaster; | ||||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | 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.PDFFactory; | ||||
import org.apache.fop.pdf.PDFObject; | |||||
import org.apache.fop.pdf.PDFParentTree; | import org.apache.fop.pdf.PDFParentTree; | ||||
import org.apache.fop.pdf.PDFStructElem; | import org.apache.fop.pdf.PDFStructElem; | ||||
import org.apache.fop.pdf.PDFStructTreeRoot; | import org.apache.fop.pdf.PDFStructTreeRoot; | ||||
import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope; | 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.StandardStructureTypes.Table; | ||||
import org.apache.fop.pdf.StructureHierarchyMember; | |||||
import org.apache.fop.pdf.StructureType; | import org.apache.fop.pdf.StructureType; | ||||
import org.apache.fop.util.XMLUtil; | |||||
class PDFStructureTreeBuilder implements StructureTreeEventHandler { | 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 PDFFactory pdfFactory; | ||||
private EventBroadcaster eventBroadcaster; | private EventBroadcaster eventBroadcaster; | ||||
this.pdfFactory = pdfFactory; | this.pdfFactory = pdfFactory; | ||||
} | } | ||||
void setEventBroadcaster(EventBroadcaster eventBroadcaster) { | |||||
this.eventBroadcaster = eventBroadcaster; | |||||
} | |||||
void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) { | void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) { | ||||
createRootStructureElement(logicalStructureHandler); | createRootStructureElement(logicalStructureHandler); | ||||
} | } | ||||
assert rootStructureElement == null; | assert rootStructureElement == null; | ||||
PDFParentTree parentTree = logicalStructureHandler.getParentTree(); | PDFParentTree parentTree = logicalStructureHandler.getParentTree(); | ||||
PDFStructTreeRoot structTreeRoot = pdfFactory.getDocument().makeStructTreeRoot(parentTree); | 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) { | public void startPageSequence(Locale language, String role) { | ||||
ancestors = new LinkedList<PDFStructElem>(); | 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) { | if (language != null) { | ||||
structElem.setLanguage(language); | structElem.setLanguage(language); | ||||
} | } | ||||
rootStructureElement.addKid(structElem); | |||||
ancestors.add(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 void endPageSequence() { | ||||
} | } | ||||
public StructureTreeElement startNode(String name, Attributes attributes) { | public StructureTreeElement startNode(String name, Attributes attributes) { | ||||
PDFStructElem parent = ancestors.getFirst(); | 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); | ancestors.addFirst(structElem); | ||||
return 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) { | public void endNode(String name) { | ||||
removeFirstAncestor(); | |||||
} | |||||
private void removeFirstAncestor() { | |||||
ancestors.removeFirst(); | ancestors.removeFirst(); | ||||
} | } | ||||
public StructureTreeElement startImageNode(String name, Attributes attributes) { | 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) { | 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); | |||||
} | } | ||||
} | } |
/* | |||||
* 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); | |||||
} | |||||
} | |||||
} | |||||
} |
/* | |||||
* 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(); | |||||
} | |||||
} |
documents. Example: the fix of marks layering will be such a case when it's done. | documents. Example: the fix of marks layering will be such a case when it's done. | ||||
--> | --> | ||||
<release version="FOP Trunk" date="TBD"> | <release version="FOP Trunk" date="TBD"> | ||||
<action context="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"> | <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 | Remove StandardEncoding as the encoding type from fonts used in the PDF renderer | ||||
</action> | </action> |
package org.apache.fop.accessibility.fo; | package org.apache.fop.accessibility.fo; | ||||
import java.io.ByteArrayInputStream; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import javax.xml.transform.dom.DOMResult; | import javax.xml.transform.dom.DOMResult; | ||||
import javax.xml.transform.sax.SAXTransformerFactory; | import javax.xml.transform.sax.SAXTransformerFactory; | ||||
import javax.xml.transform.sax.TransformerHandler; | import javax.xml.transform.sax.TransformerHandler; | ||||
import javax.xml.transform.stream.StreamResult; | |||||
import javax.xml.transform.stream.StreamSource; | import javax.xml.transform.stream.StreamSource; | ||||
import org.custommonkey.xmlunit.Diff; | import org.custommonkey.xmlunit.Diff; | ||||
public class FO2StructureTreeConverterTestCase { | 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"; | private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence"; | ||||
@Test | @Test | ||||
public void testCompleteDocument() throws Exception { | 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 | @Test | ||||
public void testTableFooters() throws Exception { | 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 | @Test | ||||
public void testArtifact() throws Exception { | 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) { | private static InputStream getResource(String name) { | ||||
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(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 expectedStructureTree = loadExpectedStructureTree(); | ||||
DOMResult actualStructureTree = buildActualStructureTree(); | DOMResult actualStructureTree = buildActualStructureTree(); | ||||
final Diff diff = createDiff(expectedStructureTree, actualStructureTree); | final Diff diff = createDiff(expectedStructureTree, actualStructureTree); |
<xsl:call-template name="copy"/> | <xsl:call-template name="copy"/> | ||||
</xsl:template> | </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 --> | <!-- Block-level Formatting Objects --> | ||||
<xsl:template match="fo:block|fo:block-container"> | <xsl:template match="fo:block|fo:block-container"> | ||||
<xsl:call-template name="copy"/> | <xsl:call-template name="copy"/> | ||||
<xsl:call-template name="copy"/> | <xsl:call-template name="copy"/> | ||||
</xsl:template> | </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:call-template name="copy"/> | ||||
</xsl:template> | </xsl:template> | ||||
<?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> |
/* | |||||
* 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")); | |||||
} | |||||
} |
<?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> |
VersionController controller = mock(VersionController.class); | VersionController controller = mock(VersionController.class); | ||||
PDFDocument document = new PDFDocument("Test", controller); | PDFDocument document = new PDFDocument("Test", controller); | ||||
document.makeStructTreeRoot(null); | 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)); | verify(controller).addTableHeaderScopeAttribute(any(PDFStructElem.class), eq(scope)); | ||||
} | } | ||||
<?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> |