Browse Source

Merged in trunk@1387627


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_XGC_URI_Resolution@1387628 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Mehdi Houshmand 11 years ago
parent
commit
c5a2f0959e
100 changed files with 2936 additions and 1683 deletions
  1. BIN
      lib/xmlgraphics-commons-1.5svn.jar
  2. 1
    1
      src/documentation/content/xdocs/dev/index.xml
  3. 3
    3
      src/documentation/content/xdocs/maillist.xml
  4. 8
    2
      src/documentation/content/xdocs/trunk/output.xml
  5. 14
    27
      src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
  6. 0
    508
      src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java
  7. 26
    11
      src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
  8. 9
    0
      src/java/org/apache/fop/afp/AFPEventProducer.java
  9. 1
    0
      src/java/org/apache/fop/afp/AFPEventProducer.xml
  10. 19
    18
      src/java/org/apache/fop/afp/DataStream.java
  11. 5
    8
      src/java/org/apache/fop/afp/Factory.java
  12. 12
    1
      src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
  13. 8
    0
      src/java/org/apache/fop/afp/fonts/CharacterSet.java
  14. 11
    14
      src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
  15. 16
    24
      src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
  16. 28
    4
      src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
  17. 6
    2
      src/java/org/apache/fop/afp/fonts/OutlineFont.java
  18. 4
    8
      src/java/org/apache/fop/afp/modca/AbstractPageObject.java
  19. 1
    1
      src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
  20. 5
    20
      src/java/org/apache/fop/afp/modca/PageGroup.java
  21. 64
    28
      src/java/org/apache/fop/afp/modca/TagLogicalElement.java
  22. 63
    0
      src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java
  23. 63
    15
      src/java/org/apache/fop/afp/util/AFPResourceAccessor.java
  24. 54
    1
      src/java/org/apache/fop/apps/io/ResourceResolverFactory.java
  25. 14
    9
      src/java/org/apache/fop/cli/CommandLineOptions.java
  26. 6
    10
      src/java/org/apache/fop/events/CompositeEventListener.java
  27. 10
    10
      src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
  28. 14
    16
      src/java/org/apache/fop/fo/FOEventHandler.java
  29. 17
    0
      src/java/org/apache/fop/fo/FONode.java
  30. 2
    1
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  31. 4
    1
      src/java/org/apache/fop/fo/pagination/Flow.java
  32. 19
    0
      src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java
  33. 1
    1
      src/java/org/apache/fop/fo/pagination/StaticContent.java
  34. 2
    2
      src/java/org/apache/fop/fonts/CIDFont.java
  35. 113
    0
      src/java/org/apache/fop/fonts/CIDFull.java
  36. 90
    0
      src/java/org/apache/fop/fonts/CIDSet.java
  37. 50
    79
      src/java/org/apache/fop/fonts/CIDSubset.java
  38. 1
    1
      src/java/org/apache/fop/fonts/DefaultFontConfig.java
  39. 7
    4
      src/java/org/apache/fop/fonts/FontCache.java
  40. 10
    8
      src/java/org/apache/fop/fonts/FontCacheManager.java
  41. 28
    9
      src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
  42. 7
    25
      src/java/org/apache/fop/fonts/FontManager.java
  43. 15
    16
      src/java/org/apache/fop/fonts/FontManagerConfigurator.java
  44. 1
    1
      src/java/org/apache/fop/fonts/FontReader.java
  45. 3
    0
      src/java/org/apache/fop/fonts/LazyFont.java
  46. 50
    19
      src/java/org/apache/fop/fonts/MultiByteFont.java
  47. 1
    1
      src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
  48. 17
    4
      src/java/org/apache/fop/layoutmgr/BreakElement.java
  49. 1
    2
      src/java/org/apache/fop/layoutmgr/PageBreaker.java
  50. 40
    40
      src/java/org/apache/fop/layoutmgr/PageProvider.java
  51. 4
    0
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  52. 2
    1
      src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
  53. 12
    10
      src/java/org/apache/fop/pdf/PDFDocument.java
  54. 76
    23
      src/java/org/apache/fop/pdf/PDFEncoding.java
  55. 31
    81
      src/java/org/apache/fop/pdf/PDFFactory.java
  56. 1
    1
      src/java/org/apache/fop/pdf/PDFFont.java
  57. 2
    1
      src/java/org/apache/fop/pdf/PDFProfile.java
  58. 18
    15
      src/java/org/apache/fop/pdf/PDFStructElem.java
  59. 2
    1
      src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
  60. 69
    0
      src/java/org/apache/fop/pdf/StandardStructureAttributes.java
  61. 137
    0
      src/java/org/apache/fop/pdf/StandardStructureTypes.java
  62. 9
    36
      src/java/org/apache/fop/pdf/StructureHierarchyMember.java
  63. 34
    0
      src/java/org/apache/fop/pdf/StructureType.java
  64. 17
    0
      src/java/org/apache/fop/pdf/VersionController.java
  65. 2
    1
      src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
  66. 4
    3
      src/java/org/apache/fop/render/afp/AFPFontConfig.java
  67. 6
    0
      src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java
  68. 23
    0
      src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java
  69. 11
    0
      src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java
  70. 1
    1
      src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java
  71. 23
    0
      src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java
  72. 98
    0
      src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java
  73. 0
    61
      src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java
  74. 3
    0
      src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java
  75. 19
    21
      src/java/org/apache/fop/render/bitmap/TIFFRenderer.java
  76. 20
    8
      src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java
  77. 16
    25
      src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java
  78. 0
    244
      src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java
  79. 1
    2
      src/java/org/apache/fop/render/pdf/PDFEventProducer.java
  80. 1
    1
      src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
  81. 276
    61
      src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
  82. 79
    0
      src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java
  83. 48
    0
      src/java/org/apache/fop/render/pdf/TableStructElem.java
  84. 24
    6
      src/java/org/apache/fop/render/ps/PSFontUtils.java
  85. 56
    0
      status.xml
  86. 115
    0
      test/events/region-body_overflow.fo
  87. 18
    45
      test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
  88. 20
    9
      test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
  89. 0
    66
      test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl
  90. 84
    0
      test/java/org/apache/fop/afp/util/AFPResourceAccessorTestCase.java
  91. 6
    1
      test/java/org/apache/fop/apps/TIFFRendererConfBuilder.java
  92. 10
    1
      test/java/org/apache/fop/events/EventChecker.java
  93. 28
    3
      test/java/org/apache/fop/events/EventProcessingTestCase.java
  94. 95
    0
      test/java/org/apache/fop/fo/pagination/LayoutMasterSetTestCase.java
  95. 181
    0
      test/java/org/apache/fop/fo/pagination/side-regions.fo
  96. 120
    0
      test/java/org/apache/fop/fonts/CIDFullTestCase.java
  97. 77
    0
      test/java/org/apache/fop/fonts/FontManagerTestCase.java
  98. 37
    0
      test/java/org/apache/fop/layoutmgr/BreakElementTestCase.java
  99. 76
    0
      test/java/org/apache/fop/pdf/PDFEncodingTestCase.java
  100. 0
    0
      test/java/org/apache/fop/pdf/PDFFactoryTestCase.java

BIN
lib/xmlgraphics-commons-1.5svn.jar View File


+ 1
- 1
src/documentation/content/xdocs/dev/index.xml View File

@@ -97,7 +97,7 @@ To review the archives, you have several options:
<li>The <link href="http://marc.theaimsgroup.com/?l=fop-dev&amp;r=1&amp;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>

+ 3
- 3
src/documentation/content/xdocs/maillist.xml View File

@@ -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&amp;r=1&amp;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.

+ 8
- 2
src/documentation/content/xdocs/trunk/output.xml View File

@@ -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>

+ 14
- 27
src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java View File

@@ -72,8 +72,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {

private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>();

private final Stack<FOEventRecorder> tableFooterRecorders = new Stack<FOEventRecorder>();

private final FOEventHandler structureTreeEventTrigger;

/** The descendants of some elements like fo:leader must be ignored. */
@@ -165,6 +163,20 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
super.endPageNumberCitationLast(pageLast);
}

@Override
public void startStatic(StaticContent staticContent) {
handleStartArtifact(staticContent);
converter.startStatic(staticContent);
super.startStatic(staticContent);
}

@Override
public void endStatic(StaticContent staticContent) {
converter.endStatic(staticContent);
handleEndArtifact(staticContent);
super.endStatic(staticContent);
}

@Override
public void startFlow(Flow fl) {
converter.startFlow(fl);
@@ -216,16 +228,11 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
@Override
public void startTable(Table tbl) {
converter.startTable(tbl);
tableFooterRecorders.push(null);
super.startTable(tbl);
}

@Override
public void endTable(Table tbl) {
FOEventRecorder tableFooterRecorder = tableFooterRecorders.pop();
if (tableFooterRecorder != null) {
tableFooterRecorder.replay(converter);
}
converter.endTable(tbl);
super.endTable(tbl);
}
@@ -256,8 +263,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {

@Override
public void startFooter(TableFooter footer) {
converters.push(converter);
converter = new FOEventRecorder();
converter.startFooter(footer);
super.startFooter(footer);
}
@@ -265,10 +270,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
@Override
public void endFooter(TableFooter footer) {
converter.endFooter(footer);
/* Replace the dummy table footer with the real one. */
tableFooterRecorders.pop();
tableFooterRecorders.push((FOEventRecorder) converter);
converter = converters.pop();
super.endFooter(footer);
}

@@ -356,20 +357,6 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
super.endListBody(listItemBody);
}

@Override
public void startStatic(StaticContent staticContent) {
handleStartArtifact(staticContent);
converter.startStatic(staticContent);
super.startStatic(staticContent);
}

@Override
public void endStatic(StaticContent statisContent) {
converter.endStatic(statisContent);
handleEndArtifact(statisContent);
super.endStatic(statisContent);
}

@Override
public void startMarkup() {
converter.startMarkup();

+ 0
- 508
src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java View File

@@ -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);
}
});
}

}

+ 26
- 11
src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java View File

@@ -55,6 +55,7 @@ import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.LayoutMasterSet;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
@@ -67,6 +68,8 @@ class StructureTreeEventTrigger extends FOEventHandler {

private StructureTreeEventHandler structureTreeEventHandler;

private LayoutMasterSet layoutMasterSet;

public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) {
this.structureTreeEventHandler = structureTreeEventHandler;
}
@@ -81,6 +84,9 @@ class StructureTreeEventTrigger extends FOEventHandler {

@Override
public void startPageSequence(PageSequence pageSeq) {
if (layoutMasterSet == null) {
layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
}
Locale locale = null;
if (pageSeq.getLanguage() != null) {
if (pageSeq.getCountry() != null) {
@@ -128,9 +134,28 @@ class StructureTreeEventTrigger extends FOEventHandler {
endElement(pageLast);
}

@Override
public void startStatic(StaticContent staticContent) {
AttributesImpl flowName = createFlowNameAttribute(staticContent.getFlowName());
startElement(staticContent, flowName);
}

private AttributesImpl createFlowNameAttribute(String flowName) {
String regionName = layoutMasterSet.getDefaultRegionNameFor(flowName);
AttributesImpl attribute = new AttributesImpl();
addNoNamespaceAttribute(attribute, Flow.FLOW_NAME, regionName);
return attribute;
}

@Override
public void endStatic(StaticContent staticContent) {
endElement(staticContent);
}

@Override
public void startFlow(Flow fl) {
startElement(fl);
AttributesImpl flowName = createFlowNameAttribute(fl.getFlowName());
startElement(fl, flowName);
}

@Override
@@ -277,16 +302,6 @@ class StructureTreeEventTrigger extends FOEventHandler {
endElement(listItemBody);
}

@Override
public void startStatic(StaticContent staticContent) {
startElement(staticContent);
}

@Override
public void endStatic(StaticContent statisContent) {
endElement(statisContent);
}

@Override
public void startLink(BasicLink basicLink) {
startElementWithID(basicLink);

+ 9
- 0
src/java/org/apache/fop/afp/AFPEventProducer.java View File

@@ -113,4 +113,13 @@ public interface AFPEventProducer extends EventProducer {
* @event.severity ERROR
*/
void invalidConfiguration(Object source, Exception e);

/**
* The characterset is missing metric information for the specified character
* @param source the event source
* @param character the character with missing metric information.
* @param charSet the character set containing missing metric information
* @event.severity WARN
*/
void charactersetMissingMetrics(Object source, char character, String charSet);
}

+ 1
- 0
src/java/org/apache/fop/afp/AFPEventProducer.xml View File

@@ -8,4 +8,5 @@
<message key="fontConfigMissing">The mandatory configuation node: '{missingConfig}' was not found at {location}.</message>
<message key="characterSetNameInvalid">The character set given has an invalid name. [ Reason: {msg} ]</message>
<message key="codePageNotFound">The code page for an AFP font cannot be found.[ Reason: {e}]</message>
<message key="charactersetMissingMetrics">Metric information is missing for the glyph `{character}` in the characterset `{charSet}`. Using space increment width.</message>
</catalogue>

+ 19
- 18
src/java/org/apache/fop/afp/DataStream.java View File

@@ -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;
}

+ 5
- 8
src/java/org/apache/fop/afp/Factory.java View File

@@ -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;
}


+ 12
- 1
src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java View File

@@ -19,6 +19,8 @@

package org.apache.fop.afp.fonts;

import org.apache.fop.afp.AFPEventProducer;

/**
* A font defined as a set of lines and curves as opposed to a bitmap font. An
* outline font can be scaled to any size and otherwise transformed more easily
@@ -29,16 +31,25 @@ public abstract class AbstractOutlineFont extends AFPFont {
/** The character set for this font */
protected CharacterSet charSet = null;

private final AFPEventProducer eventProducer;

/**
* Constructor for an outline font.
*
* @param name the name of the font
* @param embeddable sets whether or not this font is to be embedded
* @param charSet the chracter set
* @param eventProducer The object to handle any events which occur from the object.
*/
public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet) {
public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet,
AFPEventProducer eventProducer) {
super(name, embeddable);
this.charSet = charSet;
this.eventProducer = eventProducer;
}

AFPEventProducer getAFPEventProducer() {
return eventProducer;
}

/**

+ 8
- 0
src/java/org/apache/fop/afp/fonts/CharacterSet.java View File

@@ -363,4 +363,12 @@ public class CharacterSet {
return getCharacterSetOrientation().getEmSpaceIncrement();
}

/**
* Returns the nominal character increment.
* @return the nominal character increment
*/
public int getNominalCharIncrement() {
return getCharacterSetOrientation().getNominalCharIncrement();
}

}

+ 11
- 14
src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java View File

@@ -236,9 +236,9 @@ public abstract class CharacterSetBuilder {
CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer)
throws IOException {
// check for cached version of the characterset
String descriptor = characterSetName + "_" + encoding + "_" + codePageName;
CharacterSet characterSet = (CharacterSet) characterSetsCache.get(descriptor);
URI charSetURI = accessor.resolveURI(characterSetName);
String cacheKey = charSetURI.toASCIIString() + "_" + characterSetName + "_" + codePageName;
CharacterSet characterSet = (CharacterSet) characterSetsCache.get(cacheKey);
if (characterSet != null) {
return characterSet;
}
@@ -257,6 +257,8 @@ public abstract class CharacterSetBuilder {
* chracter global identifier.
*/
Map<String, String> codePage;
// TODO: This could have performance implications if several threads want to use the
// codePagesCache to retrieve different codepages.
synchronized (codePagesCache) {
codePage = codePagesCache.get(codePageName);

@@ -308,7 +310,7 @@ public abstract class CharacterSetBuilder {
} finally {
closeInputStream(inputStream);
}
characterSetsCache.put(descriptor, characterSet);
characterSetsCache.put(cacheKey, characterSet);
return characterSet;
}

@@ -446,20 +448,15 @@ public abstract class CharacterSetBuilder {
position++;

if (position == 26) {

position = 0;

int orientation = determineOrientation(fnoData[2]);
// Space Increment
int space = ((fnoData[8] & 0xFF ) << 8) + (fnoData[9] & 0xFF);
// Em-Space Increment
int em = ((fnoData[14] & 0xFF ) << 8) + (fnoData[15] & 0xFF);

CharacterSetOrientation cso = new CharacterSetOrientation(orientation);
cso.setSpaceIncrement(space);
cso.setEmSpaceIncrement(em);
orientations.add(cso);
int spaceIncrement = getUBIN(fnoData, 8);
int emIncrement = getUBIN(fnoData, 14);
int nominalCharacterIncrement = getUBIN(fnoData, 20);

orientations.add(new CharacterSetOrientation(orientation, spaceIncrement,
emIncrement, nominalCharacterIncrement));
}
}
return orientations.toArray(EMPTY_CSO_ARRAY);

+ 16
- 24
src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java View File

@@ -60,7 +60,7 @@ public class CharacterSetOrientation {
/**
* The character widths in the character set (indexed using Unicode codepoints)
*/
private int[] charsWidths = null;
private int[] charsWidths;

/**
* The height of lowercase letters
@@ -77,25 +77,26 @@ public class CharacterSetOrientation {
*/
private char lastChar;


/**
* The character set orientation
*/
private int orientation = 0;

/** The character set orientation */
private final int orientation;
/** space increment */
private int spaceIncrement;
private final int spaceIncrement;
/** em space increment */
private int emSpaceIncrement = -1;

private final int emSpaceIncrement;
/** Nominal Character Increment */
private final int nomCharIncrement;

/**
* Constructor for the CharacterSetOrientation, the orientation is
* expressed as the degrees rotation (i.e 0, 90, 180, 270)
* @param orientation the character set orientation
*/
public CharacterSetOrientation(int orientation) {
public CharacterSetOrientation(int orientation, int spaceIncrement, int emSpaceIncrement,
int nomCharIncrement) {
this.orientation = orientation;
this.spaceIncrement = spaceIncrement;
this.emSpaceIncrement = emSpaceIncrement;
this.nomCharIncrement = nomCharIncrement;
charsWidths = new int[256];
Arrays.fill(charsWidths, -1);
}
@@ -283,14 +284,6 @@ public class CharacterSetOrientation {
return this.spaceIncrement;
}

/**
* Sets the space increment.
* @param value the space increment
*/
public void setSpaceIncrement(int value) {
this.spaceIncrement = value;
}

/**
* Returns the em space increment.
* @return the em space increment
@@ -300,11 +293,10 @@ public class CharacterSetOrientation {
}

/**
* Sets the em space increment.
* @param value the em space increment
* Returns the nominal character increment.
* @return the nominal character increment
*/
public void setEmSpaceIncrement(int value) {
this.emSpaceIncrement = value;
public int getNominalCharIncrement() {
return this.nomCharIncrement;
}

}

+ 28
- 4
src/java/org/apache/fop/afp/fonts/DoubleByteFont.java View File

@@ -23,6 +23,11 @@ import java.lang.Character.UnicodeBlock;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.afp.AFPEventProducer;

/**
* Implementation of AbstractOutlineFont that supports double-byte fonts (CID Keyed font (Type 0)).
* The width of characters that are not prescribed a width metrics in the font resource use
@@ -31,7 +36,9 @@ import java.util.Set;
*/
public class DoubleByteFont extends AbstractOutlineFont {

//private static final Log LOG = LogFactory.getLog(DoubleByteFont.class);
private static final Log log = LogFactory.getLog(DoubleByteFont.class);

private final Set<Integer> charsProcessed;

//See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet
//TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.)
@@ -49,9 +56,12 @@ public class DoubleByteFont extends AbstractOutlineFont {
* @param name the name of the font
* @param embeddable whether or not this font is embeddable
* @param charSet the character set
* @param eventProducer Handles any AFP related events
*/
public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet) {
super(name, embeddable, charSet);
public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet,
AFPEventProducer eventProducer) {
super(name, embeddable, charSet, eventProducer);
charsProcessed = new HashSet<Integer>();
}

/** {@inheritDoc} */
@@ -60,16 +70,30 @@ public class DoubleByteFont extends AbstractOutlineFont {
try {
charWidth = charSet.getWidth(toUnicodeCodepoint(character));
} catch (IllegalArgumentException e) {
if (!charsProcessed.contains(character)) {
charsProcessed.add(character);
getAFPEventProducer().charactersetMissingMetrics(this, (char)character,
charSet.getName().trim());
}
// We shall try and handle characters that have no mapped width metric in font resource
charWidth = -1;
}

if (charWidth == -1) {
charWidth = inferCharWidth(character);
charWidth = getDefaultCharacterWidth(character);
}
return charWidth * size;
}

private int getDefaultCharacterWidth(int character) {
int nominalCharIncrement = charSet.getNominalCharIncrement();
if (nominalCharIncrement > 0) {
return nominalCharIncrement;
} else {
return inferCharWidth(character);
}
}

private int inferCharWidth(int character) {

//Is this character an ideograph?

+ 6
- 2
src/java/org/apache/fop/afp/fonts/OutlineFont.java View File

@@ -19,6 +19,8 @@

package org.apache.fop.afp.fonts;

import org.apache.fop.afp.AFPEventProducer;

/**
* Default implementation of AbstractOutlineFont.
*/
@@ -29,9 +31,11 @@ public class OutlineFont extends AbstractOutlineFont {
* @param name font's name
* @param embeddable whether or not this font is embeddable
* @param charSet font's character set
* @param eventProducer Handles any AFP related events
*/
public OutlineFont(String name, boolean embeddable, CharacterSet charSet) {
super(name, embeddable, charSet);
public OutlineFont(String name, boolean embeddable, CharacterSet charSet,
AFPEventProducer eventProducer) {
super(name, embeddable, charSet, eventProducer);
}

}

+ 4
- 8
src/java/org/apache/fop/afp/modca/AbstractPageObject.java View File

@@ -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.
*

+ 1
- 1
src/java/org/apache/fop/afp/modca/IncludedResourceObject.java View File

@@ -34,7 +34,7 @@ import org.apache.fop.afp.util.AFPResourceUtil;
*/
public class IncludedResourceObject extends AbstractNamedAFPObject {

private AFPResourceAccessor resourceAccessor;
private final AFPResourceAccessor resourceAccessor;
private URI uri;

/**

+ 5
- 20
src/java/org/apache/fop/afp/modca/PageGroup.java View File

@@ -35,36 +35,26 @@ 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;
}
}

+ 64
- 28
src/java/org/apache/fop/afp/modca/TagLogicalElement.java View File

@@ -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;
}


}
}

+ 63
- 0
src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java View File

@@ -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;
}

}

+ 63
- 15
src/java/org/apache/fop/afp/util/AFPResourceAccessor.java View File

@@ -24,6 +24,9 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.io.InternalResourceResolver;

/**
@@ -31,8 +34,11 @@ import org.apache.fop.apps.io.InternalResourceResolver;
*/
public final class AFPResourceAccessor {

private static final Log log = LogFactory.getLog(AFPResourceAccessor.class);

private final InternalResourceResolver resourceResolver;
private final String baseURI;
private final URI baseURI;
private final URIResolver uriResolver;

/**
* Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. This
@@ -45,7 +51,23 @@ public final class AFPResourceAccessor {
*/
public AFPResourceAccessor(InternalResourceResolver resourceResolver, String baseURI) {
this.resourceResolver = resourceResolver;
this.baseURI = baseURI;
URI actualBaseURI = null;
URIResolver uriResolver;
if (baseURI == null) {
actualBaseURI = null;
uriResolver = new NullBaseURIResolver();
} else {
try {
actualBaseURI = InternalResourceResolver.getBaseURI(baseURI);
uriResolver = new BaseURIResolver();
} catch (URISyntaxException use) {
log.error("The URI given \"" + baseURI + "\" is invalid: " + use.getMessage());
actualBaseURI = null;
uriResolver = new NullBaseURIResolver();
}
}
this.baseURI = actualBaseURI;
this.uriResolver = uriResolver;
}

/**
@@ -57,18 +79,6 @@ public final class AFPResourceAccessor {
this(resourceResolver, null);
}

private URI getResourceURI(URI uri) {
if (baseURI == null) {
return uri;
}
try {
URI baseURI = InternalResourceResolver.getBaseURI(this.baseURI);
return baseURI.resolve(uri);
} catch (URISyntaxException use) {
return uri;
}
}

/**
* Creates an {@link InputStream} given a URI.
*
@@ -77,6 +87,44 @@ public final class AFPResourceAccessor {
* @throws IOException if an I/O error occurs while creating the InputStream.
*/
public InputStream createInputStream(URI uri) throws IOException {
return resourceResolver.getResource(getResourceURI(uri));
return resourceResolver.getResource(uriResolver.resolveURI(uri));
}

/**
* Returns the resolved URI, given the URI of a resource.
*
* @param uri the resource URI
* @return the resolved URI
*/
public URI resolveURI(String uri) {
return uriResolver.resolveURI(uri);
}

private interface URIResolver {
URI resolveURI(URI uri);

URI resolveURI(String uri);
}

private static final class NullBaseURIResolver implements URIResolver {

public URI resolveURI(URI uri) {
return uri;
}

public URI resolveURI(String uri) {
return URI.create("./" + uri.trim());
}
}

private final class BaseURIResolver implements URIResolver {

public URI resolveURI(URI uri) {
return baseURI.resolve(uri);
}

public URI resolveURI(String uri) {
return baseURI.resolve(uri.trim());
}
}
}

+ 54
- 1
src/java/org/apache/fop/apps/io/ResourceResolverFactory.java View File

@@ -83,6 +83,15 @@ public final class ResourceResolverFactory {
return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver);
}

/**
* 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
* 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
*/
public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder(
ResourceResolver defaultResolver) {
return new SchemaAwareResourceResolverBuilderImpl(defaultResolver);
@@ -99,10 +108,12 @@ public final class ResourceResolverFactory {
new NormalResourceResolver());
}

/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException {
return delegate.getResource(uri);
}

/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
return delegate.getOutputStream(uri);
}
@@ -125,6 +136,7 @@ public final class ResourceResolverFactory {
return TempResourceURIGenerator.isTempUri(uri);
}

/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException {
if (isTempUri(uri)) {
return tempResourceResolver.getResource(uri.getPath());
@@ -133,6 +145,7 @@ public final class ResourceResolverFactory {
}
}

/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
if (isTempUri(uri)) {
return tempResourceResolver.getOutputStream(uri.getPath());
@@ -140,7 +153,6 @@ public final class ResourceResolverFactory {
return defaultResourceResolver.getOutputStream(uri);
}
}

}

private static class DefaultTempResourceResolver implements TempResourceResolver {
@@ -150,10 +162,12 @@ public final class ResourceResolverFactory {
return file;
}

/** {@inheritDoc} */
public Resource getResource(String id) throws IOException {
return new Resource(getTempFile(id).toURI().toURL().openStream());
}

/** {@inheritDoc} */
public OutputStream getOutputStream(String id) throws IOException {
File file = getTempFile(id);
if (file.createNewFile()) {
@@ -196,19 +210,52 @@ public final class ResourceResolverFactory {
}
}

/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException {
return getResourceResolverForSchema(uri).getResource(uri);
}

/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
return getResourceResolverForSchema(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
* 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);
* 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 {

/**
* Register a schema with its respective {@link ResourceResolver}. This resolver will be
* used as the only resolver for the specified schema.
*
* @param schema the schema to be used with the given resolver
* @param resourceResolver the resource resolver
*/
void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver);

/**
* Builds a {@link ResourceResolver} that will delegate to the respective resource resolver
* when a registered URI schema is given
*
* @return a resolver that delegates to the appropriate schema resolver
*/
ResourceResolver build();
}

@@ -218,10 +265,12 @@ public final class ResourceResolverFactory {
private static final SchemaAwareResourceResolverBuilder INSTANCE
= new CompletedSchemaAwareResourceResolverBuilder();

/** {@inheritDoc} */
public ResourceResolver build() {
throw new IllegalStateException("Resource resolver already built");
}

/** {@inheritDoc} */
public void registerResourceResolverForSchema(String schema,
ResourceResolver resourceResolver) {
throw new IllegalStateException("Resource resolver already built");
@@ -240,11 +289,13 @@ public final class ResourceResolverFactory {
this.defaultResolver = defaultResolver;
}

/** {@inheritDoc} */
public void registerResourceResolverForSchema(String schema,
ResourceResolver resourceResolver) {
schemaHandlingResourceResolvers.put(schema, resourceResolver);
}

/** {@inheritDoc} */
public ResourceResolver build() {
return new SchemaAwareResourceResolver(
Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver);
@@ -261,11 +312,13 @@ public final class ResourceResolverFactory {
this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver);
}

/** {@inheritDoc} */
public void registerResourceResolverForSchema(String schema,
ResourceResolver resourceResolver) {
delegate.registerResourceResolverForSchema(schema, resourceResolver);
}

/** {@inheritDoc} */
public ResourceResolver build() {
ResourceResolver resourceResolver = delegate.build();
delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE;

+ 14
- 9
src/java/org/apache/fop/cli/CommandLineOptions.java View File

@@ -43,6 +43,7 @@ import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopConfParser;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FopFactoryBuilder;
import org.apache.fop.apps.FopFactoryConfig;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFEncryptionManager;
@@ -117,7 +118,7 @@ public class CommandLineOptions {
/* rendering options (for the user agent) */
private Map renderingOptions = new java.util.HashMap();
/* target resolution (for the user agent) */
private int targetResolution = 0;
private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION;

private boolean strictValidation = true;
/* control memory-conservation policy */
@@ -138,7 +139,7 @@ public class CommandLineOptions {

private boolean flushCache = false;

private URI baseURI = new File(".").toURI();
private URI baseURI = new File(".").getAbsoluteFile().toURI();

/**
* Construct a command line option object.
@@ -420,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;
}
}
@@ -468,7 +469,7 @@ public class CommandLineOptions {
this.useStdIn = true;
} else {
fofile = new File(filename);
baseURI = fofile.toURI();
baseURI = getBaseURI(fofile);
}
return 1;
}
@@ -498,12 +499,16 @@ public class CommandLineOptions {
this.useStdIn = true;
} else {
xmlfile = new File(filename);
baseURI = xmlfile.toURI();
baseURI = getBaseURI(xmlfile);
}
return 1;
}
}

private URI getBaseURI(File file) {
return file.getAbsoluteFile().getParentFile().toURI();
}

private int parseAWTOutputOption(String[] args, int i) throws FOPException {
setOutputMode(MimeConstants.MIME_FOP_AWT_PREVIEW);
return 0;
@@ -730,7 +735,7 @@ public class CommandLineOptions {
this.useStdIn = true;
} else {
fofile = new File(filename);
baseURI = fofile.toURI();
baseURI = getBaseURI(fofile);
}
} else if (outputmode == null) {
outputmode = MimeConstants.MIME_PDF;
@@ -789,7 +794,7 @@ public class CommandLineOptions {
this.useStdIn = true;
} else {
areatreefile = new File(filename);
baseURI = areatreefile.toURI();
baseURI = getBaseURI(areatreefile);
}
return 1;
}
@@ -806,7 +811,7 @@ public class CommandLineOptions {
this.useStdIn = true;
} else {
iffile = new File(filename);
baseURI = iffile.toURI();
baseURI = getBaseURI(iffile);
}
return 1;
}
@@ -823,7 +828,7 @@ public class CommandLineOptions {
this.useStdIn = true;
} else {
imagefile = new File(filename);
baseURI = imagefile.toURI();
baseURI = getBaseURI(imagefile);
}
return 1;
}

+ 6
- 10
src/java/org/apache/fop/events/CompositeEventListener.java View File

@@ -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);
}
}

+ 10
- 10
src/java/org/apache/fop/fo/DelegatingFOEventHandler.java View File

@@ -142,6 +142,16 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler {
delegate.endPageNumberCitationLast(pageLast);
}

@Override
public void startStatic(StaticContent staticContent) {
delegate.startStatic(staticContent);
}

@Override
public void endStatic(StaticContent statisContent) {
delegate.endStatic(statisContent);
}

@Override
public void startFlow(Flow fl) {
delegate.startFlow(fl);
@@ -292,16 +302,6 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler {
delegate.endListBody(listItemBody);
}

@Override
public void startStatic(StaticContent staticContent) {
delegate.startStatic(staticContent);
}

@Override
public void endStatic(StaticContent statisContent) {
delegate.endStatic(statisContent);
}

@Override
public void startMarkup() {
delegate.startMarkup();

+ 14
- 16
src/java/org/apache/fop/fo/FOEventHandler.java View File

@@ -192,6 +192,20 @@ public abstract class FOEventHandler {
public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
}

/**
* Process start of a Static.
* @param staticContent StaticContent that is starting
*/
public void startStatic(StaticContent staticContent) {
}

/**
* Process end of a Static.
* @param staticContent StaticContent that is ending
*/
public void endStatic(StaticContent staticContent) {
}

/**
* This method is called to indicate the start of a new fo:flow
* or fo:static-content.
@@ -409,22 +423,6 @@ public abstract class FOEventHandler {
public void endListBody(ListItemBody listItemBody) {
}

// Static Regions
/**
* Process start of a Static.
* @param staticContent StaticContent that is starting
*/
public void startStatic(StaticContent staticContent) {
}

/**
* Process end of a Static.
* @param staticContent StaticContent that is ending
*/
public void endStatic(StaticContent staticContent) {
}


/**
* Process start of a Markup.
*/

+ 17
- 0
src/java/org/apache/fop/fo/FONode.java View File

@@ -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;
@@ -601,6 +602,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

+ 2
- 1
src/java/org/apache/fop/fo/FOPropertyMapping.java View File

@@ -26,6 +26,7 @@ import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.LengthBase;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.properties.BackgroundPositionShorthand;
import org.apache.fop.fo.properties.BorderSpacingShorthandParser;
import org.apache.fop.fo.properties.BorderWidthPropertyMaker;
@@ -2267,7 +2268,7 @@ public final class FOPropertyMapping implements Constants {
m = new StringProperty.Maker(PR_FLOW_NAME);
m.setInherited(false);
m.setDefault("");
addPropertyMaker("flow-name", m);
addPropertyMaker(Flow.FLOW_NAME, m);

// force-page-count
m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT);

+ 4
- 1
src/java/org/apache/fop/fo/pagination/Flow.java View File

@@ -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,

+ 19
- 0
src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java View File

@@ -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;
}
}


+ 1
- 1
src/java/org/apache/fop/fo/pagination/StaticContent.java View File

@@ -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);
}

+ 2
- 2
src/java/org/apache/fop/fonts/CIDFont.java View File

@@ -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 ----
/**

+ 113
- 0
src/java/org/apache/fop/fonts/CIDFull.java View File

@@ -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();
}

}

+ 90
- 0
src/java/org/apache/fop/fonts/CIDSet.java View File

@@ -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 subsetIndex 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&lt;Integer, Integer&gt; 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();

}

+ 50
- 79
src/java/org/apache/fop/fonts/CIDSubset.java View File

@@ -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&lt;Integer, Integer&gt; 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;
}

}

+ 1
- 1
src/java/org/apache/fop/fonts/DefaultFontConfig.java View File

@@ -89,7 +89,7 @@ public final class DefaultFontConfig implements FontConfig {
} else {
this.strict = strict;
this.fontInfoCfg = cfg.getChild("fonts", false);
instance = new DefaultFontConfig(cfg.getChild("auto-detect", false) != null);
instance = new DefaultFontConfig(fontInfoCfg.getChild("auto-detect", false) != null);
parse();
}
}

+ 7
- 4
src/java/org/apache/fop/fonts/FontCache.java View File

@@ -53,7 +53,7 @@ public final class FontCache implements Serializable {
* Serialization Version UID. Change this value if you want to make sure the
* user's cache file is purged after an update.
*/
private static final long serialVersionUID = 605232520271754719L;
private static final long serialVersionUID = 9129238336422194339L;

/** logging instance */
private static Log log = LogFactory.getLog(FontCache.class);
@@ -65,7 +65,7 @@ public final class FontCache implements Serializable {
private static final String DEFAULT_CACHE_FILENAME = "fop-fonts.cache";

/** has this cache been changed since it was last read? */
private transient boolean changed = false;
private transient boolean changed;

/** change lock */
private final boolean[] changeLock = new boolean[1];
@@ -73,12 +73,14 @@ public final class FontCache implements Serializable {
/**
* master mapping of font url -> font info. This needs to be a list, since a
* TTC file may contain more than 1 font.
* @serial
*/
private Map<String, CachedFontFile> fontfileMap = null;

/**
* mapping of font url -> file modified date (for all fonts that have failed
* to load)
* @serial
*/
private Map<String, Long> failedFontMap = null;

@@ -139,6 +141,7 @@ public final class FontCache implements Serializable {
*
* @return the font cache deserialized from the file (or null if no cache
* file exists or if it could not be read)
* @deprecated use {@link #loadFrom(File)} instead
*/
public static FontCache load() {
return loadFrom(getDefaultCacheFile(false));
@@ -190,8 +193,8 @@ public final class FontCache implements Serializable {
/**
* Writes the font cache to disk.
*
* @throws FOPException
* fop exception
* @throws FOPException fop exception
* @deprecated use {@link #saveTo(File)} instead
*/
public void save() throws FOPException {
saveTo(getDefaultCacheFile(true));

+ 10
- 8
src/java/org/apache/fop/fonts/FontCacheManager.java View File

@@ -19,7 +19,7 @@

package org.apache.fop.fonts;

import java.io.File;
import java.net.URI;

import org.apache.fop.apps.FOPException;

@@ -29,25 +29,27 @@ 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;
}

+ 28
- 9
src/java/org/apache/fop/fonts/FontCacheManagerFactory.java View File

@@ -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
}
}
}

+ 7
- 25
src/java/org/apache/fop/fonts/FontManager.java View File

@@ -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();
}

/**

+ 15
- 16
src/java/org/apache/fop/fonts/FontManagerConfigurator.java View File

@@ -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;
@@ -72,6 +71,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 +91,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;

+ 1
- 1
src/java/org/apache/fop/fonts/FontReader.java View File

@@ -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);

+ 3
- 0
src/java/org/apache/fop/fonts/LazyFont.java View File

@@ -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();
}


+ 50
- 19
src/java/org/apache/fop/fonts/MultiByteFont.java View File

@@ -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();
}

/**

+ 1
- 1
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java View File

@@ -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 {

+ 17
- 4
src/java/org/apache/fop/layoutmgr/BreakElement.java View File

@@ -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 */

+ 1
- 2
src/java/org/apache/fop/layoutmgr/PageBreaker.java View File

@@ -95,8 +95,7 @@ public class PageBreaker extends AbstractBreaker {
return new PageBreakingLayoutListener() {

public void notifyOverflow(int part, int amount, FObj obj) {
Page p = pageProvider.getPage(
false, part, PageProvider.RELTO_CURRENT_ELEMENT_LIST);
Page p = pageProvider.getPageFromColumnIndex(part);
RegionBody body = (RegionBody)p.getSimplePageMaster().getRegion(
Region.FO_REGION_BODY);
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(

+ 40
- 40
src/java/org/apache/fop/layoutmgr/PageProvider.java View File

@@ -151,18 +151,37 @@ public class PageProvider implements Constants {
return this.lastReportedBPD;
}

// Wish there were a more elegant way to do this in Java
private int[] getColIndexAndColCount(int index) {
private static class Column {

final Page page;

final int pageIndex;

final int colIndex;

final int columnCount;

Column(Page page, int pageIndex, int colIndex, int columnCount) {
this.page = page;
this.pageIndex = pageIndex;
this.colIndex = colIndex;
this.columnCount = columnCount;
}

}

private Column getColumn(int index) {
int columnCount = 0;
int colIndex = startColumnOfCurrentElementList + index;
int pageIndex = -1;
Page page;
do {
colIndex -= columnCount;
pageIndex++;
Page page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
} while (colIndex >= columnCount);
return new int[] {colIndex, columnCount};
return new Column(page, pageIndex, colIndex, columnCount);
}

/**
@@ -173,22 +192,13 @@ public class PageProvider implements Constants {
* than, equal to or greater than the IPD of the following part
*/
public int compareIPDs(int index) {
int columnCount = 0;
int colIndex = startColumnOfCurrentElementList + index;
int pageIndex = -1;
Page page;
do {
colIndex -= columnCount;
pageIndex++;
page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
} while (colIndex >= columnCount);
if (colIndex + 1 < columnCount) {
Column column = getColumn(index);
if (column.colIndex + 1 < column.columnCount) {
// Next part is a column on same page => same IPD
return 0;
} else {
Page nextPage = getPage(false, pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST);
return page.getPageViewport().getBodyRegion().getIPD()
Page nextPage = getPage(false, column.pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST);
return column.page.getPageViewport().getBodyRegion().getIPD()
- nextPage.getPageViewport().getBodyRegion().getIPD();
}
}
@@ -199,7 +209,7 @@ public class PageProvider implements Constants {
* @return {@code true} if the break starts a new page
*/
boolean startPage(int index) {
return getColIndexAndColCount(index)[0] == 0;
return getColumn(index).colIndex == 0;
}

/**
@@ -208,8 +218,8 @@ public class PageProvider implements Constants {
* @return {@code true} if the break ends a page
*/
boolean endPage(int index) {
int[] colIndexAndColCount = getColIndexAndColCount(index);
return colIndexAndColCount[0] == colIndexAndColCount[1] - 1;
Column column = getColumn(index);
return column.colIndex == column.columnCount - 1;
}

/**
@@ -219,7 +229,7 @@ public class PageProvider implements Constants {
* @return the number of columns
*/
int getColumnCount(int index) {
return getColIndexAndColCount(index)[1];
return getColumn(index).columnCount;
}

/**
@@ -229,24 +239,12 @@ public class PageProvider implements Constants {
* @return the requested part index
*/
public int getStartingPartIndexForLastPage(int partCount) {
int result = 0;
int idx = 0;
int pageIndex = 0;
int colIndex = startColumnOfCurrentElementList;
Page page = getPage(
false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
while (idx < partCount) {
if ((colIndex >= page.getPageViewport().getCurrentSpan().getColumnCount())) {
colIndex = 0;
pageIndex++;
page = getPage(
false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
result = idx;
}
colIndex++;
idx++;
}
return result;
int lastPartIndex = partCount - 1;
return lastPartIndex - getColumn(lastPartIndex).colIndex;
}

Page getPageFromColumnIndex(int columnIndex) {
return getColumn(columnIndex).page;
}

/**
@@ -291,7 +289,9 @@ public class PageProvider implements Constants {
log.trace("last page requested: " + index);
}
}
while (intIndex >= cachedPages.size()) {
if (intIndex > cachedPages.size()) {
throw new UnsupportedOperationException("Cannot handle holes in page cache");
} else if (intIndex == cachedPages.size()) {
if (log.isTraceEnabled()) {
log.trace("Caching " + index);
}

+ 4
- 0
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

@@ -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()) {

+ 2
- 1
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java View File

@@ -39,6 +39,7 @@ 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 +63,7 @@ import org.apache.fop.util.BreakUtil;
* the render background.
*/
public class TableLayoutManager extends BlockStackingLayoutManager
implements ConditionalElementListener {
implements ConditionalElementListener, BreakOpportunity {

/**
* logging instance

+ 12
- 10
src/java/org/apache/fop/pdf/PDFDocument.java View File

@@ -37,6 +37,7 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope;
import org.apache.fop.pdf.xref.CrossReferenceStream;
import org.apache.fop.pdf.xref.CrossReferenceTable;
import org.apache.fop.pdf.xref.TrailerDictionary;
@@ -354,19 +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(PDFName structureType, PDFObject parent) {
PDFStructElem structElem = new PDFStructElem(parent, structureType);
public void registerStructureElement(PDFStructElem structElem) {
assignObjectNumber(structElem);
structureTreeElements.add(structElem);
return 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 void registerStructureElement(PDFStructElem structElem, Scope scope) {
registerStructureElement(structElem);
versionController.addTableHeaderScopeAttribute(structElem, scope);
}

/**

+ 76
- 23
src/java/org/apache/fop/pdf/PDFEncoding.java View File

@@ -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.
*
@@ -73,6 +76,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")
@@ -82,6 +117,15 @@ public class PDFEncoding extends PDFDictionary {
return PREDEFINED_ENCODINGS.contains(name);
}

/**
* 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.
@@ -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));
}
}


+ 31
- 81
src/java/org/apache/fop/pdf/PDFFactory.java View File

@@ -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);

+ 1
- 1
src/java/org/apache/fop/pdf/PDFFont.java View File

@@ -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));
}
}

+ 2
- 1
src/java/org/apache/fop/pdf/PDFProfile.java View File

@@ -202,7 +202,8 @@ public class PDFProfile {
PDFDictionary markInfo = getDocument().getRoot().getMarkInfo();
if (markInfo == null) {
throw new PDFConformanceException(format(
"{0} requires the MarkInfo dictionary to be present", getPDFAMode()));
"{0} requires that the accessibility option in the configuration file be enabled",
getPDFAMode()));
}
if (!Boolean.TRUE.equals(markInfo.get("Marked"))) {
throw new PDFConformanceException(format(err,

+ 18
- 15
src/java/org/apache/fop/pdf/PDFStructElem.java View File

@@ -26,14 +26,16 @@ import java.util.List;
import java.util.Locale;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.pdf.StandardStructureAttributes.Table;
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 static final PDFName TABLE = new PDFName("Table");
private StructureType structureType;

private PDFStructElem parentElement;

@@ -50,12 +52,17 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement
* @param parent parent of this element
* @param structureType the structure type of this element
*/
PDFStructElem(PDFObject parent, PDFName structureType) {
public PDFStructElem(PDFObject parent, StructureType structureType) {
this(parent);
this.structureType = structureType;
put("S", structureType.getName());
setParent(parent);
}

private PDFStructElem(PDFObject parent) {
if (parent instanceof PDFStructElem) {
parentElement = (PDFStructElem) parent;
}
put("S", structureType);
setParent(parent);
}

/**
@@ -80,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>();
@@ -113,8 +121,8 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement
*
* @return the value of the S entry
*/
public PDFName getStructureType() {
return (PDFName) get("S");
public StructureType getStructureType() {
return structureType;
}

/**
@@ -201,7 +209,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement

private void setTableAttributeRowColumnSpan(String typeSpan, int span) {
PDFDictionary attribute = new PDFDictionary();
attribute.put("O", TABLE);
attribute.put("O", Table.NAME);
attribute.put(typeSpan, span);
if (attributes == null) {
attributes = new ArrayList<PDFDictionary>(2);
@@ -228,13 +236,8 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement
}
}

/**
* Constructor
* @param parent -
* @param name -
*/
public Placeholder(PDFObject parent, String name) {
super(parent, new PDFName(name));
public Placeholder(PDFObject parent) {
super(parent);
}
}


+ 2
- 1
src/java/org/apache/fop/pdf/PDFStructTreeRoot.java View File

@@ -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);
}

+ 69
- 0
src/java/org/apache/fop/pdf/StandardStructureAttributes.java View File

@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.pdf;

/**
* Standard attributes, as defined in section 10.7.5 of the PDF Reference, Fourth edition (PDF 1.5).
*/
public final class StandardStructureAttributes {

public static final class Table {

/**
* The name to use as an attribute owner. This is the value of the 'O' entry in
* the attribute's dictionary.
*/
public static final PDFName NAME = new PDFName("Table");

public static enum Scope {
ROW("Row"),
COLUMN("Column"),
BOTH("Both");

private final PDFName name;

private Scope(String name) {
this.name = new PDFName(name);
}

/**
* Returns the name of this attribute.
*
* @return a name suitable for use as a value in the attribute's dictionary
*/
public PDFName getName() {
return name;
}

/**
* Sets the given scope on the given table header element.
*/
static void addScopeAttribute(PDFStructElem th, Scope scope) {
PDFDictionary scopeAttribute = new PDFDictionary();
scopeAttribute.put("O", Table.NAME);
scopeAttribute.put("Scope", scope.getName());
th.put("A", scopeAttribute);
}
}
}

private StandardStructureAttributes() { }

}

+ 137
- 0
src/java/org/apache/fop/pdf/StandardStructureTypes.java View File

@@ -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.pdf;

import java.util.HashMap;
import java.util.Map;

/**
* Standard structure types, as defined in section 10.7.4 of the PDF Reference, Fourth Edition (PDF 1.5).
*/
public final class StandardStructureTypes {

public static final class Grouping {

public static final StructureType DOCUMENT = new StructureTypeImpl("Document");
public static final StructureType PART = new StructureTypeImpl("Part");
public static final StructureType ART = new StructureTypeImpl("Art");
public static final StructureType SECT = new StructureTypeImpl("Sect");
public static final StructureType DIV = new StructureTypeImpl("Div");
public static final StructureType BLOCK_QUOTE = new StructureTypeImpl("BlockQuote");
public static final StructureType CAPTION = new StructureTypeImpl("Caption");
public static final StructureType TOC = new StructureTypeImpl("TOC");
public static final StructureType TOCI = new StructureTypeImpl("TOCI");
public static final StructureType INDEX = new StructureTypeImpl("Index");
public static final StructureType NON_STRUCT = new StructureTypeImpl("NonStruct");
public static final StructureType PRIVATE = new StructureTypeImpl("Private");
}

public static final class Paragraphlike {
public static final StructureType H = new StructureTypeImpl("H");
public static final StructureType H1 = new StructureTypeImpl("H1");
public static final StructureType H2 = new StructureTypeImpl("H2");
public static final StructureType H3 = new StructureTypeImpl("H3");
public static final StructureType H4 = new StructureTypeImpl("H4");
public static final StructureType H5 = new StructureTypeImpl("H5");
public static final StructureType H6 = new StructureTypeImpl("H6");
public static final StructureType P = new StructureTypeImpl("P");
}

public static final class List {
public static final StructureType L = new StructureTypeImpl("L");
public static final StructureType LI = new StructureTypeImpl("LI");
public static final StructureType LBL = new StructureTypeImpl("Lbl");
public static final StructureType LBODY = new StructureTypeImpl("LBody");
}

public static final class Table {
public static final StructureType TABLE = new StructureTypeImpl("Table");
public static final StructureType TR = new StructureTypeImpl("TR");
public static final StructureType TH = new StructureTypeImpl("TH");
public static final StructureType TD = new StructureTypeImpl("TD");
public static final StructureType THEAD = new StructureTypeImpl("THead");
public static final StructureType TBODY = new StructureTypeImpl("TBody");
public static final StructureType TFOOT = new StructureTypeImpl("TFoot");
}

public static final class InlineLevelStructure {
public static final StructureType SPAN = new StructureTypeImpl("Span");
public static final StructureType QUOTE = new StructureTypeImpl("Quote");
public static final StructureType NOTE = new StructureTypeImpl("Note");
public static final StructureType REFERENCE = new StructureTypeImpl("Reference");
public static final StructureType BIB_ENTRY = new StructureTypeImpl("BibEntry");
public static final StructureType CODE = new StructureTypeImpl("Code");
public static final StructureType LINK = new StructureTypeImpl("Link");
public static final StructureType ANNOT = new StructureTypeImpl("Annot");
}

public static final class RubyOrWarichu {
public static final StructureType RUBY = new StructureTypeImpl("Ruby");
public static final StructureType RB = new StructureTypeImpl("RB");
public static final StructureType RT = new StructureTypeImpl("RT");
public static final StructureType RP = new StructureTypeImpl("RP");
public static final StructureType WARICHU = new StructureTypeImpl("Warichu");
public static final StructureType WT = new StructureTypeImpl("WT");
public static final StructureType WP = new StructureTypeImpl("WP");
}

public static final class Illustration {
public static final StructureType FIGURE = new StructureTypeImpl("Figure");
public static final StructureType FORMULA = new StructureTypeImpl("Formula");
public static final StructureType FORM = new StructureTypeImpl("Form");
}

private static class StructureTypeImpl implements StructureType {

private final PDFName name;

protected StructureTypeImpl(String name) {
this.name = new PDFName(name);
StandardStructureTypes.STRUCTURE_TYPES.put(name, this);
}

public PDFName getName() {
return name;
}

@Override
public String toString() {
return name.toString().substring(1);
}

}

private static final Map<String, StructureType> STRUCTURE_TYPES = new HashMap<String, StructureType>();

private StandardStructureTypes() { }

/**
* Returns the standard structure type of the given name.
*
* @param name the name of a structure type, case sensitive. For example, Document,
* Sect, H1, etc.
* @return the corresponding {@code StructureType} instance, or {@code null} if the given
* name does not correspond to a standard structure type
*/
public static StructureType get(String name) {
return STRUCTURE_TYPES.get(name);
}

}

src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java → src/java/org/apache/fop/pdf/StructureHierarchyMember.java View File

@@ -17,48 +17,21 @@

/* $Id$ */

package org.apache.fop.afp.modca;
package org.apache.fop.pdf;

/**
* The TagLogicalElementBean provides a bean for holding the attributes of
* a tag logical element as key value pairs.
* <p/>
* 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 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;
}
public abstract class StructureHierarchyMember extends PDFDictionary {

/**
* Getter for the value attribute.
* Adds the given object to the array of kids.
*
* @return the value
* @param kid an object to be added to the K entry
*/
public String getValue() {
return value;
}
public abstract void addKid(PDFObject kid);

}

+ 34
- 0
src/java/org/apache/fop/pdf/StructureType.java View File

@@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.pdf;

/**
* A structure type, as defined in Section 10.6.2 of the PDF Reference, fourth edition (PDF 1.5).
*/
public interface StructureType {

/**
* Returns the name of this structure type.
*
* @return the name object identifying this structure type
*/
PDFName getName();

}

+ 17
- 0
src/java/org/apache/fop/pdf/VersionController.java View File

@@ -19,6 +19,8 @@

package org.apache.fop.pdf;

import org.apache.fop.pdf.StandardStructureAttributes.Table.Scope;

/**
* An abstraction that controls the mutability of the PDF version for a document.
*/
@@ -47,6 +49,8 @@ public abstract class VersionController {
*/
public abstract void setPDFVersion(Version version);

abstract void addTableHeaderScopeAttribute(PDFStructElem th, Scope scope);

@Override
public String toString() {
return version.toString();
@@ -67,6 +71,13 @@ public abstract class VersionController {
public void setPDFVersion(Version version) {
throw new IllegalStateException("Cannot change the version of this PDF document.");
}

@Override
void addTableHeaderScopeAttribute(PDFStructElem th, Scope scope) {
if (super.version.compareTo(Version.V1_4) > 0) {
Scope.addScopeAttribute(th, scope);
}
}
}

/**
@@ -91,6 +102,12 @@ public abstract class VersionController {
doc.getRoot().setVersion(version);
}
}

@Override
void addTableHeaderScopeAttribute(PDFStructElem th, Scope scope) {
setPDFVersion(Version.V1_5);
Scope.addScopeAttribute(th, scope);
}
}

/**

+ 2
- 1
src/java/org/apache/fop/render/afp/AFPDocumentHandler.java View File

@@ -318,7 +318,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(

+ 4
- 3
src/java/org/apache/fop/render/afp/AFPFontConfig.java View File

@@ -329,8 +329,8 @@ public final class AFPFontConfig implements FontConfig {
AFPResourceAccessor accessor = getAccessor(resourceResolver);
CharacterSet characterSet = CharacterSetBuilder.getDoubleByteInstance().buildDBCS(
characterset, super.codePage, super.encoding, charsetType, accessor, eventProducer);
return getFontInfo(new DoubleByteFont(super.codePage, super.embeddable, characterSet),
this);
return getFontInfo(new DoubleByteFont(super.codePage, super.embeddable, characterSet,
eventProducer), this);
}
}

@@ -365,7 +365,8 @@ public final class AFPFontConfig implements FontConfig {
characterSet = CharacterSetBuilder.getSingleByteInstance().buildSBCS(
characterset, super.codePage, super.encoding, accessor, eventProducer);
}
return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet), this);
return getFontInfo(new OutlineFont(super.name, super.embeddable, characterSet,
eventProducer), this);
}
}


+ 6
- 0
src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.java View File

@@ -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())

+ 23
- 0
src/java/org/apache/fop/render/afp/extensions/AFPPageSetup.java View File

@@ -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.
*/
@@ -47,6 +49,27 @@ public class AFPPageSetup extends AFPExtensionAttachment {
/** defines where to place the extension in the generated file */
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.
*

+ 11
- 0
src/java/org/apache/fop/render/afp/extensions/AFPPageSetupElement.java View File

@@ -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) {

+ 1
- 1
src/java/org/apache/fop/render/bitmap/AbstractBitmapDocumentHandler.java View File

@@ -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));

+ 23
- 0
src/java/org/apache/fop/render/bitmap/BitmapRenderingSettings.java View File

@@ -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);
}
}

+ 98
- 0
src/java/org/apache/fop/render/bitmap/TIFFCompressionValue.java View File

@@ -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;
}
}

+ 0
- 61
src/java/org/apache/fop/render/bitmap/TIFFCompressionValues.java View File

@@ -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;
}
}

+ 3
- 0
src/java/org/apache/fop/render/bitmap/TIFFDocumentHandler.java View File

@@ -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} */

+ 19
- 21
src/java/org/apache/fop/render/bitmap/TIFFRenderer.java View File

@@ -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;
}
}

+ 20
- 8
src/java/org/apache/fop/render/bitmap/TIFFRendererConfig.java View File

@@ -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;
}

+ 16
- 25
src/java/org/apache/fop/render/bitmap/TIFFRendererConfigurator.java View File

@@ -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));
}
}


+ 0
- 244
src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java View File

@@ -1,244 +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.HashMap;
import java.util.Map;

import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFObject;
import org.apache.fop.pdf.PDFStructElem;

/**
* This class provides the standard mappings from Formatting Objects to PDF structure types.
*/
final class FOToPDFRoleMap {

/**
* Standard structure types defined by the PDF Reference, Fourth Edition (PDF 1.5).
*/
private static final Map<String, PDFName> STANDARD_STRUCTURE_TYPES
= new HashMap<String, PDFName>();

private static final Map<String, Mapper> DEFAULT_MAPPINGS
= new java.util.HashMap<String, Mapper>();

private static final PDFName THEAD;
private static final PDFName NON_STRUCT;

static {
// Create PDFNames for the standard structure types
// Table 10.18: Grouping elements
addStructureType("Document");
addStructureType("Part");
addStructureType("Art");
addStructureType("Sect");
addStructureType("Div");
addStructureType("BlockQuote");
addStructureType("Caption");
addStructureType("TOC");
addStructureType("TOCI");
addStructureType("Index");
addStructureType("NonStruct");
addStructureType("Private");
// Table 10.20: Paragraphlike elements
addStructureType("H");
addStructureType("H1");
addStructureType("H2");
addStructureType("H3");
addStructureType("H4");
addStructureType("H5");
addStructureType("H6");
addStructureType("P");
// Table 10.21: List elements
addStructureType("L");
addStructureType("LI");
addStructureType("Lbl");
addStructureType("LBody");
// Table 10.22: Table elements
addStructureType("Table");
addStructureType("TR");
addStructureType("TH");
addStructureType("TD");
addStructureType("THead");
addStructureType("TBody");
addStructureType("TFoot");
// Table 10.23: Inline-level structure elements
addStructureType("Span");
addStructureType("Quote");
addStructureType("Note");
addStructureType("Reference");
addStructureType("BibEntry");
addStructureType("Code");
addStructureType("Link");
addStructureType("Annot");
// Table 10.24: Ruby and Warichu elements
addStructureType("Ruby");
addStructureType("RB");
addStructureType("RT");
addStructureType("RP");
addStructureType("Warichu");
addStructureType("WT");
addStructureType("WP");
// Table 10.25: Illustration elements
addStructureType("Figure");
addStructureType("Formula");
addStructureType("Form");

NON_STRUCT = STANDARD_STRUCTURE_TYPES.get("NonStruct");
assert NON_STRUCT != null;
THEAD = STANDARD_STRUCTURE_TYPES.get("THead");
assert THEAD != null;

// Create the standard mappings
// Declarations and Pagination and Layout Formatting Objects
addMapping("root", "Document");
addMapping("page-sequence", "Part");
addMapping("flow", "Sect");
addMapping("static-content", "Sect");
// Block-level Formatting Objects
addMapping("block", "P");
addMapping("block-container", "Div");
// Inline-level Formatting Objects
addMapping("character", "Span");
addMapping("external-graphic", "Figure");
addMapping("instream-foreign-object", "Figure");
addMapping("inline", "Span");
addMapping("inline-container", "Div");
addMapping("page-number", "Quote");
addMapping("page-number-citation", "Quote");
addMapping("page-number-citation-last", "Quote");
// Formatting Objects for Tables
addMapping("table-and-caption", "Div");
addMapping("table", "Table");
addMapping("table-caption", "Caption");
addMapping("table-header", "THead");
addMapping("table-footer", "TFoot");
addMapping("table-body", "TBody");
addMapping("table-row", "TR");
addMapping("table-cell", new TableCellMapper());
// Formatting Objects for Lists
addMapping("list-block", "L");
addMapping("list-item", "LI");
addMapping("list-item-body", "LBody");
addMapping("list-item-label", "Lbl");
// Dynamic Effects: Link and Multi Formatting Objects
addMapping("basic-link", "Link");
// Out-of-Line Formatting Objects
addMapping("float", "Div");
addMapping("footnote", "Note");
addMapping("footnote-body", "Sect");
addMapping("wrapper", "Span");
addMapping("marker", "Private");
}

private static void addStructureType(String structureType) {
STANDARD_STRUCTURE_TYPES.put(structureType, new PDFName(structureType));
}

private static void addMapping(String fo, String structureType) {
PDFName type = STANDARD_STRUCTURE_TYPES.get(structureType);
assert type != null;
addMapping(fo, new SimpleMapper(type));
}

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 PDFName mapFormattingObject(String fo, String role,
PDFObject parent, EventBroadcaster eventBroadcaster) {
PDFName type = null;
if (role == null) {
type = getDefaultMappingFor(fo, parent);
} else {
type = STANDARD_STRUCTURE_TYPES.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 PDFName getDefaultMappingFor(String fo, PDFObject parent) {
Mapper mapper = DEFAULT_MAPPINGS.get(fo);
if (mapper != null) {
return mapper.getStructureType(parent);
} else {
return NON_STRUCT;
}
}

private interface Mapper {
PDFName getStructureType(PDFObject parent);
}

private static class SimpleMapper implements Mapper {

private PDFName structureType;

public SimpleMapper(PDFName structureType) {
this.structureType = structureType;
}

public PDFName getStructureType(PDFObject parent) {
return structureType;
}

}

private static class TableCellMapper implements Mapper {

public PDFName getStructureType(PDFObject parent) {
PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem();
//TODO What to do with cells from table-footer? Currently they are mapped on TD.
PDFName type;
if (THEAD.equals(grandParent.getStructureType())) {
type = STANDARD_STRUCTURE_TYPES.get("TH");
} else {
type = STANDARD_STRUCTURE_TYPES.get("TD");
}
assert type != null;
return type;
}

}

private FOToPDFRoleMap() { }
}

+ 1
- 2
src/java/org/apache/fop/render/pdf/PDFEventProducer.java View File

@@ -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.

+ 1
- 1
src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java View File

@@ -132,7 +132,7 @@ class PDFLogicalStructureHandler {
? structureTreeElement.getParentStructElem()
: structureTreeElement;
pageParentTreeArray.add(parent);
String type = parent.getStructureType().toString();
String type = parent.getStructureType().getName().toString();
int mcid = pageParentTreeArray.length() - 1;
return new MarkedContentInfo(type, mcid, structureTreeElement);
}

+ 276
- 61
src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java View File

@@ -21,25 +21,272 @@ package org.apache.fop.render.pdf;

import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.pdf.PDFFactory;
import org.apache.fop.pdf.PDFName;
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 PDFFactory pdfFactory;
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 PDFLogicalStructureHandler logicalStructureHandler;
private static class DefaultStructureElementBuilder implements StructureElementBuilder {

private final StructureType defaultStructureType;

DefaultStructureElementBuilder(StructureType structureType) {
this.defaultStructureType = structureType;
}

public final PDFStructElem build(StructureHierarchyMember parent, Attributes attributes,
PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) {
String role = attributes.getValue(ROLE);
StructureType structureType;
if (role == null) {
structureType = defaultStructureType;
} else {
structureType = StandardStructureTypes.get(role);
if (structureType == null) {
structureType = defaultStructureType;
PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(role, role,
structureType.toString());
}
}
PDFStructElem structElem = createStructureElement(parent, structureType);
setAttributes(structElem, attributes);
addKidToParent(structElem, parent, attributes);
registerStructureElement(structElem, pdfFactory);
return structElem;
}

protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
StructureType structureType) {
return new PDFStructElem(parent, structureType);
}

protected void setAttributes(PDFStructElem structElem, Attributes attributes) {
}

protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent,
Attributes attributes) {
parent.addKid(kid);
}

protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) {
pdfFactory.getDocument().registerStructureElement(structureElement);
}

}

private static class PageSequenceBuilder extends DefaultStructureElementBuilder {

PageSequenceBuilder() {
super(StandardStructureTypes.Grouping.PART);
}

@Override
protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
StructureType structureType) {
return new PageSequenceStructElem(parent, structureType);
}

}

private static class RegionBuilder extends DefaultStructureElementBuilder {

RegionBuilder() {
super(StandardStructureTypes.Grouping.SECT);
}

@Override
protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent,
Attributes attributes) {
String flowName = attributes.getValue(Flow.FLOW_NAME);
((PageSequenceStructElem) parent).addContent(flowName, kid);
}

}

private static class ImageBuilder extends DefaultStructureElementBuilder {

ImageBuilder() {
super(StandardStructureTypes.Illustration.FIGURE);
}

@Override
protected void setAttributes(PDFStructElem structElem, Attributes attributes) {
String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text");
if (altTextNode == null) {
altTextNode = "No alternate text specified";
}
structElem.put("Alt", altTextNode);
}

}

private static class TableBuilder extends DefaultStructureElementBuilder {

TableBuilder() {
super(StandardStructureTypes.Table.TABLE);
}

@Override
protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
StructureType structureType) {
return new TableStructElem(parent, structureType);
}
}

private static class TableFooterBuilder extends DefaultStructureElementBuilder {

public TableFooterBuilder() {
super(StandardStructureTypes.Table.TFOOT);
}

@Override
protected void addKidToParent(PDFStructElem kid, StructureHierarchyMember parent,
Attributes attributes) {
((TableStructElem) parent).addTableFooter(kid);
}
}

private static class TableCellBuilder extends DefaultStructureElementBuilder {

TableCellBuilder() {
super(StandardStructureTypes.Table.TD);
}

@Override
protected PDFStructElem createStructureElement(StructureHierarchyMember parent,
StructureType structureType) {
PDFStructElem grandParent = ((PDFStructElem) parent).getParentStructElem();
//TODO What to do with cells from table-footer? Currently they are mapped on TD.
if (grandParent.getStructureType() == StandardStructureTypes.Table.THEAD) {
structureType = StandardStructureTypes.Table.TH;
} else {
structureType = StandardStructureTypes.Table.TD;
}
return super.createStructureElement(parent, structureType);
}

@Override
protected void registerStructureElement(PDFStructElem structureElement, PDFFactory pdfFactory) {
if (structureElement.getStructureType() == Table.TH) {
pdfFactory.getDocument().registerStructureElement(structureElement, Scope.COLUMN);
} else {
pdfFactory.getDocument().registerStructureElement(structureElement);
}
}

@Override
protected void setAttributes(PDFStructElem structElem, Attributes attributes) {
String columnSpan = attributes.getValue("number-columns-spanned");
if (columnSpan != null) {
structElem.setTableAttributeColSpan(Integer.parseInt(columnSpan));
}
String rowSpan = attributes.getValue("number-rows-spanned");
if (rowSpan != null) {
structElem.setTableAttributeRowSpan(Integer.parseInt(rowSpan));
}
}

}

private static class PlaceholderBuilder implements StructureElementBuilder {

public PDFStructElem build(StructureHierarchyMember parent, Attributes attributes,
PDFFactory pdfFactory, EventBroadcaster eventBroadcaster) {
PDFStructElem elem = new PDFStructElem.Placeholder(parent);
parent.addKid(elem);
return elem;
}

}

private PDFFactory pdfFactory;

private EventBroadcaster eventBroadcaster;

@@ -51,97 +298,65 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler {
this.pdfFactory = pdfFactory;
}

void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
this.eventBroadcaster = eventBroadcaster;
}

void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) {
this.logicalStructureHandler = logicalStructureHandler;
createRootStructureElement();
createRootStructureElement(logicalStructureHandler);
}

private void createRootStructureElement() {
private void createRootStructureElement(PDFLogicalStructureHandler logicalStructureHandler) {
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) {
PDFName structureType = FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster);
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, name);
} else {
structElem = createStructureElement(name, parent, role);
}
parent.addKid(structElem);
ancestors.addFirst(structElem);
return structElem;
return startNode(name, attributes);
}

}

+ 79
- 0
src/java/org/apache/fop/render/pdf/PageSequenceStructElem.java View File

@@ -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);
}
}
}

}

+ 48
- 0
src/java/org/apache/fop/render/pdf/TableStructElem.java View File

@@ -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();
}

}

+ 24
- 6
src/java/org/apache/fop/render/ps/PSFontUtils.java View File

@@ -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);
}

+ 56
- 0
status.xml View File

@@ -62,6 +62,62 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
<action context="Fonts" dev="MH" type="add" fixes-bug="53868" importance="low" due-to="Luis Bernardo">
Full font embedding in PDF
</action>
<action context="Renderers" dev="PH" type="add" fixes-bug="53865" importance="low">
Added configuration for RowPerStrip configuration in the Tiff renderer.
RowsPerStrip can be configured to 1 or to the total # of rows.
See docs for fop.xconf configuration details.
</action>
<action context="Layout" dev="VH" type="fix" fixes-bug="53598" due-to="Robert Meyer">
Always set the breakClass field to a legal value in BreakElement, so as to avoid
IllegalArgumentExceptions in other parts of the code.
</action>
<action context="Layout" dev="VH" type="fix" fixes-bug="45715" due-to="Luis Bernardo">
Restored support for break-before on fo:table.
</action>
<action context="Layout" dev="VH" type="fix" fixes-bug="53827">
When an fo:block has a non-zero value for its text-indent property and is broken over two
pages of different widths, then the first line on the second page is missing one word and
appears indented.
</action>
<action context="Renderers" dev="MH" type="fix" fixes-bug="53790">
Prevented the TIFF configurator from overriding the Bitmap configurator unless CCITT
compression is enabled.
</action>
<action context="Renderers" dev="MH" type="fix" fixes-bug="53786">
Removed the Attribute Qualifier on TLEs as they aren't used.
</action>
<action context="Renderers" dev="MH" type="fix" fixes-bug="48954" due-to="PH">
Support for character encoding of TLEs in AFP output
</action>
<action context="Renderers" dev="VH" type="fix" fixes-bug="53778">
When PDF accessibility is enabled, the contents for the different regions must appear in the
proper order in the structure tree.
</action>
<action context="Renderers" dev="MH" type="fix" fixes-bug="53766" due-to="Robert Meyer">
Remove StandardEncoding as the encoding type from fonts used in the PDF renderer
</action>
<action context="Fonts" dev="MH" type="fix" fixes-bug="53685">
Cached AFP charactersets have more unique keys preventing the two characters with
but different binaries conflicting.
</action>
<action context="Fonts" dev="MH" type="fix" fixes-bug="53657" due-to="Robert Meyer">
AFP fonts default to the nominal character increment to font metrics when glyph info
is missing from the characterset.
</action>
<action context="Layout" dev="VH" type="fix" fixes-bug="53688">
Wrong page number reported when a column overflows the region-body in a multi-column
document.
</action>
<action context="Renderers" dev="VH" type="add" fixes-bug="53639">
When PDF accessibility is enabled, the Scope attribute must be present in the structure tree
for table header elements.
</action>
<action context="Fonts" dev="MH" type="add" fixes-bug="53600" due-to="Robert Meyer">
Added an event if a glyph and its metric information does not exist in the character set
</action>
<action context="Renderers" dev="VH" type="add" fixes-bug="53596">
When PDF accessibility is enabled, the structure tree must contain information about the
number of columns or rows spanned by a table cell.

+ 115
- 0
test/events/region-body_overflow.fo View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="80pt" page-width="530pt" margin="10pt" margin-bottom="0">
<fo:region-body margin-bottom="20pt" column-count="5" column-gap="10pt"/>
<fo:region-after extent="15pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt">
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="center"><fo:page-number/></fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">

<fo:block>Page 1 Column 1 Line 1</fo:block>
<fo:block>Page 1 Column 1 Line 2</fo:block>
<fo:block>Page 1 Column 1 Line 3</fo:block>
<fo:block>Page 1 Column 1 Line 4</fo:block>
<fo:block>Page 1 Column 1 Line 5</fo:block>
<fo:block>Page 1 Column 2 Line 1</fo:block>
<fo:block>Page 1 Column 2 Line 2</fo:block>
<fo:block>Page 1 Column 2 Line 3</fo:block>
<fo:block>Page 1 Column 2 Line 4</fo:block>
<fo:block>Page 1 Column 2 Line 5</fo:block>
<fo:block>Page 1 Column 3 Line 1</fo:block>
<fo:block>Page 1 Column 3 Line 2</fo:block>
<fo:block>Page 1 Column 3 Line 3</fo:block>
<fo:block>Page 1 Column 3 Line 4</fo:block>
<fo:block>Page 1 Column 3 Line 5</fo:block>
<fo:block>Page 1 Column 4 Line 1</fo:block>
<fo:block>Page 1 Column 4 Line 2</fo:block>
<fo:block>Page 1 Column 4 Line 3</fo:block>
<fo:block>Page 1 Column 4 Line 4</fo:block>
<fo:block>Page 1 Column 4 Line 5</fo:block>
<fo:block-container height="55pt" background-color="#F0F0F0">
<fo:block>Page 1 Column 5 Line 1</fo:block>
<fo:block>Page 1 Column 5 Line 2</fo:block>
<fo:block>Page 1 Column 5 Line 3</fo:block>
<fo:block>Page 1 Column 5 Line 4</fo:block>
<fo:block>Page 1 Column 5 Line 5</fo:block>
</fo:block-container>

<fo:block break-before="page">Page 2 Column 1 Line 1</fo:block>
<fo:block>Page 2 Column 1 Line 2</fo:block>
<fo:block>Page 2 Column 1 Line 3</fo:block>
<fo:block>Page 2 Column 1 Line 4</fo:block>
<fo:block>Page 2 Column 1 Line 5</fo:block>
<fo:block>Page 2 Column 2 Line 1</fo:block>
<fo:block>Page 2 Column 2 Line 2</fo:block>
<fo:block>Page 2 Column 2 Line 3</fo:block>
<fo:block>Page 2 Column 2 Line 4</fo:block>
<fo:block>Page 2 Column 2 Line 5</fo:block>
<fo:block>Page 2 Column 3 Line 1</fo:block>
<fo:block>Page 2 Column 3 Line 2</fo:block>
<fo:block>Page 2 Column 3 Line 3</fo:block>
<fo:block>Page 2 Column 3 Line 4</fo:block>
<fo:block>Page 2 Column 3 Line 5</fo:block>
<fo:block>Page 2 Column 4 Line 1</fo:block>
<fo:block>Page 2 Column 4 Line 2</fo:block>
<fo:block>Page 2 Column 4 Line 3</fo:block>
<fo:block>Page 2 Column 4 Line 4</fo:block>
<fo:block>Page 2 Column 4 Line 5</fo:block>
<fo:block>Page 2 Column 5 Line 1</fo:block>
<fo:block>Page 2 Column 5 Line 2</fo:block>
<fo:block>Page 2 Column 5 Line 3</fo:block>
<fo:block>Page 2 Column 5 Line 4</fo:block>
<fo:block>Page 2 Column 5 Line 5</fo:block>

<fo:block>Page 3 Column 1 Line 1</fo:block>
<fo:block>Page 3 Column 1 Line 2</fo:block>
<fo:block>Page 3 Column 1 Line 3</fo:block>
<fo:block>Page 3 Column 1 Line 4</fo:block>
<fo:block>Page 3 Column 1 Line 5</fo:block>
<fo:block>Page 3 Column 2 Line 1</fo:block>
<fo:block>Page 3 Column 2 Line 2</fo:block>
<fo:block>Page 3 Column 2 Line 3</fo:block>
<fo:block>Page 3 Column 2 Line 4</fo:block>
<fo:block>Page 3 Column 2 Line 5</fo:block>
<fo:block>Page 3 Column 3 Line 1</fo:block>
<fo:block>Page 3 Column 3 Line 2</fo:block>
<fo:block>Page 3 Column 3 Line 3</fo:block>
<fo:block>Page 3 Column 3 Line 4</fo:block>
<fo:block>Page 3 Column 3 Line 5</fo:block>
<fo:block>Page 3 Column 4 Line 1</fo:block>
<fo:block>Page 3 Column 4 Line 2</fo:block>
<fo:block>Page 3 Column 4 Line 3</fo:block>
<fo:block>Page 3 Column 4 Line 4</fo:block>
<fo:block>Page 3 Column 4 Line 5</fo:block>
<fo:block>Page 3 Column 5 Line 1</fo:block>
<fo:block>Page 3 Column 5 Line 2</fo:block>
<fo:block>Page 3 Column 5 Line 3</fo:block>
<fo:block>Page 3 Column 5 Line 4</fo:block>
<fo:block>Page 3 Column 5 Line 5</fo:block>

</fo:flow>
</fo:page-sequence>
</fo:root>

+ 18
- 45
test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java View File

@@ -19,8 +19,6 @@

package org.apache.fop.accessibility.fo;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

@@ -34,7 +32,6 @@ import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.custommonkey.xmlunit.Diff;
@@ -57,9 +54,17 @@ import org.apache.fop.fotreetest.DummyFOEventHandler;

public class FO2StructureTreeConverterTestCase {

private interface FOLoader {
private static class FOLoader {

InputStream getFoInputStream();
private final String resourceName;

FOLoader(String resourceName) {
this.resourceName = resourceName;
}

public InputStream getFoInputStream() {
return getResource(resourceName);
}
}

private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence";
@@ -68,62 +73,30 @@ public class FO2StructureTreeConverterTestCase {

@Test
public void testCompleteDocument() throws Exception {
foLoader = new FOLoader() {
public InputStream getFoInputStream() {
return getResource("/org/apache/fop/fo/complete_document.fo");
}
};
testConverter();
testConverter("/org/apache/fop/fo/complete_document.fo");
}

@Test
public void testTableFooters() throws Exception {
foLoader = new FOLoader() {
public InputStream getFoInputStream() {
return getResource("table-footers.fo");
}
};
testConverter();
}

@Test
public void testCompleteContentWrappedInTableFooter() throws Exception {
Source xslt = new StreamSource(getResource("wrapCompleteDocumentInTableFooter.xsl"));
Transformer transformer = createTransformer(xslt);
InputStream originalFO = getResource("/org/apache/fop/fo/complete_document.fo");
ByteArrayOutputStream transformedFoOutput = new ByteArrayOutputStream();
transformer.transform(new StreamSource(originalFO), new StreamResult(transformedFoOutput));
final byte[] transformedFoOutputBytes = transformedFoOutput.toByteArray();
foLoader = new FOLoader() {
public InputStream getFoInputStream() {
return new ByteArrayInputStream(transformedFoOutputBytes);
}
};
testConverter();
testConverter("table-footers.fo");
}

@Test
public void testArtifact() throws Exception {
foLoader = new FOLoader() {

public InputStream getFoInputStream() {
return getResource("artifact.fo");
}
};
testConverter();
testConverter("artifact.fo");
}

private Transformer createTransformer(Source xslt) throws TransformerFactoryConfigurationError,
TransformerConfigurationException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
return transformerFactory.newTransformer(xslt);
@Test
public void testSideRegions() throws Exception {
testConverter("/org/apache/fop/fo/pagination/side-regions.fo");
}

private static InputStream getResource(String name) {
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name);
}

private void testConverter() throws Exception {
private void testConverter(String foResourceName) throws Exception {
foLoader = new FOLoader(foResourceName);
DOMResult expectedStructureTree = loadExpectedStructureTree();
DOMResult actualStructureTree = buildActualStructureTree();
final Diff diff = createDiff(expectedStructureTree, actualStructureTree);

+ 20
- 9
test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl View File

@@ -50,6 +50,25 @@
<xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="fo:static-content/@flow-name|fo:flow/@flow-name">
<xsl:choose>
<xsl:when test=". = 'xsl-region-body' or
. = 'xsl-region-before' or
. = 'xsl-region-after' or
. = 'xsl-region-start' or
. = 'xsl-region-end' or
. = 'xsl-before-float-separator' or
. = 'xsl-footnote-separator'">
<xsl:copy/>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="{local-name()}">
<xsl:value-of select="concat('xsl-', local-name(//*[@region-name = current()]))"/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<!-- Block-level Formatting Objects -->
<xsl:template match="fo:block|fo:block-container">
<xsl:call-template name="copy"/>
@@ -73,15 +92,7 @@
<xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="fo:table">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*[name() != 'fo:table-footer']"/>
<xsl:apply-templates select="fo:table-footer"/>
</xsl:copy>
</xsl:template>

<xsl:template match="fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell">
<xsl:template match="fo:table|fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell">
<xsl:call-template name="copy"/>
</xsl:template>


+ 0
- 66
test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl View File

@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:template match="@*|node()" name="copy">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>


<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="500pt" page-width="300pt" margin="20pt">
<fo:region-body margin-top="20pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:apply-templates select="//fo:page-sequence"/>
</fo:root>
</xsl:template>

<xsl:template match="fo:page-sequence">
<fo:page-sequence master-reference="page">
<xsl:apply-templates select="fo:flow"/>
</fo:page-sequence>
</xsl:template>

<xsl:template match="fo:flow">
<xsl:copy>
<xsl:apply-templates select="@*[not(starts-with(name(), 'space-before'))]"/>
<fo:table width="100%" table-layout="fixed">
<fo:table-footer>
<fo:table-cell background-color="#F0F0F0">
<xsl:apply-templates select="@*[starts-with(name(), 'space-before')]"/>
<xsl:apply-templates select="*"/>
</fo:table-cell>
</fo:table-footer>
<fo:table-body>
<fo:table-cell>
<fo:block>The content below is in the table footer.</fo:block>
</fo:table-cell>
</fo:table-body>
</fo:table>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

+ 84
- 0
test/java/org/apache/fop/afp/util/AFPResourceAccessorTestCase.java View File

@@ -0,0 +1,84 @@
/*
* 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.afp.util;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import org.apache.fop.apps.io.InternalResourceResolver;

public class AFPResourceAccessorTestCase {

private InternalResourceResolver nullBaseResourceResolver;
private InternalResourceResolver absoluteBaseResourceResolver;
private InternalResourceResolver relativeBaseResourceResolver;
private final URI absoluteBaseURI = URI.create("this:///purely.for.testing");
private final URI relativeBaseURI = URI.create("./this.is.purely.for.testing");
private AFPResourceAccessor nullBaseURISut;
private AFPResourceAccessor absoluteBaseURISut;
private AFPResourceAccessor relativeBaseURISut;

@Before
public void setUp() {
nullBaseResourceResolver = mock(InternalResourceResolver.class);
absoluteBaseResourceResolver = mock(InternalResourceResolver.class);
relativeBaseResourceResolver = mock(InternalResourceResolver.class);
nullBaseURISut = new AFPResourceAccessor(nullBaseResourceResolver);
absoluteBaseURISut = new AFPResourceAccessor(absoluteBaseResourceResolver,
absoluteBaseURI.toASCIIString());
relativeBaseURISut = new AFPResourceAccessor(relativeBaseResourceResolver,
relativeBaseURI.toASCIIString());
}

@Test
public void testCreateInputStream() throws IOException, URISyntaxException {
URI testURI = URI.create("test");
nullBaseURISut.createInputStream(testURI);
verify(nullBaseResourceResolver).getResource(testURI);

absoluteBaseURISut.createInputStream(testURI);
verify(absoluteBaseResourceResolver).getResource(getActualURI(absoluteBaseURI, testURI));

relativeBaseURISut.createInputStream(testURI);
verify(relativeBaseResourceResolver).getResource(getActualURI(relativeBaseURI, testURI));
}

private URI getActualURI(URI baseURI, URI testURI) throws URISyntaxException {
return InternalResourceResolver.getBaseURI(baseURI.toASCIIString()).resolve(testURI);
}

@Test
public void testResolveURI() throws URISyntaxException {
String testURI = "anotherTestURI";
assertEquals(URI.create("./" + testURI), nullBaseURISut.resolveURI(testURI));

assertEquals(getActualURI(absoluteBaseURI, URI.create(testURI)),
absoluteBaseURISut.resolveURI(testURI));

assertEquals(getActualURI(relativeBaseURI, URI.create(testURI)),
relativeBaseURISut.resolveURI(testURI));
}
}

+ 6
- 1
test/java/org/apache/fop/apps/TIFFRendererConfBuilder.java View File

@@ -20,7 +20,7 @@
package org.apache.fop.apps;

import static org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererOption.COMPRESSION;
import static org.apache.fop.render.bitmap.TIFFRendererConfig.TIFFRendererOption.SINGLE_STRIP;
public class TIFFRendererConfBuilder extends BitmapRendererConfBuilder {

public TIFFRendererConfBuilder() {
@@ -31,4 +31,9 @@ public class TIFFRendererConfBuilder extends BitmapRendererConfBuilder {
createTextElement(COMPRESSION, mode);
return this;
}

public TIFFRendererConfBuilder setSingleStrip(boolean single) {
createTextElement(SINGLE_STRIP, String.valueOf(single));
return this;
}
}

+ 10
- 1
test/java/org/apache/fop/events/EventChecker.java View File

@@ -19,6 +19,9 @@

package org.apache.fop.events;

import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
@@ -28,10 +31,13 @@ class EventChecker implements EventListener {

private final String expectedEventID;

private final Map<String, Object> expectedParams;

private boolean eventReceived;

EventChecker(String expectedEventID) {
EventChecker(String expectedEventID, Map<String, Object> expectedParams) {
this.expectedEventID = expectedEventID;
this.expectedParams = expectedParams;
}

public void processEvent(Event event) {
@@ -39,6 +45,9 @@ class EventChecker implements EventListener {
String id = event.getEventID();
if (id.equals(expectedEventID)) {
eventReceived = true;
for (Map.Entry<String, Object> param : expectedParams.entrySet()) {
assertEquals(event.getParam(param.getKey()), param.getValue());
}
}
}


+ 28
- 3
test/java/org/apache/fop/events/EventProcessingTestCase.java View File

@@ -22,6 +22,9 @@ package org.apache.fop.events;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
@@ -62,9 +65,10 @@ public class EventProcessingTestCase {
CONFIG_BASE_DIR = base.resolve("test/config/");

}
public void doTest(InputStream inStream, URI fopConf, String expectedEventID, String mimeType)
throws Exception {
EventChecker eventChecker = new EventChecker(expectedEventID);

public void doTest(InputStream inStream, URI fopConf, String expectedEventID, String mimeType,
Map<String, Object> expectedParams) throws Exception {
EventChecker eventChecker = new EventChecker(expectedEventID, expectedParams);
FopFactory fopFactory;
if (fopConf != null) {
fopFactory = FopFactory.newInstance(new File(fopConf));
@@ -81,6 +85,19 @@ public class EventProcessingTestCase {
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(src, res);
eventChecker.end();

}

public void doTest(InputStream inStream, URI fopConf, String expectedEventID, String mimeType)
throws Exception {
Map<String, Object> noParams = Collections.emptyMap();
doTest(inStream, fopConf, expectedEventID, mimeType, noParams);
}

public void doTest(String filename, String expectedEventID, Map<String, Object> expectedParams)
throws Exception {
doTest(BASE_DIR.resolve(filename).toURL().openStream(), null, expectedEventID,
MimeConstants.MIME_PDF, expectedParams);
}

public void doTest(String filename, String expectedEventID) throws Exception {
@@ -133,4 +150,12 @@ public class EventProcessingTestCase {
public void testViewportBPDOverflow() throws Exception {
doTest("viewport-overflow.fo", BlockLevelEventProducer.class.getName() + ".viewportBPDOverflow");
}

@Test
public void testPageOverflow() throws Exception {
Map<String, Object> params = new HashMap<String, Object>();
params.put("page", "1");
doTest("region-body_overflow.fo", BlockLevelEventProducer.class.getName() + ".regionOverflow",
params);
}
}

+ 95
- 0
test/java/org/apache/fop/fo/pagination/LayoutMasterSetTestCase.java View File

@@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.fo.pagination;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.FODocumentParser;
import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
import org.apache.fop.fo.FOEventHandler;

public class LayoutMasterSetTestCase {

private static class FlowMappingTester extends FOEventHandler {

private static final String[][] FLOW_MAPPINGS = {

{"first-page-before", "xsl-region-before"},
{"first-page-after", "xsl-region-after"},
{"first-page-start", "xsl-region-start"},
{"first-page-end", "xsl-region-end"},

{"odd-page-before", "xsl-region-before"},
{"odd-page-after", "xsl-region-after"},
{"odd-page-start", "xsl-region-start"},
{"odd-page-end", "xsl-region-end"},

{"odd-page-before", "xsl-region-before"},
{"odd-page-after", "xsl-region-after"},
{"odd-page-start", "xsl-region-start"},
{"odd-page-end", "xsl-region-end"},

{"blank-page-before", "xsl-region-before"},
{"blank-page-after", "xsl-region-after"},
{"blank-page-start", "xsl-region-start"},
{"blank-page-end", "xsl-region-end"},

{"last-page-before", "xsl-region-before"},
{"last-page-after", "xsl-region-after"},
{"last-page-start", "xsl-region-start"},
{"last-page-end", "xsl-region-end"},

{"xsl-footnote-separator", "xsl-footnote-separator"}

};

FlowMappingTester(FOUserAgent userAgent) {
super(userAgent);
}

@Override
public void startPageSequence(PageSequence pageSeq) {
super.startPageSequence(pageSeq);
LayoutMasterSet layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
for (String[] mapping : FLOW_MAPPINGS) {
assertEquals(mapping[1], layoutMasterSet.getDefaultRegionNameFor(mapping[0]));
}
}

}

/**
* Tests the {@link LayoutMasterSet#getDefaultRegionNameFor(String)} method.
*/
@Test
public void testFlowMapping() throws Exception {
FODocumentParser foDocumentParser = FODocumentParser.newInstance(new FOEventHandlerFactory() {

public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
return new FlowMappingTester(foUserAgent);
}
});
foDocumentParser.parse(getClass().getResourceAsStream("side-regions.fo"));
}

}

+ 181
- 0
test/java/org/apache/fop/fo/pagination/side-regions.fo View File

@@ -0,0 +1,181 @@
<?xml version="1.0" standalone="no"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="first-page"
page-height="100pt" page-width="150pt">
<fo:region-body margin="12pt" display-align="center" background-color="#FFF0F0"/>
<fo:region-before region-name="first-page-before" extent="10pt" precedence="true"
display-align="after"/>
<fo:region-after region-name="first-page-after" extent="10pt" precedence="true"/>
<fo:region-start region-name="first-page-start" extent="10pt" reference-orientation="90"
display-align="after"/>
<fo:region-end region-name="first-page-end" extent="10pt" reference-orientation="-90"
display-align="after"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="odd-page"
page-height="100pt" page-width="150pt">
<fo:region-body margin="12pt" display-align="center" background-color="#FFFFF0"/>
<fo:region-before region-name="odd-page-before" extent="10pt" precedence="true"
display-align="after"/>
<fo:region-after region-name="odd-page-after" extent="10pt" precedence="true"/>
<fo:region-start region-name="odd-page-start" extent="10pt" reference-orientation="90"
display-align="after"/>
<fo:region-end region-name="odd-page-end" extent="10pt" reference-orientation="-90"
display-align="after"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="even-page"
page-height="100pt" page-width="150pt">
<fo:region-body margin="12pt" display-align="center" background-color="#F0FFF0"/>
<fo:region-before region-name="even-page-before" extent="10pt" precedence="true"
display-align="after"/>
<fo:region-after region-name="even-page-after" extent="10pt" precedence="true"/>
<fo:region-start region-name="even-page-start" extent="10pt" reference-orientation="90"
display-align="after"/>
<fo:region-end region-name="even-page-end" extent="10pt" reference-orientation="-90"
display-align="after"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="blank-page"
page-height="100pt" page-width="150pt">
<fo:region-body margin="12pt" display-align="center" background-color="#F0F0F0"/>
<fo:region-before region-name="blank-page-before" extent="10pt" precedence="true"
display-align="after"/>
<fo:region-after region-name="blank-page-after" extent="10pt" precedence="true"/>
<fo:region-start region-name="blank-page-start" extent="10pt" reference-orientation="90"
display-align="after"/>
<fo:region-end region-name="blank-page-end" extent="10pt" reference-orientation="-90"
display-align="after"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="last-page"
page-height="100pt" page-width="150pt">
<fo:region-body margin="45pt 12pt" display-align="center" background-color="#F0F0FF"/>
<fo:region-before region-name="last-page-before" extent="10pt" precedence="true"
display-align="after"/>
<fo:region-after region-name="last-page-after" extent="10pt" precedence="true"/>
<fo:region-start region-name="last-page-start" extent="10pt" reference-orientation="90"
display-align="after"/>
<fo:region-end region-name="last-page-end" extent="10pt" reference-orientation="-90"
display-align="after"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="pages">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference page-position="first" master-reference="first-page"/>
<fo:conditional-page-master-reference page-position="last" master-reference="last-page"/>
<fo:conditional-page-master-reference blank-or-not-blank="blank"
master-reference="blank-page"/>
<fo:conditional-page-master-reference odd-or-even="odd" master-reference="odd-page"/>
<fo:conditional-page-master-reference odd-or-even="even" master-reference="even-page"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="pages" force-page-count="even" font-size="4pt"
text-align="center">

<fo:static-content flow-name="first-page-before">
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid red"
padding-bottom="0.5pt">First Page Before.</fo:block>
</fo:static-content>
<fo:static-content flow-name="first-page-after">
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid red"
padding-top="0.5pt">First Page After.</fo:block>
</fo:static-content>
<fo:static-content flow-name="first-page-start">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red"
padding-bottom="0.5pt">First Page Start.</fo:block>
</fo:static-content>
<fo:static-content flow-name="first-page-end">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid red"
padding-bottom="0.5pt">First Page End.</fo:block>
</fo:static-content>

<fo:static-content flow-name="odd-page-after">
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid orange"
padding-top="0.5pt">Odd Page After.</fo:block>
</fo:static-content>
<fo:static-content flow-name="odd-page-end">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange"
padding-bottom="0.5pt">Odd Page End.</fo:block>
</fo:static-content>
<fo:static-content flow-name="odd-page-start">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid orange"
padding-bottom="0.5pt">Odd Page Start.</fo:block>
</fo:static-content>
<fo:static-content flow-name="odd-page-before">
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid orange"
padding-bottom="0.5pt">Odd Page Before.</fo:block>
</fo:static-content>

<fo:static-content flow-name="even-page-end">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green"
padding-bottom="0.5pt">Even Page End.</fo:block>
</fo:static-content>
<fo:static-content flow-name="even-page-start">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid green"
padding-bottom="0.5pt">Even Page Start.</fo:block>
</fo:static-content>
<fo:static-content flow-name="even-page-after">
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid green"
padding-top="0.5pt">Even Page After.</fo:block>
</fo:static-content>
<fo:static-content flow-name="even-page-before">
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid green"
padding-bottom="0.5pt">Even Page Before.</fo:block>
</fo:static-content>

<fo:static-content flow-name="blank-page-start">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black"
padding-bottom="0.5pt">Blank Page Start.</fo:block>
</fo:static-content>
<fo:static-content flow-name="blank-page-after">
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid black"
padding-top="0.5pt">Blank Page After.</fo:block>
</fo:static-content>
<fo:static-content flow-name="blank-page-before">
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid black"
padding-bottom="0.5pt">Blank Page Before.</fo:block>
</fo:static-content>
<fo:static-content flow-name="blank-page-end">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid black"
padding-bottom="0.5pt">Blank Page End.</fo:block>
</fo:static-content>

<fo:static-content flow-name="last-page-before">
<fo:block start-indent="12pt" end-indent="12pt" border-bottom="0.5pt solid blue"
padding-bottom="0.5pt">Last Page Before.</fo:block>
</fo:static-content>
<fo:static-content flow-name="last-page-end">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue"
padding-bottom="0.5pt">Last Page End.</fo:block>
</fo:static-content>
<fo:static-content flow-name="last-page-after">
<fo:block start-indent="12pt" end-indent="12pt" border-top="0.5pt solid blue"
padding-top="0.5pt">Last Page After.</fo:block>
</fo:static-content>
<fo:static-content flow-name="last-page-start">
<fo:block start-indent="2pt" end-indent="2pt" border-bottom="0.5pt solid blue"
padding-bottom="0.5pt">Last Page Start.</fo:block>
</fo:static-content>

<fo:static-content flow-name="xsl-footnote-separator">
<fo:block>
<fo:leader leader-pattern="rule" leader-length="40%" rule-thickness="0.5pt"/>
</fo:block>
</fo:static-content>

<fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt">
<fo:block>Apache™ FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter.</fo:block>
<fo:block break-before="page">It is an application<fo:footnote><fo:inline>*</fo:inline>
<fo:footnote-body><fo:block font-size="80%">* written in
Java</fo:block></fo:footnote-body></fo:footnote> that reads a formatting object (FO)
tree and renders the resulting pages to a specified output.</fo:block>
<fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which
is a wider community of users and developers of open source projects.</fo:block>
<fo:block break-before="page">Apache™ FOP (Formatting Objects Processor) is a print formatter
driven by XSL formatting objects (XSL-FO) and an output independent formatter.</fo:block>
<fo:block break-before="page">It is a Java application that reads a formatting object (FO)
tree and renders the resulting pages to a specified output.</fo:block>
<fo:block break-before="page">The FOP project is part of the Apache Software Foundation, which
is a wider community of users and developers of open source projects.</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 120
- 0
test/java/org/apache/fop/fonts/CIDFullTestCase.java View File

@@ -0,0 +1,120 @@
/*
* 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.HashMap;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.fop.util.CharUtilities;

public class CIDFullTestCase {

private CIDFull cidFull;
private MultiByteFont mbFont;
private BitSet bs;
private char[] chars;
private int[] widths;
private Map<Integer, Integer> glyphs;

@Before
public void setup() {
bs = new BitSet();
glyphs = new HashMap<Integer, Integer>();
chars = new char[18];
widths = new int[18];
int i = 0;
for (int j = 0; j < 20; j++) {
if (j == 10 || j == 11) {
continue;
}
bs.set(j);
glyphs.put(Integer.valueOf(j), Integer.valueOf(j));
chars[i] = (char) j;
widths[i] = 100;
i++;
}
mbFont = mock(MultiByteFont.class);
when(mbFont.getGlyphIndices()).thenReturn(bs);
when(mbFont.getChars()).thenReturn(chars);
when(mbFont.getWidths()).thenReturn(widths);
cidFull = new CIDFull(mbFont);
}

@Test
public void testGetOriginalGlyphIndex() {
// index 5 exists
assertEquals(cidFull.getOriginalGlyphIndex(5), 5);
}

@Test
public void testGetUnicode() {
// index 9 exists
assertEquals(cidFull.getUnicode(9), (char) 9);
// index 10 does not
assertEquals(cidFull.getUnicode(10), CharUtilities.NOT_A_CHARACTER);
}

@Test
public void testMapChar() {
// index 9 exists
char c = 'a';
assertEquals(cidFull.mapChar(9, c), (char) 9);
}

@Test
public void testGetGlyphs() {
Map<Integer, Integer> fontGlyphs = cidFull.getGlyphs();
for (Integer key : fontGlyphs.keySet()) {
assertEquals(fontGlyphs.get(key), glyphs.get(key));
}
assertTrue(fontGlyphs.size() == glyphs.size());
}

@Test
public void testGetChars() {
assertArrayEquals(cidFull.getChars(), chars);
}

@Test
public void testGetNumberOfGlyphs() {
assertTrue(cidFull.getNumberOfGlyphs() == 20);
}

@Test
public void testGetGlyphIndices() {
assertEquals(bs, cidFull.getGlyphIndices());
}

@Test
public void testGetWidths() {
assertArrayEquals(cidFull.getWidths(), widths);
}

}

+ 77
- 0
test/java/org/apache/fop/fonts/FontManagerTestCase.java View File

@@ -0,0 +1,77 @@
/*
* 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.fonts;

import java.net.URI;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.InternalResourceResolver;

public class FontManagerTestCase {

private FontManager sut;
private FontCacheManager fontCacheManager;
private FontDetector fontDetector;
private InternalResourceResolver resolver;

@Before
public void setUp() {
resolver = mock(InternalResourceResolver.class);
fontCacheManager = mock(FontCacheManager.class);
fontDetector = mock(FontDetector.class);

sut = new FontManager(resolver, fontDetector, fontCacheManager);
}

@Test
public void testSetCacheFile() {
URI testURI = URI.create("test/uri");
sut.setCacheFile(testURI);

InOrder inOrder = inOrder(resolver, fontCacheManager);
inOrder.verify(resolver).resolveFromBase(testURI);
inOrder.verify(fontCacheManager).setCacheFile(any(URI.class));
}

@Test
public void testGetFontCache() {
sut.getFontCache();
verify(fontCacheManager).load();
}

@Test
public void testSaveCache() throws FOPException {
sut.saveCache();
verify(fontCacheManager).save();
}

@Test
public void testDeleteCache() throws FOPException {
sut.deleteCache();
verify(fontCacheManager).delete();
}
}

+ 37
- 0
test/java/org/apache/fop/layoutmgr/BreakElementTestCase.java View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.fop.layoutmgr;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

import org.apache.fop.fo.Constants;

public class BreakElementTestCase {

/**
* Tests that the constructor sets the break class to a valid default value.
*/
@Test
public void breakClassMustBeValid() {
LayoutContext context = LayoutContext.newInstance();
BreakElement breakElement = new BreakElement(new Position(null), 0, context);
assertEquals(Constants.EN_AUTO, breakElement.getBreakClass());
}
}

+ 76
- 0
test/java/org/apache/fop/pdf/PDFEncodingTestCase.java View File

@@ -0,0 +1,76 @@
/*
* 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.pdf;

import org.junit.Test;

import org.apache.fop.fonts.CodePointMapping;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

public class PDFEncodingTestCase {

/**
* Tests the createPDFEncoding method to ensure a null encoding type
* is handled correctly.
*/
@Test
public void testCreatePDFEncodingForNull() {
Object encoding = PDFEncoding.createPDFEncoding(null, "Test");
assertEquals(encoding, null);
}

/**
* Tests that when a PDFEncoding object is created, if the encoding type is
* that of StandardEncoding, the baseEncoding tag is omitted.
*/
@Test
public void testStandardEncodingDiffs() {
Object encoding = PDFEncoding.createPDFEncoding(CodePointMapping.getMapping(
CodePointMapping.SYMBOL_ENCODING), "Test");
if (encoding instanceof PDFEncoding) {
PDFEncoding pdfEncoding = (PDFEncoding) encoding;
assertFalse(pdfEncoding.entries.containsKey("BaseEncoding"));
}
}

/**
* Tests that when the StandardEncoding type is provided and there are no
* differences, the returned encoding object is null.
*/
@Test
public void testStandardEncodingNoDiff() {
Object encoding = PDFEncoding.createPDFEncoding(CodePointMapping.getMapping(
CodePointMapping.STANDARD_ENCODING), "Test");
assertEquals(encoding, null);
}

/**
* Tests that when the SymbolEncoding type is provided and there are no
* differences, the returned encoding string is that of SymbolEncoding.
*/
@Test
public void testCreatePDFEncodingSymbol() {
Object encoding = PDFEncoding.createPDFEncoding(CodePointMapping.getMapping(
CodePointMapping.SYMBOL_ENCODING), "Symbol");
assert (encoding instanceof String);
String pdfEncoding = (String) encoding;
assertEquals(pdfEncoding, "SymbolEncoding");
}
}

+ 0
- 0
test/java/org/apache/fop/pdf/PDFFactoryTestCase.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save