Browse Source

Merge changes from trunk through revision 1400690; update XGC lib with new post 1.5 svn-trunk version.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-1_1@1400697 13f79535-47bb-0310-9956-ffa450edef68
fop-1_1
Glenn Adams 11 years ago
parent
commit
c64b76a7af
100 changed files with 1878 additions and 1531 deletions
  1. 1
    0
      examples/plan/src/org/apache/fop/plan/PreloaderPlan.java
  2. 14
    0
      findbugs-exclude.xml
  3. 1
    2
      fop
  4. 1
    1
      fop.bat
  5. 0
    4
      fop.js
  6. BIN
      lib/xmlgraphics-commons-svn-trunk.jar
  7. 1
    1
      src/documentation/content/xdocs/dev/index.xml
  8. 1
    0
      src/documentation/content/xdocs/dev/release.xml
  9. 3
    3
      src/documentation/content/xdocs/maillist.xml
  10. 4
    5
      src/documentation/content/xdocs/team.xml
  11. 8
    2
      src/documentation/content/xdocs/trunk/output.xml
  12. 14
    27
      src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
  13. 0
    508
      src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java
  14. 107
    28
      src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
  15. 9
    0
      src/java/org/apache/fop/afp/AFPEventProducer.java
  16. 1
    0
      src/java/org/apache/fop/afp/AFPEventProducer.xml
  17. 2
    1
      src/java/org/apache/fop/afp/AFPStreamer.java
  18. 19
    18
      src/java/org/apache/fop/afp/DataStream.java
  19. 5
    8
      src/java/org/apache/fop/afp/Factory.java
  20. 12
    1
      src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
  21. 8
    0
      src/java/org/apache/fop/afp/fonts/CharacterSet.java
  22. 11
    14
      src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
  23. 16
    24
      src/java/org/apache/fop/afp/fonts/CharacterSetOrientation.java
  24. 28
    4
      src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
  25. 6
    2
      src/java/org/apache/fop/afp/fonts/OutlineFont.java
  26. 4
    8
      src/java/org/apache/fop/afp/modca/AbstractPageObject.java
  27. 1
    1
      src/java/org/apache/fop/afp/modca/IncludedResourceObject.java
  28. 5
    20
      src/java/org/apache/fop/afp/modca/PageGroup.java
  29. 64
    28
      src/java/org/apache/fop/afp/modca/TagLogicalElement.java
  30. 63
    0
      src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java
  31. 63
    15
      src/java/org/apache/fop/afp/util/AFPResourceAccessor.java
  32. 6
    1
      src/java/org/apache/fop/apps/EnvironmentProfile.java
  33. 17
    4
      src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java
  34. 19
    20
      src/java/org/apache/fop/apps/FOUserAgent.java
  35. 5
    1
      src/java/org/apache/fop/apps/Fop.java
  36. 1
    1
      src/java/org/apache/fop/apps/FopConfParser.java
  37. 23
    53
      src/java/org/apache/fop/apps/FopFactory.java
  38. 6
    1
      src/java/org/apache/fop/apps/FopFactoryBuilder.java
  39. 55
    15
      src/java/org/apache/fop/apps/FopFactoryConfig.java
  40. 3
    1
      src/java/org/apache/fop/apps/io/InternalResourceResolver.java
  41. 0
    51
      src/java/org/apache/fop/apps/io/ResourceResolver.java
  42. 103
    46
      src/java/org/apache/fop/apps/io/ResourceResolverFactory.java
  43. 0
    48
      src/java/org/apache/fop/apps/io/TempResourceResolver.java
  44. 0
    57
      src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java
  45. 5
    4
      src/java/org/apache/fop/area/AreaTreeParser.java
  46. 2
    1
      src/java/org/apache/fop/area/CachedRenderPagesModel.java
  47. 13
    34
      src/java/org/apache/fop/area/PageSequence.java
  48. 18
    159
      src/java/org/apache/fop/area/PageViewport.java
  49. 14
    9
      src/java/org/apache/fop/cli/CommandLineOptions.java
  50. 6
    10
      src/java/org/apache/fop/events/CompositeEventListener.java
  51. 7
    2
      src/java/org/apache/fop/fo/Constants.java
  52. 10
    10
      src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
  53. 14
    16
      src/java/org/apache/fop/fo/FOEventHandler.java
  54. 30
    0
      src/java/org/apache/fop/fo/FONode.java
  55. 11
    3
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  56. 12
    0
      src/java/org/apache/fop/fo/FOValidationEventProducer.java
  57. 1
    0
      src/java/org/apache/fop/fo/FOValidationEventProducer.xml
  58. 10
    3
      src/java/org/apache/fop/fo/FObj.java
  59. 1
    0
      src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
  60. 3
    0
      src/java/org/apache/fop/fo/extensions/InternalElementMapping.java
  61. 44
    0
      src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java
  62. 216
    0
      src/java/org/apache/fop/fo/flow/Markers.java
  63. 7
    10
      src/java/org/apache/fop/fo/flow/RetrieveMarker.java
  64. 14
    11
      src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java
  65. 9
    0
      src/java/org/apache/fop/fo/flow/table/TableCell.java
  66. 12
    0
      src/java/org/apache/fop/fo/flow/table/TableColumn.java
  67. 2
    0
      src/java/org/apache/fop/fo/flow/table/TablePart.java
  68. 4
    1
      src/java/org/apache/fop/fo/pagination/Flow.java
  69. 19
    0
      src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java
  70. 9
    20
      src/java/org/apache/fop/fo/pagination/PageSequence.java
  71. 2
    11
      src/java/org/apache/fop/fo/pagination/Root.java
  72. 1
    1
      src/java/org/apache/fop/fo/pagination/StaticContent.java
  73. 37
    0
      src/java/org/apache/fop/fo/properties/CommonHyphenation.java
  74. 2
    2
      src/java/org/apache/fop/fonts/CIDFont.java
  75. 113
    0
      src/java/org/apache/fop/fonts/CIDFull.java
  76. 90
    0
      src/java/org/apache/fop/fonts/CIDSet.java
  77. 50
    79
      src/java/org/apache/fop/fonts/CIDSubset.java
  78. 1
    1
      src/java/org/apache/fop/fonts/DefaultFontConfig.java
  79. 0
    1
      src/java/org/apache/fop/fonts/DefaultFontConfigurator.java
  80. 9
    7
      src/java/org/apache/fop/fonts/FontCache.java
  81. 10
    8
      src/java/org/apache/fop/fonts/FontCacheManager.java
  82. 28
    9
      src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
  83. 8
    28
      src/java/org/apache/fop/fonts/FontManager.java
  84. 17
    17
      src/java/org/apache/fop/fonts/FontManagerConfigurator.java
  85. 1
    1
      src/java/org/apache/fop/fonts/FontReader.java
  86. 3
    0
      src/java/org/apache/fop/fonts/LazyFont.java
  87. 50
    19
      src/java/org/apache/fop/fonts/MultiByteFont.java
  88. 1
    1
      src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
  89. 3
    2
      src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
  90. 3
    2
      src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java
  91. 7
    0
      src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
  92. 52
    9
      src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
  93. 7
    4
      src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java
  94. 2
    3
      src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
  95. 2
    2
      src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  96. 2
    2
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  97. 17
    4
      src/java/org/apache/fop/layoutmgr/BreakElement.java
  98. 20
    1
      src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
  99. 137
    0
      src/java/org/apache/fop/layoutmgr/LocalBreaker.java
  100. 0
    0
      src/java/org/apache/fop/layoutmgr/PageBreaker.java

+ 1
- 0
examples/plan/src/org/apache/fop/plan/PreloaderPlan.java View File

@@ -43,6 +43,7 @@ import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.io.XmlSourceUtil;

import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.UnclosableInputStream;

+ 14
- 0
findbugs-exclude.xml View File

@@ -1078,6 +1078,15 @@
<Method name="getExternalAction"/>
<Bug pattern="DM_CONVERT_CASE"/>
</Match>
<Match>
<Class name="org.apache.fop.pdf.PDFPageLabels"/>
<Or>
<Method name="addPageLabel"/>
<Method name="alphabeticToArabic"/>
<Method name="romanToArabic"/>
</Or>
<Bug pattern="DM_CONVERT_CASE"/>
</Match>
<Match>
<Class name="org.apache.fop.render.bitmap.MultiFileRenderingUtil"/>
<Method name="&lt;init&gt;"/>
@@ -3303,6 +3312,11 @@
<Method name="make"/>
<Bug pattern="BC_UNCONFIRMED_CAST"/>
</Match>
<Match>
<Class name="org.apache.fop.layoutmgr.LayoutManagerMapping$RetrieveTableMarkerLayoutManagerMaker"/>
<Method name="make"/>
<Bug pattern="BC_UNCONFIRMED_CAST"/>
</Match>
<Match>
<Class name="org.apache.fop.layoutmgr.LayoutManagerMapping$WrapperLayoutManagerMaker"/>
<Method name="make"/>

+ 1
- 2
fop View File

@@ -18,7 +18,6 @@
# Shell script to run FOP, adapted from the Jakarta-Ant project.

rpm_mode=true
java_exec_args="-Djava.awt.headless=true"
fop_exec_args=
no_config=false
fop_exec_debug=false
@@ -248,7 +247,7 @@ fi

# Execute FOP using eval/exec to preserve spaces in paths,
# java options, and FOP args
fop_exec_command="exec \"$JAVACMD\" $java_exec_args $LOGCHOICE $LOGLEVEL -classpath \"$LOCALCLASSPATH\" $FOP_OPTS org.apache.fop.cli.Main $fop_exec_args"
fop_exec_command="exec \"$JAVACMD\" $LOGCHOICE $LOGLEVEL -classpath \"$LOCALCLASSPATH\" $FOP_OPTS org.apache.fop.cli.Main $fop_exec_args"
if $fop_exec_debug ; then
echo $fop_exec_command
fi

+ 1
- 1
fop.bat View File

@@ -58,7 +58,7 @@ set LIBDIR=%LOCAL_FOP_HOME%lib
set LOCALCLASSPATH=%FOP_HYPHENATION_PATH%
for %%l in (%LOCAL_FOP_HOME%build\*.jar %LIBDIR%\*.jar) do set LOCALCLASSPATH=!LOCALCLASSPATH!;%%l
set JAVAOPTS=-Denv.windir=%WINDIR% -Djava.awt.headless=true
set JAVAOPTS=-Denv.windir=%WINDIR%
if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome

+ 0
- 4
fop.js View File

@@ -18,7 +18,6 @@
// rpm_mode is irrelevant on Windows
// var rpm_mode=true;
var java_exec_args = "-Djava.awt.headless=true";
var fop_exec_args = "";
var no_config=false;
var fop_exec_debug=false;
@@ -63,7 +62,6 @@ function read_args() {
WScript.Echo("keepopen: " + keep_open);
WScript.Echo("noconfig: " + no_config);
WScript.Echo("help: " + show_help);
WScript.Echo("java arguments: " + java_exec_args);
WScript.Echo("fop arguments: " + fop_exec_args);
}
}
@@ -222,7 +220,6 @@ function get_local_classpath() {
// Execute fop via shell.Exec
function fop_exec() {
var fop_exec_command = "\"" + javacmd + "\" "
+ java_exec_args + " "
+ (config.Exists("JAVA_OPTS")?config.Item("JAVA_OPTS") + " ":"")
+ (config.Exists("LOGCHOICE")?config.Item("LOGCHOICE") + " ":"")
+ (config.Exists("LOGLEVEL")?config.Item("LOGLEVEL") + " ":"")
@@ -255,7 +252,6 @@ function fop_exec() {
function fop_run() {
var fop_exec_command = "cmd /" + (keep_open?"K":"C") + " \""
+ "\"" + javacmd + "\" "
+ java_exec_args + " "
+ (config.Exists("JAVA_OPTS")?config.Item("JAVA_OPTS") + " ":"")
+ (config.Exists("LOGCHOICE")?config.Item("LOGCHOICE") + " ":"")
+ (config.Exists("LOGLEVEL")?config.Item("LOGLEVEL") + " ":"")

BIN
lib/xmlgraphics-commons-1.5.jar → lib/xmlgraphics-commons-svn-trunk.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>

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

@@ -68,6 +68,7 @@
<li>Tag the source tree with the release ID. For example, if the release is 1.0:
<code>svn copy https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-1_0 https://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-1_0</code></li>
<li>Make a fresh checkout with the just created tag: <code>svn co https://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-1_0</code></li>
<li>Copy the <code>jai_core.jar</code> and <code>jai_codec.jar</code> to <code>lib</code>.</li>
<li>Copy the hyphenation patterns jar file <code>fop-hyph.jar</code> to <code>lib</code> (e.g. from <code>http://sourceforge.net/projects/offo</code></li>
<li>Alternatively, create a <code>build-local.properties</code> file that points to the above libraries.</li>
<li>Run <code>build[.sh] dist</code>. Do this using Sun JDK 1.5 or later. A Forrest installation is needed.</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.

+ 4
- 5
src/documentation/content/xdocs/team.xml View File

@@ -38,6 +38,7 @@
involved in the creation of ISO 8879 (SGML), ISO/IEC 9541 (Font Information Interchange),
ISO/IEC 10179 (DSSSL), ISO/IEC 10180 (SPDL), ISO/IEC 10646 (Universal Coded Character Set),
and, within the W3C, on XSL-FO 1.0.</li>
<li id="lb"><link href="mailto:lmpmbernardo@gmail.com">Luis Bernardo</link> (LB)</li>
<li id="cb"><link href="mailto:bowditch_chris@hotmail.com">Chris Bowditch</link> (CB)
is a Java/VB Programmer from England.</li>
<li id="ac"><link href="mailto:acumiskey AT apache.org">Adrian Cumiskey</link> (AC)
@@ -77,16 +78,15 @@
<section id="contribute-active">
<title>Active Contributors</title>
<ul>
<li id="gd">Georg Datterl is a software developer from Austria, currently working for
Geneon media solutions gmbh in Nuremberg, Germany. He needs FOP to wrestle gigabytes of
electronic data into thousands of printed pages.</li>
<li id="ag">Alexios Giotis holds a Ph.D. in the optimization of turbomachinery cascades
using evolutionary algorithms, neural networks and parallel processing. He is one of
the founding members of i-docs (software for enterprises) and he has been leading its
technical design &amp; implementation based on open source libraries since its inception.
He is relying on Apache FOP for generating high volumes of documents on major banks and
telecom operators since FOP's 1.0 release. He lives in Athens, Greece.</li>
<li id="gd">Georg Datterl is a software developer from Austria, currently working for
Geneon media solutions gmbh in Nuremberg, Germany. He needs FOP to wrestle gigabytes of
electronic data into thousands of printed pages.</li>
<li id="lb">Luis Bernardo</li>
</ul>
</section>
<section id="founder">
@@ -125,4 +125,3 @@
</section>
</body>
</document>


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

}

+ 107
- 28
src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java View File

@@ -20,8 +20,10 @@
package org.apache.fop.accessibility.fo;

import java.util.Locale;
import java.util.Stack;

import javax.xml.XMLConstants;

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

import org.apache.fop.accessibility.StructureTreeElement;
@@ -30,6 +32,7 @@ import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.fo.flow.AbstractGraphics;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block;
@@ -55,9 +58,13 @@ 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.Root;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
import org.apache.fop.fo.properties.CommonHyphenation;
import org.apache.fop.util.LanguageTags;
import org.apache.fop.util.XMLUtil;

/**
@@ -67,27 +74,38 @@ class StructureTreeEventTrigger extends FOEventHandler {

private StructureTreeEventHandler structureTreeEventHandler;

private LayoutMasterSet layoutMasterSet;

private final Stack<Table> tables = new Stack<Table>();

private final Stack<Boolean> inTableHeader = new Stack<Boolean>();

private final Stack<Locale> locales = new Stack<Locale>();

public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) {
this.structureTreeEventHandler = structureTreeEventHandler;
}

@Override
public void startDocument() throws SAXException {
public void startRoot(Root root) {
locales.push(root.getLocale());
}

@Override
public void endDocument() throws SAXException {
public void endRoot(Root root) {
locales.pop();
}

@Override
public void startPageSequence(PageSequence pageSeq) {
Locale locale = null;
if (pageSeq.getLanguage() != null) {
if (pageSeq.getCountry() != null) {
locale = new Locale(pageSeq.getLanguage(), pageSeq.getCountry());
} else {
locale = new Locale(pageSeq.getLanguage());
}
if (layoutMasterSet == null) {
layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
}
Locale locale = pageSeq.getLocale();
if (locale != null) {
locales.push(locale);
} else {
locales.push(locales.peek());
}
String role = pageSeq.getCommonAccessibility().getRole();
structureTreeEventHandler.startPageSequence(locale, role);
@@ -96,6 +114,7 @@ class StructureTreeEventTrigger extends FOEventHandler {
@Override
public void endPageSequence(PageSequence pageSeq) {
structureTreeEventHandler.endPageSequence();
locales.pop();
}

@Override
@@ -128,9 +147,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
@@ -140,12 +178,28 @@ class StructureTreeEventTrigger extends FOEventHandler {

@Override
public void startBlock(Block bl) {
startElement(bl);
CommonHyphenation hyphProperties = bl.getCommonHyphenation();
AttributesImpl attributes = createLangAttribute(hyphProperties);
startElement(bl, attributes);
}

private AttributesImpl createLangAttribute(CommonHyphenation hyphProperties) {
Locale locale = hyphProperties.getLocale();
AttributesImpl attributes = new AttributesImpl();
if (locale == null || locale.equals(locales.peek())) {
locales.push(locales.peek());
} else {
locales.push(locale);
addAttribute(attributes, XMLConstants.XML_NS_URI, "lang", "xml",
LanguageTags.toLanguageTag(locale));
}
return attributes;
}

@Override
public void endBlock(Block bl) {
endElement(bl);
locales.pop();
}

@Override
@@ -170,42 +224,51 @@ class StructureTreeEventTrigger extends FOEventHandler {

@Override
public void startTable(Table tbl) {
tables.push(tbl);
startElement(tbl);
}

@Override
public void endTable(Table tbl) {
endElement(tbl);
tables.pop();
}

@Override
public void startHeader(TableHeader header) {
inTableHeader.push(Boolean.TRUE);
startElement(header);
}

@Override
public void endHeader(TableHeader header) {
endElement(header);
inTableHeader.pop();
}

@Override
public void startFooter(TableFooter footer) {
// TODO Shouldn't it be true?
inTableHeader.push(Boolean.FALSE);
startElement(footer);
}

@Override
public void endFooter(TableFooter footer) {
endElement(footer);
inTableHeader.pop();
}

@Override
public void startBody(TableBody body) {
inTableHeader.push(Boolean.FALSE);
startElement(body);
}

@Override
public void endBody(TableBody body) {
endElement(body);
inTableHeader.pop();
}

@Override
@@ -221,14 +284,35 @@ class StructureTreeEventTrigger extends FOEventHandler {
@Override
public void startCell(TableCell tc) {
AttributesImpl attributes = new AttributesImpl();
int colSpan = tc.getNumberColumnsSpanned();
if (colSpan > 1) {
addNoNamespaceAttribute(attributes, "number-columns-spanned",
Integer.toString(colSpan));
addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned());
addSpanAttribute(attributes, "number-rows-spanned", tc.getNumberRowsSpanned());
boolean rowHeader = inTableHeader.peek();
boolean columnHeader = tables.peek().getColumn(tc.getColumnNumber() - 1).isHeader();
if (rowHeader || columnHeader) {
final String th = "TH";
String role = tc.getCommonAccessibility().getRole();
/* Do not override a custom role */
if (role == null) {
role = th;
addNoNamespaceAttribute(attributes, "role", th);
}
if (role.equals(th)) {
if (columnHeader) {
String scope = rowHeader ? "Both" : "Row";
addAttribute(attributes, InternalElementMapping.URI, InternalElementMapping.SCOPE,
InternalElementMapping.STANDARD_PREFIX, scope);
}
}
}
startElement(tc, attributes);
}

private void addSpanAttribute(AttributesImpl attributes, String attributeName, int span) {
if (span > 1) {
addNoNamespaceAttribute(attributes, attributeName, Integer.toString(span));
}
}

@Override
public void endCell(TableCell tc) {
endElement(tc);
@@ -274,16 +358,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);
@@ -342,8 +416,10 @@ class StructureTreeEventTrigger extends FOEventHandler {

@Override
public void character(Character c) {
startElementWithID(c);
AttributesImpl attributes = createLangAttribute(c.getCommonHyphenation());
startElementWithID(c, attributes);
endElement(c);
locales.pop();
}

@Override
@@ -358,7 +434,10 @@ class StructureTreeEventTrigger extends FOEventHandler {
}

private void startElementWithID(FONode node) {
AttributesImpl attributes = new AttributesImpl();
startElementWithID(node, new AttributesImpl());
}

private void startElementWithID(FONode node, AttributesImpl attributes) {
String localName = node.getLocalName();
if (node instanceof CommonAccessibilityHolder) {
addRole((CommonAccessibilityHolder) node, attributes);

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

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

@@ -32,10 +32,11 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.io.TempResourceURIGenerator;

import org.apache.fop.afp.modca.ResourceGroup;
import org.apache.fop.afp.modca.StreamedResourceGroup;
import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.TempResourceURIGenerator;

/**
* Manages the streaming of the AFP output

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

+ 6
- 1
src/java/org/apache/fop/apps/EnvironmentProfile.java View File

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

import java.net.URI;

import org.apache.fop.apps.io.ResourceResolver;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.fonts.FontManager;

/**
@@ -52,4 +54,7 @@ public interface EnvironmentProfile {
* @return the default base URI
*/
URI getDefaultBaseURI();

/** @see FopFactoryConfig#getFallbackResolver() */
FallbackResolver getFallbackResolver();
}

+ 17
- 4
src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java View File

@@ -21,8 +21,12 @@ package org.apache.fop.apps;

import java.net.URI;

import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.RestrictedFallbackResolver;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.UnrestrictedFallbackResolver;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.FontCacheManager;
import org.apache.fop.fonts.FontCacheManagerFactory;
@@ -51,7 +55,8 @@ public final class EnvironmentalProfileFactory {
return new Profile(defaultBaseUri, resourceResolver,
createFontManager(defaultBaseUri, resourceResolver,
FontDetectorFactory.createDefault(),
FontCacheManagerFactory.createDefault()));
FontCacheManagerFactory.createDefault()),
new UnrestrictedFallbackResolver());
}

/**
@@ -67,7 +72,8 @@ public final class EnvironmentalProfileFactory {
return new Profile(defaultBaseUri, resourceResolver,
createFontManager(defaultBaseUri, resourceResolver,
FontDetectorFactory.createDisabled(),
FontCacheManagerFactory.createDisabled()));
FontCacheManagerFactory.createDisabled()),
new RestrictedFallbackResolver());
}

private static final class Profile implements EnvironmentProfile {
@@ -78,8 +84,10 @@ public final class EnvironmentalProfileFactory {

private final URI defaultBaseURI;

private final FallbackResolver fallbackResolver;

private Profile(URI defaultBaseURI, ResourceResolver resourceResolver,
FontManager fontManager) {
FontManager fontManager, FallbackResolver fallbackResolver) {
if (defaultBaseURI == null) {
throw new IllegalArgumentException("Default base URI must not be null");
}
@@ -92,6 +100,7 @@ public final class EnvironmentalProfileFactory {
this.defaultBaseURI = defaultBaseURI;
this.resourceResolver = resourceResolver;
this.fontManager = fontManager;
this.fallbackResolver = fallbackResolver;
}

public ResourceResolver getResourceResolver() {
@@ -105,6 +114,10 @@ public final class EnvironmentalProfileFactory {
public URI getDefaultBaseURI() {
return defaultBaseURI;
}

public FallbackResolver getFallbackResolver() {
return fallbackResolver;
}
}

private static FontManager createFontManager(URI defaultBaseUri, ResourceResolver resourceResolver,

+ 19
- 20
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -131,21 +131,7 @@ public class FOUserAgent {
/** Set of keywords applicable to this document. */
protected String keywords = null;

private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() {

public ImageContext getParentContext() {
return factory;
}

public float getTargetResolution() {
return FOUserAgent.this.getTargetResolution();
}

public Source resolveURI(String uri) {
return FOUserAgent.this.resolveURI(uri);
}

};
private final ImageSessionContext imageSessionContext;

/**
* Main constructor. <b>This constructor should not be called directly. Please use the
@@ -154,11 +140,25 @@ public class FOUserAgent {
* @param resourceResolver the resolver used to acquire resources
* @see org.apache.fop.apps.FopFactory
*/
FOUserAgent(FopFactory factory, InternalResourceResolver resourceResolver) {
FOUserAgent(final FopFactory factory, InternalResourceResolver resourceResolver) {
this.factory = factory;
this.resourceResolver = resourceResolver;
setTargetResolution(factory.getTargetResolution());
setAccessibility(factory.isAccessibilityEnabled());
imageSessionContext = new AbstractImageSessionContext(factory.getFallbackResolver()) {

public ImageContext getParentContext() {
return factory;
}

public float getTargetResolution() {
return FOUserAgent.this.getTargetResolution();
}

public Source resolveURI(String uri) {
return FOUserAgent.this.resolveURI(uri);
}
};
}

/**
@@ -166,7 +166,7 @@ public class FOUserAgent {
* requires an output stream and you want to configure this very rendering run,
* i.e. if you want to set some metadata like the title and author of the document
* you want to render. In that case, create a new {@link FOUserAgent} instance
* using {@link #newFOUserAgent()}.
* using {@link org.apache.fop.apps.FopFactory#newFOUserAgent() newFOUserAgent()}.
* <p>
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can
* use the constants defined in {@link MimeConstants}.
@@ -184,7 +184,7 @@ public class FOUserAgent {
* Returns a new {@link Fop} instance. Use this factory method if you want to configure this
* very rendering run, i.e. if you want to set some metadata like the title and author of the
* document you want to render. In that case, create a new {@link FOUserAgent}
* instance using {@link #newFOUserAgent()}.
* instance using {@link org.apache.fop.apps.FopFactory#newFOUserAgent() newFOUserAgent()}.
* <p>
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can
* use the constants defined in {@link MimeConstants}.
@@ -791,9 +791,8 @@ public class FOUserAgent {
return factory.getColorSpaceCache();
}

/** @see {@link FopFactory#getHyphenationPatternNames()} */
/** @see FopFactory#getHyphenationPatternNames() */
public Map<String, String> getHyphenationPatternNames() {
return factory.getHyphenationPatternNames();
}
}


+ 5
- 1
src/java/org/apache/fop/apps/Fop.java View File

@@ -52,7 +52,7 @@ public class Fop {
private OutputStream stream = null;

// FOUserAgent object to set processing options
private FOUserAgent foUserAgent = null;
private final FOUserAgent foUserAgent;

// FOTreeBuilder object to maintain reference for access to results
private FOTreeBuilder foTreeBuilder = null;
@@ -81,6 +81,10 @@ public class Fop {
/**
* Get the FOUserAgent instance associated with the rendering run represented by this instance.
* @return the user agent
*
* @deprecated this getter doesn't need to exist. By virtue of the fact that the client has
* an instance of this object, it means they also have the {@link FOUserAgent} since this's
* constructor is only used in {@link FOUserAgent}
*/
public FOUserAgent getUserAgent() {
return foUserAgent;

+ 1
- 1
src/java/org/apache/fop/apps/FopConfParser.java View File

@@ -39,9 +39,9 @@ import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.spi.ImageImplRegistry;
import org.apache.xmlgraphics.image.loader.util.Penalty;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.hyphenation.HyphenationTreeCache;

+ 23
- 53
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.image.loader.ImageContext;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver;
import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.io.InternalResourceResolver;
@@ -325,48 +326,41 @@ public final class FopFactory implements ImageContext {
return config.isAccessibilityEnabled();
}

/**
* Returns the image manager.
* @return the image manager
*/
/** @see FopFactoryConfig#getImageManager() */
public ImageManager getImageManager() {
return config.getImageManager();
}

/**
* Returns the overriding LayoutManagerMaker instance, if any.
* @return the overriding LayoutManagerMaker or null
*/
/** @see FopFactoryConfig#getLayoutManagerMakerOverride() */
public LayoutManagerMaker getLayoutManagerMakerOverride() {
return config.getLayoutManagerMakerOverride();
}

/** @return the hyphenation pattern names */
/** @see FopFactoryConfig#getHyphenationPatternNames() */
public Map<String, String> getHyphenationPatternNames() {
return config.getHyphenationPatternNames();
}

/**
* Returns whether FOP is strictly validating input XSL
* @return true of strict validation turned on, false otherwise
*/
/** @see FopFactoryConfig#validateStrictly() */
public boolean validateStrictly() {
return config.validateStrictly();
}

/**
* @return true if the indent inheritance should be broken when crossing reference area
* boundaries (for more info, see the javadoc for the relative member variable)
*/
/** @see FopFactoryConfig#isBreakIndentInheritanceOnReferenceAreaBoundary() */
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() {
return config.isBreakIndentInheritanceOnReferenceAreaBoundary();
}

/** @return the resolution for resolution-dependent input */
/** @see FopFactoryConfig#getSourceResolution() */
public float getSourceResolution() {
return config.getSourceResolution();
}

/** @see FopFactoryConfig#getTargetResolution() */
public float getTargetResolution() {
return config.getTargetResolution();
}

/**
* Returns the conversion factor from pixel units to millimeters. This
* depends on the desired source resolution.
@@ -377,11 +371,6 @@ public final class FopFactory implements ImageContext {
return UnitConv.IN2MM / getSourceResolution();
}

/** @return the resolution for resolution-dependant output */
public float getTargetResolution() {
return config.getTargetResolution();
}

/**
* Returns the conversion factor from pixel units to millimeters. This
* depends on the desired target resolution.
@@ -392,42 +381,26 @@ public final class FopFactory implements ImageContext {
return 25.4f / getTargetResolution();
}

/**
* Gets the default page-height to use as fallback,
* in case page-height="auto"
*
* @return the page-height, as a String
*/
/** @see FopFactoryConfig#getPageHeight() */
public String getPageHeight() {
return config.getPageHeight();
}

/**
* Gets the default page-width to use as fallback,
* in case page-width="auto"
*
* @return the page-width, as a String
*/
/** @see FopFactoryConfig#getPageWidth() */
public String getPageWidth() {
return config.getPageWidth();
}

/**
* Indicates whether a namespace URI is on the ignored list.
* @param namespaceURI the namespace URI
* @return true if the namespace is ignored by FOP
*/
/** @see FopFactoryConfig#isNamespaceIgnored(String) */
public boolean isNamespaceIgnored(String namespaceURI) {
return config.isNamespaceIgnored(namespaceURI);
}

/** @return the set of namespaces that are ignored by FOP */
/** @see FopFactoryConfig#getIgnoredNamespaces() */
public Set<String> getIgnoredNamespace() {
return config.getIgnoredNamespaces();
}

//------------------------------------------- Configuration stuff

/**
* Get the user configuration.
* @return the user configuration
@@ -436,24 +409,21 @@ public final class FopFactory implements ImageContext {
return config.getUserConfig();
}

/**
* Is the user configuration to be validated?
* @return if the user configuration should be validated
*/
/** @see FopFactoryConfig#validateUserConfigStrictly() */
public boolean validateUserConfigStrictly() {
return config.validateUserConfigStrictly();
}

//------------------------------------------- Font related stuff

/**
* Returns the font manager.
* @return the font manager
*/
/** @see FopFactoryConfig#getFontManager() */
public FontManager getFontManager() {
return config.getFontManager();
}

/** @see FopFactoryConfig#getFallbackResolver() */
FallbackResolver getFallbackResolver() {
return config.getFallbackResolver();
}

/**
* Returns the color space cache for this instance.
* <p>

+ 6
- 1
src/java/org/apache/fop/apps/FopFactoryBuilder.java View File

@@ -30,8 +30,9 @@ import org.apache.avalon.framework.configuration.Configuration;

import org.apache.xmlgraphics.image.loader.ImageContext;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
@@ -464,6 +465,10 @@ public final class FopFactoryBuilder {
public Map<String, String> getHyphenationPatternNames() {
return hyphPatNames;
}

public FallbackResolver getFallbackResolver() {
return enviro.getFallbackResolver();
}
}

private interface FopFactoryConfigBuilder {

+ 55
- 15
src/java/org/apache/fop/apps/FopFactoryConfig.java View File

@@ -26,8 +26,9 @@ import java.util.Set;
import org.apache.avalon.framework.configuration.Configuration;

import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver;
import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.layoutmgr.LayoutManagerMaker;

@@ -67,7 +68,10 @@ public interface FopFactoryConfig {
*/
boolean isAccessibilityEnabled();

/** @see {@link FopFactory#getLayoutManagerMakerOverride()} */
/**
* Returns the overriding LayoutManagerMaker instance, if any.
* @return the overriding LayoutManagerMaker or null
*/
LayoutManagerMaker getLayoutManagerMakerOverride();

/**
@@ -84,31 +88,54 @@ public interface FopFactoryConfig {
*/
URI getBaseURI();

/** @see {@link FopFactory#validateStrictly()} */
/**
* Returns whether FOP is strictly validating input XSL
* @return true of strict validation turned on, false otherwise
*/
boolean validateStrictly();

/** @see {@link FopFactory#validateUserConfigStrictly()} */
/**
* Is the user configuration to be validated?
* @return if the user configuration should be validated
*/
boolean validateUserConfigStrictly();

/** @see {@link FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()} */
/**
* @return true if the indent inheritance should be broken when crossing reference area
* boundaries (for more info, see the javadoc for the relative member variable)
*/
boolean isBreakIndentInheritanceOnReferenceAreaBoundary();

/** @see {@link FopFactory#getSourceResolution()} */
/** @return the resolution for resolution-dependent input */
float getSourceResolution();

/** @see {@link FopFactory#getTargetResolution()} */
/** @return the resolution for resolution-dependent output */
float getTargetResolution();

/** @see {@link FopFactory#getPageHeight()} */
/**
* Gets the default page-height to use as fallback,
* in case page-height="auto"
*
* @return the page-height, as a String
*/
String getPageHeight();

/** @see {@link FopFactory#getPageWidth()} */
/**
* Gets the default page-width to use as fallback,
* in case page-width="auto"
*
* @return the page-width, as a String
*/
String getPageWidth();

/** @see {@link FopFactory#getIgnoredNamespace()} */
/** @return the set of namespaces that are ignored by FOP */
Set<String> getIgnoredNamespaces();

/** @see {@link FopFactory#isNamespaceIgnored(String)} */
/**
* Indicates whether a namespace URI is on the ignored list.
* @param namespace the namespace URI
* @return true if the namespace is ignored by FOP
*/
boolean isNamespaceIgnored(String namespace);

/**
@@ -118,17 +145,30 @@ public interface FopFactoryConfig {
*/
Configuration getUserConfig();

/** @see {@link org.apache.fop.render.RendererFactory#isRendererPreferred()} */
/** @see org.apache.fop.render.RendererFactory#isRendererPreferred() */
boolean preferRenderer();

/** @see {@link FopFactory#getFontManager()} */
/**
* Returns the font manager.
* @return the font manager
*/
FontManager getFontManager();

/** @see {@link FopFactory#getImageManager()} */
/**
* Returns the image manager.
* @return the image manager
*/
ImageManager getImageManager();

boolean isComplexScriptFeaturesEnabled();

/** @see {@link FopFactory#getHyphenationPatternNames()} */
/** @return the hyphenation pattern names */
Map<String, String> getHyphenationPatternNames();

/**
* Controls the mechanisms that are used in the event that {@link javax.xml.transform.Source}
* used for resources couldn't be read.
* @return the fallback resolver
*/
FallbackResolver getFallbackResolver();
}

+ 3
- 1
src/java/org/apache/fop/apps/io/InternalResourceResolver.java View File

@@ -29,12 +29,14 @@ import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamSource;

import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;
import org.apache.xmlgraphics.util.uri.DataURIResolver;

/**
* This object holds the base URI from which to resolve URIs against as well as the resolver for
* resource acquisition. It also does some URI sanitization of common URI syntactical errors. This
* class takes in a {@link org.apache.fop.apps.io.ResourceResolver} and delegates all relevant
* class takes in a {@link org.apache.xmlgraphics.io.ResourceResolver} and delegates all relevant
* URIs to it.
*/
public class InternalResourceResolver {

+ 0
- 51
src/java/org/apache/fop/apps/io/ResourceResolver.java View File

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

/* $Id$ */

package org.apache.fop.apps.io;

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

/**
* Implementations of this resource resolver allow FOP users to control the URI resolution
* mechanism. All resource and output stream acquisition goes through this when its implementation
* is given to the {@link org.apache.fop.apps.EnvironmentProfile}.
*/
public interface ResourceResolver {

/**
* Get a resource given the URI pointing to said resource.
*
* @param uri the resource URI
* @return the resource
* @throws IOException if an I/O error occured during resource acquisition
*/
Resource getResource(URI uri) throws IOException;

/**
* Gets an output stream of a given URI.
*
* @param uri the output stream URI
* @return the output stream
* @throws IOException if an I/O error occured while creating an output stream
*/
OutputStream getOutputStream(URI uri) throws IOException;

}

+ 103
- 46
src/java/org/apache/fop/apps/io/ResourceResolverFactory.java View File

@@ -28,6 +28,11 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;
import org.apache.xmlgraphics.io.TempResourceResolver;
import org.apache.xmlgraphics.io.TempResourceURIGenerator;

/**
* A factory class for {@link ResourceResolver}s.
*/
@@ -70,10 +75,10 @@ public final class ResourceResolverFactory {
}

/**
* Creates a temporary-resource-schema aware resource resolver. Temporary resource URIs are
* Creates a temporary-resource-scheme aware resource resolver. Temporary resource URIs are
* created by {@link TempResourceURIGenerator}.
*
* @param tempResourceResolver the temporary-resource-schema resolver to use
* @param tempResourceResolver the temporary-resource-scheme resolver to use
* @param defaultResourceResolver the default resource resolver to use
* @return the ressource resolver
*/
@@ -83,9 +88,18 @@ public final class ResourceResolverFactory {
return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver);
}

public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder(
/**
* This creates the builder class for binding URI schemes to implementations of
* {@link ResourceResolver}. This allows users to define their own URI schemes such that they
* have finer control over the acquisition of resources.
*
* @param defaultResolver the default resource resolver that should be used in the event that
* none of the other registered resolvers match the scheme
* @return the scheme aware {@link ResourceResolver} builder
*/
public static SchemeAwareResourceResolverBuilder createSchemeAwareResourceResolverBuilder(
ResourceResolver defaultResolver) {
return new SchemaAwareResourceResolverBuilderImpl(defaultResolver);
return new SchemeAwareResourceResolverBuilderImpl(defaultResolver);
}

private static final class DefaultResourceResolver implements ResourceResolver {
@@ -99,10 +113,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);
}
@@ -121,26 +137,27 @@ public final class ResourceResolverFactory {
this.defaultResourceResolver = defaultResourceResolver;
}

private static boolean isTempUri(URI uri) {
return TempResourceURIGenerator.isTempUri(uri);
private static boolean isTempURI(URI uri) {
return TempResourceURIGenerator.isTempURI(uri);
}

/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException {
if (isTempUri(uri)) {
if (isTempURI(uri)) {
return tempResourceResolver.getResource(uri.getPath());
} else {
return defaultResourceResolver.getResource(uri);
}
}

/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
if (isTempUri(uri)) {
if (isTempURI(uri)) {
return tempResourceResolver.getOutputStream(uri.getPath());
} else {
return defaultResourceResolver.getOutputStream(uri);
}
}

}

private static class DefaultTempResourceResolver implements TempResourceResolver {
@@ -150,10 +167,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()) {
@@ -174,103 +193,141 @@ public final class ResourceResolverFactory {
}
}

private static final class SchemaAwareResourceResolver implements ResourceResolver {
private static final class SchemeAwareResourceResolver implements ResourceResolver {

private final Map<String, ResourceResolver> schemaHandlingResourceResolvers;
private final Map<String, ResourceResolver> schemeHandlingResourceResolvers;

private final ResourceResolver defaultResolver;

private SchemaAwareResourceResolver(
Map<String, ResourceResolver> schemaHandlingResourceResolvers,
private SchemeAwareResourceResolver(
Map<String, ResourceResolver> schemEHandlingResourceResolvers,
ResourceResolver defaultResolver) {
this.schemaHandlingResourceResolvers = schemaHandlingResourceResolvers;
this.schemeHandlingResourceResolvers = schemEHandlingResourceResolvers;
this.defaultResolver = defaultResolver;
}

private ResourceResolver getResourceResolverForSchema(URI uri) {
String schema = uri.getScheme();
if (schemaHandlingResourceResolvers.containsKey(schema)) {
return schemaHandlingResourceResolvers.get(schema);
private ResourceResolver getResourceResolverForScheme(URI uri) {
String scheme = uri.getScheme();
if (schemeHandlingResourceResolvers.containsKey(scheme)) {
return schemeHandlingResourceResolvers.get(scheme);
} else {
return defaultResolver;
}
}

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

/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
return getResourceResolverForSchema(uri).getOutputStream(uri);
return getResourceResolverForScheme(uri).getOutputStream(uri);
}
}

public interface SchemaAwareResourceResolverBuilder {

void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver);

/**
* Implementations of this interface will be builders for {@link ResourceResolver}, they bind
* URI schemes to their respective resolver. This gives users more control over the mechanisms
* by which URIs are resolved.
* <p>
* Here is an example of how this could be used:
* </p>
* <p><code>
* SchemeAwareResourceResolverBuilder builder
* = ResourceResolverFactory.createSchemeAwareResourceResolverBuilder(defaultResolver);
* builder.registerResourceResolverForScheme("test", testResolver);
* builder.registerResourceResolverForScheme("anotherTest", test2Resolver);
* ResourceResolver resolver = builder.build();
* </code></p>
* This will result in all URIs for the form "test:///..." will be resolved using the
* <code>testResolver</code> object; URIs of the form "anotherTest:///..." will be resolved
* using <code>test2Resolver</code>; all other URIs will be resolved from the defaultResolver.
*/
public interface SchemeAwareResourceResolverBuilder {

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

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

private static final class CompletedSchemaAwareResourceResolverBuilder
implements SchemaAwareResourceResolverBuilder {
private static final class CompletedSchemeAwareResourceResolverBuilder
implements SchemeAwareResourceResolverBuilder {

private static final SchemaAwareResourceResolverBuilder INSTANCE
= new CompletedSchemaAwareResourceResolverBuilder();
private static final SchemeAwareResourceResolverBuilder INSTANCE
= new CompletedSchemeAwareResourceResolverBuilder();

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

public void registerResourceResolverForSchema(String schema,
/** {@inheritDoc} */
public void registerResourceResolverForScheme(String scheme,
ResourceResolver resourceResolver) {
throw new IllegalStateException("Resource resolver already built");
}
}

private static final class ActiveSchemaAwareResourceResolverBuilder
implements SchemaAwareResourceResolverBuilder {
private static final class ActiveSchemeAwareResourceResolverBuilder
implements SchemeAwareResourceResolverBuilder {

private final Map<String, ResourceResolver> schemaHandlingResourceResolvers
private final Map<String, ResourceResolver> schemeHandlingResourceResolvers
= new HashMap<String, ResourceResolver>();

private final ResourceResolver defaultResolver;

private ActiveSchemaAwareResourceResolverBuilder(ResourceResolver defaultResolver) {
private ActiveSchemeAwareResourceResolverBuilder(ResourceResolver defaultResolver) {
this.defaultResolver = defaultResolver;
}

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

/** {@inheritDoc} */
public ResourceResolver build() {
return new SchemaAwareResourceResolver(
Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver);
return new SchemeAwareResourceResolver(
Collections.unmodifiableMap(schemeHandlingResourceResolvers), defaultResolver);
}

}

private static final class SchemaAwareResourceResolverBuilderImpl
implements SchemaAwareResourceResolverBuilder {
private static final class SchemeAwareResourceResolverBuilderImpl
implements SchemeAwareResourceResolverBuilder {

private SchemaAwareResourceResolverBuilder delegate;
private SchemeAwareResourceResolverBuilder delegate;

private SchemaAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) {
this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver);
private SchemeAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) {
this.delegate = new ActiveSchemeAwareResourceResolverBuilder(defaultResolver);
}

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

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

}

+ 0
- 48
src/java/org/apache/fop/apps/io/TempResourceResolver.java View File

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

/* $Id$ */

package org.apache.fop.apps.io;

import java.io.IOException;
import java.io.OutputStream;

/**
* Implementations of this interface resolve URIs for temporary files used by FOP. The temporary-
* resource URI scheme comes from {@link TempResourceURIGenerator#TMP_SCHEMA}.
*/
public interface TempResourceResolver {

/**
* Get a temporary-resource given the URI pointing to said resource.
*
* @param uri the resource URI
* @return the resource
* @throws IOException if an I/O error occured during resource acquisition
*/
Resource getResource(String id) throws IOException;

/**
* Gets an temporary-output stream of a given URI.
*
* @param uri the output stream URI
* @return the output stream
* @throws IOException if an I/O error occured while creating an output stream
*/
OutputStream getOutputStream(String id) throws IOException;
}

+ 0
- 57
src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java View File

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

package org.apache.fop.apps.io;

import java.net.URI;
import java.util.concurrent.atomic.AtomicLong;

/**
* Creates a URI for any temporary resource used within FOP.
*/
public final class TempResourceURIGenerator {

public static final String TMP_SCHEMA = "tmp";

private final String tempURIPrefix;

private final AtomicLong counter;

/**
* @param uriPrefix a prefix used to name the unique URI
*/
public TempResourceURIGenerator(String uriPrefix) {
counter = new AtomicLong();
tempURIPrefix = URI.create(TMP_SCHEMA + ":///" + uriPrefix).toASCIIString();
}

/**
* Generate a unique URI for a temporary resource
* @return the URI
*/
public URI generate() {
return URI.create(tempURIPrefix + getUniqueId());
}

private String getUniqueId() {
return Long.toHexString(counter.getAndIncrement());
}

public static boolean isTempUri(URI uri) {
return TMP_SCHEMA.equals(uri.getScheme());
}
}

+ 5
- 4
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -84,6 +84,7 @@ import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.LanguageTags;
import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.XMLUtil;

@@ -394,10 +395,10 @@ public class AreaTreeParser {

public void startElement(Attributes attributes) {
PageSequence pageSequence = new PageSequence(null);
String lang = attributes.getValue("language");
pageSequence.setLanguage(lang);
String country = attributes.getValue("country");
pageSequence.setCountry(country);
String lang = attributes.getValue(javax.xml.XMLConstants.XML_NS_URI, "lang");
if (lang != null) {
pageSequence.setLocale(LanguageTags.toLocale(lang));
}
transferForeignObjects(attributes, pageSequence);
areaStack.push(pageSequence);
}

+ 2
- 1
src/java/org/apache/fop/area/CachedRenderPagesModel.java View File

@@ -35,9 +35,10 @@ import org.xml.sax.SAXException;

import org.apache.commons.io.IOUtils;

import org.apache.xmlgraphics.io.TempResourceURIGenerator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.io.TempResourceURIGenerator;
import org.apache.fop.fonts.FontInfo;

/**

+ 13
- 34
src/java/org/apache/fop/area/PageSequence.java View File

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

import java.util.List;
import java.util.Locale;

/**
* Represents a page sequence in the area tree.
@@ -28,8 +29,8 @@ public class PageSequence extends AreaTreeObject {

private List<PageViewport> pages = new java.util.ArrayList<PageViewport>();
private LineArea title;
private String language;
private String country;
private Locale locale;

/**
* Main constructor
@@ -88,43 +89,21 @@ public class PageSequence extends AreaTreeObject {
}

/**
* Returns the language of the page-sequence.
* @return the language (the value of the language property, "none" is mapped to null)
*/
public String getLanguage() {
return this.language;
}

/**
* Sets the language that applies to this page-sequence.
* @param language the language to set ("none" is mapped to null)
*/
public void setLanguage(String language) {
if ("none".equals(language)) {
this.language = null;
} else {
this.language = language;
}
}

/**
* Returns the country of the page-sequence.
* @return the country (the value of the country property, "none" is mapped to null)
* Sets the locale that applies to this page-sequence.
*
* @param locale the locale to set
*/
public String getCountry() {
return this.country;
public void setLocale(Locale locale) {
this.locale = locale;
}

/**
* Sets the country that applies to this page-sequence.
* @param country the country to set ("none" is mapped to null)
* Returns the locale of this page-sequence.
*
* @return the locale, {@code null} if not set
*/
public void setCountry(String country) {
if ("none".equals(country)) {
this.country = null;
} else {
this.country = country;
}
public Locale getLocale() {
return locale;
}

}

+ 18
- 159
src/java/org/apache/fop/area/PageViewport.java View File

@@ -34,6 +34,10 @@ import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.AbstractRetrieveMarker;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.flow.Markers;
import org.apache.fop.fo.pagination.SimplePageMaster;
import org.apache.fop.traits.WritingModeTraitsGetter;

@@ -81,13 +85,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable {

private Map<String, List<PageViewport>> pendingResolved = null;

// hashmap of markers for this page
// start and end are added by the fo that contains the markers
private Map<String, Marker> markerFirstStart = null;
private Map<String, Marker> markerLastStart = null;
private Map<String, Marker> markerFirstAny = null;
private Map<String, Marker> markerLastEnd = null;
private Map<String, Marker> markerLastAny = null;
private Markers pageMarkers;

/**
* logging instance
@@ -352,115 +350,23 @@ public class PageViewport extends AreaTreeObject implements Resolvable {
}

/**
* Add the markers for this page.
* Only the required markers are kept.
* For "first-starting-within-page" it adds the markers
* that are starting only if the marker class name is not
* already added.
* For "first-including-carryover" it adds any starting marker
* if the marker class name is not already added.
* For "last-starting-within-page" it adds all marks that
* are starting, replacing earlier markers.
* For "last-ending-within-page" it adds all markers that
* are ending, replacing earlier markers.
*
* Should this logic be placed in the Page layout manager.
* Register the markers for this page.
*
* @param marks the map of markers to add
* @param starting if the area being added is starting or ending
* @param isfirst if the area being added has is-first trait
* @param islast if the area being added has is-last trait
*/
public void addMarkers(Map<String, Marker> marks, boolean starting,
boolean isfirst, boolean islast) {

if (marks == null) {
return;
}
if (log.isDebugEnabled()) {
log.debug("--" + marks.keySet() + ": "
+ (starting ? "starting" : "ending")
+ (isfirst ? ", first" : "")
+ (islast ? ", last" : ""));
}

// at the start of the area, register is-first and any areas
if (starting) {
if (isfirst) {
if (markerFirstStart == null) {
markerFirstStart = new HashMap<String, Marker>();
}
if (markerFirstAny == null) {
markerFirstAny = new HashMap<String, Marker>();
}
// first on page: only put in new values, leave current
for (String key : marks.keySet()) {
if (!markerFirstStart.containsKey(key)) {
markerFirstStart.put(key, marks.get(key));
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": "
+ "Adding marker " + key + " to FirstStart");
}
}
if (!markerFirstAny.containsKey(key)) {
markerFirstAny.put(key, marks.get(key));
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": "
+ "Adding marker " + key + " to FirstAny");
}
}
}
if (markerLastStart == null) {
markerLastStart = new HashMap<String, Marker>();
}
// last on page: replace all
markerLastStart.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": "
+ "Adding all markers to LastStart");
}
} else {
if (markerFirstAny == null) {
markerFirstAny = new HashMap<String, Marker>();
}
// first on page: only put in new values, leave current
for (String key : marks.keySet()) {
if (!markerFirstAny.containsKey(key)) {
markerFirstAny.put(key, marks.get(key));
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": "
+ "Adding marker " + key + " to FirstAny");
}
}
}
}
} else {
// at the end of the area, register is-last and any areas
if (islast) {
if (markerLastEnd == null) {
markerLastEnd = new HashMap<String, Marker>();
}
// last on page: replace all
markerLastEnd.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": "
+ "Adding all markers to LastEnd");
}
}
if (markerLastAny == null) {
markerLastAny = new HashMap<String, Marker>();
}
// last on page: replace all
markerLastAny.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": "
+ "Adding all markers to LastAny");
}
public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) {
if (pageMarkers == null) {
pageMarkers = new Markers();
}
pageMarkers.register(marks, starting, isfirst, islast);
}


/**
* Get a marker from this page.
* Resolve a marker from this page.
* This will retrieve a marker with the class name
* and position.
*
@@ -468,64 +374,17 @@ public class PageViewport extends AreaTreeObject implements Resolvable {
* @param pos the position to retrieve
* @return Object the marker found or null
*/
public Marker getMarker(String name, int pos) {
Marker mark = null;
String posName = null;
switch (pos) {
case EN_FSWP:
if (markerFirstStart != null) {
mark = markerFirstStart.get(name);
posName = "FSWP";
}
if (mark == null && markerFirstAny != null) {
mark = markerFirstAny.get(name);
posName = "FirstAny after " + posName;
}
break;
case EN_FIC:
if (markerFirstAny != null) {
mark = markerFirstAny.get(name);
posName = "FIC";
}
break;
case EN_LSWP:
if (markerLastStart != null) {
mark = markerLastStart.get(name);
posName = "LSWP";
}
if (mark == null && markerLastAny != null) {
mark = markerLastAny.get(name);
posName = "LastAny after " + posName;
}
break;
case EN_LEWP:
if (markerLastEnd != null) {
mark = markerLastEnd.get(name);
posName = "LEWP";
}
if (mark == null && markerLastAny != null) {
mark = markerLastAny.get(name);
posName = "LastAny after " + posName;
}
break;
default:
assert false;
}
if (log.isTraceEnabled()) {
log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name
+ " at position " + posName);
public Marker resolveMarker(AbstractRetrieveMarker rm) {
if (pageMarkers == null) {
return null;
}
return mark;
return pageMarkers.resolve(rm);
}

/** Dumps the current marker data to the logger. */
public void dumpMarkers() {
if (log.isTraceEnabled()) {
log.trace("FirstAny: " + this.markerFirstAny);
log.trace("FirstStart: " + this.markerFirstStart);
log.trace("LastAny: " + this.markerLastAny);
log.trace("LastEnd: " + this.markerLastEnd);
log.trace("LastStart: " + this.markerLastStart);
if (pageMarkers != null) {
pageMarkers.dump();
}
}


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

+ 7
- 2
src/java/org/apache/fop/fo/Constants.java View File

@@ -785,8 +785,11 @@ public interface Constants {
*/
int PR_X_NUMBER_CONVERSION_FEATURES = 276;

/** Scope for table header */
int PR_X_HEADER_COLUMN = 277;

/** Number of property constants defined */
int PROPERTY_COUNT = 276;
int PROPERTY_COUNT = 277;

// compound property constants

@@ -1224,6 +1227,8 @@ public interface Constants {
int EN_BT = 204; // bottom to top
/** Enumeration constant */
int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode
/** Enumeration constant -- for fo:retrieve-table-marker */
int EN_FIRST_INCLUDING_CARRYOVER = 206;
/** Number of enumeration constants defined */
int ENUM_COUNT = 205;
int ENUM_COUNT = 206;
}

+ 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.
*/

+ 30
- 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;
@@ -561,6 +562,19 @@ public abstract class FONode implements Cloneable {
getFOValidationEventProducer().invalidChild(this, parentName, qn, ruleViolated, loc);
}

/**
* Helper function to return "not supported child" exceptions. Note that the child is valid, just not
* supported yet by FOP.
*
* @param loc org.xml.sax.Locator object of the error (*not* parent node)
* @param nsURI namespace URI of incoming invalid node
* @param lName local name (i.e., no prefix) of incoming node
* @throws ValidationException the validation error provoked by the method call
*/
protected void notSupportedChildError(Locator loc, String nsURI, String lName) throws ValidationException {
getFOValidationEventProducer().notSupportedChild(this, getName(), new QName(nsURI, lName), loc);
}

/**
* Helper function to throw an error caused by missing mandatory child elements.
* (e.g., <code>fo:layout-master-set</code> not having any <code>fo:page-master</code>
@@ -601,6 +615,22 @@ public abstract class FONode implements Cloneable {
getFOValidationEventProducer().missingProperty(this, getName(), propertyName, locator);
}



/**
* Helper function to throw an error caused by an invalid property
*
* @param propertyName the name of the property.
* @param propertyValue the value of the property.
* * @param e optional property parsing exception.
* @throws ValidationException the validation error provoked by the method call
*/
protected void invalidPropertyValueError(String propertyName, String propertyValue, Exception e)
throws ValidationException {
getFOValidationEventProducer().invalidPropertyValue(this, getName(), propertyName,
propertyValue, new PropertyException(e), locator);
}

/**
* Helper function to return "Error(line#/column#)" string for
* above exception messages

+ 11
- 3
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;
@@ -2177,7 +2178,8 @@ public final class FOPropertyMapping implements Constants {
m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE);
m.setInherited(false);
m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING"));
m.addEnum("first-including-carryover", getEnumProperty(EN_FIC, "FIC"));
m.addEnum("first-including-carryover",
getEnumProperty(EN_FIRST_INCLUDING_CARRYOVER, "FIRST_INCLUDING_CARRYOVER"));
m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING"));
m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING"));
m.setDefault("first-starting");
@@ -2188,7 +2190,7 @@ public final class FOPropertyMapping implements Constants {
m.setInherited(false);
m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE"));
m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT"));
m.addEnum("page", getEnumProperty(EN_DOCUMENT, "PAGE"));
m.addEnum("page", getEnumProperty(EN_PAGE, "PAGE"));
m.setDefault("table");
addPropertyMaker("retrieve-boundary-within-table", m);
}
@@ -2267,7 +2269,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);
@@ -2512,6 +2514,12 @@ public final class FOPropertyMapping implements Constants {
m.setInherited(false);
m.setDefault("false");
addPropertyMaker("table-omit-header-at-break", m);

// fox:scope
m = new EnumProperty.Maker(PR_X_HEADER_COLUMN);
m.useGeneric(genericBoolean);
m.setDefault("false");
addPropertyMaker("fox:header", m);
}

private void createWritingModeProperties() {

+ 12
- 0
src/java/org/apache/fop/fo/FOValidationEventProducer.java View File

@@ -89,6 +89,18 @@ public interface FOValidationEventProducer extends EventProducer {
void invalidChild(Object source, String elementName, QName offendingNode, String ruleViolated,
Locator loc) throws ValidationException;

/**
* A valid but not yet supported child was encountered.
*
* @param source the event source
* @param elementName the name of the context node
* @param offendingNode the offending node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
*/
void notSupportedChild(Object source, String elementName, QName offendingNode, Locator loc)
throws ValidationException;

/**
* A required child element is missing.
* @param source the event source

+ 1
- 0
src/java/org/apache/fop/fo/FOValidationEventProducer.xml View File

@@ -17,6 +17,7 @@
<message key="tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message>
<message key="nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message>
<message key="invalidChild">"{offendingNode}" is not a valid child of "{elementName}"![ {ruleViolated,lookup}]{{locator}}</message>
<message key="notSupportedChild">"{offendingNode}" as a child of "{elementName}" is not supported yet!{{locator}}</message>
<message key="missingChildElement">"{elementName}" is missing child elements.[ Required content model: {contentModel}]{{locator}}</message>
<message key="missingProperty">Element "{elementName}" is missing required property "{propertyName}"!{{locator}}</message>
<message key="idNotUnique">Property ID "{id}" (found on "{elementName}") previously used; ID values must be unique within a document!{severity,equals,EventSeverity:FATAL,, Any reference to it will be considered a reference to the first occurrence in the document.}{{locator}}</message>

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

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

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -35,6 +36,7 @@ import org.apache.xmlgraphics.util.QName;
import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.properties.PropertyMaker;

/**
@@ -65,7 +67,7 @@ public abstract class FObj extends FONode implements Constants {
private boolean isOutOfLineFODescendant = false;

/** Markers added to this element. */
private Map markers = null;
private Map<String, Marker> markers;

private int bidiLevel = -1;

@@ -356,7 +358,7 @@ public abstract class FObj extends FONode implements Constants {
}
}
if (markers == null) {
markers = new java.util.HashMap();
markers = new HashMap<String, Marker>();
}
if (!markers.containsKey(mcname)) {
markers.put(mcname, marker);
@@ -376,7 +378,7 @@ public abstract class FObj extends FONode implements Constants {
/**
* @return the collection of Markers attached to this object
*/
public Map getMarkers() {
public Map<String, Marker> getMarkers() {
return markers;
}

@@ -522,6 +524,11 @@ public abstract class FObj extends FONode implements Constants {
int found = 1;
FONode temp = getParent();
while (temp != null) {
if (temp instanceof TableCell && (ancestorID == FO_TABLE_HEADER || ancestorID == FO_TABLE_FOOTER)) {
// note that if the retrieve-table-marker is not in a table-header/footer an exception is
// thrown, so no need to reset this flag in that case
((TableCell) temp).flagAsHavingRetrieveTableMarker();
}
if (temp.getNameId() == ancestorID) {
return found;
}

+ 1
- 0
src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java View File

@@ -52,6 +52,7 @@ public class ExtensionElementMapping extends ElementMapping {
PROPERTY_ATTRIBUTES.add("disable-column-balancing");
//These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add("alt-text");
PROPERTY_ATTRIBUTES.add("header");
}

/**

+ 3
- 0
src/java/org/apache/fop/fo/extensions/InternalElementMapping.java View File

@@ -43,12 +43,15 @@ public class InternalElementMapping extends ElementMapping {
/** The "struct-ref" attribute, to refer to a structure tree element. */
public static final String STRUCT_REF = "struct-ref";

public static final String SCOPE = "scope";

private static final Set<String> PROPERTY_ATTRIBUTES = new java.util.HashSet<String>();

static {
//These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add(STRUCT_ID);
PROPERTY_ATTRIBUTES.add(STRUCT_REF);
PROPERTY_ATTRIBUTES.add(SCOPE);
}

/**

+ 44
- 0
src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java View File

@@ -46,6 +46,11 @@ public abstract class AbstractRetrieveMarker extends FObjMixed {

private String retrieveClassName;

private int position;
private String positionLabel;
private int boundary;
private String boundaryLabel;

/**
* Create a new AbstractRetrieveMarker instance that
* is a child of the given {@link FONode}
@@ -206,4 +211,43 @@ public abstract class AbstractRetrieveMarker extends FObjMixed {
return this.retrieveClassName;
}

protected void setBoundaryLabel(String label) {
this.boundaryLabel = label;
}

protected void setPositionLabel(String label) {
this.positionLabel = label;
}

public String getBoundaryLabel() {
return this.boundaryLabel;
}

public String getPositionLabel() {
return this.positionLabel;
}

protected void setPosition(int position) {
this.position = position;
}

protected void setBoundary(int boundary) {
this.boundary = boundary;
}

public int getPosition() {
return this.position;
}

public int getBoundary() {
return this.boundary;
}

public abstract String getLocalName();

public abstract int getNameId();

public void changePositionTo(int position) {
this.position = position;
}
}

+ 216
- 0
src/java/org/apache/fop/fo/flow/Markers.java View File

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

/* $Id$ */

package org.apache.fop.fo.flow;

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

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

import org.apache.fop.fo.Constants;

/**
* A class to register and resolve markers.
*/
public final class Markers {

// IsAny means either IsFirst or IsLast
private Map<String, Marker> firstQualifyingIsFirst;
private Map<String, Marker> firstQualifyingIsAny;
private Map<String, Marker> lastQualifyingIsFirst;
private Map<String, Marker> lastQualifyingIsLast;
private Map<String, Marker> lastQualifyingIsAny;

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

/**
* Registers a marker with the position traits set.
* Only the required markers are kept.
* For "first-starting-within-page" it adds the markers
* that are starting only if the marker class name is not
* already added.
* For "first-including-carryover" it adds any starting marker
* if the marker class name is not already added.
* For "last-starting-within-page" it adds all marks that
* are starting, replacing earlier markers.
* For "last-ending-within-page" it adds all markers that
* are ending, replacing earlier markers.
*
* @param marks a map of markers to register
* @param starting whether the registration happens at the start (true) or end (false) the the area
* @param isfirst whether it is the first area of the parent LM
* @param islast whether it is the last area of the parent LM
*/
public void register(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) {
// TODO: find way to put the page number in the log tracing

if (marks == null) {
return;
}
if (log.isDebugEnabled()) {
log.debug("--" + marks.keySet() + ": " + (starting ? "starting" : "ending")
+ (isfirst ? ", first" : "") + (islast ? ", last" : ""));
}

if (starting) {
// at the start of the area, register is-first and any areas
if (firstQualifyingIsAny == null) {
firstQualifyingIsAny = new HashMap<String, Marker>();
}
if (isfirst) {
if (firstQualifyingIsFirst == null) {
firstQualifyingIsFirst = new HashMap<String, Marker>();
}
// first on scope: only put in new values, leave current
Set<Map.Entry<String, Marker>> entries = marks.entrySet();
for (Map.Entry<String, Marker> entry : entries) {
String key = entry.getKey();
Marker marker = entry.getValue();
if (!firstQualifyingIsFirst.containsKey(key)) {
firstQualifyingIsFirst.put(key, marker);
if (log.isTraceEnabled()) {
log.trace("Adding marker " + key + " to firstQualifyingIsFirst");
}
}
if (!firstQualifyingIsAny.containsKey(key)) {
firstQualifyingIsAny.put(key, marker);
if (log.isTraceEnabled()) {
log.trace("Adding marker " + key + " to firstQualifyingIsAny");
}
}
}
if (lastQualifyingIsFirst == null) {
lastQualifyingIsFirst = new HashMap<String, Marker>();
}
// last on scope: replace all
lastQualifyingIsFirst.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("Adding all markers to LastStart");
}
} else {
// first on scope: only put in new values, leave current
Set<Map.Entry<String, Marker>> entries = marks.entrySet();
for (Map.Entry<String, Marker> entry : entries) {
String key = entry.getKey();
Marker marker = entry.getValue();
if (!firstQualifyingIsAny.containsKey(key)) {
firstQualifyingIsAny.put(key, marker);
if (log.isTraceEnabled()) {
log.trace("Adding marker " + key + " to firstQualifyingIsAny");
}
}
}
}
} else {
// at the end of the area, register is-last and any areas
if (islast) {
if (lastQualifyingIsLast == null) {
lastQualifyingIsLast = new HashMap<String, Marker>();
}
// last on page: replace all
lastQualifyingIsLast.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("Adding all markers to lastQualifyingIsLast");
}
}
if (lastQualifyingIsAny == null) {
lastQualifyingIsAny = new HashMap<String, Marker>();
}
// last on page: replace all
lastQualifyingIsAny.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("Adding all markers to lastQualifyingIsAny");
}
}
}

/**
* Retrieves the best candidate marker for the given position.
* @param name the key used to register the marker
* @param pos the retrieval scope position
* @return a Marker instance
*/
public Marker resolve(AbstractRetrieveMarker arm) {
Marker mark = null;
int pos = arm.getPosition();
String name = arm.getRetrieveClassName();
String posName = arm.getPositionLabel();
String localName = arm.getLocalName();
switch (pos) {
case Constants.EN_FSWP: // retrieve-marker
case Constants.EN_FIRST_STARTING: // retrieve-table-marker
if (firstQualifyingIsFirst != null) {
mark = firstQualifyingIsFirst.get(name);
}
if (mark == null && firstQualifyingIsAny != null) {
mark = firstQualifyingIsAny.get(name);
posName = "FirstAny after " + posName;
}
break;
case Constants.EN_FIC: // retrieve-marker
case Constants.EN_FIRST_INCLUDING_CARRYOVER: // retrieve-table-marker
if (firstQualifyingIsAny != null) {
mark = firstQualifyingIsAny.get(name);
}
break;
case Constants.EN_LSWP: // retrieve-marker
case Constants.EN_LAST_STARTING: // retrieve-table-marker
if (lastQualifyingIsFirst != null) {
mark = lastQualifyingIsFirst.get(name);
}
if (mark == null && lastQualifyingIsAny != null) {
mark = lastQualifyingIsAny.get(name);
posName = "LastAny after " + posName;
}
break;
case Constants.EN_LEWP: // retrieve-marker
case Constants.EN_LAST_ENDING: // retrieve-table-marker
if (lastQualifyingIsLast != null) {
mark = lastQualifyingIsLast.get(name);
}
if (mark == null && lastQualifyingIsAny != null) {
mark = lastQualifyingIsAny.get(name);
posName = "LastAny after " + posName;
}
break;
default:
throw new RuntimeException("Invalid position attribute in " + localName + ".");
}
if (log.isTraceEnabled()) {
// TODO: find way to put the page number here
log.trace(localName + ": name[" + name + "]; position [" + posName + "]");
}
return mark;
}

/** Dumps the current marker data to the logger. */
public void dump() {
if (log.isTraceEnabled()) {
log.trace("FirstAny: " + this.firstQualifyingIsAny);
log.trace("FirstStart: " + this.firstQualifyingIsFirst);
log.trace("LastAny: " + this.lastQualifyingIsAny);
log.trace("LastEnd: " + this.lastQualifyingIsLast);
log.trace("LastStart: " + this.lastQualifyingIsFirst);
}
}

}

+ 7
- 10
src/java/org/apache/fop/fo/flow/RetrieveMarker.java View File

@@ -34,11 +34,6 @@ import org.apache.fop.fo.PropertyList;
*/
public class RetrieveMarker extends AbstractRetrieveMarker {

// The value of properties relevant for fo:retrieve-marker.
private int retrievePosition;
private int retrieveBoundary;
// End of property values

/**
* Create a new RetrieveMarker instance that is a
* child of the given {@link FONode}.
@@ -70,8 +65,10 @@ public class RetrieveMarker extends AbstractRetrieveMarker {
/** {@inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
this.retrievePosition = pList.get(PR_RETRIEVE_POSITION).getEnum();
this.retrieveBoundary = pList.get(PR_RETRIEVE_BOUNDARY).getEnum();
setPosition(pList.get(PR_RETRIEVE_POSITION).getEnum());
setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION).getObject());
setBoundary(pList.get(PR_RETRIEVE_BOUNDARY).getEnum());
setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY).getObject());
}

/**
@@ -84,19 +81,19 @@ public class RetrieveMarker extends AbstractRetrieveMarker {
* {@link org.apache.fop.fo.Constants#EN_LEWP}.
*/
public int getRetrievePosition() {
return this.retrievePosition;
return getPosition();
}

/**
* Return the value for the <code>retrieve-boundary</code>
* property
* @return the value for retrieve-boundary-within-table; one of
* @return the value for retrieve-boundary; one of
* {@link org.apache.fop.fo.Constants#EN_PAGE},
* {@link org.apache.fop.fo.Constants#EN_PAGE_SEQUENCE},
* {@link org.apache.fop.fo.Constants#EN_DOCUMENT}.
*/
public int getRetrieveBoundary() {
return this.retrieveBoundary;
return getBoundary();
}

/** {@inheritDoc} */

+ 14
- 11
src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java View File

@@ -32,11 +32,6 @@ import org.apache.fop.fo.PropertyList;
*/
public class RetrieveTableMarker extends AbstractRetrieveMarker {

// The value of properties relevant for fo:retrieve-table-marker.
private int retrievePositionWithinTable;
private int retrieveBoundaryWithinTable;
// end property values

/**
* Create a new RetrieveTableMarker instance that is
* a child of the given {@link FONode}.
@@ -67,10 +62,10 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker {
/** {@inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
this.retrievePositionWithinTable
= pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum();
this.retrieveBoundaryWithinTable
= pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum();
setPosition(pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum());
setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getObject());
setBoundary(pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum());
setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getObject());
}

/**
@@ -83,7 +78,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker {
* {@link org.apache.fop.fo.Constants#EN_LAST_ENDING}.
*/
public int getRetrievePositionWithinTable() {
return this.retrievePositionWithinTable;
return getPosition();
}

/**
@@ -95,7 +90,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker {
* {@link org.apache.fop.fo.Constants#EN_PAGE}.
*/
public int getRetrieveBoundaryWithinTable() {
return this.retrieveBoundaryWithinTable;
return getBoundary();
}

/** {@inheritDoc} */
@@ -110,4 +105,12 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker {
public int getNameId() {
return FO_RETRIEVE_TABLE_MARKER;
}

/** {@inheritDoc} */
public void clearChildNodes() {
super.clearChildNodes();
this.currentTextNode = null;
this.lastFOTextProcessed = null;
}

}

+ 9
- 0
src/java/org/apache/fop/fo/flow/table/TableCell.java View File

@@ -62,6 +62,8 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder {
/** used for FO validation */
private boolean blockItemFound = false;

private boolean hasRetrieveTableMarker;

/**
* Create a TableCell instance with the given {@link FONode}
* as parent.
@@ -247,4 +249,11 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder {
return FO_TABLE_CELL;
}

public void flagAsHavingRetrieveTableMarker() {
hasRetrieveTableMarker = true;
}

public boolean hasRetrieveTableMarker() {
return hasRetrieveTableMarker;
}
}

+ 12
- 0
src/java/org/apache/fop/fo/flow/table/TableColumn.java View File

@@ -24,6 +24,7 @@ import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
@@ -44,6 +45,7 @@ public class TableColumn extends TableFObj {
private Length columnWidth;
private int numberColumnsRepeated;
private int numberColumnsSpanned;
private boolean isHeader;
// Unused but valid items, commented out for performance:
// private int visibility;
// End of property values
@@ -120,6 +122,7 @@ public class TableColumn extends TableFObj {
if (!this.implicitColumn) {
this.pList = pList;
}
isHeader = (pList.get(Constants.PR_X_HEADER_COLUMN).getEnum() == Constants.EN_TRUE);
}

/** {@inheritDoc} */
@@ -263,4 +266,13 @@ public class TableColumn extends TableFObj {
this.pList = null;
}

/**
* Returns {@code true} if this column is made of header cells.
*
* @return {@code true} if cells in this column are like TH cells in HTML
*/
public boolean isHeader() {
return isHeader;
}

}

+ 2
- 0
src/java/org/apache/fop/fo/flow/table/TablePart.java View File

@@ -169,6 +169,8 @@ public abstract class TablePart extends TableCellContainer {
getUserAgent().getEventBroadcaster());
eventProducer.noMixRowsAndCells(this, getName(), getLocator());
}
} else if (localName.equals("retrieve-table-marker")) {
notSupportedChildError(loc, nsURI, localName);
} else {
invalidChildError(loc, nsURI, localName);
}

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


+ 9
- 20
src/java/org/apache/fop/fo/pagination/PageSequence.java View File

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

package org.apache.fop.fo.pagination;

import java.util.Locale;
import java.util.Map;
import java.util.Stack;

@@ -30,6 +31,7 @@ import org.apache.fop.datatypes.Numeric;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.properties.CommonHyphenation;
import org.apache.fop.traits.Direction;
import org.apache.fop.traits.WritingMode;
import org.apache.fop.traits.WritingModeTraits;
@@ -41,13 +43,11 @@ import org.apache.fop.traits.WritingModeTraitsGetter;
*/
public class PageSequence extends AbstractPageSequence implements WritingModeTraitsGetter {

// The value of FO traits (refined properties) that apply to fo:page-sequence.
private String country;
private String language;
private String masterReference;
private Numeric referenceOrientation;
private WritingModeTraits writingModeTraits;
// End of trait values

private Locale locale;

// There doesn't seem to be anything in the spec requiring flows
// to be in the order given, only that they map to the regions
@@ -90,8 +90,9 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra
/** {@inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
country = pList.get(PR_COUNTRY).getString();
language = pList.get(PR_LANGUAGE).getString();
String country = pList.get(PR_COUNTRY).getString();
String language = pList.get(PR_LANGUAGE).getString();
locale = CommonHyphenation.toLocale(language, country);
masterReference = pList.get(PR_MASTER_REFERENCE).getString();
referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric();
writingModeTraits = new WritingModeTraits
@@ -320,20 +321,8 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra
return FO_PAGE_SEQUENCE;
}

/**
* Get the value of the <code>country</code> trait.
* @return the country trait value
*/
public String getCountry() {
return this.country;
}

/**
* Get the value of the <code>language</code> trait.
* @return the language trait value
*/
public String getLanguage() {
return this.language;
public Locale getLocale() {
return locale;
}

/**

+ 2
- 11
src/java/org/apache/fop/fo/pagination/Root.java View File

@@ -36,6 +36,7 @@ import org.apache.fop.fo.extensions.destination.Destination;
import org.apache.fop.fo.pagination.bookmarks.BookmarkTree;
import org.apache.fop.fo.properties.CommonAccessibility;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
import org.apache.fop.fo.properties.CommonHyphenation;

/**
* Class modeling the <a href="http://www.w3.org/TR/xsl/#fo_root">
@@ -92,17 +93,7 @@ public class Root extends FObj implements CommonAccessibilityHolder {
mediaUsage = pList.get(PR_MEDIA_USAGE).getEnum();
String language = pList.get(PR_LANGUAGE).getString();
String country = pList.get(PR_COUNTRY).getString();
if (isLocalePropertySet(language)) {
if (isLocalePropertySet(country)) {
locale = new Locale(language, country);
} else {
locale = new Locale(language);
}
}
}

private boolean isLocalePropertySet(String property) {
return property != null && !property.equals("none");
locale = CommonHyphenation.toLocale(language, country);
}

/** {@inheritDoc} */

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

+ 37
- 0
src/java/org/apache/fop/fo/properties/CommonHyphenation.java View File

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

package org.apache.fop.fo.properties;

import java.util.Locale;

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

@@ -185,6 +187,41 @@ public final class CommonHyphenation {
return font.getCharWidth(hyphChar);
}

/**
* Creates and returns a {@link Locale} representation of the language and country.
*
* @return the language (and the country if set) represented as a locale, {@code null}
* if the language has not been set (i.e., has been left to its initial value of
* "none")
*/
public Locale getLocale() {
return toLocale(language.getString(), country.getString());
}

/**
* Creates and returns a {@link Locale} representation of the given language, and the
* given country if set. The country is considered to be set if not {@code null} and
* not set to "none".
*
* @return the language and country represented as a locale, {@code null} if the
* language is null or "none" (case insensitive)
*/
public static Locale toLocale(String language, String country) {
Locale locale = null;
if (isDefined(language)) {
if (isDefined(country)) {
locale = new Locale(language, country);
} else {
locale = new Locale(language);
}
}
return locale;
}

private static boolean isDefined(String property) {
return !(property == null || property.equalsIgnoreCase("none"));
}

/** {@inheritDoc} */
public boolean equals(Object obj) {
if (obj == 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 index the subset index (character selector)
* @return the Unicode value or "NOT A CHARACTER" (0xFFFF)
*/
char getUnicode(int index);

/**
* Maps a character to a character selector for a font subset. If the character isn't in the
* subset, yet, it is added and a new character selector returned. Otherwise, the already
* allocated character selector is returned from the existing map/subset.
* @param glyphIndex the glyph index of the character
* @param unicode the Unicode index of the character
* @return the subset index
*/
int mapChar(int glyphIndex, char unicode);

/**
* Returns an unmodifiable Map of the font subset. It maps from glyph index to
* character selector (i.e. the subset index in this case).
* @return Map Map&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();
}
}

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

@@ -52,7 +52,6 @@ public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo>

/**
* Main constructor
* @param fontInfoConfig the configuration object
* @param fontManager the font manager
* @param listener the font event listener
* @param strict true if an Exception should be thrown if an error is found.

+ 9
- 7
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));
@@ -462,10 +465,9 @@ public final class FontCache implements Serializable {
}

/**
* Retrieve the last modified date/time of a URL.
* Retrieve the last modified date/time of a URI.
*
* @param url
* the URL
* @param uri the URI
* @return the last modified date/time
*/
public static long getLastModified(URI uri) {

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

+ 8
- 28
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,30 +112,14 @@ 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));
}

/**
* Whether or not to cache results of font triplet detection/auto-config
* @param useCache use cache or not
*/
public void disableFontCache() {
fontCacheManager = FontCacheManagerFactory.createDisabled();
@@ -149,7 +130,7 @@ public class FontManager {
* @return the font cache
*/
public FontCache getFontCache() {
return fontCacheManager.load(getCacheFile());
return fontCacheManager.load();
}

/**
@@ -158,16 +139,15 @@ public class FontManager {
* @throws FOPException fop exception
*/
public void saveCache() throws FOPException {
fontCacheManager.save(getCacheFile());
fontCacheManager.save();
}

/**
* Deletes the current FontCache file
* @return Returns true if the font cache file was successfully deleted.
* @throws FOPException -
* @throws FOPException if an error was thrown while deleting the cache
*/
public void deleteCache() throws FOPException {
fontCacheManager.delete(getCacheFile(true));
fontCacheManager.delete();
}

/**

+ 17
- 17
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;
@@ -30,9 +29,10 @@ import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.io.ResourceResolver;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.ResourceResolverFactory;
import org.apache.fop.fonts.substitute.FontSubstitutions;
import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator;
@@ -72,6 +72,19 @@ public class FontManagerConfigurator {
* @throws FOPException if an exception occurs while processing the configuration
*/
public void configure(FontManager fontManager, boolean strict) throws FOPException {
if (cfg.getChild("font-base", false) != null) {
try {
URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base")
.getValue(null));
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver(
defaultBaseUri.resolve(fontBase), resourceResolver));
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, true);
}
} else {
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver(
defaultBaseUri, resourceResolver));
}
// caching (fonts)
if (cfg.getChild("use-cache", false) != null) {
try {
@@ -79,27 +92,14 @@ public class FontManagerConfigurator {
fontManager.disableFontCache();
} else {
if (cfg.getChild("cache-file", false) != null) {
fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue()));

fontManager.setCacheFile(URI.create(cfg.getChild("cache-file").getValue()));
}
}
} catch (ConfigurationException mfue) {
LogUtil.handleException(log, mfue, true);
}
}
if (cfg.getChild("font-base", false) != null) {
try {
URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base").getValue(
null));
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver(
defaultBaseUri.resolve(fontBase), resourceResolver));
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, true);
}
} else {
fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver(
defaultBaseUri, resourceResolver));
}

// [GA] permit configuration control over base14 kerning; without this,
// there is no way for a user to enable base14 kerning other than by
// programmatic API;

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

+ 3
- 2
src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java View File

@@ -45,6 +45,7 @@ import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.io.XmlSourceUtil;
import org.apache.xmlgraphics.util.MimeConstants;
import org.apache.xmlgraphics.util.UnitConv;

@@ -79,7 +80,7 @@ public class PreloaderSVG extends AbstractImagePreloader {
}
}
if (info != null) {
ImageUtil.closeQuietly(src); //Image is fully read
XmlSourceUtil.closeQuietly(src); //Image is fully read
}
return info;
}
@@ -119,7 +120,7 @@ public class PreloaderSVG extends AbstractImagePreloader {
DOMSource domSrc = (DOMSource)src;
doc = (SVGDocument)domSrc.getNode();
} else {
in = new UnclosableInputStream(ImageUtil.needInputStream(src));
in = new UnclosableInputStream(XmlSourceUtil.needInputStream(src));
int length = in.available();
in.mark(length + 1);
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(

+ 3
- 2
src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java View File

@@ -38,6 +38,7 @@ import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
import org.apache.xmlgraphics.image.loader.util.ImageUtil;
import org.apache.xmlgraphics.io.XmlSourceUtil;

import org.apache.fop.util.UnclosableInputStream;

@@ -69,7 +70,7 @@ public class PreloaderWMF extends AbstractImagePreloader {
}
}
if (info != null) {
ImageUtil.closeQuietly(src); //Image is fully read
XmlSourceUtil.closeQuietly(src); //Image is fully read
}
return info;
}
@@ -88,7 +89,7 @@ public class PreloaderWMF extends AbstractImagePreloader {
ImageContext context) {
// parse document and get the size attributes of the svg element

InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src));
InputStream in = new UnclosableInputStream(XmlSourceUtil.needInputStream(src));
try {
in.mark(4 + 1);


+ 7
- 0
src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java View File

@@ -273,4 +273,11 @@ public abstract class AbstractBaseLayoutManager
throw new UnsupportedOperationException("Not implemented");
}

public void preserveChildrenAtEndOfLayout() {

}

public void recreateChildrenLMs() {

}
}

+ 52
- 9
src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java View File

@@ -37,6 +37,7 @@ import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.flow.RetrieveMarker;
import org.apache.fop.layoutmgr.table.TableLayoutManager;

/**
* The base class for most LayoutManagers.
@@ -67,6 +68,8 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im
private int lastGeneratedPosition = -1;
private int smallestPosNumberChecked = Integer.MAX_VALUE;

private boolean preserveChildrenAtEndOfLayout;

/**
* Abstract layout manager.
*/
@@ -370,19 +373,20 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im
}

/**
* Registers the FO's markers on the current PageViewport
* Registers the FO's markers on the current PageViewport, and if applicable on the parent TableLM.
*
* @param isStarting boolean indicating whether the markers qualify as 'starting'
* @param isFirst boolean indicating whether the markers qualify as 'first'
* @param isLast boolean indicating whether the markers qualify as 'last'
*/
protected void addMarkersToPage(boolean isStarting, boolean isFirst, boolean isLast) {
protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) {
if (this.markers != null) {
getCurrentPV().addMarkers(
getCurrentPV().registerMarkers(
this.markers,
isStarting,
isFirst,
isLast);
possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast);
}
}

@@ -419,11 +423,12 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im

notifyEndOfLayout();

/* References to the child LMs are no longer needed
*/
childLMs = null;
curChildLM = null;
childLMiter = null;
if (!preserveChildrenAtEndOfLayout) {
// References to the child LMs are no longer needed
childLMs = null;
curChildLM = null;
childLMiter = null;
}

/* markers that qualify have been transferred to the page
*/
@@ -438,13 +443,21 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im
|| lm instanceof PageSequenceLayoutManager)) {
lm = lm.getParent();
}
if (lm instanceof FlowLayoutManager) {
if (lm instanceof FlowLayoutManager && !preserveChildrenAtEndOfLayout) {
fobj.clearChildNodes();
fobjIter = null;
}
}
}

/*
* Preserves the children LMs at the end of layout. This is necessary if the layout is expected to be
* repeated, as when using retrieve-table-markers.
*/
public void preserveChildrenAtEndOfLayout() {
preserveChildrenAtEndOfLayout = true;
}

/** {@inheritDoc} */
@Override
public String toString() {
@@ -467,4 +480,34 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im
lastGeneratedPosition = -1;
}

public void recreateChildrenLMs() {
childLMs = new ArrayList();
isFinished = false;
if (fobj == null) {
return;
}
fobjIter = fobj.getChildNodes();
int position = 0;
while (createNextChildLMs(position++)) {
//
}
childLMiter = new LMiter(this);
for (LMiter iter = new LMiter(this); iter.hasNext();) {
AbstractBaseLayoutManager alm = (AbstractBaseLayoutManager) iter.next();
alm.initialize();
alm.recreateChildrenLMs();
alm.preserveChildrenAtEndOfLayout();
}
curChildLM = getChildLM();
}

protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting,
boolean isFirst, boolean isLast) {
LayoutManager lm = this.parentLayoutManager;
if (lm instanceof FlowLayoutManager || lm instanceof PageSequenceLayoutManager
|| !(lm instanceof AbstractLayoutManager)) {
return;
}
((AbstractLayoutManager) lm).possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast);
}
}

+ 7
- 4
src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java View File

@@ -226,15 +226,14 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa
public RetrieveMarker resolveRetrieveMarker(RetrieveMarker rm) {
AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel();
String name = rm.getRetrieveClassName();
int pos = rm.getRetrievePosition();
int boundary = rm.getRetrieveBoundary();

// get marker from the current markers on area tree
Marker mark = (Marker)getCurrentPV().getMarker(name, pos);
Marker mark = getCurrentPV().resolveMarker(rm);
if (mark == null && boundary != EN_PAGE) {
// go back over pages until mark found
// if document boundary then keep going
boolean doc = boundary == EN_DOCUMENT;
boolean doc = (boundary == EN_DOCUMENT);
int seq = areaTreeModel.getPageSequenceCount();
int page = areaTreeModel.getPageCount(seq) - 1;
while (page < 0 && doc && seq > 1) {
@@ -243,7 +242,11 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa
}
while (page >= 0) {
PageViewport pv = areaTreeModel.getPage(seq, page);
mark = (Marker)pv.getMarker(name, Constants.EN_LEWP);
int originalPosition = rm.getPosition();
rm.changePositionTo(Constants.EN_LEWP);
mark = (Marker) pv.resolveMarker(rm);
// this is probably not necessary since the RM will not be used again, but to be safe...
rm.changePositionTo(originalPosition);
if (mark != null) {
break;
}

+ 2
- 3
src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java View File

@@ -87,7 +87,7 @@ public final class AreaAdditionUtil {
}

if (bslm != null) {
bslm.addMarkersToPage(
bslm.registerMarkers(
true,
bslm.isFirst(firstPos),
bslm.isLast(lastPos));
@@ -114,11 +114,10 @@ public final class AreaAdditionUtil {
}

if (bslm != null) {
bslm.addMarkersToPage(
bslm.registerMarkers(
false,
bslm.isFirst(firstPos),
bslm.isLast(lastPos));
bslm.checkEndOfLayout(lastPos);
}



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

@@ -806,7 +806,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl

addId();

addMarkersToPage(true, isFirst(firstPos), isLast(lastPos));
registerMarkers(true, isFirst(firstPos), isLast(lastPos));

if (bcpos == null) {
// the Positions in positionList were inside the elements
@@ -826,7 +826,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl
bcpos.getBreaker().addContainedAreas(layoutContext);
}

addMarkersToPage(false, isFirst(firstPos), isLast(lastPos));
registerMarkers(false, isFirst(firstPos), isLast(lastPos));

TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter);

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

@@ -312,7 +312,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co

addId();

addMarkersToPage(true, isFirst(firstPos), isLast(lastPos));
registerMarkers(true, isFirst(firstPos), isLast(lastPos));

// the Positions in positionList were inside the elements
// created by the LineLM
@@ -327,7 +327,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co
childLM.addAreas(childPosIter, lc);
}

addMarkersToPage(false, isFirst(firstPos), isLast(lastPos));
registerMarkers(false, isFirst(firstPos), isLast(lastPos));

TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter);

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

+ 20
- 1
src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java View File

@@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.FOElementMapping;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FONode.FONodeIterator;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.extensions.ExternalDocument;
@@ -117,7 +118,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
registerMaker(Block.class, new BlockLayoutManagerMaker());
registerMaker(Leader.class, new LeaderLayoutManagerMaker());
registerMaker(RetrieveMarker.class, new RetrieveMarkerLayoutManagerMaker());
registerMaker(RetrieveTableMarker.class, new Maker());
registerMaker(RetrieveTableMarker.class, new RetrieveTableMarkerLayoutManagerMaker());
registerMaker(Character.class, new CharacterLayoutManagerMaker());
registerMaker(ExternalGraphic.class,
new ExternalGraphicLayoutManagerMaker());
@@ -407,6 +408,24 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
}
}

public class RetrieveTableMarkerLayoutManagerMaker extends Maker {
public void make(FONode node, List lms) {
FONodeIterator baseIter = node.getChildNodes();
if (baseIter == null) {
// this happens when the retrieve-table-marker cannot be resolved yet
RetrieveTableMarker rtm = (RetrieveTableMarker) node;
RetrieveTableMarkerLayoutManager rtmlm = new RetrieveTableMarkerLayoutManager(rtm);
lms.add(rtmlm);
return;
}
while (baseIter.hasNext()) {
// this happens when the retrieve-table-marker has been resolved
FONode child = (FONode) baseIter.next();
makeLayoutManagers(child, lms);
}
}
}

/** a layout manager maker */
public class WrapperLayoutManagerMaker extends Maker {
/** {@inheritDoc} */

+ 137
- 0
src/java/org/apache/fop/layoutmgr/LocalBreaker.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.layoutmgr;

import java.util.LinkedList;
import java.util.List;

import org.apache.fop.fo.FObj;
import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener;
import org.apache.fop.layoutmgr.inline.TextLayoutManager;

public abstract class LocalBreaker extends AbstractBreaker {
protected BlockStackingLayoutManager lm;
private int displayAlign;
private int ipd;
private int overflow = 0;

public LocalBreaker(BlockStackingLayoutManager lm, int ipd, int displayAlign) {
this.lm = lm;
this.ipd = ipd;
this.displayAlign = displayAlign;
}

/** {@inheritDoc} */
protected boolean isPartOverflowRecoveryActivated() {
// For side regions, this must be disabled because of wanted overflow.
return false;
}

public boolean isOverflow() {
return (this.overflow != 0);
}

public int getOverflowAmount() {
return this.overflow;
}

/** {@inheritDoc} */
protected PageBreakingLayoutListener createLayoutListener() {
return new PageBreakingLayoutListener() {

public void notifyOverflow(int part, int amount, FObj obj) {
if (LocalBreaker.this.overflow == 0) {
LocalBreaker.this.overflow = amount;
}
}

};
}

protected LayoutManager getTopLevelLM() {
return lm;
}

protected LayoutContext createLayoutContext() {
LayoutContext lc = super.createLayoutContext();
lc.setRefIPD(ipd);
return lc;
}

protected List getNextKnuthElements(LayoutContext context, int alignment) {
LayoutManager curLM; // currently active LM
List returnList = new LinkedList();

while ((curLM = lm.getChildLM()) != null) {
LayoutContext childLC = LayoutContext.newInstance();
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(context.getRefIPD());
childLC.setWritingMode(context.getWritingMode());

List returnedList = null;
// The following is a HACK! Ignore leading and trailing white space
boolean ignore = curLM instanceof TextLayoutManager;
if (!curLM.isFinished()) {
returnedList = curLM.getNextKnuthElements(childLC, alignment);
}
if (returnedList != null && !ignore) {
lm.wrapPositionElements(returnedList, returnList);
}
}
SpaceResolver.resolveElementList(returnList);
lm.setFinished(true);
return returnList;
}

protected int getCurrentDisplayAlign() {
return displayAlign;
}

protected boolean hasMoreContent() {
return !lm.isFinished();
}

protected void addAreas(PositionIterator posIter, LayoutContext context) {
AreaAdditionUtil.addAreas(lm, posIter, context);
}

protected void doPhase3(PageBreakingAlgorithm alg, int partCount, BlockSequence originalList,
BlockSequence effectiveList) {
if (partCount > 1) {
PageBreakPosition pos = (PageBreakPosition) alg.getPageBreaks().getFirst();
int firstPartLength = ElementListUtils.calcContentLength(effectiveList,
effectiveList.ignoreAtStart, pos.getLeafPos());
overflow += alg.totalWidth - firstPartLength;
}
// Rendering all parts (not just the first) at once for the case where the parts that
// overflow should be visible.
alg.removeAllPageBreaks();
// Directly add areas after finding the breaks
this.addAreas(alg, 1, originalList, effectiveList);
}

protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
// nop for static content
}

protected LayoutManager getCurrentChildLM() {
return null; // TODO NYI
}
}

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


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

Loading…
Cancel
Save