diff options
author | Peter Hancock <phancock@apache.org> | 2012-10-04 14:46:01 +0000 |
---|---|---|
committer | Peter Hancock <phancock@apache.org> | 2012-10-04 14:46:01 +0000 |
commit | af57408966c6e9a525475f52bdc96add31cb0e51 (patch) | |
tree | 7aec6fd97d2d6c501be6b2473aa399b236e37a51 /src | |
parent | 118f9d4f0f6aeed4971ea9cc61fd4d63198c9a84 (diff) | |
parent | d261730a4f7be752ae12a5ec52e6bad8ee4fa5c1 (diff) | |
download | xmlgraphics-fop-af57408966c6e9a525475f52bdc96add31cb0e51.tar.gz xmlgraphics-fop-af57408966c6e9a525475f52bdc96add31cb0e51.zip |
Merged trunk@1391502
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_RoundedCorners@1394098 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
113 files changed, 2651 insertions, 1991 deletions
diff --git a/src/documentation/content/xdocs/dev/index.xml b/src/documentation/content/xdocs/dev/index.xml index 357402026..27f1b2cd9 100644 --- a/src/documentation/content/xdocs/dev/index.xml +++ b/src/documentation/content/xdocs/dev/index.xml @@ -97,7 +97,7 @@ To review the archives, you have several options: <li>The <link href="http://marc.theaimsgroup.com/?l=fop-dev&r=1&w=2">Mailing list ARChives</link> (MARC) at the AIMS group (search).</li> <li><link href="http://www.mail-archive.com/fop-dev%40xmlgraphics.apache.org/">The Mail Archive</link>.</li> <li>The <link href="http://dir.gmane.org/gmane.text.xml.fop.devel">GMANE</link> archive.</li> - <li>The <link href="http://www.nabble.com/FOP---Dev-f352.html">Nabble</link> archive.</li> + <li>The <link href="http://apache-fop.1065347.n5.nabble.com/">Nabble</link> archive.</li> <li>The <link href="http://fop-dev.markmail.org">MarkMail</link> archive.</li> </ul> </li> diff --git a/src/documentation/content/xdocs/maillist.xml b/src/documentation/content/xdocs/maillist.xml index b24166462..406ccf3c0 100644 --- a/src/documentation/content/xdocs/maillist.xml +++ b/src/documentation/content/xdocs/maillist.xml @@ -43,17 +43,17 @@ If you are using Microsoft Outlook, this setting can be found at the "Mail Forma <title>Archives</title> <p>To review the archives, you have several options:</p> <ul> - + <li>The <link href="http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-users/">Apache Mailing List archive</link> (mod_mbox archive, no full-text search, yet).</li> <li>The <link href="http://xmlgraphics.apache.org/mail/fop-users/">Apache Mailing List archive</link> (gzipped mbox files).</li> <li>The <jump href="http://marc.theaimsgroup.com/?l=fop-user&r=1&w=2">Mailing list ARChives </jump> (MARC) at the AIMS group.</li> <li><jump href="http://www.mail-archive.com/fop-users%40xmlgraphics.apache.org/">The Mail Archive</jump>.</li> <li>The <jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE archive</jump>.</li> - <li>The <jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble archive</jump> (only posts after May 2005).</li> + <li>The <jump href="http://apache-fop.1065347.n5.nabble.com/FOP-Users-f3.html">Nabble archive</jump> (only posts after May 2005).</li> <li>The <jump href="http://fop-users.markmail.org/">MarkMail archive</jump>.</li> </ul> <note> - If you don't like mailing lists and prefer a forum-like system, have a look at + If you don't like mailing lists and prefer a forum-like system, have a look at <jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE</jump> or <jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble</jump>. They allow you to post to the mailing list without having to subscribe. diff --git a/src/documentation/content/xdocs/trunk/output.xml b/src/documentation/content/xdocs/trunk/output.xml index 7c4ace72e..5de820c18 100644 --- a/src/documentation/content/xdocs/trunk/output.xml +++ b/src/documentation/content/xdocs/trunk/output.xml @@ -971,7 +971,8 @@ Note that the value of the encoding attribute in the example is the double-byte xmlns:afp="http://xmlgraphics.apache.org/fop/extensions/afp"> <fo:layout-master-set> <fo:simple-page-master master-name="simple"> - <afp:tag-logical-element name="The TLE Name" value="The TLE Value" /> + <afp:tag-logical-element name="The TLE Name" value="The TLE Value" + encoding="500" /> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> @@ -985,7 +986,7 @@ Note that the value of the encoding attribute in the example is the double-byte The tag-logical-element extension element can appear within a simple-page-master (page level) or it can appear as child of page-sequence (page group level). Multiple tag-logical-element extension elements within a simple-page-master or - page-sequence are allowed. The name and value attributes are mandatory. + page-sequence are allowed. The name and value attributes are mandatory. The encoding attribute specifying a CCSID encoding is optional. </p> </section> <section id="afp-no-operation"> @@ -1269,6 +1270,7 @@ Note that the value of the encoding attribute in the example is the double-byte <source><![CDATA[<renderer mime="image/tiff"> <transparent-page-background>true</transparent-page-background> <compression>CCITT T.6</compression> + <single-strip>true</single-strip> <fonts><!-- described elsewhere --></fonts> </renderer>]]></source> <p> @@ -1302,6 +1304,10 @@ Note that the value of the encoding attribute in the example is the double-byte added separately. The internal TIFF codec from XML Graphics Commons only supports PackBits, Deflate and JPEG compression for writing. </note> + <p> + The default value for the <code>"single-strip"</code> is <code>"false"</code> resulting in the RowsPerStrip Tiff Tag equal to the number of rows. + If set to <code>true</code> RowsPerStrip is set to 1. + </p> </section> <section id="bitmap-rendering-options"> <title>Runtime Rendering Options</title> diff --git a/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java b/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java index 27469d6e0..aaf112cb5 100644 --- a/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java +++ b/src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java @@ -72,8 +72,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>(); - private final Stack<FOEventRecorder> tableFooterRecorders = new Stack<FOEventRecorder>(); - private final FOEventHandler structureTreeEventTrigger; /** The descendants of some elements like fo:leader must be ignored. */ @@ -166,6 +164,20 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } @Override + public void startStatic(StaticContent staticContent) { + handleStartArtifact(staticContent); + converter.startStatic(staticContent); + super.startStatic(staticContent); + } + + @Override + public void endStatic(StaticContent staticContent) { + converter.endStatic(staticContent); + handleEndArtifact(staticContent); + super.endStatic(staticContent); + } + + @Override public void startFlow(Flow fl) { converter.startFlow(fl); super.startFlow(fl); @@ -216,16 +228,11 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { @Override public void startTable(Table tbl) { converter.startTable(tbl); - tableFooterRecorders.push(null); super.startTable(tbl); } @Override public void endTable(Table tbl) { - FOEventRecorder tableFooterRecorder = tableFooterRecorders.pop(); - if (tableFooterRecorder != null) { - tableFooterRecorder.replay(converter); - } converter.endTable(tbl); super.endTable(tbl); } @@ -256,8 +263,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { @Override public void startFooter(TableFooter footer) { - converters.push(converter); - converter = new FOEventRecorder(); converter.startFooter(footer); super.startFooter(footer); } @@ -265,10 +270,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { @Override public void endFooter(TableFooter footer) { converter.endFooter(footer); - /* Replace the dummy table footer with the real one. */ - tableFooterRecorders.pop(); - tableFooterRecorders.push((FOEventRecorder) converter); - converter = converters.pop(); super.endFooter(footer); } @@ -357,20 +358,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } @Override - public void startStatic(StaticContent staticContent) { - handleStartArtifact(staticContent); - converter.startStatic(staticContent); - super.startStatic(staticContent); - } - - @Override - public void endStatic(StaticContent statisContent) { - converter.endStatic(statisContent); - handleEndArtifact(statisContent); - super.endStatic(statisContent); - } - - @Override public void startMarkup() { converter.startMarkup(); super.startMarkup(); diff --git a/src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java b/src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java deleted file mode 100644 index b2b18046d..000000000 --- a/src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.accessibility.fo; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.fop.fo.FOEventHandler; -import org.apache.fop.fo.FOText; -import org.apache.fop.fo.flow.BasicLink; -import org.apache.fop.fo.flow.Block; -import org.apache.fop.fo.flow.BlockContainer; -import org.apache.fop.fo.flow.Character; -import org.apache.fop.fo.flow.ExternalGraphic; -import org.apache.fop.fo.flow.Footnote; -import org.apache.fop.fo.flow.FootnoteBody; -import org.apache.fop.fo.flow.Inline; -import org.apache.fop.fo.flow.InstreamForeignObject; -import org.apache.fop.fo.flow.Leader; -import org.apache.fop.fo.flow.ListBlock; -import org.apache.fop.fo.flow.ListItem; -import org.apache.fop.fo.flow.ListItemBody; -import org.apache.fop.fo.flow.ListItemLabel; -import org.apache.fop.fo.flow.PageNumber; -import org.apache.fop.fo.flow.PageNumberCitation; -import org.apache.fop.fo.flow.PageNumberCitationLast; -import org.apache.fop.fo.flow.Wrapper; -import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.fo.flow.table.TableBody; -import org.apache.fop.fo.flow.table.TableCell; -import org.apache.fop.fo.flow.table.TableColumn; -import org.apache.fop.fo.flow.table.TableFooter; -import org.apache.fop.fo.flow.table.TableHeader; -import org.apache.fop.fo.flow.table.TableRow; - -final class FOEventRecorder extends FOEventHandler { - - private interface Event { - void replay(FOEventHandler target); - } - - private final List<Event> events = new ArrayList<Event>(); - - public void replay(FOEventHandler target) { - for (Event event : events) { - event.replay(target); - } - } - - @Override - public void startPageNumber(final PageNumber pagenum) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startPageNumber(pagenum); - } - }); - } - - @Override - public void endPageNumber(final PageNumber pagenum) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endPageNumber(pagenum); - } - }); - } - - @Override - public void startPageNumberCitation(final PageNumberCitation pageCite) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startPageNumberCitation(pageCite); - } - }); - } - - @Override - public void endPageNumberCitation(final PageNumberCitation pageCite) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endPageNumberCitation(pageCite); - } - }); - } - - @Override - public void startPageNumberCitationLast(final PageNumberCitationLast pageLast) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startPageNumberCitationLast(pageLast); - } - }); - } - - @Override - public void endPageNumberCitationLast(final PageNumberCitationLast pageLast) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endPageNumberCitationLast(pageLast); - } - }); - } - - @Override - public void startBlock(final Block bl) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startBlock(bl); - } - }); - } - - @Override - public void endBlock(final Block bl) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endBlock(bl); - } - }); - } - - @Override - public void startBlockContainer(final BlockContainer blc) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startBlockContainer(blc); - } - }); - } - - @Override - public void endBlockContainer(final BlockContainer blc) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endBlockContainer(blc); - } - }); - } - - @Override - public void startInline(final Inline inl) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startInline(inl); - } - }); - } - - @Override - public void endInline(final Inline inl) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endInline(inl); - } - }); - } - - @Override - public void startTable(final Table tbl) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startTable(tbl); - } - }); - } - - @Override - public void endTable(final Table tbl) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endTable(tbl); - } - }); - } - - @Override - public void startColumn(final TableColumn tc) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startColumn(tc); - } - }); - } - - @Override - public void endColumn(final TableColumn tc) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endColumn(tc); - } - }); - } - - @Override - public void startHeader(final TableHeader header) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startHeader(header); - } - }); - } - - @Override - public void endHeader(final TableHeader header) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endHeader(header); - } - }); - } - - @Override - public void startFooter(final TableFooter footer) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startFooter(footer); - } - }); - } - - @Override - public void endFooter(final TableFooter footer) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endFooter(footer); - } - }); - } - - @Override - public void startBody(final TableBody body) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startBody(body); - } - }); - } - - @Override - public void endBody(final TableBody body) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endBody(body); - } - }); - } - - @Override - public void startRow(final TableRow tr) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startRow(tr); - } - }); - } - - @Override - public void endRow(final TableRow tr) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endRow(tr); - } - }); - } - - @Override - public void startCell(final TableCell tc) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startCell(tc); - } - }); - } - - @Override - public void endCell(final TableCell tc) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endCell(tc); - } - }); - } - - @Override - public void startList(final ListBlock lb) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startList(lb); - } - }); - } - - @Override - public void endList(final ListBlock lb) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endList(lb); - } - }); - } - - @Override - public void startListItem(final ListItem li) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startListItem(li); - } - }); - } - - @Override - public void endListItem(final ListItem li) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endListItem(li); - } - }); - } - - @Override - public void startListLabel(final ListItemLabel listItemLabel) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startListLabel(listItemLabel); - } - }); - } - - @Override - public void endListLabel(final ListItemLabel listItemLabel) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endListLabel(listItemLabel); - } - }); - } - - @Override - public void startListBody(final ListItemBody listItemBody) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startListBody(listItemBody); - } - }); - } - - @Override - public void endListBody(final ListItemBody listItemBody) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endListBody(listItemBody); - } - }); - } - - @Override - public void startLink(final BasicLink basicLink) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startLink(basicLink); - } - }); - } - - @Override - public void endLink(final BasicLink basicLink) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endLink(basicLink); - } - }); - } - - @Override - public void image(final ExternalGraphic eg) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.image(eg); - } - }); - } - - @Override - public void startInstreamForeignObject(final InstreamForeignObject ifo) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startInstreamForeignObject(ifo); - } - }); - } - - @Override - public void endInstreamForeignObject(final InstreamForeignObject ifo) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endInstreamForeignObject(ifo); - } - }); - } - - @Override - public void startFootnote(final Footnote footnote) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startFootnote(footnote); - } - }); - } - - @Override - public void endFootnote(final Footnote footnote) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endFootnote(footnote); - } - }); - } - - @Override - public void startFootnoteBody(final FootnoteBody body) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startFootnoteBody(body); - } - }); - } - - @Override - public void endFootnoteBody(final FootnoteBody body) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endFootnoteBody(body); - } - }); - } - - @Override - public void startLeader(final Leader l) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startLeader(l); - } - }); - } - - @Override - public void endLeader(final Leader l) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endLeader(l); - } - }); - } - - @Override - public void startWrapper(final Wrapper wrapper) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.startWrapper(wrapper); - } - }); - } - - @Override - public void endWrapper(final Wrapper wrapper) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.endWrapper(wrapper); - } - }); - } - - @Override - public void character(final Character c) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.character(c); - } - }); - } - - @Override - public void characters(final FOText foText) { - events.add(new Event() { - public void replay(FOEventHandler target) { - target.characters(foText); - } - }); - } - -} diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java index 7e3ed0591..09a814ef5 100644 --- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java +++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java @@ -20,6 +20,7 @@ package org.apache.fop.accessibility.fo; import java.util.Locale; +import java.util.Stack; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; @@ -30,6 +31,7 @@ import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FOText; import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.fo.extensions.InternalElementMapping; import org.apache.fop.fo.flow.AbstractGraphics; import org.apache.fop.fo.flow.BasicLink; import org.apache.fop.fo.flow.Block; @@ -55,6 +57,7 @@ import org.apache.fop.fo.flow.table.TableFooter; import org.apache.fop.fo.flow.table.TableHeader; import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.pagination.Flow; +import org.apache.fop.fo.pagination.LayoutMasterSet; import org.apache.fop.fo.pagination.PageSequence; import org.apache.fop.fo.pagination.StaticContent; import org.apache.fop.fo.properties.CommonAccessibilityHolder; @@ -67,6 +70,12 @@ class StructureTreeEventTrigger extends FOEventHandler { private StructureTreeEventHandler structureTreeEventHandler; + private LayoutMasterSet layoutMasterSet; + + private final Stack<Table> tables = new Stack<Table>(); + + private final Stack<Boolean> inTableHeader = new Stack<Boolean>(); + public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { this.structureTreeEventHandler = structureTreeEventHandler; } @@ -81,6 +90,9 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void startPageSequence(PageSequence pageSeq) { + if (layoutMasterSet == null) { + layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet(); + } Locale locale = null; if (pageSeq.getLanguage() != null) { if (pageSeq.getCountry() != null) { @@ -129,8 +141,27 @@ class StructureTreeEventTrigger extends FOEventHandler { } @Override + public void startStatic(StaticContent staticContent) { + AttributesImpl flowName = createFlowNameAttribute(staticContent.getFlowName()); + startElement(staticContent, flowName); + } + + private AttributesImpl createFlowNameAttribute(String flowName) { + String regionName = layoutMasterSet.getDefaultRegionNameFor(flowName); + AttributesImpl attribute = new AttributesImpl(); + addNoNamespaceAttribute(attribute, Flow.FLOW_NAME, regionName); + return attribute; + } + + @Override + public void endStatic(StaticContent staticContent) { + endElement(staticContent); + } + + @Override public void startFlow(Flow fl) { - startElement(fl); + AttributesImpl flowName = createFlowNameAttribute(fl.getFlowName()); + startElement(fl, flowName); } @Override @@ -170,42 +201,51 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void startTable(Table tbl) { + tables.push(tbl); startElement(tbl); } @Override public void endTable(Table tbl) { endElement(tbl); + tables.pop(); } @Override public void startHeader(TableHeader header) { + inTableHeader.push(Boolean.TRUE); startElement(header); } @Override public void endHeader(TableHeader header) { endElement(header); + inTableHeader.pop(); } @Override public void startFooter(TableFooter footer) { + // TODO Shouldn't it be true? + inTableHeader.push(Boolean.FALSE); startElement(footer); } @Override public void endFooter(TableFooter footer) { endElement(footer); + inTableHeader.pop(); } @Override public void startBody(TableBody body) { + inTableHeader.push(Boolean.FALSE); startElement(body); } @Override public void endBody(TableBody body) { endElement(body); + inTableHeader.pop(); } @Override @@ -223,6 +263,24 @@ class StructureTreeEventTrigger extends FOEventHandler { AttributesImpl attributes = new AttributesImpl(); addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned()); addSpanAttribute(attributes, "number-rows-spanned", tc.getNumberRowsSpanned()); + boolean rowHeader = inTableHeader.peek(); + boolean columnHeader = tables.peek().getColumn(tc.getColumnNumber() - 1).isHeader(); + if (rowHeader || columnHeader) { + final String th = "TH"; + String role = tc.getCommonAccessibility().getRole(); + /* Do not override a custom role */ + if (role == null) { + role = th; + addNoNamespaceAttribute(attributes, "role", th); + } + if (role.equals(th)) { + if (columnHeader) { + String scope = rowHeader ? "Both" : "Row"; + addAttribute(attributes, InternalElementMapping.URI, InternalElementMapping.SCOPE, + InternalElementMapping.STANDARD_PREFIX, scope); + } + } + } startElement(tc, attributes); } @@ -278,16 +336,6 @@ class StructureTreeEventTrigger extends FOEventHandler { } @Override - public void startStatic(StaticContent staticContent) { - startElement(staticContent); - } - - @Override - public void endStatic(StaticContent statisContent) { - endElement(statisContent); - } - - @Override public void startLink(BasicLink basicLink) { startElementWithID(basicLink); } diff --git a/src/java/org/apache/fop/afp/AFPStreamer.java b/src/java/org/apache/fop/afp/AFPStreamer.java index fb2b282f6..5e6b5a79e 100644 --- a/src/java/org/apache/fop/afp/AFPStreamer.java +++ b/src/java/org/apache/fop/afp/AFPStreamer.java @@ -32,10 +32,11 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.xmlgraphics.io.TempResourceURIGenerator; + import org.apache.fop.afp.modca.ResourceGroup; import org.apache.fop.afp.modca.StreamedResourceGroup; import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.apps.io.TempResourceURIGenerator; /** * Manages the streaming of the AFP output diff --git a/src/java/org/apache/fop/afp/DataStream.java b/src/java/org/apache/fop/afp/DataStream.java index 2794ae932..272c000bd 100644 --- a/src/java/org/apache/fop/afp/DataStream.java +++ b/src/java/org/apache/fop/afp/DataStream.java @@ -40,7 +40,7 @@ import org.apache.fop.afp.modca.Overlay; import org.apache.fop.afp.modca.PageGroup; import org.apache.fop.afp.modca.PageObject; import org.apache.fop.afp.modca.ResourceGroup; -import org.apache.fop.afp.modca.TagLogicalElementBean; +import org.apache.fop.afp.modca.TagLogicalElement; import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; import org.apache.fop.afp.ptoca.PtocaBuilder; import org.apache.fop.afp.ptoca.PtocaProducer; @@ -85,12 +85,9 @@ public class DataStream { /** The current page */ private AbstractPageObject currentPage = null; - /** Sequence number for TLE's.*/ - private int tleSequence = 0; - /** The MO:DCA interchange set in use (default to MO:DCA-P IS/2 set) */ private InterchangeSet interchangeSet - = InterchangeSet.valueOf(InterchangeSet.MODCA_PRESENTATION_INTERCHANGE_SET_2); + = InterchangeSet.valueOf(InterchangeSet.MODCA_PRESENTATION_INTERCHANGE_SET_2); private final Factory factory; @@ -544,17 +541,19 @@ public class DataStream { currentPage.createIncludePageSegment(name, xOrigin, yOrigin, createHardPageSegments); } + + /** * Creates a TagLogicalElement on the current page. * * @param attributes * the array of key value pairs. */ - public void createPageTagLogicalElement(TagLogicalElementBean[] attributes) { + + public void createPageTagLogicalElement(TagLogicalElement.State[] attributes) { for (int i = 0; i < attributes.length; i++) { - String name = attributes[i].getKey(); - String value = attributes[i].getValue(); - currentPage.createTagLogicalElement(name, value, tleSequence++); + + currentPage.createTagLogicalElement(attributes[i]); } } @@ -564,11 +563,9 @@ public class DataStream { * @param attributes * the array of key value pairs. */ - public void createPageGroupTagLogicalElement(TagLogicalElementBean[] attributes) { + public void createPageGroupTagLogicalElement(TagLogicalElement.State[] attributes) { for (int i = 0; i < attributes.length; i++) { - String name = attributes[i].getKey(); - String value = attributes[i].getValue(); - currentPageGroup.createTagLogicalElement(name, value); + currentPageGroup.createTagLogicalElement(attributes[i]); } } @@ -579,12 +576,17 @@ public class DataStream { * The tag name * @param value * The tag value + * @param encoding The CCSID character set encoding */ - public void createTagLogicalElement(String name, String value) { + public void createTagLogicalElement(String name, String value, int encoding) { + + TagLogicalElement.State tleState = new TagLogicalElement.State(name, value, encoding); if (currentPage != null) { - currentPage.createTagLogicalElement(name, value, tleSequence++); + + currentPage.createTagLogicalElement(tleState); + } else { - currentPageGroup.createTagLogicalElement(name, value); + currentPageGroup.createTagLogicalElement(tleState); } } @@ -632,7 +634,7 @@ public class DataStream { */ public void startPageGroup() throws IOException { endPageGroup(); - this.currentPageGroup = factory.createPageGroup(tleSequence); + this.currentPageGroup = factory.createPageGroup(); } /** @@ -643,7 +645,6 @@ public class DataStream { public void endPageGroup() throws IOException { if (currentPageGroup != null) { currentPageGroup.endPageGroup(); - tleSequence = currentPageGroup.getTleSequence(); document.addPageGroup(currentPageGroup); currentPageGroup = null; } diff --git a/src/java/org/apache/fop/afp/Factory.java b/src/java/org/apache/fop/afp/Factory.java index ef68a22fb..f3e75c1af 100644 --- a/src/java/org/apache/fop/afp/Factory.java +++ b/src/java/org/apache/fop/afp/Factory.java @@ -214,13 +214,12 @@ public class Factory { /** * Creates a new MO:DCA {@link PageGroup} - * @param tleSequence current start tle sequence number within stream * @return a new {@link PageGroup} */ - public PageGroup createPageGroup(int tleSequence) { + public PageGroup createPageGroup() { String name = PAGE_GROUP_NAME_PREFIX + StringUtils.lpad(String.valueOf(++pageGroupCount), '0', 5); - return new PageGroup(this, name, tleSequence); + return new PageGroup(this, name); } /** @@ -374,13 +373,11 @@ public class Factory { /** * Creates a MO:DCA {@link TagLogicalElement} * - * @param name name of the element - * @param value value of the element - * @param tleSequence current start tle sequence number within stream* + * @param state the attribute state for the TLE * @return a new {@link TagLogicalElement} */ - public TagLogicalElement createTagLogicalElement(String name, String value, int tleSequence) { - TagLogicalElement tle = new TagLogicalElement(name, value, tleSequence); + public TagLogicalElement createTagLogicalElement(TagLogicalElement.State state) { + TagLogicalElement tle = new TagLogicalElement(state); return tle; } diff --git a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java index e8b8bc1df..f429af28d 100644 --- a/src/java/org/apache/fop/afp/modca/AbstractPageObject.java +++ b/src/java/org/apache/fop/afp/modca/AbstractPageObject.java @@ -223,19 +223,15 @@ public abstract class AbstractPageObject extends AbstractNamedAFPObject implemen /** * Creates a TagLogicalElement on the page. * - * @param name - * the name of the tag - * @param value - * the value of the tag - * @param tleID - * unique ID within AFP stream + * @param state the state of the TLE */ - public void createTagLogicalElement(String name, String value, int tleID) { - TagLogicalElement tle = new TagLogicalElement(name, value, tleID); + public void createTagLogicalElement(TagLogicalElement.State state) { + TagLogicalElement tle = new TagLogicalElement(state); List list = getTagLogicalElements(); list.add(tle); } + /** * Creates a NoOperation on the page. * diff --git a/src/java/org/apache/fop/afp/modca/PageGroup.java b/src/java/org/apache/fop/afp/modca/PageGroup.java index e7c18d72b..7d472a2cd 100644 --- a/src/java/org/apache/fop/afp/modca/PageGroup.java +++ b/src/java/org/apache/fop/afp/modca/PageGroup.java @@ -36,35 +36,25 @@ import org.apache.fop.afp.Factory; public class PageGroup extends AbstractResourceEnvironmentGroupContainer { /** - * Sequence number for TLE's. - */ - private int tleSequence = 0; - - /** * Constructor for the PageGroup. * * @param factory the resource manager * @param name the name of the page group - * @param tleSequence current start tle sequence number within stream */ - public PageGroup(Factory factory, String name, int tleSequence) { + public PageGroup(Factory factory, String name) { super(factory, name); - this.tleSequence = tleSequence; } /** * Creates a TagLogicalElement on the page. * - * @param name - * the name of the tag - * @param value - * the value of the tag + * @param state + * the state of the TLE */ - public void createTagLogicalElement(String name, String value) { - TagLogicalElement tle = factory.createTagLogicalElement(name, value, tleSequence); + public void createTagLogicalElement(TagLogicalElement.State state) { + TagLogicalElement tle = factory.createTagLogicalElement(state); if (!getTagLogicalElements().contains(tle)) { getTagLogicalElements().add(tle); - tleSequence++; } } @@ -93,9 +83,4 @@ public class PageGroup extends AbstractResourceEnvironmentGroupContainer { public String toString() { return this.getName(); } - - /** @return the TLE sequence number */ - public int getTleSequence() { - return tleSequence; - } } diff --git a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java index 706ceae3b..9ae88b46f 100644 --- a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java +++ b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java @@ -24,6 +24,7 @@ import java.io.OutputStream; import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet; import org.apache.fop.afp.modca.triplets.AttributeValueTriplet; +import org.apache.fop.afp.modca.triplets.EncodingTriplet; import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet; import org.apache.fop.afp.util.BinaryUtils; @@ -49,42 +50,30 @@ import org.apache.fop.afp.util.BinaryUtils; public class TagLogicalElement extends AbstractTripletStructuredObject { /** - * Name of the key, used within the TLE + * the params of the TLE */ - private String name = null; - - /** - * Value returned by the key - */ - private String value = null; - - /** - * Sequence of TLE within document - */ - private int tleID; + private State state; /** * Construct a tag logical element with the name and value specified. * - * @param name the name of the tag logical element - * @param value the value of the tag logical element - * @param tleID unique identifier for TLE within AFP stream + * @param state the state of the tag logical element */ - public TagLogicalElement(String name, String value, int tleID) { - this.name = name; - this.value = value; - this.tleID = tleID; + + public TagLogicalElement(State state) { + this.state = state; } - /** - * Sets the attribute value of this structured field - * - * @param value the attribute value - */ - public void setAttributeValue(String value) { + private void setAttributeValue(String value) { addTriplet(new AttributeValueTriplet(value)); } + private void setEncoding(int encoding) { + if (encoding != State.ENCODING_NONE) { + addTriplet(new EncodingTriplet(encoding)); + } + } + /** * Sets the attribute qualifier of this structured field * @@ -100,9 +89,9 @@ public class TagLogicalElement extends AbstractTripletStructuredObject { setFullyQualifiedName( FullyQualifiedNameTriplet.TYPE_ATTRIBUTE_GID, FullyQualifiedNameTriplet.FORMAT_CHARSTR, - name); - setAttributeValue(value); - setAttributeQualifier(tleID, 1); + state.key); + setAttributeValue(state.value); + setEncoding(state.encoding); byte[] data = new byte[SF_HEADER_LENGTH]; copySF(data, Type.ATTRIBUTE, Category.PROCESS_ELEMENT); @@ -115,4 +104,51 @@ public class TagLogicalElement extends AbstractTripletStructuredObject { writeTriplets(os); } + + /** + * + * Holds the attribute state of a TLE + * + */ + public static class State { + + /** + * value interpreted as no encoding + */ + public static final int ENCODING_NONE = -1; + /** The key attribute */ + private String key; + + /** The value attribute */ + private String value; + + /** The CCSID character et encoding attribute */ + private int encoding = ENCODING_NONE; + + + /** + * Constructor + * + * @param key the key attribute + * @param value the value attribute + */ + public State(String key, String value) { + this.key = key; + this.value = value; + } + + /** + * + * @param key the key attribute + * @param value the value attribute + * @param encoding the CCSID character set encoding attribute + */ + public State(String key, String value, int encoding) { + this.key = key; + this.value = value; + this.encoding = encoding; + } + + + } } diff --git a/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java b/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java deleted file mode 100644 index 923a5d590..000000000 --- a/src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.afp.modca; - -/** - * The TagLogicalElementBean provides a bean for holding the attributes of - * a tag logical element as key value pairs. - * <p/> - */ -public class TagLogicalElementBean { - - /** The key attribute */ - private String key; - - /** The value attribute */ - private String value; - - /** - * Constructor for the TagLogicalElementBean. - * - * @param key the key attribute - * @param value the value attribute - */ - public TagLogicalElementBean(String key, String value) { - this.key = key; - this.value = value; - } - - /** - * Getter for the key attribute. - * - * @return the key - */ - public String getKey() { - return key; - } - - /** - * Getter for the value attribute. - * - * @return the value - */ - public String getValue() { - return value; - } - -} diff --git a/src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java new file mode 100644 index 000000000..05e56e5ae --- /dev/null +++ b/src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java @@ -0,0 +1,63 @@ +/* + * 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.afp.modca.triplets; + +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.fop.afp.util.BinaryUtils; +/** + * + * Represents a CCSID encoding triplet. + * + */ +public class EncodingTriplet extends AbstractTriplet { + + + private int encoding; + /** + * @param encoding the CCSID character set encoding + */ + public EncodingTriplet( int encoding) { + super(CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER); + this.encoding = encoding; + } + /** {@inheritDoc} */ + public void writeToStream(OutputStream os) throws IOException { + + // [len,id,0,0,0,0] + byte[] data = getData(); + + byte[] encodingBytes = BinaryUtils.convert(encoding, 2); + + // [len,id,0,0,0,0] -> [len.id,0,0,encodingBytes[0],encodingBytes[1]] + System.arraycopy(encodingBytes, 0, data, 4, encodingBytes.length); + + os.write(data); + + } + + /** {@inheritDoc} */ + public int getDataLength() { + //len(1b) + id(1b) + 0x0000 (2b) + encoding (2b) = 6b + return 6; + } + +} diff --git a/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java b/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java index 46b09be21..f760e6c7c 100644 --- a/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java +++ b/src/java/org/apache/fop/afp/util/AFPResourceAccessor.java @@ -106,7 +106,7 @@ public final class AFPResourceAccessor { URI resolveURI(String uri); } - private final class NullBaseURIResolver implements URIResolver { + private static final class NullBaseURIResolver implements URIResolver { public URI resolveURI(URI uri) { return uri; diff --git a/src/java/org/apache/fop/apps/EnvironmentProfile.java b/src/java/org/apache/fop/apps/EnvironmentProfile.java index c964120e3..1a585353e 100644 --- a/src/java/org/apache/fop/apps/EnvironmentProfile.java +++ b/src/java/org/apache/fop/apps/EnvironmentProfile.java @@ -21,7 +21,9 @@ package org.apache.fop.apps; import java.net.URI; -import org.apache.fop.apps.io.ResourceResolver; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; +import org.apache.xmlgraphics.io.ResourceResolver; + import org.apache.fop.fonts.FontManager; /** @@ -52,4 +54,7 @@ public interface EnvironmentProfile { * @return the default base URI */ URI getDefaultBaseURI(); + + /** @see FopFactoryConfig#getFallbackResolver() */ + FallbackResolver getFallbackResolver(); } diff --git a/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java b/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java index 9ba7632d2..922ecff4b 100644 --- a/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java +++ b/src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java @@ -21,8 +21,12 @@ package org.apache.fop.apps; import java.net.URI; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.RestrictedFallbackResolver; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.UnrestrictedFallbackResolver; +import org.apache.xmlgraphics.io.ResourceResolver; + import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.apps.io.ResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.fonts.FontCacheManager; import org.apache.fop.fonts.FontCacheManagerFactory; @@ -51,7 +55,8 @@ public final class EnvironmentalProfileFactory { return new Profile(defaultBaseUri, resourceResolver, createFontManager(defaultBaseUri, resourceResolver, FontDetectorFactory.createDefault(), - FontCacheManagerFactory.createDefault())); + FontCacheManagerFactory.createDefault()), + new UnrestrictedFallbackResolver()); } /** @@ -67,7 +72,8 @@ public final class EnvironmentalProfileFactory { return new Profile(defaultBaseUri, resourceResolver, createFontManager(defaultBaseUri, resourceResolver, FontDetectorFactory.createDisabled(), - FontCacheManagerFactory.createDisabled())); + FontCacheManagerFactory.createDisabled()), + new RestrictedFallbackResolver()); } private static final class Profile implements EnvironmentProfile { @@ -78,8 +84,10 @@ public final class EnvironmentalProfileFactory { private final URI defaultBaseURI; + private final FallbackResolver fallbackResolver; + private Profile(URI defaultBaseURI, ResourceResolver resourceResolver, - FontManager fontManager) { + FontManager fontManager, FallbackResolver fallbackResolver) { if (defaultBaseURI == null) { throw new IllegalArgumentException("Default base URI must not be null"); } @@ -92,6 +100,7 @@ public final class EnvironmentalProfileFactory { this.defaultBaseURI = defaultBaseURI; this.resourceResolver = resourceResolver; this.fontManager = fontManager; + this.fallbackResolver = fallbackResolver; } public ResourceResolver getResourceResolver() { @@ -105,6 +114,10 @@ public final class EnvironmentalProfileFactory { public URI getDefaultBaseURI() { return defaultBaseURI; } + + public FallbackResolver getFallbackResolver() { + return fallbackResolver; + } } private static FontManager createFontManager(URI defaultBaseUri, ResourceResolver resourceResolver, diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 0ed5b7228..68064343e 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -131,21 +131,7 @@ public class FOUserAgent { /** Set of keywords applicable to this document. */ protected String keywords = null; - private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { - - public ImageContext getParentContext() { - return factory; - } - - public float getTargetResolution() { - return FOUserAgent.this.getTargetResolution(); - } - - public Source resolveURI(String uri) { - return FOUserAgent.this.resolveURI(uri); - } - - }; + private final ImageSessionContext imageSessionContext; /** * Main constructor. <b>This constructor should not be called directly. Please use the @@ -154,11 +140,25 @@ public class FOUserAgent { * @param resourceResolver the resolver used to acquire resources * @see org.apache.fop.apps.FopFactory */ - FOUserAgent(FopFactory factory, InternalResourceResolver resourceResolver) { + FOUserAgent(final FopFactory factory, InternalResourceResolver resourceResolver) { this.factory = factory; this.resourceResolver = resourceResolver; setTargetResolution(factory.getTargetResolution()); setAccessibility(factory.isAccessibilityEnabled()); + imageSessionContext = new AbstractImageSessionContext(factory.getFallbackResolver()) { + + public ImageContext getParentContext() { + return factory; + } + + public float getTargetResolution() { + return FOUserAgent.this.getTargetResolution(); + } + + public Source resolveURI(String uri) { + return FOUserAgent.this.resolveURI(uri); + } + }; } /** diff --git a/src/java/org/apache/fop/apps/FopConfParser.java b/src/java/org/apache/fop/apps/FopConfParser.java index c6e3dbd19..b4918ef30 100644 --- a/src/java/org/apache/fop/apps/FopConfParser.java +++ b/src/java/org/apache/fop/apps/FopConfParser.java @@ -39,9 +39,9 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.image.loader.spi.ImageImplRegistry; import org.apache.xmlgraphics.image.loader.util.Penalty; +import org.apache.xmlgraphics.io.ResourceResolver; import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.apps.io.ResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.fonts.FontManagerConfigurator; import org.apache.fop.hyphenation.HyphenationTreeCache; diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index 80c957f9f..6bc744b7e 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.image.loader.ImageContext; import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; import org.apache.xmlgraphics.util.UnitConv; import org.apache.fop.apps.io.InternalResourceResolver; @@ -418,6 +419,11 @@ public final class FopFactory implements ImageContext { return config.getFontManager(); } + /** @see FopFactoryConfig#getFallbackResolver() */ + FallbackResolver getFallbackResolver() { + return config.getFallbackResolver(); + } + /** * Returns the color space cache for this instance. * <p> diff --git a/src/java/org/apache/fop/apps/FopFactoryBuilder.java b/src/java/org/apache/fop/apps/FopFactoryBuilder.java index cfc47496c..b1fd5e979 100644 --- a/src/java/org/apache/fop/apps/FopFactoryBuilder.java +++ b/src/java/org/apache/fop/apps/FopFactoryBuilder.java @@ -30,8 +30,9 @@ import org.apache.avalon.framework.configuration.Configuration; import org.apache.xmlgraphics.image.loader.ImageContext; import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; +import org.apache.xmlgraphics.io.ResourceResolver; -import org.apache.fop.apps.io.ResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.fonts.FontManager; import org.apache.fop.layoutmgr.LayoutManagerMaker; @@ -464,6 +465,10 @@ public final class FopFactoryBuilder { public Map<String, String> getHyphenationPatternNames() { return hyphPatNames; } + + public FallbackResolver getFallbackResolver() { + return enviro.getFallbackResolver(); + } } private interface FopFactoryConfigBuilder { diff --git a/src/java/org/apache/fop/apps/FopFactoryConfig.java b/src/java/org/apache/fop/apps/FopFactoryConfig.java index 60e8d98e7..d3ea3127f 100644 --- a/src/java/org/apache/fop/apps/FopFactoryConfig.java +++ b/src/java/org/apache/fop/apps/FopFactoryConfig.java @@ -26,8 +26,9 @@ import java.util.Set; import org.apache.avalon.framework.configuration.Configuration; import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; +import org.apache.xmlgraphics.io.ResourceResolver; -import org.apache.fop.apps.io.ResourceResolver; import org.apache.fop.fonts.FontManager; import org.apache.fop.layoutmgr.LayoutManagerMaker; @@ -163,4 +164,11 @@ public interface FopFactoryConfig { /** @return the hyphenation pattern names */ Map<String, String> getHyphenationPatternNames(); + + /** + * Controls the mechanisms that are used in the event that {@link javax.xml.transform.Source} + * used for resources couldn't be read. + * @return the fallback resolver + */ + FallbackResolver getFallbackResolver(); } diff --git a/src/java/org/apache/fop/apps/io/InternalResourceResolver.java b/src/java/org/apache/fop/apps/io/InternalResourceResolver.java index 4d664c8f5..af0a26478 100644 --- a/src/java/org/apache/fop/apps/io/InternalResourceResolver.java +++ b/src/java/org/apache/fop/apps/io/InternalResourceResolver.java @@ -29,12 +29,14 @@ import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.stream.StreamSource; +import org.apache.xmlgraphics.io.Resource; +import org.apache.xmlgraphics.io.ResourceResolver; import org.apache.xmlgraphics.util.uri.DataURIResolver; /** * This object holds the base URI from which to resolve URIs against as well as the resolver for * resource acquisition. It also does some URI sanitization of common URI syntactical errors. This - * class takes in a {@link org.apache.fop.apps.io.ResourceResolver} and delegates all relevant + * class takes in a {@link org.apache.xmlgraphics.io.ResourceResolver} and delegates all relevant * URIs to it. */ public class InternalResourceResolver { diff --git a/src/java/org/apache/fop/apps/io/ResourceResolver.java b/src/java/org/apache/fop/apps/io/ResourceResolver.java deleted file mode 100644 index a3a9cf0c3..000000000 --- a/src/java/org/apache/fop/apps/io/ResourceResolver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.apps.io; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.URI; - -/** - * Implementations of this resource resolver allow FOP users to control the URI resolution - * mechanism. All resource and output stream acquisition goes through this when its implementation - * is given to the {@link org.apache.fop.apps.EnvironmentProfile}. - */ -public interface ResourceResolver { - - /** - * Get a resource given the URI pointing to said resource. - * - * @param uri the resource URI - * @return the resource - * @throws IOException if an I/O error occured during resource acquisition - */ - Resource getResource(URI uri) throws IOException; - - /** - * Gets an output stream of a given URI. - * - * @param uri the output stream URI - * @return the output stream - * @throws IOException if an I/O error occured while creating an output stream - */ - OutputStream getOutputStream(URI uri) throws IOException; - -} diff --git a/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java b/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java index 72eac456d..cdc9438b9 100644 --- a/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java +++ b/src/java/org/apache/fop/apps/io/ResourceResolverFactory.java @@ -28,6 +28,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.apache.xmlgraphics.io.Resource; +import org.apache.xmlgraphics.io.ResourceResolver; +import org.apache.xmlgraphics.io.TempResourceResolver; +import org.apache.xmlgraphics.io.TempResourceURIGenerator; + /** * A factory class for {@link ResourceResolver}s. */ @@ -70,10 +75,10 @@ public final class ResourceResolverFactory { } /** - * Creates a temporary-resource-schema aware resource resolver. Temporary resource URIs are + * Creates a temporary-resource-scheme aware resource resolver. Temporary resource URIs are * created by {@link TempResourceURIGenerator}. * - * @param tempResourceResolver the temporary-resource-schema resolver to use + * @param tempResourceResolver the temporary-resource-scheme resolver to use * @param defaultResourceResolver the default resource resolver to use * @return the ressource resolver */ @@ -84,17 +89,17 @@ public final class ResourceResolverFactory { } /** - * This creates the builder class for binding URI schemas to implementations of - * {@link ResourceResolver}. This allows users to define their own URI schemas such that they + * This creates the builder class for binding URI schemes to implementations of + * {@link ResourceResolver}. This allows users to define their own URI schemes such that they * have finer control over the acquisition of resources. * * @param defaultResolver the default resource resolver that should be used in the event that - * none of the other registered resolvers match the schema - * @return the schema aware {@link ResourceResolver} builder + * none of the other registered resolvers match the scheme + * @return the scheme aware {@link ResourceResolver} builder */ - public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder( + public static SchemeAwareResourceResolverBuilder createSchemeAwareResourceResolverBuilder( ResourceResolver defaultResolver) { - return new SchemaAwareResourceResolverBuilderImpl(defaultResolver); + return new SchemeAwareResourceResolverBuilderImpl(defaultResolver); } private static final class DefaultResourceResolver implements ResourceResolver { @@ -132,13 +137,13 @@ public final class ResourceResolverFactory { this.defaultResourceResolver = defaultResourceResolver; } - private static boolean isTempUri(URI uri) { - return TempResourceURIGenerator.isTempUri(uri); + private static boolean isTempURI(URI uri) { + return TempResourceURIGenerator.isTempURI(uri); } /** {@inheritDoc} */ public Resource getResource(URI uri) throws IOException { - if (isTempUri(uri)) { + if (isTempURI(uri)) { return tempResourceResolver.getResource(uri.getPath()); } else { return defaultResourceResolver.getResource(uri); @@ -147,7 +152,7 @@ public final class ResourceResolverFactory { /** {@inheritDoc} */ public OutputStream getOutputStream(URI uri) throws IOException { - if (isTempUri(uri)) { + if (isTempURI(uri)) { return tempResourceResolver.getOutputStream(uri.getPath()); } else { return defaultResourceResolver.getOutputStream(uri); @@ -188,23 +193,23 @@ public final class ResourceResolverFactory { } } - private static final class SchemaAwareResourceResolver implements ResourceResolver { + private static final class SchemeAwareResourceResolver implements ResourceResolver { - private final Map<String, ResourceResolver> schemaHandlingResourceResolvers; + private final Map<String, ResourceResolver> schemeHandlingResourceResolvers; private final ResourceResolver defaultResolver; - private SchemaAwareResourceResolver( - Map<String, ResourceResolver> schemaHandlingResourceResolvers, + private SchemeAwareResourceResolver( + Map<String, ResourceResolver> schemEHandlingResourceResolvers, ResourceResolver defaultResolver) { - this.schemaHandlingResourceResolvers = schemaHandlingResourceResolvers; + this.schemeHandlingResourceResolvers = schemEHandlingResourceResolvers; this.defaultResolver = defaultResolver; } - private ResourceResolver getResourceResolverForSchema(URI uri) { - String schema = uri.getScheme(); - if (schemaHandlingResourceResolvers.containsKey(schema)) { - return schemaHandlingResourceResolvers.get(schema); + private ResourceResolver getResourceResolverForScheme(URI uri) { + String scheme = uri.getScheme(); + if (schemeHandlingResourceResolvers.containsKey(scheme)) { + return schemeHandlingResourceResolvers.get(scheme); } else { return defaultResolver; } @@ -212,58 +217,58 @@ public final class ResourceResolverFactory { /** {@inheritDoc} */ public Resource getResource(URI uri) throws IOException { - return getResourceResolverForSchema(uri).getResource(uri); + return getResourceResolverForScheme(uri).getResource(uri); } /** {@inheritDoc} */ public OutputStream getOutputStream(URI uri) throws IOException { - return getResourceResolverForSchema(uri).getOutputStream(uri); + return getResourceResolverForScheme(uri).getOutputStream(uri); } } /** * Implementations of this interface will be builders for {@link ResourceResolver}, they bind - * URI schemas to their respective resolver. This gives users more control over the mechanisms + * URI schemes to their respective resolver. This gives users more control over the mechanisms * by which URIs are resolved. * <p> * Here is an example of how this could be used: * </p> * <p><code> - * SchemaAwareResourceResolverBuilder builder - * = ResourceResolverFactory.createSchemaAwareResourceResolverBuilder(defaultResolver); - * builder.registerResourceResolverForSchema("test", testResolver); - * builder.registerResourceResolverForSchema("anotherTest", test2Resolver); + * SchemeAwareResourceResolverBuilder builder + * = ResourceResolverFactory.createSchemeAwareResourceResolverBuilder(defaultResolver); + * builder.registerResourceResolverForScheme("test", testResolver); + * builder.registerResourceResolverForScheme("anotherTest", test2Resolver); * ResourceResolver resolver = builder.build(); * </code></p> * This will result in all URIs for the form "test:///..." will be resolved using the * <code>testResolver</code> object; URIs of the form "anotherTest:///..." will be resolved * using <code>test2Resolver</code>; all other URIs will be resolved from the defaultResolver. */ - public interface SchemaAwareResourceResolverBuilder { + public interface SchemeAwareResourceResolverBuilder { /** - * Register a schema with its respective {@link ResourceResolver}. This resolver will be - * used as the only resolver for the specified schema. + * Register a scheme with its respective {@link ResourceResolver}. This resolver will be + * used as the only resolver for the specified scheme. * - * @param schema the schema to be used with the given resolver + * @param scheme the scheme to be used with the given resolver * @param resourceResolver the resource resolver */ - void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver); + void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver); /** * Builds a {@link ResourceResolver} that will delegate to the respective resource resolver - * when a registered URI schema is given + * when a registered URI scheme is given * - * @return a resolver that delegates to the appropriate schema resolver + * @return a resolver that delegates to the appropriate scheme resolver */ ResourceResolver build(); } - private static final class CompletedSchemaAwareResourceResolverBuilder - implements SchemaAwareResourceResolverBuilder { + private static final class CompletedSchemeAwareResourceResolverBuilder + implements SchemeAwareResourceResolverBuilder { - private static final SchemaAwareResourceResolverBuilder INSTANCE - = new CompletedSchemaAwareResourceResolverBuilder(); + private static final SchemeAwareResourceResolverBuilder INSTANCE + = new CompletedSchemeAwareResourceResolverBuilder(); /** {@inheritDoc} */ public ResourceResolver build() { @@ -271,59 +276,58 @@ public final class ResourceResolverFactory { } /** {@inheritDoc} */ - public void registerResourceResolverForSchema(String schema, + public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { throw new IllegalStateException("Resource resolver already built"); } } - private static final class ActiveSchemaAwareResourceResolverBuilder - implements SchemaAwareResourceResolverBuilder { + private static final class ActiveSchemeAwareResourceResolverBuilder + implements SchemeAwareResourceResolverBuilder { - private final Map<String, ResourceResolver> schemaHandlingResourceResolvers + private final Map<String, ResourceResolver> schemeHandlingResourceResolvers = new HashMap<String, ResourceResolver>(); private final ResourceResolver defaultResolver; - private ActiveSchemaAwareResourceResolverBuilder(ResourceResolver defaultResolver) { + private ActiveSchemeAwareResourceResolverBuilder(ResourceResolver defaultResolver) { this.defaultResolver = defaultResolver; } /** {@inheritDoc} */ - public void registerResourceResolverForSchema(String schema, + public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { - schemaHandlingResourceResolvers.put(schema, resourceResolver); + schemeHandlingResourceResolvers.put(scheme, resourceResolver); } /** {@inheritDoc} */ public ResourceResolver build() { - return new SchemaAwareResourceResolver( - Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver); + return new SchemeAwareResourceResolver( + Collections.unmodifiableMap(schemeHandlingResourceResolvers), defaultResolver); } } - private static final class SchemaAwareResourceResolverBuilderImpl - implements SchemaAwareResourceResolverBuilder { + private static final class SchemeAwareResourceResolverBuilderImpl + implements SchemeAwareResourceResolverBuilder { - private SchemaAwareResourceResolverBuilder delegate; + private SchemeAwareResourceResolverBuilder delegate; - private SchemaAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { - this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver); + private SchemeAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { + this.delegate = new ActiveSchemeAwareResourceResolverBuilder(defaultResolver); } /** {@inheritDoc} */ - public void registerResourceResolverForSchema(String schema, + public void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver) { - delegate.registerResourceResolverForSchema(schema, resourceResolver); + delegate.registerResourceResolverForScheme(scheme, resourceResolver); } /** {@inheritDoc} */ public ResourceResolver build() { ResourceResolver resourceResolver = delegate.build(); - delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE; + delegate = CompletedSchemeAwareResourceResolverBuilder.INSTANCE; return resourceResolver; } } - } diff --git a/src/java/org/apache/fop/apps/io/TempResourceResolver.java b/src/java/org/apache/fop/apps/io/TempResourceResolver.java deleted file mode 100644 index cf307fab6..000000000 --- a/src/java/org/apache/fop/apps/io/TempResourceResolver.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.apps.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Implementations of this interface resolve URIs for temporary files used by FOP. The temporary- - * resource URI scheme comes from {@link TempResourceURIGenerator#TMP_SCHEMA}. - */ -public interface TempResourceResolver { - - /** - * Get a temporary-resource given the URI pointing to said resource. - * - * @param uri the resource URI - * @return the resource - * @throws IOException if an I/O error occured during resource acquisition - */ - Resource getResource(String uri) throws IOException; - - /** - * Gets an temporary-output stream of a given URI. - * - * @param uri the output stream URI - * @return the output stream - * @throws IOException if an I/O error occured while creating an output stream - */ - OutputStream getOutputStream(String uri) throws IOException; -} diff --git a/src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java b/src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java deleted file mode 100644 index 8e6c3606c..000000000 --- a/src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.fop.apps.io; - -import java.net.URI; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Creates a URI for any temporary resource used within FOP. - */ -public final class TempResourceURIGenerator { - - public static final String TMP_SCHEMA = "tmp"; - - private final String tempURIPrefix; - - private final AtomicLong counter; - - /** - * @param uriPrefix a prefix used to name the unique URI - */ - public TempResourceURIGenerator(String uriPrefix) { - counter = new AtomicLong(); - tempURIPrefix = URI.create(TMP_SCHEMA + ":///" + uriPrefix).toASCIIString(); - } - - /** - * Generate a unique URI for a temporary resource - * @return the URI - */ - public URI generate() { - return URI.create(tempURIPrefix + getUniqueId()); - } - - private String getUniqueId() { - return Long.toHexString(counter.getAndIncrement()); - } - - public static boolean isTempUri(URI uri) { - return TMP_SCHEMA.equals(uri.getScheme()); - } -} diff --git a/src/java/org/apache/fop/area/CachedRenderPagesModel.java b/src/java/org/apache/fop/area/CachedRenderPagesModel.java index fcc82cdd3..0837e5ae5 100644 --- a/src/java/org/apache/fop/area/CachedRenderPagesModel.java +++ b/src/java/org/apache/fop/area/CachedRenderPagesModel.java @@ -35,9 +35,10 @@ import org.xml.sax.SAXException; import org.apache.commons.io.IOUtils; +import org.apache.xmlgraphics.io.TempResourceURIGenerator; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.io.TempResourceURIGenerator; import org.apache.fop.fonts.FontInfo; /** diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java index f38964ebc..d1250238a 100644 --- a/src/java/org/apache/fop/area/PageViewport.java +++ b/src/java/org/apache/fop/area/PageViewport.java @@ -34,6 +34,10 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.flow.AbstractRetrieveMarker; +import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.flow.Markers; import org.apache.fop.fo.pagination.SimplePageMaster; import org.apache.fop.traits.WritingModeTraitsGetter; @@ -81,13 +85,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable { private Map<String, List<PageViewport>> pendingResolved = null; - // hashmap of markers for this page - // start and end are added by the fo that contains the markers - private Map<String, Marker> markerFirstStart = null; - private Map<String, Marker> markerLastStart = null; - private Map<String, Marker> markerFirstAny = null; - private Map<String, Marker> markerLastEnd = null; - private Map<String, Marker> markerLastAny = null; + private Markers pageMarkers; /** * logging instance @@ -352,115 +350,23 @@ public class PageViewport extends AreaTreeObject implements Resolvable { } /** - * Add the markers for this page. - * Only the required markers are kept. - * For "first-starting-within-page" it adds the markers - * that are starting only if the marker class name is not - * already added. - * For "first-including-carryover" it adds any starting marker - * if the marker class name is not already added. - * For "last-starting-within-page" it adds all marks that - * are starting, replacing earlier markers. - * For "last-ending-within-page" it adds all markers that - * are ending, replacing earlier markers. - * - * Should this logic be placed in the Page layout manager. + * Register the markers for this page. * * @param marks the map of markers to add * @param starting if the area being added is starting or ending * @param isfirst if the area being added has is-first trait * @param islast if the area being added has is-last trait */ - public void addMarkers(Map<String, Marker> marks, boolean starting, - boolean isfirst, boolean islast) { - - if (marks == null) { - return; - } - if (log.isDebugEnabled()) { - log.debug("--" + marks.keySet() + ": " - + (starting ? "starting" : "ending") - + (isfirst ? ", first" : "") - + (islast ? ", last" : "")); - } - - // at the start of the area, register is-first and any areas - if (starting) { - if (isfirst) { - if (markerFirstStart == null) { - markerFirstStart = new HashMap<String, Marker>(); - } - if (markerFirstAny == null) { - markerFirstAny = new HashMap<String, Marker>(); - } - // first on page: only put in new values, leave current - for (String key : marks.keySet()) { - if (!markerFirstStart.containsKey(key)) { - markerFirstStart.put(key, marks.get(key)); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding marker " + key + " to FirstStart"); - } - } - if (!markerFirstAny.containsKey(key)) { - markerFirstAny.put(key, marks.get(key)); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding marker " + key + " to FirstAny"); - } - } - } - if (markerLastStart == null) { - markerLastStart = new HashMap<String, Marker>(); - } - // last on page: replace all - markerLastStart.putAll(marks); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding all markers to LastStart"); - } - } else { - if (markerFirstAny == null) { - markerFirstAny = new HashMap<String, Marker>(); - } - // first on page: only put in new values, leave current - for (String key : marks.keySet()) { - if (!markerFirstAny.containsKey(key)) { - markerFirstAny.put(key, marks.get(key)); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding marker " + key + " to FirstAny"); - } - } - } - } - } else { - // at the end of the area, register is-last and any areas - if (islast) { - if (markerLastEnd == null) { - markerLastEnd = new HashMap<String, Marker>(); - } - // last on page: replace all - markerLastEnd.putAll(marks); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding all markers to LastEnd"); - } - } - if (markerLastAny == null) { - markerLastAny = new HashMap<String, Marker>(); - } - // last on page: replace all - markerLastAny.putAll(marks); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding all markers to LastAny"); - } + public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { + if (pageMarkers == null) { + pageMarkers = new Markers(); } + pageMarkers.register(marks, starting, isfirst, islast); } + /** - * Get a marker from this page. + * Resolve a marker from this page. * This will retrieve a marker with the class name * and position. * @@ -468,64 +374,17 @@ public class PageViewport extends AreaTreeObject implements Resolvable { * @param pos the position to retrieve * @return Object the marker found or null */ - public Marker getMarker(String name, int pos) { - Marker mark = null; - String posName = null; - switch (pos) { - case EN_FSWP: - if (markerFirstStart != null) { - mark = markerFirstStart.get(name); - posName = "FSWP"; - } - if (mark == null && markerFirstAny != null) { - mark = markerFirstAny.get(name); - posName = "FirstAny after " + posName; - } - break; - case EN_FIC: - if (markerFirstAny != null) { - mark = markerFirstAny.get(name); - posName = "FIC"; - } - break; - case EN_LSWP: - if (markerLastStart != null) { - mark = markerLastStart.get(name); - posName = "LSWP"; - } - if (mark == null && markerLastAny != null) { - mark = markerLastAny.get(name); - posName = "LastAny after " + posName; - } - break; - case EN_LEWP: - if (markerLastEnd != null) { - mark = markerLastEnd.get(name); - posName = "LEWP"; - } - if (mark == null && markerLastAny != null) { - mark = markerLastAny.get(name); - posName = "LastAny after " + posName; - } - break; - default: - assert false; - } - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name - + " at position " + posName); + public Marker resolveMarker(AbstractRetrieveMarker rm) { + if (pageMarkers == null) { + return null; } - return mark; + return pageMarkers.resolve(rm); } /** Dumps the current marker data to the logger. */ public void dumpMarkers() { - if (log.isTraceEnabled()) { - log.trace("FirstAny: " + this.markerFirstAny); - log.trace("FirstStart: " + this.markerFirstStart); - log.trace("LastAny: " + this.markerLastAny); - log.trace("LastEnd: " + this.markerLastEnd); - log.trace("LastStart: " + this.markerLastStart); + if (pageMarkers != null) { + pageMarkers.dump(); } } diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index 886e27527..7a11df71a 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -421,7 +421,7 @@ public class CommandLineOptions { throw new FOPException("if you use '-cache', you must specify " + "the name of the font cache file"); } else { - factory.getFontManager().setCacheFile(new File(args[i + 1])); + factory.getFontManager().setCacheFile(URI.create(args[i + 1])); return 1; } } diff --git a/src/java/org/apache/fop/events/CompositeEventListener.java b/src/java/org/apache/fop/events/CompositeEventListener.java index 2b5cbffb2..c2bef322e 100644 --- a/src/java/org/apache/fop/events/CompositeEventListener.java +++ b/src/java/org/apache/fop/events/CompositeEventListener.java @@ -19,6 +19,7 @@ package org.apache.fop.events; +import java.util.ArrayList; import java.util.List; /** @@ -26,7 +27,7 @@ import java.util.List; */ public class CompositeEventListener implements EventListener { - private List listeners = new java.util.ArrayList(); + private List<EventListener> listeners = new ArrayList<EventListener>(); /** * Adds an event listener to the broadcaster. It is appended to the list of previously @@ -46,22 +47,17 @@ public class CompositeEventListener implements EventListener { this.listeners.remove(listener); } - private synchronized int getListenerCount() { - return this.listeners.size(); - } - /** * Indicates whether any listeners have been registered with the broadcaster. * @return true if listeners are present, false otherwise */ - public boolean hasEventListeners() { - return (getListenerCount() > 0); + public synchronized boolean hasEventListeners() { + return !listeners.isEmpty(); } - /** {@inheritDoc} */ + /** {@inheritDoc } */ public synchronized void processEvent(Event event) { - for (int i = 0, c = getListenerCount(); i < c; i++) { - EventListener listener = (EventListener)this.listeners.get(i); + for (EventListener listener : listeners) { listener.processEvent(event); } } diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index 14c4b5890..722a4ca94 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -807,8 +807,11 @@ public interface Constants { */ int PR_X_NUMBER_CONVERSION_FEATURES = 285; + /** Scope for table header */ + int PR_X_HEADER_COLUMN = 286; + /** Number of property constants defined */ - int PROPERTY_COUNT = 285; + int PROPERTY_COUNT = 286; // compound property constants @@ -1246,6 +1249,8 @@ public interface Constants { int EN_BT = 204; // bottom to top /** Enumeration constant */ int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode + /** Enumeration constant -- for fo:retrieve-table-marker */ + int EN_FIRST_INCLUDING_CARRYOVER = 206; /** Number of enumeration constants defined */ - int ENUM_COUNT = 205; + int ENUM_COUNT = 206; } diff --git a/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java b/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java index 50026c996..bb0a1ba75 100644 --- a/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java +++ b/src/java/org/apache/fop/fo/DelegatingFOEventHandler.java @@ -143,6 +143,16 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler { } @Override + public void startStatic(StaticContent staticContent) { + delegate.startStatic(staticContent); + } + + @Override + public void endStatic(StaticContent statisContent) { + delegate.endStatic(statisContent); + } + + @Override public void startFlow(Flow fl) { delegate.startFlow(fl); } @@ -293,16 +303,6 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler { } @Override - public void startStatic(StaticContent staticContent) { - delegate.startStatic(staticContent); - } - - @Override - public void endStatic(StaticContent statisContent) { - delegate.endStatic(statisContent); - } - - @Override public void startMarkup() { delegate.startMarkup(); } diff --git a/src/java/org/apache/fop/fo/FOEventHandler.java b/src/java/org/apache/fop/fo/FOEventHandler.java index 11b6d4a2f..ad647e42a 100644 --- a/src/java/org/apache/fop/fo/FOEventHandler.java +++ b/src/java/org/apache/fop/fo/FOEventHandler.java @@ -193,6 +193,20 @@ public abstract class FOEventHandler { } /** + * Process start of a Static. + * @param staticContent StaticContent that is starting + */ + public void startStatic(StaticContent staticContent) { + } + + /** + * Process end of a Static. + * @param staticContent StaticContent that is ending + */ + public void endStatic(StaticContent staticContent) { + } + + /** * This method is called to indicate the start of a new fo:flow * or fo:static-content. * This method also handles fo:static-content tags, because the @@ -409,22 +423,6 @@ public abstract class FOEventHandler { public void endListBody(ListItemBody listItemBody) { } - // Static Regions - /** - * Process start of a Static. - * @param staticContent StaticContent that is starting - */ - public void startStatic(StaticContent staticContent) { - } - - /** - * Process end of a Static. - * @param staticContent StaticContent that is ending - */ - public void endStatic(StaticContent staticContent) { - } - - /** * Process start of a Markup. */ diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java index c66259f11..707dae91e 100644 --- a/src/java/org/apache/fop/fo/FONode.java +++ b/src/java/org/apache/fop/fo/FONode.java @@ -38,6 +38,7 @@ import org.apache.fop.accessibility.StructureTreeElement; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.complexscripts.bidi.DelimitedTextRange; +import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fo.extensions.InternalElementMapping; @@ -562,6 +563,19 @@ public abstract class FONode implements Cloneable { } /** + * Helper function to return "not supported child" exceptions. Note that the child is valid, just not + * supported yet by FOP. + * + * @param loc org.xml.sax.Locator object of the error (*not* parent node) + * @param nsURI namespace URI of incoming invalid node + * @param lName local name (i.e., no prefix) of incoming node + * @throws ValidationException the validation error provoked by the method call + */ + protected void notSupportedChildError(Locator loc, String nsURI, String lName) throws ValidationException { + getFOValidationEventProducer().notSupportedChild(this, getName(), new QName(nsURI, lName), loc); + } + + /** * Helper function to throw an error caused by missing mandatory child elements. * (e.g., <code>fo:layout-master-set</code> not having any <code>fo:page-master</code> * child element. @@ -601,6 +615,22 @@ public abstract class FONode implements Cloneable { getFOValidationEventProducer().missingProperty(this, getName(), propertyName, locator); } + + + /** + * Helper function to throw an error caused by an invalid property + * + * @param propertyName the name of the property. + * @param propertyValue the value of the property. + * * @param e optional property parsing exception. + * @throws ValidationException the validation error provoked by the method call + */ + protected void invalidPropertyValueError(String propertyName, String propertyValue, Exception e) + throws ValidationException { + getFOValidationEventProducer().invalidPropertyValue(this, getName(), propertyName, + propertyValue, new PropertyException(e), locator); + } + /** * Helper function to return "Error(line#/column#)" string for * above exception messages diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index eac510fb0..08afbcd52 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -26,6 +26,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.datatypes.LengthBase; import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker; +import org.apache.fop.fo.pagination.Flow; import org.apache.fop.fo.properties.BackgroundPositionShorthand; import org.apache.fop.fo.properties.BorderSpacingShorthandParser; import org.apache.fop.fo.properties.BorderWidthPropertyMaker; @@ -2187,7 +2188,8 @@ public final class FOPropertyMapping implements Constants { m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE); m.setInherited(false); m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING")); - m.addEnum("first-including-carryover", getEnumProperty(EN_FIC, "FIC")); + m.addEnum("first-including-carryover", + getEnumProperty(EN_FIRST_INCLUDING_CARRYOVER, "FIRST_INCLUDING_CARRYOVER")); m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING")); m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING")); m.setDefault("first-starting"); @@ -2198,7 +2200,7 @@ public final class FOPropertyMapping implements Constants { m.setInherited(false); m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE")); m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT")); - m.addEnum("page", getEnumProperty(EN_DOCUMENT, "PAGE")); + m.addEnum("page", getEnumProperty(EN_PAGE, "PAGE")); m.setDefault("table"); addPropertyMaker("retrieve-boundary-within-table", m); } @@ -2277,7 +2279,7 @@ public final class FOPropertyMapping implements Constants { m = new StringProperty.Maker(PR_FLOW_NAME); m.setInherited(false); m.setDefault(""); - addPropertyMaker("flow-name", m); + addPropertyMaker(Flow.FLOW_NAME, m); // force-page-count m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT); @@ -2522,6 +2524,12 @@ public final class FOPropertyMapping implements Constants { m.setInherited(false); m.setDefault("false"); addPropertyMaker("table-omit-header-at-break", m); + + // fox:scope + m = new EnumProperty.Maker(PR_X_HEADER_COLUMN); + m.useGeneric(genericBoolean); + m.setDefault("false"); + addPropertyMaker("fox:header", m); } private void createWritingModeProperties() { diff --git a/src/java/org/apache/fop/fo/FOValidationEventProducer.java b/src/java/org/apache/fop/fo/FOValidationEventProducer.java index ff005b1b4..ee6b078b5 100644 --- a/src/java/org/apache/fop/fo/FOValidationEventProducer.java +++ b/src/java/org/apache/fop/fo/FOValidationEventProducer.java @@ -90,6 +90,18 @@ public interface FOValidationEventProducer extends EventProducer { Locator loc) throws ValidationException; /** + * A valid but not yet supported child was encountered. + * + * @param source the event source + * @param elementName the name of the context node + * @param offendingNode the offending node + * @param loc the location of the error or null + * @throws ValidationException the validation error provoked by the method call + */ + void notSupportedChild(Object source, String elementName, QName offendingNode, Locator loc) + throws ValidationException; + + /** * A required child element is missing. * @param source the event source * @param elementName the name of the context node diff --git a/src/java/org/apache/fop/fo/FOValidationEventProducer.xml b/src/java/org/apache/fop/fo/FOValidationEventProducer.xml index 509f7c1d3..a8b2fffb1 100644 --- a/src/java/org/apache/fop/fo/FOValidationEventProducer.xml +++ b/src/java/org/apache/fop/fo/FOValidationEventProducer.xml @@ -17,6 +17,7 @@ <message key="tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message> <message key="nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message> <message key="invalidChild">"{offendingNode}" is not a valid child of "{elementName}"![ {ruleViolated,lookup}]{{locator}}</message> + <message key="notSupportedChild">"{offendingNode}" as a child of "{elementName}" is not supported yet!{{locator}}</message> <message key="missingChildElement">"{elementName}" is missing child elements.[ Required content model: {contentModel}]{{locator}}</message> <message key="missingProperty">Element "{elementName}" is missing required property "{propertyName}"!{{locator}}</message> <message key="idNotUnique">Property ID "{id}" (found on "{elementName}") previously used; ID values must be unique within a document!{severity,equals,EventSeverity:FATAL,, Any reference to it will be considered a reference to the first occurrence in the document.}{{locator}}</message> diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 241a442ab..0e7e55aa9 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -20,6 +20,7 @@ package org.apache.fop.fo; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -35,6 +36,7 @@ import org.apache.xmlgraphics.util.QName; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.properties.PropertyMaker; /** @@ -65,7 +67,7 @@ public abstract class FObj extends FONode implements Constants { private boolean isOutOfLineFODescendant = false; /** Markers added to this element. */ - private Map markers = null; + private Map<String, Marker> markers; private int bidiLevel = -1; @@ -356,7 +358,7 @@ public abstract class FObj extends FONode implements Constants { } } if (markers == null) { - markers = new java.util.HashMap(); + markers = new HashMap<String, Marker>(); } if (!markers.containsKey(mcname)) { markers.put(mcname, marker); @@ -376,7 +378,7 @@ public abstract class FObj extends FONode implements Constants { /** * @return the collection of Markers attached to this object */ - public Map getMarkers() { + public Map<String, Marker> getMarkers() { return markers; } @@ -522,6 +524,11 @@ public abstract class FObj extends FONode implements Constants { int found = 1; FONode temp = getParent(); while (temp != null) { + if (temp instanceof TableCell && (ancestorID == FO_TABLE_HEADER || ancestorID == FO_TABLE_FOOTER)) { + // note that if the retrieve-table-marker is not in a table-header/footer an exception is + // thrown, so no need to reset this flag in that case + ((TableCell) temp).flagAsHavingRetrieveTableMarker(); + } if (temp.getNameId() == ancestorID) { return found; } diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java index 008bca8a8..076691cb4 100644 --- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java @@ -52,6 +52,7 @@ public class ExtensionElementMapping extends ElementMapping { PROPERTY_ATTRIBUTES.add("disable-column-balancing"); //These are FOP's extension properties for accessibility PROPERTY_ATTRIBUTES.add("alt-text"); + PROPERTY_ATTRIBUTES.add("header"); //fox:border-*-radius-* PROPERTY_ATTRIBUTES.add("border-before-radius-start"); PROPERTY_ATTRIBUTES.add("border-before-radius-end"); diff --git a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java index 687952d25..f257dd79d 100644 --- a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java @@ -43,12 +43,15 @@ public class InternalElementMapping extends ElementMapping { /** The "struct-ref" attribute, to refer to a structure tree element. */ public static final String STRUCT_REF = "struct-ref"; + public static final String SCOPE = "scope"; + private static final Set<String> PROPERTY_ATTRIBUTES = new java.util.HashSet<String>(); static { //These are FOP's extension properties for accessibility PROPERTY_ATTRIBUTES.add(STRUCT_ID); PROPERTY_ATTRIBUTES.add(STRUCT_REF); + PROPERTY_ATTRIBUTES.add(SCOPE); } /** diff --git a/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java b/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java index 62c821504..636bc04df 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java @@ -46,6 +46,11 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { private String retrieveClassName; + private int position; + private String positionLabel; + private int boundary; + private String boundaryLabel; + /** * Create a new AbstractRetrieveMarker instance that * is a child of the given {@link FONode} @@ -206,4 +211,43 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { return this.retrieveClassName; } + protected void setBoundaryLabel(String label) { + this.boundaryLabel = label; + } + + protected void setPositionLabel(String label) { + this.positionLabel = label; + } + + public String getBoundaryLabel() { + return this.boundaryLabel; + } + + public String getPositionLabel() { + return this.positionLabel; + } + + protected void setPosition(int position) { + this.position = position; + } + + protected void setBoundary(int boundary) { + this.boundary = boundary; + } + + public int getPosition() { + return this.position; + } + + public int getBoundary() { + return this.boundary; + } + + public abstract String getLocalName(); + + public abstract int getNameId(); + + public void changePositionTo(int position) { + this.position = position; + } } diff --git a/src/java/org/apache/fop/fo/flow/Markers.java b/src/java/org/apache/fop/fo/flow/Markers.java new file mode 100644 index 000000000..24da818af --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/Markers.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.flow; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.fo.Constants; + +/** + * A class to register and resolve markers. + */ +public final class Markers { + + // IsAny means either IsFirst or IsLast + private Map<String, Marker> firstQualifyingIsFirst; + private Map<String, Marker> firstQualifyingIsAny; + private Map<String, Marker> lastQualifyingIsFirst; + private Map<String, Marker> lastQualifyingIsLast; + private Map<String, Marker> lastQualifyingIsAny; + + private static Log log = LogFactory.getLog(Markers.class); + + /** + * Registers a marker with the position traits set. + * Only the required markers are kept. + * For "first-starting-within-page" it adds the markers + * that are starting only if the marker class name is not + * already added. + * For "first-including-carryover" it adds any starting marker + * if the marker class name is not already added. + * For "last-starting-within-page" it adds all marks that + * are starting, replacing earlier markers. + * For "last-ending-within-page" it adds all markers that + * are ending, replacing earlier markers. + * + * @param marks a map of markers to register + * @param starting whether the registration happens at the start (true) or end (false) the the area + * @param isfirst whether it is the first area of the parent LM + * @param islast whether it is the last area of the parent LM + */ + public void register(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { + // TODO: find way to put the page number in the log tracing + + if (marks == null) { + return; + } + if (log.isDebugEnabled()) { + log.debug("--" + marks.keySet() + ": " + (starting ? "starting" : "ending") + + (isfirst ? ", first" : "") + (islast ? ", last" : "")); + } + + if (starting) { + // at the start of the area, register is-first and any areas + if (firstQualifyingIsAny == null) { + firstQualifyingIsAny = new HashMap<String, Marker>(); + } + if (isfirst) { + if (firstQualifyingIsFirst == null) { + firstQualifyingIsFirst = new HashMap<String, Marker>(); + } + // first on scope: only put in new values, leave current + for (Iterator<String> iter = marks.keySet().iterator(); iter.hasNext();) { + String key = iter.next(); + if (!firstQualifyingIsFirst.containsKey(key)) { + firstQualifyingIsFirst.put(key, marks.get(key)); + if (log.isTraceEnabled()) { + log.trace("Adding marker " + key + " to firstQualifyingIsFirst"); + } + } + if (!firstQualifyingIsAny.containsKey(key)) { + firstQualifyingIsAny.put(key, marks.get(key)); + if (log.isTraceEnabled()) { + log.trace("Adding marker " + key + " to firstQualifyingIsAny"); + } + } + } + if (lastQualifyingIsFirst == null) { + lastQualifyingIsFirst = new HashMap<String, Marker>(); + } + // last on scope: replace all + lastQualifyingIsFirst.putAll(marks); + if (log.isTraceEnabled()) { + log.trace("Adding all markers to LastStart"); + } + } else { + // first on scope: only put in new values, leave current + for (Iterator<String> iter = marks.keySet().iterator(); iter.hasNext();) { + String key = iter.next(); + if (!firstQualifyingIsAny.containsKey(key)) { + firstQualifyingIsAny.put(key, marks.get(key)); + if (log.isTraceEnabled()) { + log.trace("Adding marker " + key + " to firstQualifyingIsAny"); + } + } + } + } + } else { + // at the end of the area, register is-last and any areas + if (islast) { + if (lastQualifyingIsLast == null) { + lastQualifyingIsLast = new HashMap<String, Marker>(); + } + // last on page: replace all + lastQualifyingIsLast.putAll(marks); + if (log.isTraceEnabled()) { + log.trace("Adding all markers to lastQualifyingIsLast"); + } + } + if (lastQualifyingIsAny == null) { + lastQualifyingIsAny = new HashMap<String, Marker>(); + } + // last on page: replace all + lastQualifyingIsAny.putAll(marks); + if (log.isTraceEnabled()) { + log.trace("Adding all markers to lastQualifyingIsAny"); + } + } + } + + /** + * Retrieves the best candidate marker for the given position. + * @param name the key used to register the marker + * @param pos the retrieval scope position + * @return a Marker instance + */ + public Marker resolve(AbstractRetrieveMarker arm) { + Marker mark = null; + int pos = arm.getPosition(); + String name = arm.getRetrieveClassName(); + String posName = arm.getPositionLabel(); + String localName = arm.getLocalName(); + switch (pos) { + case Constants.EN_FSWP: // retrieve-marker + case Constants.EN_FIRST_STARTING: // retrieve-table-marker + if (firstQualifyingIsFirst != null) { + mark = firstQualifyingIsFirst.get(name); + } + if (mark == null && firstQualifyingIsAny != null) { + mark = firstQualifyingIsAny.get(name); + posName = "FirstAny after " + posName; + } + break; + case Constants.EN_FIC: // retrieve-marker + case Constants.EN_FIRST_INCLUDING_CARRYOVER: // retrieve-table-marker + if (firstQualifyingIsAny != null) { + mark = firstQualifyingIsAny.get(name); + } + break; + case Constants.EN_LSWP: // retrieve-marker + case Constants.EN_LAST_STARTING: // retrieve-table-marker + if (lastQualifyingIsFirst != null) { + mark = lastQualifyingIsFirst.get(name); + } + if (mark == null && lastQualifyingIsAny != null) { + mark = lastQualifyingIsAny.get(name); + posName = "LastAny after " + posName; + } + break; + case Constants.EN_LEWP: // retrieve-marker + case Constants.EN_LAST_ENDING: // retrieve-table-marker + if (lastQualifyingIsLast != null) { + mark = lastQualifyingIsLast.get(name); + } + if (mark == null && lastQualifyingIsAny != null) { + mark = lastQualifyingIsAny.get(name); + posName = "LastAny after " + posName; + } + break; + default: + throw new RuntimeException("Invalid position attribute in " + localName + "."); + } + if (log.isTraceEnabled()) { + // TODO: find way to put the page number here + log.trace(localName + ": name[" + name + "]; position [" + posName + "]"); + } + return mark; + } + + /** Dumps the current marker data to the logger. */ + public void dump() { + if (log.isTraceEnabled()) { + log.trace("FirstAny: " + this.firstQualifyingIsAny); + log.trace("FirstStart: " + this.firstQualifyingIsFirst); + log.trace("LastAny: " + this.lastQualifyingIsAny); + log.trace("LastEnd: " + this.lastQualifyingIsLast); + log.trace("LastStart: " + this.lastQualifyingIsFirst); + } + } + +} diff --git a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java index 5fc70c7f2..b001a41ee 100644 --- a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java @@ -34,11 +34,6 @@ import org.apache.fop.fo.PropertyList; */ public class RetrieveMarker extends AbstractRetrieveMarker { - // The value of properties relevant for fo:retrieve-marker. - private int retrievePosition; - private int retrieveBoundary; - // End of property values - /** * Create a new RetrieveMarker instance that is a * child of the given {@link FONode}. @@ -70,8 +65,10 @@ public class RetrieveMarker extends AbstractRetrieveMarker { /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { super.bind(pList); - this.retrievePosition = pList.get(PR_RETRIEVE_POSITION).getEnum(); - this.retrieveBoundary = pList.get(PR_RETRIEVE_BOUNDARY).getEnum(); + setPosition(pList.get(PR_RETRIEVE_POSITION).getEnum()); + setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION).getObject()); + setBoundary(pList.get(PR_RETRIEVE_BOUNDARY).getEnum()); + setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY).getObject()); } /** @@ -84,19 +81,19 @@ public class RetrieveMarker extends AbstractRetrieveMarker { * {@link org.apache.fop.fo.Constants#EN_LEWP}. */ public int getRetrievePosition() { - return this.retrievePosition; + return getPosition(); } /** * Return the value for the <code>retrieve-boundary</code> * property - * @return the value for retrieve-boundary-within-table; one of + * @return the value for retrieve-boundary; one of * {@link org.apache.fop.fo.Constants#EN_PAGE}, * {@link org.apache.fop.fo.Constants#EN_PAGE_SEQUENCE}, * {@link org.apache.fop.fo.Constants#EN_DOCUMENT}. */ public int getRetrieveBoundary() { - return this.retrieveBoundary; + return getBoundary(); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java b/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java index 3090cb702..efacba864 100644 --- a/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java +++ b/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java @@ -32,11 +32,6 @@ import org.apache.fop.fo.PropertyList; */ public class RetrieveTableMarker extends AbstractRetrieveMarker { - // The value of properties relevant for fo:retrieve-table-marker. - private int retrievePositionWithinTable; - private int retrieveBoundaryWithinTable; - // end property values - /** * Create a new RetrieveTableMarker instance that is * a child of the given {@link FONode}. @@ -67,10 +62,10 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { super.bind(pList); - this.retrievePositionWithinTable - = pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum(); - this.retrieveBoundaryWithinTable - = pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum(); + setPosition(pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum()); + setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getObject()); + setBoundary(pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum()); + setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getObject()); } /** @@ -83,7 +78,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { * {@link org.apache.fop.fo.Constants#EN_LAST_ENDING}. */ public int getRetrievePositionWithinTable() { - return this.retrievePositionWithinTable; + return getPosition(); } /** @@ -95,7 +90,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { * {@link org.apache.fop.fo.Constants#EN_PAGE}. */ public int getRetrieveBoundaryWithinTable() { - return this.retrieveBoundaryWithinTable; + return getBoundary(); } /** {@inheritDoc} */ @@ -110,4 +105,12 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { public int getNameId() { return FO_RETRIEVE_TABLE_MARKER; } + + /** {@inheritDoc} */ + public void clearChildNodes() { + super.clearChildNodes(); + this.currentTextNode = null; + this.lastFOTextProcessed = null; + } + } diff --git a/src/java/org/apache/fop/fo/flow/table/TableCell.java b/src/java/org/apache/fop/fo/flow/table/TableCell.java index c4f9c2aa6..f198f3aad 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCell.java @@ -62,6 +62,8 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder { /** used for FO validation */ private boolean blockItemFound = false; + private boolean hasRetrieveTableMarker; + /** * Create a TableCell instance with the given {@link FONode} * as parent. @@ -247,4 +249,11 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder { return FO_TABLE_CELL; } + public void flagAsHavingRetrieveTableMarker() { + hasRetrieveTableMarker = true; + } + + public boolean hasRetrieveTableMarker() { + return hasRetrieveTableMarker; + } } diff --git a/src/java/org/apache/fop/fo/flow/table/TableColumn.java b/src/java/org/apache/fop/fo/flow/table/TableColumn.java index 5047822da..33cbff884 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableColumn.java +++ b/src/java/org/apache/fop/fo/flow/table/TableColumn.java @@ -24,6 +24,7 @@ import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; +import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; @@ -44,6 +45,7 @@ public class TableColumn extends TableFObj { private Length columnWidth; private int numberColumnsRepeated; private int numberColumnsSpanned; + private boolean isHeader; // Unused but valid items, commented out for performance: // private int visibility; // End of property values @@ -120,6 +122,7 @@ public class TableColumn extends TableFObj { if (!this.implicitColumn) { this.pList = pList; } + isHeader = (pList.get(Constants.PR_X_HEADER_COLUMN).getEnum() == Constants.EN_TRUE); } /** {@inheritDoc} */ @@ -263,4 +266,13 @@ public class TableColumn extends TableFObj { this.pList = null; } + /** + * Returns {@code true} if this column is made of header cells. + * + * @return {@code true} if cells in this column are like TH cells in HTML + */ + public boolean isHeader() { + return isHeader; + } + } diff --git a/src/java/org/apache/fop/fo/flow/table/TablePart.java b/src/java/org/apache/fop/fo/flow/table/TablePart.java index 3ab92cc94..032340681 100644 --- a/src/java/org/apache/fop/fo/flow/table/TablePart.java +++ b/src/java/org/apache/fop/fo/flow/table/TablePart.java @@ -169,6 +169,8 @@ public abstract class TablePart extends TableCellContainer { getUserAgent().getEventBroadcaster()); eventProducer.noMixRowsAndCells(this, getName(), getLocator()); } + } else if (localName.equals("retrieve-table-marker")) { + notSupportedChildError(loc, nsURI, localName); } else { invalidChildError(loc, nsURI, localName); } diff --git a/src/java/org/apache/fop/fo/pagination/Flow.java b/src/java/org/apache/fop/fo/pagination/Flow.java index 981485e32..45c8f7804 100644 --- a/src/java/org/apache/fop/fo/pagination/Flow.java +++ b/src/java/org/apache/fop/fo/pagination/Flow.java @@ -36,6 +36,9 @@ import org.apache.fop.fo.properties.CommonAccessibilityHolder; */ public class Flow extends FObj implements CommonAccessibilityHolder { + /** The "flow-name" property name. */ + public static final String FLOW_NAME = "flow-name"; + private String flowName; private CommonAccessibility commonAccessibility; @@ -61,7 +64,7 @@ public class Flow extends FObj implements CommonAccessibilityHolder { /** {@inheritDoc} */ protected void startOfNode() throws FOPException { if (flowName == null || flowName.equals("")) { - missingPropertyError("flow-name"); + missingPropertyError(FLOW_NAME); } // according to communication from Paul Grosso (XSL-List, diff --git a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java index 533b113d2..8b109dd0e 100644 --- a/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java +++ b/src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java @@ -217,5 +217,24 @@ public class LayoutMasterSet extends FObj { public int getNameId() { return FO_LAYOUT_MASTER_SET; } + + /** + * Returns the default name of the region to which the flow or static-content having + * the given flow-name is assigned. + * + * @param flowName the value of the flow-name property + * @return the default region name ("xsl-region-body", "xsl-region-before", etc.) + */ + public String getDefaultRegionNameFor(String flowName) { + for (SimplePageMaster spm : simplePageMasters.values()) { + for (Region region : spm.getRegions().values()) { + if (region.getRegionName().equals(flowName)) { + return region.getDefaultRegionName(); + } + } + } + assert flowName.equals("xsl-before-float-separator") || flowName.equals("xsl-footnote-separator"); + return flowName; + } } diff --git a/src/java/org/apache/fop/fo/pagination/StaticContent.java b/src/java/org/apache/fop/fo/pagination/StaticContent.java index e70c80c5d..412cdbcca 100644 --- a/src/java/org/apache/fop/fo/pagination/StaticContent.java +++ b/src/java/org/apache/fop/fo/pagination/StaticContent.java @@ -42,7 +42,7 @@ public class StaticContent extends Flow { /** {@inheritDoc} */ protected void startOfNode() throws FOPException { if (getFlowName() == null || getFlowName().equals("")) { - missingPropertyError("flow-name"); + missingPropertyError(FLOW_NAME); } getFOEventHandler().startStatic(this); } diff --git a/src/java/org/apache/fop/fonts/CIDFont.java b/src/java/org/apache/fop/fonts/CIDFont.java index 82213dd65..dc398263e 100644 --- a/src/java/org/apache/fop/fonts/CIDFont.java +++ b/src/java/org/apache/fop/fonts/CIDFont.java @@ -29,7 +29,7 @@ import org.apache.fop.apps.io.InternalResourceResolver; public abstract class CIDFont extends CustomFont { /** Contains the character widths for all characters in the font */ - protected int[] width = null; + protected int[] width; /** * @param resourceResolver the URI resolver for controlling file access @@ -69,7 +69,7 @@ public abstract class CIDFont extends CustomFont { * Returns the subset information for this font. * @return the subset information */ - public abstract CIDSubset getCIDSubset(); + public abstract CIDSet getCIDSet(); // ---- Optional ---- /** diff --git a/src/java/org/apache/fop/fonts/CIDFull.java b/src/java/org/apache/fop/fonts/CIDFull.java new file mode 100644 index 000000000..ee062a2bb --- /dev/null +++ b/src/java/org/apache/fop/fonts/CIDFull.java @@ -0,0 +1,113 @@ +/* + * 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.fonts; + +import java.util.BitSet; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.fop.util.CharUtilities; + +/** + * Provides methods to get font information. + * Naming: + * glyph index: original index of the glyph in the non-subset font (!= unicode index) + * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset + * fonts, this is the same as the glyph index. + * Unicode index: The Unicode codepoint of a character. + * Glyph name: the Adobe glyph name (as found in Glyphs.java) + */ +public class CIDFull implements CIDSet { + + private BitSet glyphIndices; + private final MultiByteFont font; + + public CIDFull(MultiByteFont mbf) { + font = mbf; + } + + private void initGlyphIndices() { + // this cannot be called in the constructor since the font is not ready... + if (glyphIndices == null) { + glyphIndices = font.getGlyphIndices(); + } + } + + /** {@inheritDoc} */ + public int getOriginalGlyphIndex(int index) { + return index; + } + + /** {@inheritDoc} */ + public char getUnicode(int index) { + initGlyphIndices(); + if (glyphIndices.get(index)) { + return (char) index; + } else { + return CharUtilities.NOT_A_CHARACTER; + } + } + + /** {@inheritDoc} */ + public int mapChar(int glyphIndex, char unicode) { + return (char) glyphIndex; + } + + /** {@inheritDoc} */ + public Map<Integer, Integer> getGlyphs() { + // this is never really called for full embedded fonts but the equivalent map would be the identity + initGlyphIndices(); + Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>(); + int nextBitSet = 0; + for (int j = 0; j < glyphIndices.cardinality(); j++) { + nextBitSet = glyphIndices.nextSetBit(nextBitSet); + glyphs.put(Integer.valueOf(nextBitSet), Integer.valueOf(nextBitSet)); + nextBitSet++; + } + return Collections.unmodifiableMap(glyphs); + } + + /** {@inheritDoc} */ + public char[] getChars() { + return font.getChars(); + } + + /** {@inheritDoc} */ + public int getNumberOfGlyphs() { + initGlyphIndices(); + // note: the real number of glyphs is given by the cardinality() method (not the length()) but since + // we will pad gaps in the indices with zeros we really want the length() here. this method is only + // called when embedding a font in PostScript and this will be the value of the CIDCount entry + return glyphIndices.length(); + } + + /** {@inheritDoc} */ + public BitSet getGlyphIndices() { + initGlyphIndices(); + return glyphIndices; + } + + /** {@inheritDoc} */ + public int[] getWidths() { + return font.getWidths(); + } + +} diff --git a/src/java/org/apache/fop/fonts/CIDSet.java b/src/java/org/apache/fop/fonts/CIDSet.java new file mode 100644 index 000000000..7530ea6e7 --- /dev/null +++ b/src/java/org/apache/fop/fonts/CIDSet.java @@ -0,0 +1,90 @@ +/* + * 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.fonts; + +import java.util.BitSet; +import java.util.Map; + +/** + * Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font. + */ +public interface CIDSet { + + /** + * Returns the original index of the glyph inside the (non-subset) font's glyph list. This + * index can be used to access the character width information, for example. + * @param index the subset index (character selector) to access the glyph + * @return the original index (or -1 if no glyph index is available for the subset index) + */ + int getOriginalGlyphIndex(int index); + + /** + * Returns the Unicode value for a subset index (character selector). If there's no such + * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. + * @param index the subset index (character selector) + * @return the Unicode value or "NOT A CHARACTER" (0xFFFF) + */ + char getUnicode(int index); + + /** + * Maps a character to a character selector for a font subset. If the character isn't in the + * subset, yet, it is added and a new character selector returned. Otherwise, the already + * allocated character selector is returned from the existing map/subset. + * @param glyphIndex the glyph index of the character + * @param unicode the Unicode index of the character + * @return the subset index + */ + int mapChar(int glyphIndex, char unicode); + + /** + * Returns an unmodifiable Map of the font subset. It maps from glyph index to + * character selector (i.e. the subset index in this case). + * @return Map Map<Integer, Integer> of the font subset + */ + Map<Integer, Integer> getGlyphs(); + + /** + * Returns a char array containing all Unicode characters that are in the subset. + * @return a char array with all used Unicode characters + */ + char[] getChars(); + + /** + * Returns the number of glyphs in the subset. + * @return the number of glyphs in the subset + */ + int getNumberOfGlyphs(); + + /** + * Returns a BitSet with bits set for each available glyph index in the subset. + * @return a BitSet indicating available glyph indices + */ + BitSet getGlyphIndices(); + + /** + * Return the array of widths. + * <p> + * This is used to get an array for inserting in an output format. + * It should not be used for lookup. + * @return an array of widths + */ + int[] getWidths(); + +} diff --git a/src/java/org/apache/fop/fonts/CIDSubset.java b/src/java/org/apache/fop/fonts/CIDSubset.java index 372a638d1..f442c13ed 100644 --- a/src/java/org/apache/fop/fonts/CIDSubset.java +++ b/src/java/org/apache/fop/fonts/CIDSubset.java @@ -26,18 +26,16 @@ import java.util.Map; import org.apache.fop.util.CharUtilities; -//Naming: -//glyph index: original index of the glyph in the non-subset font (!= unicode index) -//character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For -// non-subset fonts, this is the same as the glyph index. -//Unicode index: The Unicode codepoint of a character. -//Glyph name: the Adobe glyph name (as found in Glyphs.java) - /** - * Keeps track of the glyphs used in a document. This information is later used to build - * a subset of a font. + * Provides methods to get font information. + * Naming: + * glyph index: original index of the glyph in the non-subset font (!= unicode index) + * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset + * fonts, this is the same as the glyph index. + * Unicode index: The Unicode codepoint of a character. + * Glyph name: the Adobe glyph name (as found in Glyphs.java) */ -public class CIDSubset { +public class CIDSubset implements CIDSet { /** * usedGlyphs contains orginal, new glyph index (glyph index -> char selector) @@ -48,51 +46,36 @@ public class CIDSubset { * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index) */ private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>(); - private int usedGlyphsCount = 0; + private int usedGlyphsCount; /** * usedCharsIndex contains new glyph, original char (char selector -> Unicode) */ private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>(); - /** - * Default constructor. - */ - public CIDSubset() { - } + private final MultiByteFont font; - /** - * Adds the first glyph which is reserved for .notdef for all CID subsets. - */ - public void setupFirstGlyph() { - usedGlyphs.put(Integer.valueOf(0), Integer.valueOf(0)); - usedGlyphsIndex.put(Integer.valueOf(0), Integer.valueOf(0)); + public CIDSubset(MultiByteFont mbf) { + font = mbf; + // The zeroth value is reserved for .notdef + usedGlyphs.put(0, 0); + usedGlyphsIndex.put(0, 0); usedGlyphsCount++; } - /** - * Returns the original index of the glyph inside the (non-subset) font's glyph list. This - * index can be used to access the character width information, for example. - * @param subsetIndex the subset index (character selector) to access the glyph - * @return the original index (or -1 if no glyph index is available for the subset index) - */ - public int getGlyphIndexForSubsetIndex(int subsetIndex) { - Integer glyphIndex = usedGlyphsIndex.get(Integer.valueOf(subsetIndex)); + /** {@inheritDoc} */ + public int getOriginalGlyphIndex(int index) { + Integer glyphIndex = usedGlyphsIndex.get(index); if (glyphIndex != null) { - return glyphIndex.intValue(); + return glyphIndex; } else { return -1; } } - /** - * Returns the Unicode value for a subset index (character selector). If there's no such - * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. - * @param subsetIndex the subset index (character selector) - * @return the Unicode value or "NOT A CHARACTER" (0xFFFF) - */ - public char getUnicodeForSubsetIndex(int subsetIndex) { - Character mapValue = usedCharsIndex.get(Integer.valueOf(subsetIndex)); + /** {@inheritDoc} */ + public char getUnicode(int index) { + Character mapValue = usedCharsIndex.get(index); if (mapValue != null) { return mapValue.charValue(); } else { @@ -100,72 +83,60 @@ public class CIDSubset { } } - /** - * Maps a character to a character selector for a font subset. If the character isn't in the - * subset, yet, it is added and a new character selector returned. Otherwise, the already - * allocated character selector is returned from the existing map/subset. - * @param glyphIndex the glyph index of the character - * @param unicode the Unicode index of the character - * @return the subset index - */ - public int mapSubsetChar(int glyphIndex, char unicode) { + /** {@inheritDoc} */ + public int mapChar(int glyphIndex, char unicode) { // Reencode to a new subset font or get the reencoded value // IOW, accumulate the accessed characters and build a character map for them - Integer subsetCharSelector = usedGlyphs.get(Integer.valueOf(glyphIndex)); + Integer subsetCharSelector = usedGlyphs.get(glyphIndex); if (subsetCharSelector == null) { int selector = usedGlyphsCount; - usedGlyphs.put(Integer.valueOf(glyphIndex), - Integer.valueOf(selector)); - usedGlyphsIndex.put(Integer.valueOf(selector), - Integer.valueOf(glyphIndex)); - usedCharsIndex.put(Integer.valueOf(selector), - Character.valueOf(unicode)); + usedGlyphs.put(glyphIndex, selector); + usedGlyphsIndex.put(selector, glyphIndex); + usedCharsIndex.put(selector, unicode); usedGlyphsCount++; return selector; } else { - return subsetCharSelector.intValue(); + return subsetCharSelector; } } - /** - * Returns an unmodifiable Map of the font subset. It maps from glyph index to - * character selector (i.e. the subset index in this case). - * @return Map Map<Integer, Integer> of the font subset - */ - public Map<Integer, Integer> getSubsetGlyphs() { + /** {@inheritDoc} */ + public Map<Integer, Integer> getGlyphs() { return Collections.unmodifiableMap(this.usedGlyphs); } - /** - * Returns a char array containing all Unicode characters that are in the subset. - * @return a char array with all used Unicode characters - */ - public char[] getSubsetChars() { + /** {@inheritDoc} */ + public char[] getChars() { char[] charArray = new char[usedGlyphsCount]; for (int i = 0; i < usedGlyphsCount; i++) { - charArray[i] = getUnicodeForSubsetIndex(i); + charArray[i] = getUnicode(i); } return charArray; } - /** - * Returns the number of glyphs in the subset. - * @return the number of glyphs in the subset - */ - public int getSubsetSize() { + /** {@inheritDoc} */ + public int getNumberOfGlyphs() { return this.usedGlyphsCount; } - /** - * Returns a BitSet with bits set for each available glyph index in the subset. - * @return a BitSet indicating available glyph indices - */ - public BitSet getGlyphIndexBitSet() { + /** {@inheritDoc} */ + public BitSet getGlyphIndices() { BitSet bitset = new BitSet(); for (Integer cid : usedGlyphs.keySet()) { - bitset.set(cid.intValue()); + bitset.set(cid); } return bitset; } + /** {@inheritDoc} */ + public int[] getWidths() { + int[] widths = font.getWidths(); + int[] tmpWidth = new int[getNumberOfGlyphs()]; + for (int i = 0, c = getNumberOfGlyphs(); i < c; i++) { + int nwx = Math.max(0, getOriginalGlyphIndex(i)); + tmpWidth[i] = widths[nwx]; + } + return tmpWidth; + } + } diff --git a/src/java/org/apache/fop/fonts/FontCacheManager.java b/src/java/org/apache/fop/fonts/FontCacheManager.java index fb0a0322b..a4acd43a4 100644 --- a/src/java/org/apache/fop/fonts/FontCacheManager.java +++ b/src/java/org/apache/fop/fonts/FontCacheManager.java @@ -19,7 +19,7 @@ package org.apache.fop.fonts; -import java.io.File; +import java.net.URI; import org.apache.fop.apps.FOPException; @@ -30,24 +30,26 @@ import org.apache.fop.apps.FOPException; public interface FontCacheManager { /** + * Sets the font cache file given the URI pointing to the file. + * @param fontCacheURI the font cache URI + */ + void setCacheFile(URI fontCacheURI); + + /** * Loads the font cache into memory from the given file. - * @param file the serialized font cache * @return the de-serialized font cache */ - FontCache load(File file); + FontCache load(); /** * Serializes the font cache to file. - * @param file the file to serialize the font cache to * @throws FOPException if an error occurs serializing the font cache */ - void save(File file) throws FOPException; + void save() throws FOPException; /** * Deletes the font cache from the file-system. - * @param file delete the serialized font cache * @throws FOPException if an error occurs deleting the font cache */ - void delete(File file) throws FOPException; - + void delete() throws FOPException; } diff --git a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java index 0236effce..c1d736b0d 100644 --- a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java +++ b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java @@ -20,6 +20,7 @@ package org.apache.fop.fonts; import java.io.File; +import java.net.URI; import org.apache.fop.apps.FOPException; @@ -50,11 +51,14 @@ public final class FontCacheManagerFactory { private static final class FontCacheManagerImpl implements FontCacheManager { + /** Provides a font cache file path **/ + private File cacheFile; + private FontCache fontCache; - public FontCache load(File cacheFile) { + public FontCache load() { if (fontCache == null) { - fontCache = FontCache.loadFrom(cacheFile); + fontCache = FontCache.loadFrom(getCacheFile(false)); if (fontCache == null) { fontCache = new FontCache(); } @@ -62,31 +66,46 @@ public final class FontCacheManagerFactory { return fontCache; } - public void save(File cacheFile) throws FOPException { + public void save() throws FOPException { if (fontCache != null && fontCache.hasChanged()) { - fontCache.saveTo(cacheFile); + fontCache.saveTo(getCacheFile(true)); } } - public void delete(File cacheFile) throws FOPException { - if (!cacheFile.delete()) { + public void delete() throws FOPException { + if (!getCacheFile(true).delete()) { throw new FOPException("Failed to flush the font cache file '" + cacheFile + "'."); } } + + private File getCacheFile(boolean forWriting) { + if (cacheFile != null) { + return cacheFile; + } + return FontCache.getDefaultCacheFile(forWriting); + } + + public void setCacheFile(URI fontCacheURI) { + cacheFile = new File(fontCacheURI); + } } private static final class DisabledFontCacheManager implements FontCacheManager { - public FontCache load(File cacheFile) { + public FontCache load() { return null; } - public void save(File cacheFile) throws FOPException { + public void save() throws FOPException { // nop } - public void delete(File cacheFile) throws FOPException { + public void delete() throws FOPException { throw new FOPException("Font Cache disabled"); } + + public void setCacheFile(URI fontCacheURI) { + // nop + } } } diff --git a/src/java/org/apache/fop/fonts/FontManager.java b/src/java/org/apache/fop/fonts/FontManager.java index bff001f73..3df8a9078 100644 --- a/src/java/org/apache/fop/fonts/FontManager.java +++ b/src/java/org/apache/fop/fonts/FontManager.java @@ -19,7 +19,7 @@ package org.apache.fop.fonts; -import java.io.File; +import java.net.URI; import java.util.List; import org.apache.fop.apps.FOPException; @@ -52,9 +52,6 @@ public class FontManager { /** FontTriplet matcher for fonts that shall be referenced rather than embedded. */ private FontTriplet.Matcher referencedFontsMatcher; - /** Provides a font cache file path **/ - private File cacheFile; - /** * Main constructor * @@ -115,25 +112,10 @@ public class FontManager { /** * Sets the font cache file - * @param cacheFile the font cache file - */ - public void setCacheFile(File cacheFile) { - this.cacheFile = cacheFile; - } - - /** - * Returns the font cache file - * @return the font cache file + * @param cacheFileURI the URI of the font cache file */ - public File getCacheFile() { - return getCacheFile(false); - } - - private File getCacheFile(boolean writable) { - if (cacheFile != null) { - return cacheFile; - } - return FontCache.getDefaultCacheFile(writable); + public void setCacheFile(URI cacheFileURI) { + fontCacheManager.setCacheFile(resourceResolver.resolveFromBase(cacheFileURI)); } /** @@ -148,7 +130,7 @@ public class FontManager { * @return the font cache */ public FontCache getFontCache() { - return fontCacheManager.load(getCacheFile()); + return fontCacheManager.load(); } /** @@ -157,7 +139,7 @@ public class FontManager { * @throws FOPException fop exception */ public void saveCache() throws FOPException { - fontCacheManager.save(getCacheFile()); + fontCacheManager.save(); } /** @@ -165,7 +147,7 @@ public class FontManager { * @throws FOPException if an error was thrown while deleting the cache */ public void deleteCache() throws FOPException { - fontCacheManager.delete(getCacheFile(true)); + fontCacheManager.delete(); } /** diff --git a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java index c4fe19444..fc2ce06a6 100644 --- a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java +++ b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java @@ -19,7 +19,6 @@ package org.apache.fop.fonts; -import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.util.List; @@ -30,9 +29,10 @@ import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.xmlgraphics.io.ResourceResolver; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.apps.io.ResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.fonts.substitute.FontSubstitutions; import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator; @@ -72,6 +72,19 @@ public class FontManagerConfigurator { * @throws FOPException if an exception occurs while processing the configuration */ public void configure(FontManager fontManager, boolean strict) throws FOPException { + if (cfg.getChild("font-base", false) != null) { + try { + URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base") + .getValue(null)); + fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( + defaultBaseUri.resolve(fontBase), resourceResolver)); + } catch (URISyntaxException use) { + LogUtil.handleException(log, use, true); + } + } else { + fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( + defaultBaseUri, resourceResolver)); + } // caching (fonts) if (cfg.getChild("use-cache", false) != null) { try { @@ -79,27 +92,14 @@ public class FontManagerConfigurator { fontManager.disableFontCache(); } else { if (cfg.getChild("cache-file", false) != null) { - fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue())); + + fontManager.setCacheFile(URI.create(cfg.getChild("cache-file").getValue())); } } } catch (ConfigurationException mfue) { LogUtil.handleException(log, mfue, true); } } - if (cfg.getChild("font-base", false) != null) { - try { - URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base").getValue( - null)); - fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( - defaultBaseUri.resolve(fontBase), resourceResolver)); - } catch (URISyntaxException use) { - LogUtil.handleException(log, use, true); - } - } else { - fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( - defaultBaseUri, resourceResolver)); - } - // [GA] permit configuration control over base14 kerning; without this, // there is no way for a user to enable base14 kerning other than by // programmatic API; diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java index 68c5c7177..0448c317e 100644 --- a/src/java/org/apache/fop/fonts/FontReader.java +++ b/src/java/org/apache/fop/fonts/FontReader.java @@ -157,7 +157,7 @@ public class FontReader extends DefaultHandler { throws SAXException { if (localName.equals("font-metrics")) { if ("TYPE0".equals(attributes.getValue("type"))) { - multiFont = new MultiByteFont(resourceResolver); + multiFont = new MultiByteFont(resourceResolver, EmbeddingMode.AUTO); returnFont = multiFont; isCID = true; TTFReader.checkMetricsVersion(attributes); diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index 4c42387f2..fef42f74c 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -438,6 +438,9 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable, */ public boolean isSubsetEmbedded() { load(true); + if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) { + return false; + } return realFont.isMultiByte(); } diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java index a460140cb..da454c504 100644 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ b/src/java/org/apache/fop/fonts/MultiByteFont.java @@ -21,6 +21,7 @@ package org.apache.fop.fonts; import java.nio.CharBuffer; import java.nio.IntBuffer; +import java.util.BitSet; import java.util.Map; import org.apache.commons.logging.Log; @@ -44,13 +45,13 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl private static final Log log // CSOK: ConstantNameCheck = LogFactory.getLog(MultiByteFont.class); - private String ttcName = null; + private String ttcName; private String encoding = "Identity-H"; - private int defaultWidth = 0; + private int defaultWidth; private CIDFontType cidType = CIDFontType.CIDTYPE2; - private CIDSubset subset = new CIDSubset(); + private final CIDSet cidSet; /* advanced typographic support */ private GlyphDefinitionTable gdef; @@ -69,10 +70,15 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl /** * Default constructor */ - public MultiByteFont(InternalResourceResolver resourceResolver) { + public MultiByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) { super(resourceResolver); - subset.setupFirstGlyph(); setFontType(FontType.TYPE0); + setEmbeddingMode(embeddingMode); + if (embeddingMode != EmbeddingMode.FULL) { + cidSet = new CIDSubset(this); + } else { + cidSet = new CIDFull(this); + } } /** {@inheritDoc} */ @@ -129,13 +135,16 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl } public boolean isSubsetEmbedded() { + if (getEmbeddingMode() == EmbeddingMode.FULL) { + return false; + } return true; } /** {@inheritDoc} */ @Override - public CIDSubset getCIDSubset() { - return this.subset; + public CIDSet getCIDSet() { + return this.cidSet; } /** {@inheritDoc} */ @@ -147,7 +156,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl /** {@inheritDoc} */ public int getWidth(int i, int size) { if (isEmbeddable()) { - int glyphIndex = subset.getGlyphIndexForSubsetIndex(i); + int glyphIndex = cidSet.getOriginalGlyphIndex(i); return size * width[glyphIndex]; } else { return size * width[i]; @@ -283,9 +292,39 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl glyphIndex = findGlyphIndex(Typeface.NOT_FOUND); } if (isEmbeddable()) { - glyphIndex = subset.mapSubsetChar(glyphIndex, c); + glyphIndex = cidSet.mapChar(glyphIndex, c); } - return (char)glyphIndex; + return (char) glyphIndex; + } + + protected BitSet getGlyphIndices() { + BitSet bitset = new BitSet(); + bitset.set(0); + bitset.set(1); + bitset.set(2); + for (int i = 0; i < cmap.length; i++) { + int start = cmap[i].getUnicodeStart(); + int end = cmap[i].getUnicodeEnd(); + int glyphIndex = cmap[i].getGlyphStartIndex(); + while (start++ < end + 1) { + bitset.set(glyphIndex++); + } + } + return bitset; + } + + protected char[] getChars() { + // the width array is set when the font is built + char[] chars = new char[width.length]; + for (int i = 0; i < cmap.length; i++) { + int start = cmap[i].getUnicodeStart(); + int end = cmap[i].getUnicodeEnd(); + int glyphIndex = cmap[i].getGlyphStartIndex(); + while (start < end + 1) { + chars[glyphIndex++] = (char) start++; + } + } + return chars; } /** {@inheritDoc} */ @@ -331,15 +370,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl * @return Map Map of used Glyphs */ public Map<Integer, Integer> getUsedGlyphs() { - return subset.getSubsetGlyphs(); - } - - /** @return an array of the chars used */ - public char[] getCharsUsed() { - if (!isEmbeddable()) { - return null; - } - return subset.getSubsetChars(); + return cidSet.getGlyphs(); } /** diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java index c97b17211..a427fe54e 100644 --- a/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java +++ b/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java @@ -127,7 +127,7 @@ public class TTFFontLoader extends FontLoader { } if (isCid) { - multiFont = new MultiByteFont(resourceResolver); + multiFont = new MultiByteFont(resourceResolver, embeddingMode); returnFont = multiFont; multiFont.setTTCName(ttcFontName); } else { diff --git a/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java b/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java index 022ff462f..3aa340a4a 100644 --- a/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java +++ b/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java @@ -45,6 +45,7 @@ import org.apache.xmlgraphics.image.loader.ImageSize; import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader; import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; import org.apache.xmlgraphics.image.loader.util.ImageUtil; +import org.apache.xmlgraphics.io.XmlSourceUtil; import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.UnitConv; @@ -79,7 +80,7 @@ public class PreloaderSVG extends AbstractImagePreloader { } } if (info != null) { - ImageUtil.closeQuietly(src); //Image is fully read + XmlSourceUtil.closeQuietly(src); //Image is fully read } return info; } @@ -119,7 +120,7 @@ public class PreloaderSVG extends AbstractImagePreloader { DOMSource domSrc = (DOMSource)src; doc = (SVGDocument)domSrc.getNode(); } else { - in = new UnclosableInputStream(ImageUtil.needInputStream(src)); + in = new UnclosableInputStream(XmlSourceUtil.needInputStream(src)); int length = in.available(); in.mark(length + 1); SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory( diff --git a/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java b/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java index 3bef0f41d..43341cbe6 100644 --- a/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java +++ b/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java @@ -38,6 +38,7 @@ import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageSize; import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader; import org.apache.xmlgraphics.image.loader.util.ImageUtil; +import org.apache.xmlgraphics.io.XmlSourceUtil; import org.apache.fop.util.UnclosableInputStream; @@ -69,7 +70,7 @@ public class PreloaderWMF extends AbstractImagePreloader { } } if (info != null) { - ImageUtil.closeQuietly(src); //Image is fully read + XmlSourceUtil.closeQuietly(src); //Image is fully read } return info; } @@ -88,7 +89,7 @@ public class PreloaderWMF extends AbstractImagePreloader { ImageContext context) { // parse document and get the size attributes of the svg element - InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); + InputStream in = new UnclosableInputStream(XmlSourceUtil.needInputStream(src)); try { in.mark(4 + 1); diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java index 8c213d7d5..5d7cc0b64 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java @@ -273,4 +273,11 @@ public abstract class AbstractBaseLayoutManager throw new UnsupportedOperationException("Not implemented"); } + public void preserveChildrenAtEndOfLayout() { + + } + + public void recreateChildrenLMs() { + + } } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java index 0089f228f..3d64c436c 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java @@ -37,6 +37,7 @@ import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.RetrieveMarker; +import org.apache.fop.layoutmgr.table.TableLayoutManager; /** * The base class for most LayoutManagers. @@ -67,6 +68,8 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im private int lastGeneratedPosition = -1; private int smallestPosNumberChecked = Integer.MAX_VALUE; + private boolean preserveChildrenAtEndOfLayout; + /** * Abstract layout manager. */ @@ -370,19 +373,20 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im } /** - * Registers the FO's markers on the current PageViewport + * Registers the FO's markers on the current PageViewport, and if applicable on the parent TableLM. * * @param isStarting boolean indicating whether the markers qualify as 'starting' * @param isFirst boolean indicating whether the markers qualify as 'first' * @param isLast boolean indicating whether the markers qualify as 'last' */ - protected void addMarkersToPage(boolean isStarting, boolean isFirst, boolean isLast) { + protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) { if (this.markers != null) { - getCurrentPV().addMarkers( + getCurrentPV().registerMarkers( this.markers, isStarting, isFirst, isLast); + possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); } } @@ -419,11 +423,12 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im notifyEndOfLayout(); - /* References to the child LMs are no longer needed - */ - childLMs = null; - curChildLM = null; - childLMiter = null; + if (!preserveChildrenAtEndOfLayout) { + // References to the child LMs are no longer needed + childLMs = null; + curChildLM = null; + childLMiter = null; + } /* markers that qualify have been transferred to the page */ @@ -438,13 +443,21 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im || lm instanceof PageSequenceLayoutManager)) { lm = lm.getParent(); } - if (lm instanceof FlowLayoutManager) { + if (lm instanceof FlowLayoutManager && !preserveChildrenAtEndOfLayout) { fobj.clearChildNodes(); fobjIter = null; } } } + /* + * Preserves the children LMs at the end of layout. This is necessary if the layout is expected to be + * repeated, as when using retrieve-table-markers. + */ + public void preserveChildrenAtEndOfLayout() { + preserveChildrenAtEndOfLayout = true; + } + /** {@inheritDoc} */ @Override public String toString() { @@ -467,4 +480,34 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im lastGeneratedPosition = -1; } + public void recreateChildrenLMs() { + childLMs = new ArrayList(); + isFinished = false; + if (fobj == null) { + return; + } + fobjIter = fobj.getChildNodes(); + int position = 0; + while (createNextChildLMs(position++)) { + // + } + childLMiter = new LMiter(this); + for (LMiter iter = new LMiter(this); iter.hasNext();) { + AbstractBaseLayoutManager alm = (AbstractBaseLayoutManager) iter.next(); + alm.initialize(); + alm.recreateChildrenLMs(); + alm.preserveChildrenAtEndOfLayout(); + } + curChildLM = getChildLM(); + } + + protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting, + boolean isFirst, boolean isLast) { + LayoutManager lm = this.parentLayoutManager; + if (lm instanceof FlowLayoutManager || lm instanceof PageSequenceLayoutManager + || !(lm instanceof AbstractLayoutManager)) { + return; + } + ((AbstractLayoutManager) lm).possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); + } } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java index f36cde158..edfb389ed 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java @@ -226,15 +226,14 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa public RetrieveMarker resolveRetrieveMarker(RetrieveMarker rm) { AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel(); String name = rm.getRetrieveClassName(); - int pos = rm.getRetrievePosition(); int boundary = rm.getRetrieveBoundary(); // get marker from the current markers on area tree - Marker mark = (Marker)getCurrentPV().getMarker(name, pos); + Marker mark = getCurrentPV().resolveMarker(rm); if (mark == null && boundary != EN_PAGE) { // go back over pages until mark found // if document boundary then keep going - boolean doc = boundary == EN_DOCUMENT; + boolean doc = (boundary == EN_DOCUMENT); int seq = areaTreeModel.getPageSequenceCount(); int page = areaTreeModel.getPageCount(seq) - 1; while (page < 0 && doc && seq > 1) { @@ -243,7 +242,11 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa } while (page >= 0) { PageViewport pv = areaTreeModel.getPage(seq, page); - mark = (Marker)pv.getMarker(name, Constants.EN_LEWP); + int originalPosition = rm.getPosition(); + rm.changePositionTo(Constants.EN_LEWP); + mark = (Marker) pv.resolveMarker(rm); + // this is probably not necessary since the RM will not be used again, but to be safe... + rm.changePositionTo(originalPosition); if (mark != null) { break; } diff --git a/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java b/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java index c80982cce..0ed6cb69b 100644 --- a/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java +++ b/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java @@ -87,7 +87,7 @@ public final class AreaAdditionUtil { } if (bslm != null) { - bslm.addMarkersToPage( + bslm.registerMarkers( true, bslm.isFirst(firstPos), bslm.isLast(lastPos)); @@ -114,11 +114,10 @@ public final class AreaAdditionUtil { } if (bslm != null) { - bslm.addMarkersToPage( + bslm.registerMarkers( false, bslm.isFirst(firstPos), bslm.isLast(lastPos)); - bslm.checkEndOfLayout(lastPos); } diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java index 920589657..d20215151 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java @@ -806,7 +806,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl addId(); - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); if (bcpos == null) { // the Positions in positionList were inside the elements @@ -826,7 +826,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl bcpos.getBreaker().addContainedAreas(layoutContext); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(), effSpaceBefore, effSpaceAfter); diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java index a99b45620..f62d7f946 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -312,7 +312,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co addId(); - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); // the Positions in positionList were inside the elements // created by the LineLM @@ -327,7 +327,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co childLM.addAreas(childPosIter, lc); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), effSpaceBefore, effSpaceAfter); diff --git a/src/java/org/apache/fop/layoutmgr/BreakElement.java b/src/java/org/apache/fop/layoutmgr/BreakElement.java index 77e7f140b..f3f173d8c 100644 --- a/src/java/org/apache/fop/layoutmgr/BreakElement.java +++ b/src/java/org/apache/fop/layoutmgr/BreakElement.java @@ -21,6 +21,8 @@ package org.apache.fop.layoutmgr; import java.util.List; +import org.apache.fop.fo.Constants; + /** * This class represents an unresolved break possibility. */ @@ -28,7 +30,7 @@ public class BreakElement extends UnresolvedListElement { private int penaltyWidth; private int penaltyValue; - private int breakClass = -1; + private int breakClass; private List pendingBeforeMarks; private List pendingAfterMarks; @@ -39,7 +41,7 @@ public class BreakElement extends UnresolvedListElement { * @param context the layout context which contains the pending conditional elements */ public BreakElement(Position position, int penaltyValue, LayoutContext context) { - this(position, penaltyValue, -1, context); + this(position, penaltyValue, Constants.EN_AUTO, context); } /** @@ -80,7 +82,7 @@ public class BreakElement extends UnresolvedListElement { super(position); this.penaltyWidth = penaltyWidth; this.penaltyValue = penaltyValue; - this.breakClass = breakClass; + setBreakClass(breakClass); this.pendingBeforeMarks = context.getPendingBeforeMarks(); this.pendingAfterMarks = context.getPendingAfterMarks(); } @@ -142,13 +144,24 @@ public class BreakElement extends UnresolvedListElement { * * @param breakClass one of * {@link org.apache.fop.fo.Constants#EN_AUTO}, + * {@link org.apache.fop.fo.Constants#EN_LINE}, * {@link org.apache.fop.fo.Constants#EN_COLUMN}, * {@link org.apache.fop.fo.Constants#EN_PAGE}, * {@link org.apache.fop.fo.Constants#EN_EVEN_PAGE}, * {@link org.apache.fop.fo.Constants#EN_ODD_PAGE}. */ public void setBreakClass(int breakClass) { - this.breakClass = breakClass; + switch (breakClass) { + case Constants.EN_AUTO: + case Constants.EN_LINE: + case Constants.EN_COLUMN: + case Constants.EN_PAGE: + case Constants.EN_EVEN_PAGE: + case Constants.EN_ODD_PAGE: + this.breakClass = breakClass; + break; + default: throw new IllegalArgumentException("Illegal value for break class: " + breakClass); + } } /** @return the pending border and padding elements at the before edge */ diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java index 76a1cb9e4..5f4aa5725 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java @@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.FOElementMapping; import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FONode.FONodeIterator; import org.apache.fop.fo.FOText; import org.apache.fop.fo.FObjMixed; import org.apache.fop.fo.extensions.ExternalDocument; @@ -117,7 +118,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker { registerMaker(Block.class, new BlockLayoutManagerMaker()); registerMaker(Leader.class, new LeaderLayoutManagerMaker()); registerMaker(RetrieveMarker.class, new RetrieveMarkerLayoutManagerMaker()); - registerMaker(RetrieveTableMarker.class, new Maker()); + registerMaker(RetrieveTableMarker.class, new RetrieveTableMarkerLayoutManagerMaker()); registerMaker(Character.class, new CharacterLayoutManagerMaker()); registerMaker(ExternalGraphic.class, new ExternalGraphicLayoutManagerMaker()); @@ -407,6 +408,24 @@ public class LayoutManagerMapping implements LayoutManagerMaker { } } + public class RetrieveTableMarkerLayoutManagerMaker extends Maker { + public void make(FONode node, List lms) { + FONodeIterator baseIter = node.getChildNodes(); + if (baseIter == null) { + // this happens when the retrieve-table-marker cannot be resolved yet + RetrieveTableMarker rtm = (RetrieveTableMarker) node; + RetrieveTableMarkerLayoutManager rtmlm = new RetrieveTableMarkerLayoutManager(rtm); + lms.add(rtmlm); + return; + } + while (baseIter.hasNext()) { + // this happens when the retrieve-table-marker has been resolved + FONode child = (FONode) baseIter.next(); + makeLayoutManagers(child, lms); + } + } + } + /** a layout manager maker */ public class WrapperLayoutManagerMaker extends Maker { /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/layoutmgr/LocalBreaker.java b/src/java/org/apache/fop/layoutmgr/LocalBreaker.java new file mode 100644 index 000000000..bb08446cc --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/LocalBreaker.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.layoutmgr; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.fop.fo.FObj; +import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; +import org.apache.fop.layoutmgr.inline.TextLayoutManager; + +public abstract class LocalBreaker extends AbstractBreaker { + protected BlockStackingLayoutManager lm; + private int displayAlign; + private int ipd; + private int overflow = 0; + + public LocalBreaker(BlockStackingLayoutManager lm, int ipd, int displayAlign) { + this.lm = lm; + this.ipd = ipd; + this.displayAlign = displayAlign; + } + + /** {@inheritDoc} */ + protected boolean isPartOverflowRecoveryActivated() { + // For side regions, this must be disabled because of wanted overflow. + return false; + } + + public boolean isOverflow() { + return (this.overflow != 0); + } + + public int getOverflowAmount() { + return this.overflow; + } + + /** {@inheritDoc} */ + protected PageBreakingLayoutListener createLayoutListener() { + return new PageBreakingLayoutListener() { + + public void notifyOverflow(int part, int amount, FObj obj) { + if (LocalBreaker.this.overflow == 0) { + LocalBreaker.this.overflow = amount; + } + } + + }; + } + + protected LayoutManager getTopLevelLM() { + return lm; + } + + protected LayoutContext createLayoutContext() { + LayoutContext lc = super.createLayoutContext(); + lc.setRefIPD(ipd); + return lc; + } + + protected List getNextKnuthElements(LayoutContext context, int alignment) { + LayoutManager curLM; // currently active LM + List returnList = new LinkedList(); + + while ((curLM = lm.getChildLM()) != null) { + LayoutContext childLC = LayoutContext.newInstance(); + childLC.setStackLimitBP(context.getStackLimitBP()); + childLC.setRefIPD(context.getRefIPD()); + childLC.setWritingMode(context.getWritingMode()); + + List returnedList = null; + // The following is a HACK! Ignore leading and trailing white space + boolean ignore = curLM instanceof TextLayoutManager; + if (!curLM.isFinished()) { + returnedList = curLM.getNextKnuthElements(childLC, alignment); + } + if (returnedList != null && !ignore) { + lm.wrapPositionElements(returnedList, returnList); + } + } + SpaceResolver.resolveElementList(returnList); + lm.setFinished(true); + return returnList; + } + + protected int getCurrentDisplayAlign() { + return displayAlign; + } + + protected boolean hasMoreContent() { + return !lm.isFinished(); + } + + protected void addAreas(PositionIterator posIter, LayoutContext context) { + AreaAdditionUtil.addAreas(lm, posIter, context); + } + + protected void doPhase3(PageBreakingAlgorithm alg, int partCount, BlockSequence originalList, + BlockSequence effectiveList) { + if (partCount > 1) { + PageBreakPosition pos = (PageBreakPosition) alg.getPageBreaks().getFirst(); + int firstPartLength = ElementListUtils.calcContentLength(effectiveList, + effectiveList.ignoreAtStart, pos.getLeafPos()); + overflow += alg.totalWidth - firstPartLength; + } + // Rendering all parts (not just the first) at once for the case where the parts that + // overflow should be visible. + alg.removeAllPageBreaks(); + // Directly add areas after finding the breaks + this.addAreas(alg, 1, originalList, effectiveList); + } + + protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { + // nop for static content + } + + protected LayoutManager getCurrentChildLM() { + return null; // TODO NYI + } +} diff --git a/src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java new file mode 100644 index 000000000..9d0979a29 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.layoutmgr; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.flow.RetrieveTableMarker; +import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager; +import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager; +import org.apache.fop.layoutmgr.table.TableLayoutManager; + +public class RetrieveTableMarkerLayoutManager extends LeafNodeLayoutManager { + + private static Log log = LogFactory.getLog(RetrieveTableMarkerLayoutManager.class); + + public RetrieveTableMarkerLayoutManager(RetrieveTableMarker node) { + super(node); + } + + /** {@inheritDoc} */ + public List getNextKnuthElements(LayoutContext context, int alignment) { + setFinished(true); + FONode foNode = (FONode) getFObj(); + foNode = getTableLayoutManager().resolveRetrieveTableMarker((RetrieveTableMarker) foNode); + if (foNode != null) { + // resolve the RTM and replace current LM by the resolved target LM + InlineLevelLayoutManager illm = (InlineLevelLayoutManager) getPSLM().getLayoutManagerMaker() + .makeLayoutManager(foNode); + if (illm instanceof RetrieveTableMarkerLayoutManager) { + // happens if the retrieve-marker was empty + return null; + } + illm.setParent(getParent()); + illm.initialize(); + return illm.getNextKnuthElements(context, alignment); + } else { + return null; + } + } + + /** {@inheritDoc} */ + public void addAreas(PositionIterator posIter, LayoutContext context) { + } + + private TableLayoutManager getTableLayoutManager() { + LayoutManager parentLM = getParent(); + while (!(parentLM instanceof TableLayoutManager)) { + parentLM = parentLM.getParent(); + } + TableLayoutManager tlm = (TableLayoutManager) parentLM; + return tlm; + } + +} diff --git a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java index 403daceb3..058b02270 100644 --- a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java @@ -167,125 +167,22 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager { return (StaticContent) fobj; } - private class StaticContentBreaker extends AbstractBreaker { - private StaticContentLayoutManager lm; - private int displayAlign; - private int ipd; - private int overflow = 0; - - public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, - int displayAlign) { - this.lm = lm; - this.ipd = ipd; - this.displayAlign = displayAlign; + private class StaticContentBreaker extends LocalBreaker { + + public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, int displayAlign) { + super(lm, ipd, displayAlign); } /** {@inheritDoc} */ protected void observeElementList(List elementList) { String elementListID = getStaticContentFO().getFlowName(); - String pageSequenceID = ((PageSequence)lm.getParent().getFObj()).getId(); + String pageSequenceID = ((PageSequence) lm.getParent().getFObj()).getId(); if (pageSequenceID != null && pageSequenceID.length() > 0) { elementListID += "-" + pageSequenceID; } ElementListObserver.observe(elementList, "static-content", elementListID); } - /** {@inheritDoc} */ - protected boolean isPartOverflowRecoveryActivated() { - //For side regions, this must be disabled because of wanted overflow. - return false; - } - - public boolean isOverflow() { - return (this.overflow != 0); - } - - public int getOverflowAmount() { - return this.overflow; - } - - /** {@inheritDoc} */ - protected PageBreakingLayoutListener createLayoutListener() { - return new PageBreakingLayoutListener() { - - public void notifyOverflow(int part, int amount, FObj obj) { - if (StaticContentBreaker.this.overflow == 0) { - StaticContentBreaker.this.overflow = amount; - } - } - - }; - } - - protected LayoutManager getTopLevelLM() { - return lm; - } - - protected LayoutContext createLayoutContext() { - LayoutContext lc = super.createLayoutContext(); - lc.setRefIPD(ipd); - return lc; - } - - protected List getNextKnuthElements(LayoutContext context, int alignment) { - LayoutManager curLM; // currently active LM - List returnList = new LinkedList(); - - while ((curLM = getChildLM()) != null) { - LayoutContext childLC = LayoutContext.newInstance(); - childLC.setStackLimitBP(context.getStackLimitBP()); - childLC.setRefIPD(context.getRefIPD()); - childLC.setWritingMode(context.getWritingMode()); - - List returnedList = null; - //The following is a HACK! Ignore leading and trailing white space - boolean ignore = curLM instanceof TextLayoutManager; - if (!curLM.isFinished()) { - returnedList = curLM.getNextKnuthElements(childLC, alignment); - } - if (returnedList != null && !ignore) { - lm.wrapPositionElements(returnedList, returnList); - } - } - SpaceResolver.resolveElementList(returnList); - setFinished(true); - return returnList; - } - - protected int getCurrentDisplayAlign() { - return displayAlign; - } - - protected boolean hasMoreContent() { - return !lm.isFinished(); - } - - protected void addAreas(PositionIterator posIter, LayoutContext context) { - AreaAdditionUtil.addAreas(lm, posIter, context); - } - - protected void doPhase3(PageBreakingAlgorithm alg, int partCount, - BlockSequence originalList, BlockSequence effectiveList) { - if (partCount > 1) { - PageBreakPosition pos = (PageBreakPosition)alg.getPageBreaks().getFirst(); - int firstPartLength = ElementListUtils.calcContentLength(effectiveList, - effectiveList.ignoreAtStart, pos.getLeafPos()); - overflow += alg.totalWidth - firstPartLength; - } - //Rendering all parts (not just the first) at once for the case where the parts that - //overflow should be visible. - alg.removeAllPageBreaks(); - //Directly add areas after finding the breaks - this.addAreas(alg, 1, originalList, effectiveList); - } - - protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { - //nop for static content - } - - protected LayoutManager getCurrentChildLM() { - return null; //TODO NYI - } } /** diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java index 77ac8c4d6..ebf7a9ccb 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java @@ -480,7 +480,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); } - addMarkersToPage( + registerMarkers( true, !areaCreated, lastPos == null || isLast(lastPos)); @@ -542,7 +542,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { setTraits(areaCreated, lastPos == null || !isLast(lastPos)); parentLayoutManager.addChildArea(getCurrentArea()); - addMarkersToPage( + registerMarkers( false, !areaCreated, lastPos == null || isLast(lastPos)); diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java index 00cd427d9..ac3f8f878 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java @@ -649,6 +649,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager log.trace("Restarting line breaking from index " + restartPosition.getIndex()); int parIndex = restartPosition.getLeafPos(); KnuthSequence paragraph = knuthParagraphs.get(parIndex); + if (paragraph instanceof Paragraph) { + ((Paragraph) paragraph).ignoreAtStart = 0; + isFirstInBlock = false; + } paragraph.subList(0, restartPosition.getIndex() + 1).clear(); Iterator<KnuthElement> iter = paragraph.iterator(); while (iter.hasNext() && !iter.next().isBox()) { diff --git a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java index 480934bf3..61d8a891d 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java @@ -171,7 +171,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager } } - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); while ((childLM = childPosIter.getNextChildLM()) != null) { @@ -184,7 +184,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager childLM.addAreas(childPosIter, lc); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); // We are done with this area add the background TraitSetter.addBackground(curBlockArea, diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java index 3204a867e..f017da381 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java @@ -136,7 +136,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp } } - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); while ((childLM = childPosIter.getNextChildLM()) != null) { @@ -149,7 +149,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp childLM.addAreas(childPosIter, lc); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); flush(); diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java index 32aa4c674..083e4ee1b 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java @@ -509,7 +509,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements } } - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); // use the first and the last ListItemPosition to determine the // corresponding indexes in the original labelList and bodyList @@ -563,7 +563,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements } curBlockArea.setBPD(itemBPD); - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); // We are done with this area add the background TraitSetter.addBackground(curBlockArea, diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 955dafabd..6b0ef6ebb 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -303,11 +303,16 @@ class RowPainter { borderAfterWhich = ConditionalBorder.REST; } + // when adding the areas for the TableCellLayoutManager this helps with the isLast trait + // if, say, the first cell of a row has content that fits in the page, but the content of + // the second cell does not fit this will assure that the isLast trait for the first cell + // will also be false + lastCellParts[i].pgu.getCellLM().setLastTrait(lastCellParts[i].isLastPart()); addAreasForCell(firstCellParts[i].pgu, firstCellParts[i].start, lastCellParts[i].end, actualRowHeight, borderBeforeWhich, borderAfterWhich, lastOnPage); - firstCellParts[i] = null; + firstCellParts[i] = null; // why? what about the lastCellParts[i]? Arrays.fill(firstCellOnPage, i, i + currentGU.getCell().getNumberColumnsSpanned(), false); } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 2ca5a26d1..f810d20c5 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -28,19 +29,24 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.area.Area; import org.apache.fop.area.Block; import org.apache.fop.area.Trait; +import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.table.ConditionalBorder; import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableColumn; +import org.apache.fop.fo.flow.table.TableFooter; +import org.apache.fop.fo.flow.table.TableHeader; import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; +import org.apache.fop.layoutmgr.AbstractLayoutManager; import org.apache.fop.layoutmgr.AreaAdditionUtil; import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.ElementListObserver; import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBox; @@ -49,8 +55,10 @@ import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LocalBreaker; import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager; import org.apache.fop.layoutmgr.SpaceResolver; import org.apache.fop.layoutmgr.TraitSetter; import org.apache.fop.traits.BorderProps; @@ -79,6 +87,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager private int totalHeight; private int usedBPD; private boolean emptyCell = true; + private boolean isDescendantOfTableFooter; + private boolean isDescendantOfTableHeader; + private boolean hasRetrieveTableMarker; + + // place holder for the addAreas arguments + private boolean savedAddAreasArguments; + private PositionIterator savedParentIter; + private LayoutContext savedLayoutContext; + private int[] savedSpannedGridRowHeights; + private int savedStartRow; + private int savedEndRow; + private int savedBorderBeforeWhich; + private int savedBorderAfterWhich; + private boolean savedFirstOnPage; + private boolean savedLastOnPage; + private RowPainter savedPainter; + private int savedFirstRowHeight; + // this is set to false when the table-cell has a retrieve-table-marker and is in the table-header + private boolean flushArea = true; + + // this information is set by the RowPainter + private boolean isLastTrait; /** * Create a new Cell layout manager. @@ -88,6 +118,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) { super(node); this.primaryGridUnit = pgu; + this.isDescendantOfTableHeader = node.getParent().getParent() instanceof TableHeader + || node.getParent() instanceof TableHeader; + this.isDescendantOfTableFooter = node.getParent().getParent() instanceof TableFooter + || node.getParent() instanceof TableFooter; + this.hasRetrieveTableMarker = node.hasRetrieveTableMarker(); } /** @return the table-cell FO */ @@ -248,6 +283,84 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager totalHeight = h; } + private void clearRetrieveTableMarkerChildNodes(List<LayoutManager> childrenLMs) { + if (childrenLMs == null) { + return; + } + int n = childrenLMs.size(); + for (int j = 0; j < n; j++) { + LayoutManager lm = (LayoutManager) childrenLMs.get(j); + if (lm == null) { + return; + } else if (lm instanceof RetrieveTableMarkerLayoutManager) { + ((AbstractLayoutManager) lm).getFObj().clearChildNodes(); + } else { + List<LayoutManager> lms = lm.getChildLMs(); + clearRetrieveTableMarkerChildNodes(lms); + } + } + } + + /** + * Checks whether the associated table cell of this LM is in a table header or footer. + * @return true if descendant of table header or footer + */ + private boolean isDescendantOfTableHeaderOrFooter() { + return (isDescendantOfTableFooter || isDescendantOfTableHeader); + } + + private void saveAddAreasArguments(PositionIterator parentIter, LayoutContext layoutContext, + int[] spannedGridRowHeights, int startRow, int endRow, int borderBeforeWhich, + int borderAfterWhich, boolean firstOnPage, boolean lastOnPage, RowPainter painter, + int firstRowHeight) { + // checks for savedAddAreasArguments and isDescendantOfTableHeader were already made but repeat them + if (savedAddAreasArguments) { + return; + } + if (isDescendantOfTableHeader) { + savedAddAreasArguments = true; + savedParentIter = null /* parentIter */; + savedLayoutContext = null /* layoutContext */; + savedSpannedGridRowHeights = spannedGridRowHeights; + savedStartRow = startRow; + savedEndRow = endRow; + savedBorderBeforeWhich = borderBeforeWhich; + savedBorderAfterWhich = borderAfterWhich; + savedFirstOnPage = firstOnPage; + savedLastOnPage = lastOnPage; + savedPainter = painter; + savedFirstRowHeight = firstRowHeight; + TableLayoutManager parentTableLayoutManager = getTableLayoutManager(); + parentTableLayoutManager.saveTableHeaderTableCellLayoutManagers(this); + // this saving is done the first time the addArea() is called; since the retrieve-table-markers + // cannot be resolved at this time we do not want to flush the area; the area needs nevertheless + // be built so that space is allocated for it. + flushArea = false; + } + } + + private TableLayoutManager getTableLayoutManager() { + LayoutManager parentLM = getParent(); + while (!(parentLM instanceof TableLayoutManager)) { + parentLM = parentLM.getParent(); + } + TableLayoutManager tlm = (TableLayoutManager) parentLM; + return tlm; + } + + /** + * Calls the addAreas() using the original arguments. + */ + protected void repeatAddAreas() { + if (savedAddAreasArguments) { + addAreas(savedParentIter, savedLayoutContext, savedSpannedGridRowHeights, savedStartRow, + savedEndRow, savedBorderBeforeWhich, savedBorderAfterWhich, savedFirstOnPage, + savedLastOnPage, savedPainter, savedFirstRowHeight); + // so that the arguments of the next table fragment header can be saved + savedAddAreasArguments = false; + } + } + /** * Add the areas for the break points. The cell contains block stacking layout * managers that add block areas. @@ -407,7 +520,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager } } - AreaAdditionUtil.addAreas(this, parentIter, layoutContext); + if (isDescendantOfTableHeaderOrFooter()) { + if (hasRetrieveTableMarker) { + if (isDescendantOfTableHeader && !savedAddAreasArguments) { + saveAddAreasArguments(parentIter, layoutContext, spannedGridRowHeights, startRow, endRow, + borderBeforeWhich, borderAfterWhich, firstOnPage, lastOnPage, painter, + firstRowHeight); + } + recreateChildrenLMs(); + int displayAlign = ((TableCell) this.getFObj()).getDisplayAlign(); + TableCellBreaker breaker = new TableCellBreaker(this, cellIPD, displayAlign); + breaker.doLayout(usedBPD, false); + // this is needed so the next time the LMs are recreated they look like the originals; this + // is due to the fact that during the doLayout() above the FO tree changes when the + // retrieve-table-markers are resolved + clearRetrieveTableMarkerChildNodes(getChildLMs()); + } + } + + // if hasRetrieveTableMarker == true the areas were already added when the re-layout was done above + if (!hasRetrieveTableMarker) { + AreaAdditionUtil.addAreas(this, parentIter, layoutContext); + } // Re-adjust the cell's bpd as it may have been modified by the previous call // for some reason (?) curBlockArea.setBPD(cellBPD); @@ -418,7 +552,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager getTableCell().getCommonBorderPaddingBackground(), this); } - flush(); + if (flushArea) { + flush(); + } else { + flushArea = true; + } curBlockArea = null; @@ -604,4 +742,49 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager return true; } + private class TableCellBreaker extends LocalBreaker { + + public TableCellBreaker(TableCellLayoutManager lm, int ipd, int displayAlign) { + super(lm, ipd, displayAlign); + } + + /** + * {@inheritDoc} + */ + protected void observeElementList(List elementList) { + String elementListID = lm.getParent().getFObj().getId() + "-" + lm.getFObj().getId(); + ElementListObserver.observe(elementList, "table-cell", elementListID); + } + + } + + /** + * Registers the FO's markers on the current PageViewport and parent Table. + * + * @param isStarting boolean indicating whether the markers qualify as 'starting' + * @param isFirst boolean indicating whether the markers qualify as 'first' + * @param isLast boolean indicating whether the markers qualify as 'last' + */ + protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) { + Map<String, Marker> markers = getTableCell().getMarkers(); + if (markers != null) { + getCurrentPV().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait); + if (!isDescendantOfTableHeaderOrFooter()) { + getTableLayoutManager().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait); + } + } + } + + void setLastTrait(boolean isLast) { + isLastTrait = isLast; + } + + /** {@inheritDoc} */ + public void setParent(LayoutManager lm) { + this.parentLayoutManager = lm; + if (this.hasRetrieveTableMarker) { + this.getTableLayoutManager().flagAsHavingRetrieveTableMarker(); + } + } + } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index ea8774716..d423b339d 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -31,9 +31,11 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.datatypes.PercentBaseContext; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; +import org.apache.fop.fo.flow.table.TableBody; import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListUtils; @@ -400,9 +402,13 @@ public class TableContentLayoutManager implements PercentBaseContext { } } - Map markers = getTableLM().getTable().getMarkers(); + // there may be table fragment markers stored; clear them since we are starting a new fragment + tableLM.clearTableFragmentMarkers(); + + // note: markers at table level are to be retrieved by the page, not by the table itself + Map<String, Marker> markers = getTableLM().getTable().getMarkers(); if (markers != null) { - getTableLM().getCurrentPV().addMarkers(markers, + getTableLM().getCurrentPV().registerMarkers(markers, true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); } @@ -430,6 +436,10 @@ public class TableContentLayoutManager implements PercentBaseContext { addBodyAreas(tablePositions.iterator(), painter, footerElements == null); } + // if there are TCLMs saved because they have a RetrieveTableMarker, we repeat the header areas now; + // this can also be done after the areas for the footer are added but should be the same as here + tableLM.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); + if (footerElements != null) { boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); layoutContext.setTreatAsArtifact(treatFooterAsArtifact); @@ -442,7 +452,7 @@ public class TableContentLayoutManager implements PercentBaseContext { this.usedBPD += painter.getAccumulatedBPD(); if (markers != null) { - getTableLM().getCurrentPV().addMarkers(markers, + getTableLM().getCurrentPV().registerMarkers(markers, false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); } } @@ -503,14 +513,20 @@ public class TableContentLayoutManager implements PercentBaseContext { */ private void addTablePartAreas(List positions, RowPainter painter, TablePart body, boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { - getTableLM().getCurrentPV().addMarkers(body.getMarkers(), + getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); + if (body instanceof TableBody) { + getTableLM().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); + } painter.startTablePart(body); for (Iterator iter = positions.iterator(); iter.hasNext();) { painter.handleTableContentPosition((TableContentPosition) iter.next()); } - getTableLM().getCurrentPV().addMarkers(body.getMarkers(), + getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); + if (body instanceof TableBody) { + getTableLM().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); + } painter.endTablePart(lastInBody, lastOnPage); } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java index 5a4152c69..7d4c26546 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -33,12 +34,16 @@ import org.apache.fop.datatypes.LengthBase; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.flow.Markers; +import org.apache.fop.fo.flow.RetrieveTableMarker; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableColumn; import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.layoutmgr.BlockLevelEventProducer; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; import org.apache.fop.layoutmgr.BreakElement; +import org.apache.fop.layoutmgr.BreakOpportunity; import org.apache.fop.layoutmgr.ConditionalElementListener; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; @@ -62,7 +67,7 @@ import org.apache.fop.util.BreakUtil; * the render background. */ public class TableLayoutManager extends BlockStackingLayoutManager - implements ConditionalElementListener { + implements ConditionalElementListener, BreakOpportunity { /** * logging instance @@ -92,6 +97,15 @@ public class TableLayoutManager extends BlockStackingLayoutManager private Position auxiliaryPosition; + // this holds a possible list of TCLMs that needed to have their addAreas() repeated + private List<TableCellLayoutManager> savedTCLMs; + private boolean areAllTCLMsSaved; + + private Markers tableMarkers; + private Markers tableFragmentMarkers; + + private boolean hasRetrieveTableMarker; + /** * Temporary holder of column background informations for a table-cell's area. * @@ -559,4 +573,112 @@ public class TableLayoutManager extends BlockStackingLayoutManager tableUnit = 0.0; } + /** + * Saves a TableCellLayoutManager for later use. + * + * @param tclm a TableCellLayoutManager that has a RetrieveTableMarker + */ + protected void saveTableHeaderTableCellLayoutManagers(TableCellLayoutManager tclm) { + if (savedTCLMs == null) { + savedTCLMs = new ArrayList<TableCellLayoutManager>(); + } + if (!areAllTCLMsSaved) { + savedTCLMs.add(tclm); + } + } + + /** + * Calls addAreas() for each of the saved TableCellLayoutManagers. + */ + protected void repeatAddAreasForSavedTableHeaderTableCellLayoutManagers() { + if (savedTCLMs == null) { + return; + } + // if we get to this stage then we are at the footer of the table fragment; this means that no more + // different TCLM need to be saved (we already have all); we flag the list as being complete then + areAllTCLMsSaved = true; + for (int i = 0; i < savedTCLMs.size(); i++) { + TableCellLayoutManager tclm = savedTCLMs.get(i); + tclm.repeatAddAreas(); + } + } + + /** + * Resolves a RetrieveTableMarker by finding a qualifying Marker to which it is bound to. + * @param rtm the RetrieveTableMarker to be resolved + * @return a bound RetrieveTableMarker instance or null if no qualifying Marker found + */ + public RetrieveTableMarker resolveRetrieveTableMarker(RetrieveTableMarker rtm) { + String name = rtm.getRetrieveClassName(); + int originalPosition = rtm.getPosition(); + boolean changedPosition = false; + + Marker mark = null; + // try the primary retrieve scope area, which is the same as table-fragment + mark = (tableFragmentMarkers == null) ? null : tableFragmentMarkers.resolve(rtm); + if (mark == null && rtm.getBoundary() != Constants.EN_TABLE_FRAGMENT) { + rtm.changePositionTo(Constants.EN_LAST_ENDING); + changedPosition = true; + // try the page scope area + mark = getCurrentPV().resolveMarker(rtm); + if (mark == null && rtm.getBoundary() != Constants.EN_PAGE) { + // try the table scope area + mark = (tableMarkers == null) ? null : tableMarkers.resolve(rtm); + } + } + if (changedPosition) { + // so that the next time it is called looks unchanged + rtm.changePositionTo(originalPosition); + } + if (mark == null) { + log.debug("found no marker with name: " + name); + return null; + } else { + rtm.bindMarker(mark); + return rtm; + } + } + + /** + * Register the markers for this table. + * + * @param marks the map of markers to add + * @param starting if the area being added is starting or ending + * @param isfirst if the area being added has is-first trait + * @param islast if the area being added has is-last trait + */ + public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, + boolean islast) { + if (tableMarkers == null) { + tableMarkers = new Markers(); + } + tableMarkers.register(marks, starting, isfirst, islast); + if (tableFragmentMarkers == null) { + tableFragmentMarkers = new Markers(); + } + tableFragmentMarkers.register(marks, starting, isfirst, islast); + } + + /** + * Clears the list of markers in the current table fragment. Should be called just before starting a new + * header (that belongs to the next table fragment). + */ + protected void clearTableFragmentMarkers() { + tableFragmentMarkers = null; + } + + public void flagAsHavingRetrieveTableMarker() { + hasRetrieveTableMarker = true; + } + + protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting, + boolean isFirst, boolean isLast) { + // note: if we allow table-footer after a table-body this check should not be made and the markers + // should be registered regardless because the retrieval may be done only in the footer + if (hasRetrieveTableMarker) { + registerMarkers(markers, isStarting, isFirst, isLast); + } + super.possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); + } + } diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index e46a22c4a..0b412842f 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -355,36 +355,20 @@ public class PDFDocument { } /** - * Creates and returns a structure element. - * - * @param structureType the structure type of the new element (value for the - * S entry) - * @param parent the parent of the new structure element in the structure - * hierarchy - * @return a dictionary of type StructElem + * Adds the given element to the structure tree. */ - public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent) { - PDFStructElem structElem = new PDFStructElem(parent, structureType); + public void registerStructureElement(PDFStructElem structElem) { assignObjectNumber(structElem); structureTreeElements.add(structElem); - return structElem; } /** - * Creates and returns a structure element. - * - * @param structureType the structure type of the new element (value for the - * S entry) - * @param parent the parent of the new structure element in the structure - * hierarchy - * @param scope the scope of the given table header element - * @return a dictionary of type StructElem + * Assigns the given scope to the given element and adds it to the structure tree. The + * scope may not be added if it's not compatible with this document's PDF version. */ - public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent, - Scope scope) { - PDFStructElem structElem = makeStructureElement(structureType, parent); + public void registerStructureElement(PDFStructElem structElem, Scope scope) { + registerStructureElement(structElem); versionController.addTableHeaderScopeAttribute(structElem, scope); - return structElem; } /** diff --git a/src/java/org/apache/fop/pdf/PDFEncoding.java b/src/java/org/apache/fop/pdf/PDFEncoding.java index bf2799c70..64fd6f866 100644 --- a/src/java/org/apache/fop/pdf/PDFEncoding.java +++ b/src/java/org/apache/fop/pdf/PDFEncoding.java @@ -23,6 +23,9 @@ package org.apache.fop.pdf; import java.util.Collections; import java.util.Set; +import org.apache.fop.fonts.CodePointMapping; +import org.apache.fop.fonts.SingleByteEncoding; + /** * Class representing an /Encoding object. * @@ -74,6 +77,38 @@ public class PDFEncoding extends PDFDictionary { } /** + * Creates a PDFEncoding instance from a CodePointMapping instance. + * @param encoding the code point mapping (encoding) + * @param fontName ... + * @return the PDF Encoding dictionary (or a String with the predefined encoding) + */ + static Object createPDFEncoding(SingleByteEncoding encoding, String fontName) { + //If encoding type is null, return null which causes /Encoding to be omitted. + if (encoding == null) { + return null; + } + String encodingName = null; + SingleByteEncoding baseEncoding; + if (fontName.indexOf("Symbol") >= 0) { + baseEncoding = CodePointMapping.getMapping(CodePointMapping.SYMBOL_ENCODING); + encodingName = baseEncoding.getName(); + } else { + baseEncoding = CodePointMapping.getMapping(CodePointMapping.STANDARD_ENCODING); + } + PDFEncoding pdfEncoding = new PDFEncoding(encodingName); + PDFEncoding.DifferencesBuilder builder = pdfEncoding.createDifferencesBuilder(); + PDFArray differences = builder.buildDifferencesArray(baseEncoding, encoding); + // TODO This method should not be returning an Object with two different outcomes + // resulting in subsequent `if (X instanceof Y)` statements. + if (differences.length() > 0) { + pdfEncoding.setDifferences(differences); + return pdfEncoding; + } else { + return encodingName; + } + } + + /** * Indicates whether a given encoding is one of the predefined encodings. * @param name the encoding name (ex. "StandardEncoding") * @return true if it is a predefined encoding @@ -83,6 +118,15 @@ public class PDFEncoding extends PDFDictionary { } /** + * Indicates whether the given encoding type is that of standard encoding + * @param name The encoding name + * @return Returns true if it is of type standard encoding + */ + static boolean hasStandardEncoding(String encodingName) { + return encodingName.equals(STANDARD_ENCODING); + } + + /** * Creates and returns a new DifferencesBuilder instance for constructing the Differences * array. * @return the DifferencesBuilder @@ -104,18 +148,44 @@ public class PDFEncoding extends PDFDictionary { */ public class DifferencesBuilder { - private PDFArray differences = new PDFArray(); private int currentCode = -1; /** + * Creates an array containing the differences between two single-byte. + * font encodings. + * @param encodingA The first single-byte encoding + * @param encodingB The second single-byte encoding + * @return The PDFArray of differences between encodings + */ + public PDFArray buildDifferencesArray(SingleByteEncoding encodingA, + SingleByteEncoding encodingB) { + PDFArray differences = new PDFArray(); + int start = -1; + String[] baseNames = encodingA.getCharNameMap(); + String[] charNameMap = encodingB.getCharNameMap(); + for (int i = 0, ci = charNameMap.length; i < ci; i++) { + String basec = baseNames[i]; + String c = charNameMap[i]; + if (!basec.equals(c)) { + if (start != i) { + addDifference(i, differences); + start = i; + } + addName(c, differences); + start++; + } + } + return differences; + } + + /** * Start a new difference. * @param code the starting code index inside the encoding * @return this builder instance */ - public DifferencesBuilder addDifference(int code) { + private void addDifference(int code, PDFArray differences) { this.currentCode = code; - this.differences.add(new Integer(code)); - return this; + differences.add(Integer.valueOf(code)); } /** @@ -123,28 +193,11 @@ public class PDFEncoding extends PDFDictionary { * @param name the character name * @return this builder instance */ - public DifferencesBuilder addName(String name) { + private void addName(String name, PDFArray differences) { if (this.currentCode < 0) { throw new IllegalStateException("addDifference(int) must be called first"); } - this.differences.add(new PDFName(name)); - return this; - } - - /** - * Indicates whether any differences have been recorded. - * @return true if there are differences. - */ - public boolean hasDifferences() { - return (this.differences.length() > 0); - } - - /** - * Creates and returns the PDFArray representing the Differences entry. - * @return the Differences entry - */ - public PDFArray toPDFArray() { - return this.differences; + differences.add(new PDFName(name)); } } diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index 633ce9dd1..31be73a00 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -44,9 +44,9 @@ import org.apache.xmlgraphics.java2d.color.NamedColorSpace; import org.apache.xmlgraphics.xmp.Metadata; import org.apache.fop.fonts.CIDFont; -import org.apache.fop.fonts.CIDSubset; import org.apache.fop.fonts.CodePointMapping; import org.apache.fop.fonts.CustomFont; +import org.apache.fop.fonts.EmbeddingMode; import org.apache.fop.fonts.FontDescriptor; import org.apache.fop.fonts.FontMetrics; import org.apache.fop.fonts.FontType; @@ -1369,23 +1369,14 @@ public class PDFFactory { } else { cidMetrics = (CIDFont)metrics; } - PDFCIDSystemInfo sysInfo - = new PDFCIDSystemInfo(cidMetrics.getRegistry(), - cidMetrics.getOrdering(), - cidMetrics.getSupplement()); - PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, - cidMetrics.getCIDType(), - cidMetrics.getDefaultWidth(), - getSubsetWidths(cidMetrics), sysInfo, - (PDFCIDFontDescriptor)pdfdesc); + PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(), + cidMetrics.getOrdering(), cidMetrics.getSupplement()); + PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(), + cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo, + (PDFCIDFontDescriptor) pdfdesc); getDocument().registerObject(cidFont); - - PDFCMap cmap = new PDFToUnicodeCMap( - cidMetrics.getCIDSubset().getSubsetChars(), - "fop-ucs-H", - new PDFCIDSystemInfo("Adobe", - "Identity", - 0), false); + PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H", + new PDFCIDSystemInfo("Adobe", "Identity", 0), false); getDocument().registerObject(cmap); ((PDFFontType0)font).setCMAP(cmap); ((PDFFontType0)font).setDescendantFonts(cidFont); @@ -1469,61 +1460,18 @@ public class PDFFactory { /** * Creates a PDFEncoding instance from a CodePointMapping instance. * @param encoding the code point mapping (encoding) - * @param fontNameHint ... + * @param fontName ... * @return the PDF Encoding dictionary (or a String with the predefined encoding) */ - public Object createPDFEncoding(SingleByteEncoding encoding, String fontNameHint) { - SingleByteEncoding baseEncoding; - if (fontNameHint.indexOf("Symbol") >= 0) { - baseEncoding = CodePointMapping.getMapping( - CodePointMapping.SYMBOL_ENCODING); - } else { - baseEncoding = CodePointMapping.getMapping( - CodePointMapping.STANDARD_ENCODING); - } - PDFEncoding pdfEncoding = new PDFEncoding(baseEncoding.getName()); - PDFEncoding.DifferencesBuilder builder - = pdfEncoding.createDifferencesBuilder(); - int start = -1; - String[] baseNames = baseEncoding.getCharNameMap(); - String[] charNameMap = encoding.getCharNameMap(); - for (int i = 0, ci = charNameMap.length; i < ci; i++) { - String basec = baseNames[i]; - String c = charNameMap[i]; - if (!basec.equals(c)) { - if (start != i) { - builder.addDifference(i); - start = i; - } - builder.addName(c); - start++; - } - } - if (builder.hasDifferences()) { - pdfEncoding.setDifferences(builder.toPDFArray()); - return pdfEncoding; - } else { - return baseEncoding.getName(); - } + public Object createPDFEncoding(SingleByteEncoding encoding, String fontName) { + return PDFEncoding.createPDFEncoding(encoding, fontName); } - /** - * Creates and returns a width array with the widths of all the characters in the subset. - * @param cidFont the font - * @return the width array - */ - public PDFWArray getSubsetWidths(CIDFont cidFont) { + private PDFWArray getFontWidths(CIDFont cidFont) { // Create widths for reencoded chars PDFWArray warray = new PDFWArray(); - int[] widths = cidFont.getWidths(); - CIDSubset subset = cidFont.getCIDSubset(); - int[] tmpWidth = new int[subset.getSubsetSize()]; - - for (int i = 0, c = subset.getSubsetSize(); i < c; i++) { - int nwx = Math.max(0, subset.getGlyphIndexForSubsetIndex(i)); - tmpWidth[i] = widths[nwx]; - } - warray.addEntry(0, tmpWidth); + int[] widths = cidFont.getCIDSet().getWidths(); + warray.addEntry(0, widths); return warray; } @@ -1591,13 +1539,13 @@ public class PDFFactory { } private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) { - BitSet cidSubset = cidFont.getCIDSubset().getGlyphIndexBitSet(); - PDFStream cidSet = makeStream(null, true); - ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSubset.length() / 8 + 1); + BitSet cidSet = cidFont.getCIDSet().getGlyphIndices(); + PDFStream pdfStream = makeStream(null, true); + ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSet.length() / 8 + 1); int value = 0; - for (int i = 0, c = cidSubset.length(); i < c; i++) { + for (int i = 0, c = cidSet.length(); i < c; i++) { int shift = i % 8; - boolean b = cidSubset.get(i); + boolean b = cidSet.get(i); if (b) { value |= 1 << 7 - shift; } @@ -1608,8 +1556,8 @@ public class PDFFactory { } baout.write(value); try { - cidSet.setData(baout.toByteArray()); - descriptor.setCIDSet(cidSet); + pdfStream.setData(baout.toByteArray()); + descriptor.setCIDSet(pdfStream); } catch (IOException ioe) { log.error( "Failed to write CIDSet [" + cidFont + "] " @@ -1640,14 +1588,16 @@ public class PDFFactory { if (desc.getFontType() == FontType.TYPE0) { MultiByteFont mbfont = (MultiByteFont) font; FontFileReader reader = new FontFileReader(in); - - TTFSubSetFile subset = new TTFSubSetFile(); - subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); - byte[] subsetFont = subset.getFontSubset(); - // Only TrueType CID fonts are supported now - - embeddedFont = new PDFTTFStream(subsetFont.length); - ((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length); + byte[] fontBytes; + if (font.getEmbeddingMode() == EmbeddingMode.FULL) { + fontBytes = reader.getAllBytes(); + } else { + TTFSubSetFile ttfFile = new TTFSubSetFile(); + ttfFile.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs()); + fontBytes = ttfFile.getFontSubset(); + } + embeddedFont = new PDFTTFStream(fontBytes.length); + ((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length); } else if (desc.getFontType() == FontType.TYPE1) { PFBParser parser = new PFBParser(); PFBData pfb = parser.parsePFB(in); diff --git a/src/java/org/apache/fop/pdf/PDFFont.java b/src/java/org/apache/fop/pdf/PDFFont.java index 191fd223e..9b9d1c129 100644 --- a/src/java/org/apache/fop/pdf/PDFFont.java +++ b/src/java/org/apache/fop/pdf/PDFFont.java @@ -70,7 +70,7 @@ public class PDFFont extends PDFDictionary { * @param encoding the encoding */ public void setEncoding(String encoding) { - if (encoding != null) { + if (encoding != null && !PDFEncoding.hasStandardEncoding(encoding)) { put("Encoding", new PDFName(encoding)); } } diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java index 28cebb3ee..8250318d7 100644 --- a/src/java/org/apache/fop/pdf/PDFStructElem.java +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -32,7 +32,8 @@ import org.apache.fop.util.LanguageTags; /** * Class representing a PDF Structure Element. */ -public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject { +public class PDFStructElem extends StructureHierarchyMember + implements StructureTreeElement, CompressedObject { private StructureType structureType; @@ -51,7 +52,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement * @param parent parent of this element * @param structureType the structure type of this element */ - PDFStructElem(PDFObject parent, StructureType structureType) { + public PDFStructElem(PDFObject parent, StructureType structureType) { this(parent); this.structureType = structureType; put("S", structureType.getName()); @@ -86,6 +87,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement * * @param kid element to be added */ + @Override public void addKid(PDFObject kid) { if (kids == null) { kids = new ArrayList<PDFObject>(); diff --git a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java index 5f19bb2e2..ca6d82d22 100644 --- a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java +++ b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java @@ -22,7 +22,7 @@ package org.apache.fop.pdf; /** * Class representing a PDF /StructTreeRoot dictionary. */ -public class PDFStructTreeRoot extends PDFDictionary { +public class PDFStructTreeRoot extends StructureHierarchyMember { /** * Creates a new /StructTreeRoot dictionary. @@ -49,6 +49,7 @@ public class PDFStructTreeRoot extends PDFDictionary { * * @param kid an object to be added to the K entry */ + @Override public void addKid(PDFObject kid) { getKids().add(kid); } diff --git a/src/java/org/apache/fop/pdf/StandardStructureTypes.java b/src/java/org/apache/fop/pdf/StandardStructureTypes.java index dc045e180..69550119a 100644 --- a/src/java/org/apache/fop/pdf/StandardStructureTypes.java +++ b/src/java/org/apache/fop/pdf/StandardStructureTypes.java @@ -111,6 +111,11 @@ public final class StandardStructureTypes { return name; } + @Override + public String toString() { + return name.toString().substring(1); + } + } private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>(); diff --git a/src/java/org/apache/fop/apps/io/Resource.java b/src/java/org/apache/fop/pdf/StructureHierarchyMember.java index 0a8b8c22a..e3be92102 100644 --- a/src/java/org/apache/fop/apps/io/Resource.java +++ b/src/java/org/apache/fop/pdf/StructureHierarchyMember.java @@ -17,43 +17,21 @@ /* $Id$ */ -package org.apache.fop.apps.io; - -import java.io.FilterInputStream; -import java.io.InputStream; +package org.apache.fop.pdf; /** - * This class represents a resolved resource. The type property is used by FOP to identify the resource - * content. + * 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 class Resource extends FilterInputStream { - - private final String type; - - /** - * @param type resource type - * @param inputStream input stream of the resource - */ - public Resource(String type, InputStream inputStream) { - super(inputStream); - this.type = type; - } +public abstract class StructureHierarchyMember extends PDFDictionary { /** - * Constructs a resource of 'unknown' type. + * Adds the given object to the array of kids. * - * @param inputStream input stream of the resource - */ - public Resource(InputStream inputStream) { - this("unknown", inputStream); - } - - /** - * @return the resource type + * @param kid an object to be added to the K entry */ - public String getType() { - return this.type; - } + public abstract void addKid(PDFObject kid); } diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index a82c27bac..5a0732c84 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -328,7 +328,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler case IN_PAGE_HEADER: String name = aps.getName(); String value = aps.getValue(); - dataStream.createTagLogicalElement(name, value); + int encoding = aps.getEncoding(); + dataStream.createTagLogicalElement(name, value, encoding); break; default: throw new IFException( diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java index 14a34a0b3..abf6e359e 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java @@ -144,6 +144,12 @@ public class AFPExtensionHandler extends DefaultHandler if (placement != null && placement.length() > 0) { pageSetupExtn.setPlacement(ExtensionPlacement.fromXMLValue(placement)); } + + String encoding = lastAttributes.getValue("encoding"); + if (encoding != null && pageSetupExtn != null) { + pageSetupExtn.setEncoding(Integer.parseInt(encoding)); + } + if (content.length() > 0 && pageSetupExtn != null) { pageSetupExtn.setContent(content.toString()); content.setLength(0); //Reset text buffer (see characters()) diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java index 2d30f3ae8..27db41d39 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java @@ -23,6 +23,8 @@ import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; +import org.apache.fop.afp.modca.TagLogicalElement; + /** * This is the pass-through value object for the AFP extension. */ @@ -48,6 +50,27 @@ public class AFPPageSetup extends AFPExtensionAttachment { protected ExtensionPlacement placement = ExtensionPlacement.DEFAULT; /** + * the CCSID character set encoding + */ + protected int encoding = TagLogicalElement.State.ENCODING_NONE; + + /** + * + * @return CCSID character set encoding + */ + public int getEncoding() { + return encoding; + } + + /** + * + * @param encoding CCSID character set encoding + */ + public void setEncoding(int encoding) { + this.encoding = encoding; + } + + /** * Default constructor. * * @param elementName the name of the setup code object, may be null diff --git a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java index 42be9bfe0..9b325c5cd 100644 --- a/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java +++ b/src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java @@ -35,6 +35,7 @@ import org.apache.fop.fo.extensions.ExtensionAttachment; */ public class AFPPageSetupElement extends AbstractAFPExtensionObject { + private static final String ATT_ENCODING = "encoding"; private static final String ATT_SRC = "src"; /** @@ -105,6 +106,16 @@ public class AFPPageSetupElement extends AbstractAFPExtensionObject { } else { missingPropertyError(AFPPageSetup.ATT_VALUE); } + attr = attlist.getValue(ATT_ENCODING); + if (attr != null) { + try { + pageSetup.setEncoding(Integer.parseInt(attr)); + } catch (NumberFormatException nfe) { + invalidPropertyValueError(ATT_ENCODING, attr, nfe); + } + + } + } String placement = attlist.getValue(AFPPageSetup.ATT_PLACEMENT); if (placement != null && placement.length() > 0) { diff --git a/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java index 262caa53b..8d0ce14ac 100644 --- a/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java +++ b/src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java @@ -84,7 +84,7 @@ public abstract class AbstractBitmapDocumentHandler extends AbstractBinaryWritin super(context); //Set target resolution int dpi = Math.round(context.getUserAgent().getTargetResolution()); - getSettings().getWriterParams().setResolution(dpi); + getSettings().setResolution(dpi); Map renderingOptions = getUserAgent().getRendererOptions(); setTargetBitmapSize((Dimension)renderingOptions.get(TARGET_BITMAP_SIZE)); diff --git a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java index d239fe0fd..4363f1d5e 100644 --- a/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java +++ b/src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java @@ -107,4 +107,27 @@ public class BitmapRenderingSettings extends Java2DRenderingSettings { return this.qualityRendering; } + /** + * Sets the compression method for the image writer. + * @param compressionMethod the compression method name + */ + public void setCompressionMethod(String compressionMethod) { + writerParams.setCompressionMethod(compressionMethod); + } + + /** + * Returns the compression method being used by the image writer. + * @return the compression method in use + */ + public String getCompressionMethod() { + return writerParams.getCompressionMethod(); + } + + /** + * Sets the resolution of the output image. + * @param dpi the dots-per-inch of the image + */ + public void setResolution(int dpi) { + writerParams.setResolution(dpi); + } } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java new file mode 100644 index 000000000..4e9c3bd26 --- /dev/null +++ b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java @@ -0,0 +1,98 @@ +/* + * 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.bitmap; + +import java.awt.image.BufferedImage; + +/** + * Compression constants for TIFF image output. + */ +public enum TIFFCompressionValue { + /** No compression */ + NONE("NONE"), + /** JPEG compression */ + JPEG("JPEG"), + /** Packbits (RLE) compression */ + PACKBITS("PackBits"), + /** Deflate compression */ + DEFLATE("Deflate"), + /** LZW compression */ + LZW("LZW"), + /** ZLib compression */ + ZLIB("ZLib"), + /** CCITT Group 3 (T.4) compression */ + CCITT_T4("CCITT T.4", BufferedImage.TYPE_BYTE_BINARY, true), + /** CCITT Group 4 (T.6) compression */ + CCITT_T6("CCITT T.6", BufferedImage.TYPE_BYTE_BINARY, true); + + private final String name; + private final int imageType; + private boolean isCcitt; + + private TIFFCompressionValue(String name, int imageType, boolean isCcitt) { + this.name = name; + this.imageType = imageType; + this.isCcitt = isCcitt; + } + + private TIFFCompressionValue(String name) { + this(name, BufferedImage.TYPE_INT_ARGB, false); + } + + /** + * Returns the name of this compression type. + * @return the compression name + */ + String getName() { + return name; + } + + /** + * Returns an image type for this compression type, a constant from {@link BufferedImage} e.g. + * {@link BufferedImage#TYPE_INT_ARGB} for {@link #ZLIB} + * @return the image type + */ + int getImageType() { + return imageType; + } + + /** + * Returns whether or not this compression type is a CCITT type. + * @return true if the compression type is CCITT + */ + boolean hasCCITTCompression() { + return isCcitt; + } + + /** + * Return the TIFF compression constant given the string representing the type. In the case that + * the name doesn't match any of the compression values, <code>null</code> is returned. + * @param name the compression type name + * @return the compression constant + */ + static TIFFCompressionValue getType(String name) { + for (TIFFCompressionValue tiffConst : TIFFCompressionValue.values()) { + if (tiffConst.name.equalsIgnoreCase(name)) { + return tiffConst; + } + } + return null; + } +} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java b/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java deleted file mode 100644 index 71649022e..000000000 --- a/src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.bitmap; - -/** - * Constants for TIFF output. - */ -public enum TIFFCompressionValues { - /** No compression */ - NONE("NONE"), - /** JPEG compression */ - JPEG("JPEG"), - /** Packbits (RLE) compression */ - PACKBITS("PackBits"), - /** Deflate compression */ - DEFLATE("Deflate"), - /** LZW compression */ - LZW("LZW"), - /** ZLib compression */ - ZLIB("ZLib"), - /** CCITT Group 4 (T.6) compression */ - CCITT_T6("CCITT T.6"), //CCITT Group 4 - /** CCITT Group 3 (T.4) compression */ - CCITT_T4("CCITT T.4"); //CCITT Group 3 - - private final String name; - - private TIFFCompressionValues(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public static TIFFCompressionValues getValue(String name) { - for (TIFFCompressionValues tiffConst : TIFFCompressionValues.values()) { - if (tiffConst.name.equalsIgnoreCase(name)) { - return tiffConst; - } - } - return null; - } -} diff --git a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java index 48e79520f..0de02c766 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java @@ -19,6 +19,8 @@ package org.apache.fop.render.bitmap; +import org.apache.xmlgraphics.image.writer.ResolutionUnit; + import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; import org.apache.fop.render.intermediate.IFContext; @@ -32,6 +34,7 @@ public class TIFFDocumentHandler extends AbstractBitmapDocumentHandler { TIFFDocumentHandler(IFContext context) { super(context); + getSettings().getWriterParams().setResolutionUnit(ResolutionUnit.CENTIMETER); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java index 5b75a372c..48da62ef7 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRenderer.java @@ -38,7 +38,6 @@ import org.apache.commons.logging.Log; import org.apache.xmlgraphics.image.GraphicsUtil; import org.apache.xmlgraphics.image.rendered.FormatRed; import org.apache.xmlgraphics.image.writer.ImageWriter; -import org.apache.xmlgraphics.image.writer.ImageWriterParams; import org.apache.xmlgraphics.image.writer.ImageWriterRegistry; import org.apache.xmlgraphics.image.writer.MultiImageWriter; @@ -47,9 +46,9 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; import org.apache.fop.render.java2d.Java2DRenderer; -import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4; -import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6; -import static org.apache.fop.render.bitmap.TIFFCompressionValues.PACKBITS; +import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T4; +import static org.apache.fop.render.bitmap.TIFFCompressionValue.CCITT_T6; +import static org.apache.fop.render.bitmap.TIFFCompressionValue.PACKBITS; /** * <p> @@ -74,11 +73,7 @@ import static org.apache.fop.render.bitmap.TIFFCompressionValues.PACKBITS; */ public class TIFFRenderer extends Java2DRenderer { - /** ImageWriter parameters */ - private ImageWriterParams writerParams; - - /** Image Type as parameter for the BufferedImage constructor (see BufferedImage.TYPE_*) */ - private int bufferedImageType = BufferedImage.TYPE_INT_ARGB; + private BitmapRenderingSettings imageSettings; private OutputStream outputStream; @@ -94,11 +89,11 @@ public class TIFFRenderer extends Java2DRenderer { */ public TIFFRenderer(FOUserAgent userAgent) { super(userAgent); - writerParams = new ImageWriterParams(); - writerParams.setCompressionMethod(PACKBITS.getName()); - + imageSettings = new BitmapRenderingSettings(); + imageSettings.setCompressionMethod(PACKBITS.getName()); + imageSettings.setBufferedImageType(BufferedImage.TYPE_INT_ARGB); int dpi = Math.round(userAgent.getTargetResolution()); - writerParams.setResolution(dpi); + imageSettings.setResolution(dpi); } /** {@inheritDoc} */ @@ -129,7 +124,7 @@ public class TIFFRenderer extends Java2DRenderer { // Write all pages/images while (pageImagesItr.hasNext()) { RenderedImage img = (RenderedImage) pageImagesItr.next(); - multiWriter.writeImage(img, writerParams); + multiWriter.writeImage(img, imageSettings.getWriterParams()); } } finally { multiWriter.close(); @@ -139,7 +134,7 @@ public class TIFFRenderer extends Java2DRenderer { if (pageImagesItr.hasNext()) { renderedImage = (RenderedImage) pageImagesItr.next(); } - writer.writeImage(renderedImage, outputStream, writerParams); + writer.writeImage(renderedImage, outputStream, imageSettings.getWriterParams()); if (pageImagesItr.hasNext()) { BitmapRendererEventProducer eventProducer = BitmapRendererEventProducer.Provider.get( @@ -156,7 +151,7 @@ public class TIFFRenderer extends Java2DRenderer { /** {@inheritDoc} */ protected BufferedImage getBufferedImage(int bitmapWidth, int bitmapHeight) { - return new BufferedImage(bitmapWidth, bitmapHeight, bufferedImageType); + return new BufferedImage(bitmapWidth, bitmapHeight, imageSettings.getBufferedImageType()); } /** Private inner class to lazy page rendering. */ @@ -195,7 +190,7 @@ public class TIFFRenderer extends Java2DRenderer { throw new NoSuchElementException(e.getMessage()); } - TIFFCompressionValues compression = TIFFCompressionValues.getValue(writerParams.getCompressionMethod()); + TIFFCompressionValue compression = TIFFCompressionValue.getType(imageSettings.getCompressionMethod()); if (compression == CCITT_T4 || compression == CCITT_T6) { return pageImage; } else { @@ -226,11 +221,14 @@ public class TIFFRenderer extends Java2DRenderer { /** @param bufferedImageType an image type */ public void setBufferedImageType(int bufferedImageType) { - this.bufferedImageType = bufferedImageType; + imageSettings.setBufferedImageType(bufferedImageType); } - /** @return image writer parameters */ - public ImageWriterParams getWriterParams() { - return writerParams; + /** + * Returns the settings for the image rendering. + * @return the image rendering settings + */ + public BitmapRenderingSettings getRenderingSettings() { + return imageSettings; } } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java index 5417ecc1e..1e44397f6 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java @@ -23,21 +23,24 @@ import java.util.EnumMap; import org.apache.avalon.framework.configuration.Configuration; -import org.apache.xmlgraphics.util.MimeConstants; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.MimeConstants; import org.apache.fop.fonts.DefaultFontConfig; import org.apache.fop.fonts.DefaultFontConfig.DefaultFontConfigParser; import org.apache.fop.render.RendererConfigOption; +import static org.apache.fop.render.bitmap.TIFFCompressionValue.PACKBITS; + /** * The renderer configuration object for the TIFF renderer. */ public final class TIFFRendererConfig extends BitmapRendererConfig { public enum TIFFRendererOption implements RendererConfigOption { - COMPRESSION("compression", TIFFCompressionValues.PACKBITS); + COMPRESSION("compression", PACKBITS), + /** option to encode one row per strip or a all rows in a single strip*/ + SINGLE_STRIP("single-strip", Boolean.FALSE); private final String name; private final Object defaultValue; @@ -63,8 +66,16 @@ public final class TIFFRendererConfig extends BitmapRendererConfig { super(fontConfig); } - public TIFFCompressionValues getCompressionType() { - return (TIFFCompressionValues) params.get(TIFFRendererOption.COMPRESSION); + public TIFFCompressionValue getCompressionType() { + return (TIFFCompressionValue) params.get(TIFFRendererOption.COMPRESSION); + } + + /** + * @return True if all rows are contained in a single strip, False each strip contains one row or null + * if not set. + */ + public Boolean isSingleStrip() { + return (Boolean) params.get(TIFFRendererOption.SINGLE_STRIP); } /** @@ -92,9 +103,10 @@ public final class TIFFRendererConfig extends BitmapRendererConfig { .parse(cfg, userAgent.validateStrictly())); super.build(config, userAgent, cfg); if (cfg != null) { - setParam(TIFFRendererOption.COMPRESSION, - TIFFCompressionValues.getValue(getValue(cfg, - TIFFRendererOption.COMPRESSION))); + setParam(TIFFRendererOption.COMPRESSION, + TIFFCompressionValue.getType(getValue(cfg, TIFFRendererOption.COMPRESSION))); + setParam(TIFFRendererOption.SINGLE_STRIP, Boolean.valueOf(getValue(cfg, + TIFFRendererOption.SINGLE_STRIP))); } return config; } diff --git a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java index b10f2a381..19abb8131 100644 --- a/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java +++ b/src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java @@ -19,13 +19,9 @@ package org.apache.fop.render.bitmap; -import java.awt.image.BufferedImage; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.xmlgraphics.image.writer.ImageWriterParams; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.render.Renderer; @@ -33,9 +29,7 @@ import org.apache.fop.render.RendererConfig.RendererConfigParser; import org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererConfigParser; import org.apache.fop.render.intermediate.IFDocumentHandler; -import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T4; -import static org.apache.fop.render.bitmap.TIFFCompressionValues.CCITT_T6; -import static org.apache.fop.render.bitmap.TIFFCompressionValues.NONE; +import static org.apache.fop.render.bitmap.TIFFCompressionValue.NONE; /** * TIFF Renderer configurator @@ -62,43 +56,40 @@ public class TIFFRendererConfigurator extends BitmapRendererConfigurator { final TIFFRendererConfig config = (TIFFRendererConfig) getRendererConfig(renderer); if (config != null) { TIFFRenderer tiffRenderer = (TIFFRenderer) renderer; - //set compression - tiffRenderer.setBufferedImageType(getCompressionType(config, tiffRenderer.getWriterParams())); + setCompressionMethod(config.getCompressionType(), tiffRenderer.getRenderingSettings()); } super.configure(renderer); } - private int getCompressionType(TIFFRendererConfig config, ImageWriterParams writerParms) - throws FOPException { - //Some compression formats need a special image format: - TIFFCompressionValues compression = config.getCompressionType(); + private void setCompressionMethod(TIFFCompressionValue compression, + BitmapRenderingSettings settings) throws FOPException { if (compression != null) { if (compression != NONE) { - writerParms.setCompressionMethod(compression.getName()); + settings.setCompressionMethod(compression.getName()); } if (LOG.isInfoEnabled()) { LOG.info("TIFF compression set to " + compression.getName()); } + if (compression.hasCCITTCompression()) { + settings.setBufferedImageType(compression.getImageType()); + } } - return getBufferedImageTypeFor(compression); } - private int getBufferedImageTypeFor(TIFFCompressionValues compressionType) { - if (compressionType == CCITT_T6 || compressionType == CCITT_T4) { - return BufferedImage.TYPE_BYTE_BINARY; - } else { - return BufferedImage.TYPE_INT_ARGB; - } + private boolean isSingleStrip(TIFFRendererConfig config) { + Boolean singleRowPerStrip = config.isSingleStrip(); + return singleRowPerStrip == null ? false : singleRowPerStrip; } - /** {@inheritDoc} */ + @Override public void configure(IFDocumentHandler documentHandler) throws FOPException { - final TIFFRendererConfig tiffConfig = (TIFFRendererConfig) getRendererConfig(documentHandler); - if (tiffConfig != null) { + final TIFFRendererConfig config = (TIFFRendererConfig) getRendererConfig(documentHandler); + if (config != null) { TIFFDocumentHandler tiffHandler = (TIFFDocumentHandler) documentHandler; BitmapRenderingSettings settings = tiffHandler.getSettings(); configure(documentHandler, settings, new TIFFRendererConfigParser()); - settings.setBufferedImageType(getCompressionType(tiffConfig, settings.getWriterParams())); + setCompressionMethod(config.getCompressionType(), settings); + settings.getWriterParams().setSingleStrip(isSingleStrip(config)); } } diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java deleted file mode 100644 index 68bfd8686..000000000 --- a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.render.pdf; - -import java.util.Map; - -import org.apache.fop.events.EventBroadcaster; -import org.apache.fop.pdf.PDFObject; -import org.apache.fop.pdf.PDFStructElem; -import org.apache.fop.pdf.StandardStructureTypes; -import org.apache.fop.pdf.StructureType; - -/** - * This class provides the standard mappings from Formatting Objects to PDF structure types. - */ -final class FOToPDFRoleMap { - - private static final Map<String, Mapper> DEFAULT_MAPPINGS = new java.util.HashMap<String, Mapper>(); - - static { - // Create the standard mappings - // Declarations and Pagination and Layout Formatting Objects - addMapping("root", StandardStructureTypes.Grouping.DOCUMENT); - addMapping("page-sequence", StandardStructureTypes.Grouping.PART); - addMapping("flow", StandardStructureTypes.Grouping.SECT); - addMapping("static-content", StandardStructureTypes.Grouping.SECT); - // Block-level Formatting Objects - addMapping("block", StandardStructureTypes.Paragraphlike.P); - addMapping("block-container", StandardStructureTypes.Grouping.DIV); - // Inline-level Formatting Objects - addMapping("character", StandardStructureTypes.InlineLevelStructure.SPAN); - addMapping("external-graphic", StandardStructureTypes.Illustration.FIGURE); - addMapping("instream-foreign-object", StandardStructureTypes.Illustration.FIGURE); - addMapping("inline", StandardStructureTypes.InlineLevelStructure.SPAN); - addMapping("inline-container", StandardStructureTypes.Grouping.DIV); - addMapping("page-number", StandardStructureTypes.InlineLevelStructure.QUOTE); - addMapping("page-number-citation", StandardStructureTypes.InlineLevelStructure.QUOTE); - addMapping("page-number-citation-last", StandardStructureTypes.InlineLevelStructure.QUOTE); - // Formatting Objects for Tables - addMapping("table-and-caption", StandardStructureTypes.Grouping.DIV); - addMapping("table", StandardStructureTypes.Table.TABLE); - addMapping("table-caption", StandardStructureTypes.Grouping.CAPTION); - addMapping("table-header", StandardStructureTypes.Table.THEAD); - addMapping("table-footer", StandardStructureTypes.Table.TFOOT); - addMapping("table-body", StandardStructureTypes.Table.TBODY); - addMapping("table-row", StandardStructureTypes.Table.TR); - addMapping("table-cell", new TableCellMapper()); - // Formatting Objects for Lists - addMapping("list-block", StandardStructureTypes.List.L); - addMapping("list-item", StandardStructureTypes.List.LI); - addMapping("list-item-body", StandardStructureTypes.List.LBODY); - addMapping("list-item-label", StandardStructureTypes.List.LBL); - // Dynamic Effects: Link and Multi Formatting Objects - addMapping("basic-link", StandardStructureTypes.InlineLevelStructure.LINK); - // Out-of-Line Formatting Objects - addMapping("float", StandardStructureTypes.Grouping.DIV); - addMapping("footnote", StandardStructureTypes.InlineLevelStructure.NOTE); - addMapping("footnote-body", StandardStructureTypes.Grouping.SECT); - addMapping("wrapper", StandardStructureTypes.InlineLevelStructure.SPAN); - addMapping("marker", StandardStructureTypes.Grouping.PRIVATE); - } - - private static void addMapping(String fo, StructureType structureType) { - addMapping(fo, new SimpleMapper(structureType)); - } - - private static void addMapping(String fo, Mapper mapper) { - DEFAULT_MAPPINGS.put(fo, mapper); - } - - - /** - * Maps a Formatting Object to a PDFName representing the associated structure type. - * @param fo the formatting object's local name - * @param role the value of the formatting object's role property - * @param parent the parent of the structure element to be mapped - * @param eventBroadcaster the event broadcaster - * @return the structure type or null if no match could be found - */ - public static StructureType mapFormattingObject(String fo, String role, - PDFObject parent, EventBroadcaster eventBroadcaster) { - StructureType type = null; - if (role == null) { - type = getDefaultMappingFor(fo, parent); - } else { - type = StandardStructureTypes.get(role); - if (type == null) { - type = getDefaultMappingFor(fo, parent); - PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(fo, - fo, role, type.toString().substring(1)); - } - } - assert type != null; - return type; - } - - /** - * Maps a Formatting Object to a PDFName representing the associated structure type. - * @param fo the formatting object's local name - * @param parent the parent of the structure element to be mapped - * @return the structure type or NonStruct if no match could be found - */ - private static StructureType getDefaultMappingFor(String fo, PDFObject parent) { - Mapper mapper = DEFAULT_MAPPINGS.get(fo); - if (mapper != null) { - return mapper.getStructureType(parent); - } else { - return StandardStructureTypes.Grouping.NON_STRUCT; - } - } - - private interface Mapper { - StructureType getStructureType(PDFObject parent); - } - - private static class SimpleMapper implements Mapper { - - private StructureType structureType; - - public SimpleMapper(StructureType structureType) { - this.structureType = structureType; - } - - public StructureType getStructureType(PDFObject parent) { - return structureType; - } - - } - - private static class TableCellMapper implements Mapper { - - public StructureType getStructureType(PDFObject parent) { - PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem(); - //TODO What to do with cells from table-footer? Currently they are mapped on TD. - if (grandParent.getStructureType() == StandardStructureTypes.Table.THEAD) { - return StandardStructureTypes.Table.TH; - } else { - return StandardStructureTypes.Table.TD; - } - } - - } - - private FOToPDFRoleMap() { } -} diff --git a/src/java/org/apache/fop/render/pdf/PDFEventProducer.java b/src/java/org/apache/fop/render/pdf/PDFEventProducer.java index 40062f73f..4b8253867 100644 --- a/src/java/org/apache/fop/render/pdf/PDFEventProducer.java +++ b/src/java/org/apache/fop/render/pdf/PDFEventProducer.java @@ -59,12 +59,11 @@ public interface PDFEventProducer extends EventProducer { * Custom structure type is not standard as per the PDF reference. * * @param source the event source - * @param fo the local name of the formatting object having the custom type * @param type custom structure type * @param fallback default structure type used as a fallback * @event.severity WARN */ - void nonStandardStructureType(Object source, String fo, String type, String fallback); + void nonStandardStructureType(Object source, String type, String fallback); /** * The encryption length must be a multiple of 8 between 40 and 128. diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java index 1377bbfce..031224ffb 100644 --- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java @@ -21,24 +21,266 @@ package org.apache.fop.render.pdf; import java.util.LinkedList; import java.util.Locale; +import java.util.Map; import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; import org.apache.fop.accessibility.StructureTreeElement; import org.apache.fop.accessibility.StructureTreeEventHandler; import org.apache.fop.events.EventBroadcaster; import org.apache.fop.fo.extensions.ExtensionElementMapping; +import org.apache.fop.fo.extensions.InternalElementMapping; +import org.apache.fop.fo.pagination.Flow; import org.apache.fop.pdf.PDFFactory; -import org.apache.fop.pdf.PDFObject; import org.apache.fop.pdf.PDFParentTree; import org.apache.fop.pdf.PDFStructElem; import org.apache.fop.pdf.PDFStructTreeRoot; import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope; +import org.apache.fop.pdf.StandardStructureTypes; +import org.apache.fop.pdf.StandardStructureTypes.Grouping; import org.apache.fop.pdf.StandardStructureTypes.Table; +import org.apache.fop.pdf.StructureHierarchyMember; import org.apache.fop.pdf.StructureType; +import org.apache.fop.util.XMLUtil; class PDFStructureTreeBuilder implements StructureTreeEventHandler { + private static final String ROLE = "role"; + + private static final Map<String, StructureElementBuilder> BUILDERS + = new java.util.HashMap<String, StructureElementBuilder>(); + + private static final StructureElementBuilder DEFAULT_BUILDER + = new DefaultStructureElementBuilder(Grouping.NON_STRUCT); + + static { + // Declarations and Pagination and Layout Formatting Objects + StructureElementBuilder regionBuilder = new RegionBuilder(); + addBuilder("root", StandardStructureTypes.Grouping.DOCUMENT); + addBuilder("page-sequence", new PageSequenceBuilder()); + addBuilder("static-content", regionBuilder); + addBuilder("flow", regionBuilder); + // Block-level Formatting Objects + addBuilder("block", StandardStructureTypes.Paragraphlike.P); + addBuilder("block-container", StandardStructureTypes.Grouping.DIV); + // Inline-level Formatting Objects + addBuilder("character", StandardStructureTypes.InlineLevelStructure.SPAN); + addBuilder("external-graphic", new ImageBuilder()); + addBuilder("instream-foreign-object", new ImageBuilder()); + addBuilder("inline", StandardStructureTypes.InlineLevelStructure.SPAN); + addBuilder("inline-container", StandardStructureTypes.Grouping.DIV); + addBuilder("page-number", StandardStructureTypes.InlineLevelStructure.QUOTE); + addBuilder("page-number-citation", StandardStructureTypes.InlineLevelStructure.QUOTE); + addBuilder("page-number-citation-last", StandardStructureTypes.InlineLevelStructure.QUOTE); + // Formatting Objects for Tables + addBuilder("table-and-caption", StandardStructureTypes.Grouping.DIV); + addBuilder("table", new TableBuilder()); + addBuilder("table-caption", StandardStructureTypes.Grouping.CAPTION); + addBuilder("table-header", StandardStructureTypes.Table.THEAD); + addBuilder("table-footer", new TableFooterBuilder()); + addBuilder("table-body", StandardStructureTypes.Table.TBODY); + addBuilder("table-row", StandardStructureTypes.Table.TR); + addBuilder("table-cell", new TableCellBuilder()); + // Formatting Objects for Lists + addBuilder("list-block", StandardStructureTypes.List.L); + addBuilder("list-item", StandardStructureTypes.List.LI); + addBuilder("list-item-body", StandardStructureTypes.List.LBODY); + addBuilder("list-item-label", StandardStructureTypes.List.LBL); + // Dynamic Effects: Link and Multi Formatting Objects + addBuilder("basic-link", StandardStructureTypes.InlineLevelStructure.LINK); + // Out-of-Line Formatting Objects + addBuilder("float", StandardStructureTypes.Grouping.DIV); + addBuilder("footnote", StandardStructureTypes.InlineLevelStructure.NOTE); + addBuilder("footnote-body", StandardStructureTypes.Grouping.SECT); + addBuilder("wrapper", StandardStructureTypes.InlineLevelStructure.SPAN); + addBuilder("marker", StandardStructureTypes.Grouping.PRIVATE); + + addBuilder("#PCDATA", new PlaceholderBuilder()); + } + + private static void addBuilder(String fo, StructureType structureType) { + addBuilder(fo, new DefaultStructureElementBuilder(structureType)); + } + + private static void addBuilder(String fo, StructureElementBuilder mapper) { + BUILDERS.put(fo, mapper); + } + + private interface StructureElementBuilder { + + PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, PDFFactory pdfFactory, + EventBroadcaster eventBroadcaster); + + } + + private static class DefaultStructureElementBuilder implements StructureElementBuilder { + + private final StructureType defaultStructureType; + + DefaultStructureElementBuilder(StructureType structureType) { + this.defaultStructureType = structureType; + } + + public final PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, + PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) { + String role = attributes.getValue(ROLE); + StructureType structureType; + if (role == null) { + structureType = defaultStructureType; + } else { + structureType = StandardStructureTypes.get(role); + if (structureType == null) { + structureType = defaultStructureType; + PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(role, role, + structureType.toString()); + } + } + PDFStructElem structElem = createStructureElement(parent, structureType); + setAttributes(structElem, attributes); + addKidToParent(structElem, parent, attributes); + registerStructureElement(structElem, pdfFactory, attributes); + 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, + Attributes attributes) { + 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 void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory, + Attributes attributes) { + if (structureElement.getStructureType() == Table.TH) { + String scopeAttribute = attributes.getValue(InternalElementMapping.URI, + InternalElementMapping.SCOPE); + Scope scope = (scopeAttribute == null) + ? Scope.COLUMN + : Scope.valueOf(scopeAttribute.toUpperCase(Locale.ENGLISH)); + pdfFactory.getDocument().registerStructureElement(structureElement, scope); + } else { + pdfFactory.getDocument().registerStructureElement(structureElement); + } + } + + @Override + protected void setAttributes(PDFStructElem structElem, Attributes attributes) { + String columnSpan = attributes.getValue("number-columns-spanned"); + if (columnSpan != null) { + structElem.setTableAttributeColSpan(Integer.parseInt(columnSpan)); + } + String rowSpan = attributes.getValue("number-rows-spanned"); + if (rowSpan != null) { + structElem.setTableAttributeRowSpan(Integer.parseInt(rowSpan)); + } + } + + } + + private static class PlaceholderBuilder implements StructureElementBuilder { + + public PDFStructElem build(StructureHierarchyMember parent, Attributes attributes, + PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) { + PDFStructElem elem = new PDFStructElem.Placeholder(parent); + parent.addKid(elem); + return elem; + } + + } + private PDFFactory pdfFactory; private EventBroadcaster eventBroadcaster; @@ -51,6 +293,10 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { this.pdfFactory = pdfFactory; } + void setEventBroadcaster(EventBroadcaster eventBroadcaster) { + this.eventBroadcaster = eventBroadcaster; + } + void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) { createRootStructureElement(logicalStructureHandler); } @@ -59,93 +305,53 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { assert rootStructureElement == null; PDFParentTree parentTree = logicalStructureHandler.getParentTree(); PDFStructTreeRoot structTreeRoot = pdfFactory.getDocument().makeStructTreeRoot(parentTree); - rootStructureElement = createStructureElement("root", structTreeRoot, null); - structTreeRoot.addKid(rootStructureElement); + rootStructureElement = createStructureElement("root", structTreeRoot, + new AttributesImpl(), pdfFactory, eventBroadcaster); } - void setEventBroadcaster(EventBroadcaster eventBroadcaster) { - this.eventBroadcaster = eventBroadcaster; - } + private static PDFStructElem createStructureElement(String name, StructureHierarchyMember parent, + Attributes attributes, PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) { + StructureElementBuilder builder = BUILDERS.get(name); + if (builder == null) { + // TODO is a fallback really necessary? + builder = DEFAULT_BUILDER; + } + return builder.build(parent, attributes, pdfFactory, eventBroadcaster); + } public void startPageSequence(Locale language, String role) { ancestors = new LinkedList<PDFStructElem>(); - PDFStructElem structElem = createStructureElement("page-sequence", rootStructureElement, role); + AttributesImpl attributes = new AttributesImpl(); + attributes.addAttribute("", ROLE, ROLE, XMLUtil.CDATA, role); + PDFStructElem structElem = createStructureElement("page-sequence", + rootStructureElement, attributes, pdfFactory, eventBroadcaster); if (language != null) { structElem.setLanguage(language); } - rootStructureElement.addKid(structElem); ancestors.add(structElem); } - private PDFStructElem createStructureElement(String name, PDFObject parent, String role) { - StructureType structureType = FOToPDFRoleMap.mapFormattingObject(name, role, parent, - eventBroadcaster); - if (structureType == Table.TH) { - return pdfFactory.getDocument().makeStructureElement(structureType, parent, Scope.COLUMN); - } else { - return pdfFactory.getDocument().makeStructureElement(structureType, parent); - } - } - public void endPageSequence() { } public StructureTreeElement startNode(String name, Attributes attributes) { PDFStructElem parent = ancestors.getFirst(); - String role = attributes.getValue("role"); - PDFStructElem structElem = createStructureElement(name, parent, role); - setSpanAttributes(structElem, attributes); - parent.addKid(structElem); + PDFStructElem structElem = createStructureElement(name, parent, attributes, + pdfFactory, eventBroadcaster); ancestors.addFirst(structElem); return structElem; } - private void setSpanAttributes(PDFStructElem structElem, Attributes attributes) { - String columnSpan = attributes.getValue("number-columns-spanned"); - if (columnSpan != null) { - structElem.setTableAttributeColSpan(Integer.parseInt(columnSpan)); - } - String rowSpan = attributes.getValue("number-rows-spanned"); - if (rowSpan != null) { - structElem.setTableAttributeRowSpan(Integer.parseInt(rowSpan)); - } - } - public void endNode(String name) { - removeFirstAncestor(); - } - - private void removeFirstAncestor() { ancestors.removeFirst(); } public StructureTreeElement startImageNode(String name, Attributes attributes) { - PDFStructElem parent = ancestors.getFirst(); - String role = attributes.getValue("role"); - PDFStructElem structElem = createStructureElement(name, parent, role); - parent.addKid(structElem); - String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text"); - if (altTextNode != null) { - structElem.put("Alt", altTextNode); - } else { - structElem.put("Alt", "No alternate text specified"); - } - ancestors.addFirst(structElem); - return structElem; + return startNode(name, attributes); } public StructureTreeElement startReferencedNode(String name, Attributes attributes) { - PDFStructElem parent = ancestors.getFirst(); - String role = attributes.getValue("role"); - PDFStructElem structElem; - if ("#PCDATA".equals(name)) { - structElem = new PDFStructElem.Placeholder(parent); - } else { - structElem = createStructureElement(name, parent, role); - } - parent.addKid(structElem); - ancestors.addFirst(structElem); - return structElem; + return startNode(name, attributes); } } diff --git a/src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java b/src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java new file mode 100644 index 000000000..09d5b81a2 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.pdf; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.fop.pdf.PDFArray; +import org.apache.fop.pdf.PDFObject; +import org.apache.fop.pdf.PDFStructElem; +import org.apache.fop.pdf.StructureType; + +class PageSequenceStructElem extends PDFStructElem { + + private List<PDFStructElem> regionBefores = new ArrayList<PDFStructElem>(); + + private List<PDFStructElem> regionAfters = new ArrayList<PDFStructElem>(); + + private List<PDFStructElem> regionStarts = new ArrayList<PDFStructElem>(); + + private List<PDFStructElem> regionEnds = new ArrayList<PDFStructElem>(); + + PageSequenceStructElem(PDFObject parent, StructureType structureType) { + super(parent, structureType); + } + + void addContent(String flowName, PDFStructElem content) { + if (flowName.equals("xsl-region-before")) { + regionBefores.add(content); + } else if (flowName.equals("xsl-region-after")) { + regionAfters.add(content); + } else if (flowName.equals("xsl-region-start")) { + regionStarts.add(content); + } else if (flowName.equals("xsl-region-end")) { + regionEnds.add(content); + } else { + addKid(content); + } + } + + @Override + protected boolean attachKids() { + assert !kids.isEmpty(); + PDFArray k = new PDFArray(); + addRegions(k, regionBefores); + addRegions(k, regionStarts); + addRegions(k, kids); + addRegions(k, regionEnds); + addRegions(k, regionAfters); + put("K", k); + return true; + } + + private void addRegions(PDFArray k, List<? extends PDFObject> regions) { + if (!regions.isEmpty()) { + for (PDFObject kid : regions) { + k.add(kid); + } + } + } + +} diff --git a/src/java/org/apache/fop/render/pdf/TableStructElem.java b/src/java/org/apache/fop/render/pdf/TableStructElem.java new file mode 100644 index 000000000..c44acb25c --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/TableStructElem.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.pdf; + +import org.apache.fop.pdf.PDFObject; +import org.apache.fop.pdf.PDFStructElem; +import org.apache.fop.pdf.StructureType; + +class TableStructElem extends PDFStructElem { + + private PDFStructElem tableFooter; + + public TableStructElem(PDFObject parent, StructureType structureType) { + super(parent, structureType); + } + + void addTableFooter(PDFStructElem footer) { + assert tableFooter == null; + tableFooter = footer; + } + + @Override + protected boolean attachKids() { + assert !kids.isEmpty(); + if (tableFooter != null) { + kids.add(tableFooter); + } + return super.attachKids(); + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java index 0ec5fdda6..897ed8fb8 100644 --- a/src/java/org/apache/fop/render/ps/PSDocumentHandler.java +++ b/src/java/org/apache/fop/render/ps/PSDocumentHandler.java @@ -39,6 +39,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.xmlgraphics.io.TempResourceURIGenerator; import org.apache.xmlgraphics.java2d.Dimension2DDouble; import org.apache.xmlgraphics.ps.DSCConstants; import org.apache.xmlgraphics.ps.PSDictionary; @@ -53,7 +54,6 @@ import org.apache.xmlgraphics.ps.dsc.events.DSCCommentBoundingBox; import org.apache.xmlgraphics.ps.dsc.events.DSCCommentHiResBoundingBox; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.apps.io.TempResourceURIGenerator; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; diff --git a/src/java/org/apache/fop/render/ps/PSFontUtils.java b/src/java/org/apache/fop/render/ps/PSFontUtils.java index c99bb21e1..9e810c824 100644 --- a/src/java/org/apache/fop/render/ps/PSFontUtils.java +++ b/src/java/org/apache/fop/render/ps/PSFontUtils.java @@ -38,7 +38,7 @@ import org.apache.xmlgraphics.ps.dsc.ResourceTracker; import org.apache.fop.fonts.Base14Font; import org.apache.fop.fonts.CIDFontType; -import org.apache.fop.fonts.CIDSubset; +import org.apache.fop.fonts.CIDSet; import org.apache.fop.fonts.CMapSegment; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbeddingMode; @@ -457,15 +457,17 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { // TODO /FontInfo gen.write("/CIDCount "); - CIDSubset cidSubset = font.getCIDSubset(); - int subsetSize = cidSubset.getSubsetSize(); - gen.write(subsetSize); + CIDSet cidSet = font.getCIDSet(); + int numberOfGlyphs = cidSet.getNumberOfGlyphs(); + gen.write(numberOfGlyphs); gen.writeln(" def"); gen.writeln("/GDBytes 2 def"); // TODO always 2? gen.writeln("/CIDMap [<"); int colCount = 0; int lineCount = 1; - for (int cid = 0; cid < subsetSize; cid++) { + int nextBitSet = 0; + int previousBitSet = 0; + for (int cid = 0; cid < numberOfGlyphs; cid++) { if (colCount++ == 20) { gen.newLine(); colCount = 1; @@ -478,7 +480,23 @@ public class PSFontUtils extends org.apache.xmlgraphics.ps.PSFontUtils { if (font.getEmbeddingMode() != EmbeddingMode.FULL) { gid = HexEncoder.encode(cid, 4); } else { - gid = HexEncoder.encode(cidSubset.getGlyphIndexForSubsetIndex(cid), 4); + previousBitSet = nextBitSet; + nextBitSet = cidSet.getGlyphIndices().nextSetBit(nextBitSet); + while (previousBitSet++ < nextBitSet) { + // if there are gaps in the indices we pad them with zeros + gen.write("0000"); + cid++; + if (colCount++ == 20) { + gen.newLine(); + colCount = 1; + if (lineCount++ == 800) { + gen.writeln("> <"); + lineCount = 1; + } + } + } + gid = HexEncoder.encode(nextBitSet, 4); + nextBitSet++; } gen.write(gid); } diff --git a/src/java/org/apache/fop/servlet/FopServlet.java b/src/java/org/apache/fop/servlet/FopServlet.java index 9dcf10a2b..c65b6af3b 100644 --- a/src/java/org/apache/fop/servlet/FopServlet.java +++ b/src/java/org/apache/fop/servlet/FopServlet.java @@ -41,14 +41,15 @@ import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.xmlgraphics.io.Resource; +import org.apache.xmlgraphics.io.ResourceResolver; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.FopFactoryBuilder; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.apps.io.Resource; -import org.apache.fop.apps.io.ResourceResolver; /** * Example servlet to generate a PDF from a servlet. |