Browse Source

Merged trunk@1391502


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_RoundedCorners@1394098 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Peter Hancock 11 years ago
parent
commit
af57408966
100 changed files with 2012 additions and 1649 deletions
  1. 1
    0
      examples/plan/src/org/apache/fop/plan/PreloaderPlan.java
  2. 1
    2
      fop
  3. 1
    1
      fop.bat
  4. 0
    4
      fop.js
  5. BIN
      lib/xmlgraphics-commons-1.5svn.jar
  6. 1
    1
      src/documentation/content/xdocs/dev/index.xml
  7. 3
    3
      src/documentation/content/xdocs/maillist.xml
  8. 8
    2
      src/documentation/content/xdocs/trunk/output.xml
  9. 14
    27
      src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
  10. 0
    508
      src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java
  11. 59
    11
      src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
  12. 2
    1
      src/java/org/apache/fop/afp/AFPStreamer.java
  13. 19
    18
      src/java/org/apache/fop/afp/DataStream.java
  14. 5
    8
      src/java/org/apache/fop/afp/Factory.java
  15. 4
    8
      src/java/org/apache/fop/afp/modca/AbstractPageObject.java
  16. 5
    20
      src/java/org/apache/fop/afp/modca/PageGroup.java
  17. 64
    28
      src/java/org/apache/fop/afp/modca/TagLogicalElement.java
  18. 0
    64
      src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java
  19. 63
    0
      src/java/org/apache/fop/afp/modca/triplets/EncodingTriplet.java
  20. 1
    1
      src/java/org/apache/fop/afp/util/AFPResourceAccessor.java
  21. 6
    1
      src/java/org/apache/fop/apps/EnvironmentProfile.java
  22. 17
    4
      src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java
  23. 16
    16
      src/java/org/apache/fop/apps/FOUserAgent.java
  24. 1
    1
      src/java/org/apache/fop/apps/FopConfParser.java
  25. 6
    0
      src/java/org/apache/fop/apps/FopFactory.java
  26. 6
    1
      src/java/org/apache/fop/apps/FopFactoryBuilder.java
  27. 9
    1
      src/java/org/apache/fop/apps/FopFactoryConfig.java
  28. 3
    1
      src/java/org/apache/fop/apps/io/InternalResourceResolver.java
  29. 0
    51
      src/java/org/apache/fop/apps/io/ResourceResolver.java
  30. 61
    57
      src/java/org/apache/fop/apps/io/ResourceResolverFactory.java
  31. 0
    48
      src/java/org/apache/fop/apps/io/TempResourceResolver.java
  32. 0
    57
      src/java/org/apache/fop/apps/io/TempResourceURIGenerator.java
  33. 2
    1
      src/java/org/apache/fop/area/CachedRenderPagesModel.java
  34. 18
    159
      src/java/org/apache/fop/area/PageViewport.java
  35. 1
    1
      src/java/org/apache/fop/cli/CommandLineOptions.java
  36. 6
    10
      src/java/org/apache/fop/events/CompositeEventListener.java
  37. 7
    2
      src/java/org/apache/fop/fo/Constants.java
  38. 10
    10
      src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
  39. 14
    16
      src/java/org/apache/fop/fo/FOEventHandler.java
  40. 30
    0
      src/java/org/apache/fop/fo/FONode.java
  41. 11
    3
      src/java/org/apache/fop/fo/FOPropertyMapping.java
  42. 12
    0
      src/java/org/apache/fop/fo/FOValidationEventProducer.java
  43. 1
    0
      src/java/org/apache/fop/fo/FOValidationEventProducer.xml
  44. 10
    3
      src/java/org/apache/fop/fo/FObj.java
  45. 1
    0
      src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
  46. 3
    0
      src/java/org/apache/fop/fo/extensions/InternalElementMapping.java
  47. 44
    0
      src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java
  48. 212
    0
      src/java/org/apache/fop/fo/flow/Markers.java
  49. 7
    10
      src/java/org/apache/fop/fo/flow/RetrieveMarker.java
  50. 14
    11
      src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java
  51. 9
    0
      src/java/org/apache/fop/fo/flow/table/TableCell.java
  52. 12
    0
      src/java/org/apache/fop/fo/flow/table/TableColumn.java
  53. 2
    0
      src/java/org/apache/fop/fo/flow/table/TablePart.java
  54. 4
    1
      src/java/org/apache/fop/fo/pagination/Flow.java
  55. 19
    0
      src/java/org/apache/fop/fo/pagination/LayoutMasterSet.java
  56. 1
    1
      src/java/org/apache/fop/fo/pagination/StaticContent.java
  57. 2
    2
      src/java/org/apache/fop/fonts/CIDFont.java
  58. 113
    0
      src/java/org/apache/fop/fonts/CIDFull.java
  59. 90
    0
      src/java/org/apache/fop/fonts/CIDSet.java
  60. 50
    79
      src/java/org/apache/fop/fonts/CIDSubset.java
  61. 10
    8
      src/java/org/apache/fop/fonts/FontCacheManager.java
  62. 28
    9
      src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
  63. 7
    25
      src/java/org/apache/fop/fonts/FontManager.java
  64. 17
    17
      src/java/org/apache/fop/fonts/FontManagerConfigurator.java
  65. 1
    1
      src/java/org/apache/fop/fonts/FontReader.java
  66. 3
    0
      src/java/org/apache/fop/fonts/LazyFont.java
  67. 50
    19
      src/java/org/apache/fop/fonts/MultiByteFont.java
  68. 1
    1
      src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
  69. 3
    2
      src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
  70. 3
    2
      src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java
  71. 7
    0
      src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
  72. 52
    9
      src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
  73. 7
    4
      src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java
  74. 2
    3
      src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
  75. 2
    2
      src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  76. 2
    2
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  77. 17
    4
      src/java/org/apache/fop/layoutmgr/BreakElement.java
  78. 20
    1
      src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
  79. 137
    0
      src/java/org/apache/fop/layoutmgr/LocalBreaker.java
  80. 75
    0
      src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java
  81. 5
    108
      src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  82. 2
    2
      src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
  83. 4
    0
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  84. 2
    2
      src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
  85. 2
    2
      src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
  86. 2
    2
      src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
  87. 6
    1
      src/java/org/apache/fop/layoutmgr/table/RowPainter.java
  88. 185
    2
      src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
  89. 21
    5
      src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
  90. 123
    1
      src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
  91. 6
    22
      src/java/org/apache/fop/pdf/PDFDocument.java
  92. 76
    23
      src/java/org/apache/fop/pdf/PDFEncoding.java
  93. 31
    81
      src/java/org/apache/fop/pdf/PDFFactory.java
  94. 1
    1
      src/java/org/apache/fop/pdf/PDFFont.java
  95. 4
    2
      src/java/org/apache/fop/pdf/PDFStructElem.java
  96. 2
    1
      src/java/org/apache/fop/pdf/PDFStructTreeRoot.java
  97. 5
    0
      src/java/org/apache/fop/pdf/StandardStructureTypes.java
  98. 8
    30
      src/java/org/apache/fop/pdf/StructureHierarchyMember.java
  99. 2
    1
      src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
  100. 0
    0
      src/java/org/apache/fop/render/afp/extensions/AFPExtensionHandler.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;

+ 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.5svn.jar View File


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

@@ -97,7 +97,7 @@ To review the archives, you have several options:
<li>The <link href="http://marc.theaimsgroup.com/?l=fop-dev&amp;r=1&amp;w=2">Mailing list ARChives</link> (MARC) at the AIMS group (search).</li>
<li><link href="http://www.mail-archive.com/fop-dev%40xmlgraphics.apache.org/">The Mail Archive</link>.</li>
<li>The <link href="http://dir.gmane.org/gmane.text.xml.fop.devel">GMANE</link> archive.</li>
<li>The <link href="http://www.nabble.com/FOP---Dev-f352.html">Nabble</link> archive.</li>
<li>The <link href="http://apache-fop.1065347.n5.nabble.com/">Nabble</link> archive.</li>
<li>The <link href="http://fop-dev.markmail.org">MarkMail</link> archive.</li>
</ul>
</li>

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

@@ -43,17 +43,17 @@ If you are using Microsoft Outlook, this setting can be found at the "Mail Forma
<title>Archives</title>
<p>To review the archives, you have several options:</p>
<ul>
<li>The <link href="http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-users/">Apache Mailing List archive</link> (mod_mbox archive, no full-text search, yet).</li>
<li>The <link href="http://xmlgraphics.apache.org/mail/fop-users/">Apache Mailing List archive</link> (gzipped mbox files).</li>
<li>The <jump href="http://marc.theaimsgroup.com/?l=fop-user&amp;r=1&amp;w=2">Mailing list ARChives </jump> (MARC) at the AIMS group.</li>
<li><jump href="http://www.mail-archive.com/fop-users%40xmlgraphics.apache.org/">The Mail Archive</jump>.</li>
<li>The <jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE archive</jump>.</li>
<li>The <jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble archive</jump> (only posts after May 2005).</li>
<li>The <jump href="http://apache-fop.1065347.n5.nabble.com/FOP-Users-f3.html">Nabble archive</jump> (only posts after May 2005).</li>
<li>The <jump href="http://fop-users.markmail.org/">MarkMail archive</jump>.</li>
</ul>
<note>
If you don't like mailing lists and prefer a forum-like system, have a look at
If you don't like mailing lists and prefer a forum-like system, have a look at
<jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE</jump> or
<jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble</jump>. They
allow you to post to the mailing list without having to subscribe.

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

@@ -971,7 +971,8 @@ Note that the value of the encoding attribute in the example is the double-byte
xmlns:afp="http://xmlgraphics.apache.org/fop/extensions/afp">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple">
<afp:tag-logical-element name="The TLE Name" value="The TLE Value" />
<afp:tag-logical-element name="The TLE Name" value="The TLE Value"
encoding="500" />
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
@@ -985,7 +986,7 @@ Note that the value of the encoding attribute in the example is the double-byte
The tag-logical-element extension element can appear within a simple-page-master
(page level) or it can appear as child of page-sequence (page group level).
Multiple tag-logical-element extension elements within a simple-page-master or
page-sequence are allowed. The name and value attributes are mandatory.
page-sequence are allowed. The name and value attributes are mandatory. The encoding attribute specifying a CCSID encoding is optional.
</p>
</section>
<section id="afp-no-operation">
@@ -1269,6 +1270,7 @@ Note that the value of the encoding attribute in the example is the double-byte
<source><![CDATA[<renderer mime="image/tiff">
<transparent-page-background>true</transparent-page-background>
<compression>CCITT T.6</compression>
<single-strip>true</single-strip>
<fonts><!-- described elsewhere --></fonts>
</renderer>]]></source>
<p>
@@ -1302,6 +1304,10 @@ Note that the value of the encoding attribute in the example is the double-byte
added separately. The internal TIFF codec from XML Graphics Commons only supports PackBits,
Deflate and JPEG compression for writing.
</note>
<p>
The default value for the <code>"single-strip"</code> is <code>"false"</code> resulting in the RowsPerStrip Tiff Tag equal to the number of rows.
If set to <code>true</code> RowsPerStrip is set to 1.
</p>
</section>
<section id="bitmap-rendering-options">
<title>Runtime Rendering Options</title>

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

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

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

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

private final FOEventHandler structureTreeEventTrigger;

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

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

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

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

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

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

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

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

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

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

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

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

/* $Id$ */

package org.apache.fop.accessibility.fo;

import java.util.ArrayList;
import java.util.List;

import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.flow.Character;
import org.apache.fop.fo.flow.ExternalGraphic;
import org.apache.fop.fo.flow.Footnote;
import org.apache.fop.fo.flow.FootnoteBody;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.InstreamForeignObject;
import org.apache.fop.fo.flow.Leader;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.fo.flow.PageNumber;
import org.apache.fop.fo.flow.PageNumberCitation;
import org.apache.fop.fo.flow.PageNumberCitationLast;
import org.apache.fop.fo.flow.Wrapper;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableBody;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TableRow;

final class FOEventRecorder extends FOEventHandler {

private interface Event {
void replay(FOEventHandler target);
}

private final List<Event> events = new ArrayList<Event>();

public void replay(FOEventHandler target) {
for (Event event : events) {
event.replay(target);
}
}

@Override
public void startPageNumber(final PageNumber pagenum) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startPageNumber(pagenum);
}
});
}

@Override
public void endPageNumber(final PageNumber pagenum) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endPageNumber(pagenum);
}
});
}

@Override
public void startPageNumberCitation(final PageNumberCitation pageCite) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startPageNumberCitation(pageCite);
}
});
}

@Override
public void endPageNumberCitation(final PageNumberCitation pageCite) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endPageNumberCitation(pageCite);
}
});
}

@Override
public void startPageNumberCitationLast(final PageNumberCitationLast pageLast) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startPageNumberCitationLast(pageLast);
}
});
}

@Override
public void endPageNumberCitationLast(final PageNumberCitationLast pageLast) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endPageNumberCitationLast(pageLast);
}
});
}

@Override
public void startBlock(final Block bl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startBlock(bl);
}
});
}

@Override
public void endBlock(final Block bl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endBlock(bl);
}
});
}

@Override
public void startBlockContainer(final BlockContainer blc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startBlockContainer(blc);
}
});
}

@Override
public void endBlockContainer(final BlockContainer blc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endBlockContainer(blc);
}
});
}

@Override
public void startInline(final Inline inl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startInline(inl);
}
});
}

@Override
public void endInline(final Inline inl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endInline(inl);
}
});
}

@Override
public void startTable(final Table tbl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startTable(tbl);
}
});
}

@Override
public void endTable(final Table tbl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endTable(tbl);
}
});
}

@Override
public void startColumn(final TableColumn tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startColumn(tc);
}
});
}

@Override
public void endColumn(final TableColumn tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endColumn(tc);
}
});
}

@Override
public void startHeader(final TableHeader header) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startHeader(header);
}
});
}

@Override
public void endHeader(final TableHeader header) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endHeader(header);
}
});
}

@Override
public void startFooter(final TableFooter footer) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startFooter(footer);
}
});
}

@Override
public void endFooter(final TableFooter footer) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endFooter(footer);
}
});
}

@Override
public void startBody(final TableBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startBody(body);
}
});
}

@Override
public void endBody(final TableBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endBody(body);
}
});
}

@Override
public void startRow(final TableRow tr) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startRow(tr);
}
});
}

@Override
public void endRow(final TableRow tr) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endRow(tr);
}
});
}

@Override
public void startCell(final TableCell tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startCell(tc);
}
});
}

@Override
public void endCell(final TableCell tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endCell(tc);
}
});
}

@Override
public void startList(final ListBlock lb) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startList(lb);
}
});
}

@Override
public void endList(final ListBlock lb) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endList(lb);
}
});
}

@Override
public void startListItem(final ListItem li) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startListItem(li);
}
});
}

@Override
public void endListItem(final ListItem li) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endListItem(li);
}
});
}

@Override
public void startListLabel(final ListItemLabel listItemLabel) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startListLabel(listItemLabel);
}
});
}

@Override
public void endListLabel(final ListItemLabel listItemLabel) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endListLabel(listItemLabel);
}
});
}

@Override
public void startListBody(final ListItemBody listItemBody) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startListBody(listItemBody);
}
});
}

@Override
public void endListBody(final ListItemBody listItemBody) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endListBody(listItemBody);
}
});
}

@Override
public void startLink(final BasicLink basicLink) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startLink(basicLink);
}
});
}

@Override
public void endLink(final BasicLink basicLink) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endLink(basicLink);
}
});
}

@Override
public void image(final ExternalGraphic eg) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.image(eg);
}
});
}

@Override
public void startInstreamForeignObject(final InstreamForeignObject ifo) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startInstreamForeignObject(ifo);
}
});
}

@Override
public void endInstreamForeignObject(final InstreamForeignObject ifo) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endInstreamForeignObject(ifo);
}
});
}

@Override
public void startFootnote(final Footnote footnote) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startFootnote(footnote);
}
});
}

@Override
public void endFootnote(final Footnote footnote) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endFootnote(footnote);
}
});
}

@Override
public void startFootnoteBody(final FootnoteBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startFootnoteBody(body);
}
});
}

@Override
public void endFootnoteBody(final FootnoteBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endFootnoteBody(body);
}
});
}

@Override
public void startLeader(final Leader l) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startLeader(l);
}
});
}

@Override
public void endLeader(final Leader l) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endLeader(l);
}
});
}

@Override
public void startWrapper(final Wrapper wrapper) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startWrapper(wrapper);
}
});
}

@Override
public void endWrapper(final Wrapper wrapper) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endWrapper(wrapper);
}
});
}

@Override
public void character(final Character c) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.character(c);
}
});
}

@Override
public void characters(final FOText foText) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.characters(foText);
}
});
}

}

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

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

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

import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@@ -30,6 +31,7 @@ import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.fo.flow.AbstractGraphics;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block;
@@ -55,6 +57,7 @@ import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.LayoutMasterSet;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
@@ -67,6 +70,12 @@ class StructureTreeEventTrigger extends FOEventHandler {

private StructureTreeEventHandler structureTreeEventHandler;

private LayoutMasterSet layoutMasterSet;

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

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

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

@Override
public void startPageSequence(PageSequence pageSeq) {
if (layoutMasterSet == null) {
layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet();
}
Locale locale = null;
if (pageSeq.getLanguage() != null) {
if (pageSeq.getCountry() != null) {
@@ -128,9 +140,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
@@ -170,42 +201,51 @@ class StructureTreeEventTrigger extends FOEventHandler {

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

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

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

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

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

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

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

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

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

@@ -277,16 +335,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);

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


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

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


}
}

+ 0
- 64
src/java/org/apache/fop/afp/modca/TagLogicalElementBean.java View File

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

/* $Id$ */

package org.apache.fop.afp.modca;

/**
* The TagLogicalElementBean provides a bean for holding the attributes of
* a tag logical element as key value pairs.
* <p/>
*/
public class TagLogicalElementBean {

/** The key attribute */
private String key;

/** The value attribute */
private String value;

/**
* Constructor for the TagLogicalElementBean.
*
* @param key the key attribute
* @param value the value attribute
*/
public TagLogicalElementBean(String key, String value) {
this.key = key;
this.value = value;
}

/**
* Getter for the key attribute.
*
* @return the key
*/
public String getKey() {
return key;
}

/**
* Getter for the value attribute.
*
* @return the value
*/
public String getValue() {
return value;
}

}

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

}

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

@@ -106,7 +106,7 @@ public final class AFPResourceAccessor {
URI resolveURI(String uri);
}

private final class NullBaseURIResolver implements URIResolver {
private static final class NullBaseURIResolver implements URIResolver {

public URI resolveURI(URI uri) {
return uri;

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

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

/**

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

+ 6
- 0
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;
@@ -418,6 +419,11 @@ public final class FopFactory implements ImageContext {
return config.getFontManager();
}

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

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

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

+ 9
- 1
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;

@@ -163,4 +164,11 @@ public interface FopFactoryConfig {

/** @return the hyphenation pattern names */
Map<String, String> getHyphenationPatternNames();

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

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

}

+ 61
- 57
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
*/
@@ -84,17 +89,17 @@ public final class ResourceResolverFactory {
}

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

private static final class DefaultResourceResolver implements ResourceResolver {
@@ -132,13 +137,13 @@ public final class ResourceResolverFactory {
this.defaultResourceResolver = defaultResourceResolver;
}

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

/** {@inheritDoc} */
public Resource getResource(URI uri) throws IOException {
if (isTempUri(uri)) {
if (isTempURI(uri)) {
return tempResourceResolver.getResource(uri.getPath());
} else {
return defaultResourceResolver.getResource(uri);
@@ -147,7 +152,7 @@ public final class ResourceResolverFactory {

/** {@inheritDoc} */
public OutputStream getOutputStream(URI uri) throws IOException {
if (isTempUri(uri)) {
if (isTempURI(uri)) {
return tempResourceResolver.getOutputStream(uri.getPath());
} else {
return defaultResourceResolver.getOutputStream(uri);
@@ -188,23 +193,23 @@ public final class ResourceResolverFactory {
}
}

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

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

private final ResourceResolver defaultResolver;

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

private ResourceResolver getResourceResolverForSchema(URI uri) {
String schema = uri.getScheme();
if (schemaHandlingResourceResolvers.containsKey(schema)) {
return schemaHandlingResourceResolvers.get(schema);
private ResourceResolver getResourceResolverForScheme(URI uri) {
String scheme = uri.getScheme();
if (schemeHandlingResourceResolvers.containsKey(scheme)) {
return schemeHandlingResourceResolvers.get(scheme);
} else {
return defaultResolver;
}
@@ -212,58 +217,58 @@ public final class ResourceResolverFactory {

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

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

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

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

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

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

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

/** {@inheritDoc} */
public ResourceResolver build() {
@@ -271,59 +276,58 @@ public final class ResourceResolverFactory {
}

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

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

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

private final ResourceResolver defaultResolver;

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

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

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

}

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

private SchemaAwareResourceResolverBuilder delegate;
private SchemeAwareResourceResolverBuilder delegate;

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

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

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

}

+ 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 uri) throws IOException;

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

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

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

/**

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


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

@@ -421,7 +421,7 @@ public class CommandLineOptions {
throw new FOPException("if you use '-cache', you must specify "
+ "the name of the font cache file");
} else {
factory.getFontManager().setCacheFile(new File(args[i + 1]));
factory.getFontManager().setCacheFile(URI.create(args[i + 1]));
return 1;
}
}

+ 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

@@ -807,8 +807,11 @@ public interface Constants {
*/
int PR_X_NUMBER_CONVERSION_FEATURES = 285;
/** Scope for table header */
int PR_X_HEADER_COLUMN = 286;

/** Number of property constants defined */
int PROPERTY_COUNT = 285;
int PROPERTY_COUNT = 286;

// compound property constants

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

+ 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;
@@ -2187,7 +2188,8 @@ public final class FOPropertyMapping implements Constants {
m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE);
m.setInherited(false);
m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING"));
m.addEnum("first-including-carryover", getEnumProperty(EN_FIC, "FIC"));
m.addEnum("first-including-carryover",
getEnumProperty(EN_FIRST_INCLUDING_CARRYOVER, "FIRST_INCLUDING_CARRYOVER"));
m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING"));
m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING"));
m.setDefault("first-starting");
@@ -2198,7 +2200,7 @@ public final class FOPropertyMapping implements Constants {
m.setInherited(false);
m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE"));
m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT"));
m.addEnum("page", getEnumProperty(EN_DOCUMENT, "PAGE"));
m.addEnum("page", getEnumProperty(EN_PAGE, "PAGE"));
m.setDefault("table");
addPropertyMaker("retrieve-boundary-within-table", m);
}
@@ -2277,7 +2279,7 @@ public final class FOPropertyMapping implements Constants {
m = new StringProperty.Maker(PR_FLOW_NAME);
m.setInherited(false);
m.setDefault("");
addPropertyMaker("flow-name", m);
addPropertyMaker(Flow.FLOW_NAME, m);

// force-page-count
m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT);
@@ -2522,6 +2524,12 @@ public final class FOPropertyMapping implements Constants {
m.setInherited(false);
m.setDefault("false");
addPropertyMaker("table-omit-header-at-break", m);

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

private void createWritingModeProperties() {

+ 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");
//fox:border-*-radius-*
PROPERTY_ATTRIBUTES.add("border-before-radius-start");
PROPERTY_ATTRIBUTES.add("border-before-radius-end");

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

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

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

/* $Id$ */

package org.apache.fop.fo.flow;

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

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

import org.apache.fop.fo.Constants;

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

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

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

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

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

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

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

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

}

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


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

@@ -42,7 +42,7 @@ public class StaticContent extends Flow {
/** {@inheritDoc} */
protected void startOfNode() throws FOPException {
if (getFlowName() == null || getFlowName().equals("")) {
missingPropertyError("flow-name");
missingPropertyError(FLOW_NAME);
}
getFOEventHandler().startStatic(this);
}

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

@@ -29,7 +29,7 @@ import org.apache.fop.apps.io.InternalResourceResolver;
public abstract class CIDFont extends CustomFont {

/** Contains the character widths for all characters in the font */
protected int[] width = null;
protected int[] width;

/**
* @param resourceResolver the URI resolver for controlling file access
@@ -69,7 +69,7 @@ public abstract class CIDFont extends CustomFont {
* Returns the subset information for this font.
* @return the subset information
*/
public abstract CIDSubset getCIDSubset();
public abstract CIDSet getCIDSet();

// ---- Optional ----
/**

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

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

/* $Id$ */

package org.apache.fop.fonts;

import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.fop.util.CharUtilities;

/**
* Provides methods to get font information.
* Naming:
* glyph index: original index of the glyph in the non-subset font (!= unicode index)
* character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset
* fonts, this is the same as the glyph index.
* Unicode index: The Unicode codepoint of a character.
* Glyph name: the Adobe glyph name (as found in Glyphs.java)
*/
public class CIDFull implements CIDSet {

private BitSet glyphIndices;
private final MultiByteFont font;

public CIDFull(MultiByteFont mbf) {
font = mbf;
}

private void initGlyphIndices() {
// this cannot be called in the constructor since the font is not ready...
if (glyphIndices == null) {
glyphIndices = font.getGlyphIndices();
}
}

/** {@inheritDoc} */
public int getOriginalGlyphIndex(int index) {
return index;
}

/** {@inheritDoc} */
public char getUnicode(int index) {
initGlyphIndices();
if (glyphIndices.get(index)) {
return (char) index;
} else {
return CharUtilities.NOT_A_CHARACTER;
}
}

/** {@inheritDoc} */
public int mapChar(int glyphIndex, char unicode) {
return (char) glyphIndex;
}

/** {@inheritDoc} */
public Map<Integer, Integer> getGlyphs() {
// this is never really called for full embedded fonts but the equivalent map would be the identity
initGlyphIndices();
Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>();
int nextBitSet = 0;
for (int j = 0; j < glyphIndices.cardinality(); j++) {
nextBitSet = glyphIndices.nextSetBit(nextBitSet);
glyphs.put(Integer.valueOf(nextBitSet), Integer.valueOf(nextBitSet));
nextBitSet++;
}
return Collections.unmodifiableMap(glyphs);
}

/** {@inheritDoc} */
public char[] getChars() {
return font.getChars();
}

/** {@inheritDoc} */
public int getNumberOfGlyphs() {
initGlyphIndices();
// note: the real number of glyphs is given by the cardinality() method (not the length()) but since
// we will pad gaps in the indices with zeros we really want the length() here. this method is only
// called when embedding a font in PostScript and this will be the value of the CIDCount entry
return glyphIndices.length();
}

/** {@inheritDoc} */
public BitSet getGlyphIndices() {
initGlyphIndices();
return glyphIndices;
}

/** {@inheritDoc} */
public int[] getWidths() {
return font.getWidths();
}

}

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

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

/* $Id$ */

package org.apache.fop.fonts;

import java.util.BitSet;
import java.util.Map;

/**
* Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font.
*/
public interface CIDSet {

/**
* Returns the original index of the glyph inside the (non-subset) font's glyph list. This
* index can be used to access the character width information, for example.
* @param index the subset index (character selector) to access the glyph
* @return the original index (or -1 if no glyph index is available for the subset index)
*/
int getOriginalGlyphIndex(int index);

/**
* Returns the Unicode value for a subset index (character selector). If there's no such
* Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned.
* @param 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;
}

}

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

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

package org.apache.fop.fonts;

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

import org.apache.fop.apps.FOPException;

@@ -29,25 +29,27 @@ import org.apache.fop.apps.FOPException;
*/
public interface FontCacheManager {

/**
* Sets the font cache file given the URI pointing to the file.
* @param fontCacheURI the font cache URI
*/
void setCacheFile(URI fontCacheURI);

/**
* Loads the font cache into memory from the given file.
* @param file the serialized font cache
* @return the de-serialized font cache
*/
FontCache load(File file);
FontCache load();

/**
* Serializes the font cache to file.
* @param file the file to serialize the font cache to
* @throws FOPException if an error occurs serializing the font cache
*/
void save(File file) throws FOPException;
void save() throws FOPException;

/**
* Deletes the font cache from the file-system.
* @param file delete the serialized font cache
* @throws FOPException if an error occurs deleting the font cache
*/
void delete(File file) throws FOPException;

void delete() throws FOPException;
}

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

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

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

import org.apache.fop.apps.FOPException;

@@ -50,11 +51,14 @@ public final class FontCacheManagerFactory {

private static final class FontCacheManagerImpl implements FontCacheManager {

/** Provides a font cache file path **/
private File cacheFile;

private FontCache fontCache;

public FontCache load(File cacheFile) {
public FontCache load() {
if (fontCache == null) {
fontCache = FontCache.loadFrom(cacheFile);
fontCache = FontCache.loadFrom(getCacheFile(false));
if (fontCache == null) {
fontCache = new FontCache();
}
@@ -62,31 +66,46 @@ public final class FontCacheManagerFactory {
return fontCache;
}

public void save(File cacheFile) throws FOPException {
public void save() throws FOPException {
if (fontCache != null && fontCache.hasChanged()) {
fontCache.saveTo(cacheFile);
fontCache.saveTo(getCacheFile(true));
}
}

public void delete(File cacheFile) throws FOPException {
if (!cacheFile.delete()) {
public void delete() throws FOPException {
if (!getCacheFile(true).delete()) {
throw new FOPException("Failed to flush the font cache file '" + cacheFile + "'.");
}
}

private File getCacheFile(boolean forWriting) {
if (cacheFile != null) {
return cacheFile;
}
return FontCache.getDefaultCacheFile(forWriting);
}

public void setCacheFile(URI fontCacheURI) {
cacheFile = new File(fontCacheURI);
}
}

private static final class DisabledFontCacheManager implements FontCacheManager {

public FontCache load(File cacheFile) {
public FontCache load() {
return null;
}

public void save(File cacheFile) throws FOPException {
public void save() throws FOPException {
// nop
}

public void delete(File cacheFile) throws FOPException {
public void delete() throws FOPException {
throw new FOPException("Font Cache disabled");
}

public void setCacheFile(URI fontCacheURI) {
// nop
}
}
}

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

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

package org.apache.fop.fonts;

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

import org.apache.fop.apps.FOPException;
@@ -52,9 +52,6 @@ public class FontManager {
/** FontTriplet matcher for fonts that shall be referenced rather than embedded. */
private FontTriplet.Matcher referencedFontsMatcher;

/** Provides a font cache file path **/
private File cacheFile;

/**
* Main constructor
*
@@ -115,25 +112,10 @@ public class FontManager {

/**
* Sets the font cache file
* @param cacheFile the font cache file
*/
public void setCacheFile(File cacheFile) {
this.cacheFile = cacheFile;
}

/**
* Returns the font cache file
* @return the font cache file
* @param cacheFileURI the URI of the font cache file
*/
public File getCacheFile() {
return getCacheFile(false);
}

private File getCacheFile(boolean writable) {
if (cacheFile != null) {
return cacheFile;
}
return FontCache.getDefaultCacheFile(writable);
public void setCacheFile(URI cacheFileURI) {
fontCacheManager.setCacheFile(resourceResolver.resolveFromBase(cacheFileURI));
}

/**
@@ -148,7 +130,7 @@ public class FontManager {
* @return the font cache
*/
public FontCache getFontCache() {
return fontCacheManager.load(getCacheFile());
return fontCacheManager.load();
}

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

/**
@@ -165,7 +147,7 @@ public class FontManager {
* @throws FOPException if an error was thrown while deleting the cache
*/
public void deleteCache() throws FOPException {
fontCacheManager.delete(getCacheFile(true));
fontCacheManager.delete();
}

/**

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

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

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

/* $Id$ */

package org.apache.fop.layoutmgr;

import java.util.List;

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

import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.RetrieveTableMarker;
import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager;
import org.apache.fop.layoutmgr.table.TableLayoutManager;

public class RetrieveTableMarkerLayoutManager extends LeafNodeLayoutManager {

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

public RetrieveTableMarkerLayoutManager(RetrieveTableMarker node) {
super(node);
}

/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
setFinished(true);
FONode foNode = (FONode) getFObj();
foNode = getTableLayoutManager().resolveRetrieveTableMarker((RetrieveTableMarker) foNode);
if (foNode != null) {
// resolve the RTM and replace current LM by the resolved target LM
InlineLevelLayoutManager illm = (InlineLevelLayoutManager) getPSLM().getLayoutManagerMaker()
.makeLayoutManager(foNode);
if (illm instanceof RetrieveTableMarkerLayoutManager) {
// happens if the retrieve-marker was empty
return null;
}
illm.setParent(getParent());
illm.initialize();
return illm.getNextKnuthElements(context, alignment);
} else {
return null;
}
}

/** {@inheritDoc} */
public void addAreas(PositionIterator posIter, LayoutContext context) {
}

private TableLayoutManager getTableLayoutManager() {
LayoutManager parentLM = getParent();
while (!(parentLM instanceof TableLayoutManager)) {
parentLM = parentLM.getParent();
}
TableLayoutManager tlm = (TableLayoutManager) parentLM;
return tlm;
}

}

+ 5
- 108
src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java View File

@@ -167,125 +167,22 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
return (StaticContent) fobj;
}

private class StaticContentBreaker extends AbstractBreaker {
private StaticContentLayoutManager lm;
private int displayAlign;
private int ipd;
private int overflow = 0;

public StaticContentBreaker(StaticContentLayoutManager lm, int ipd,
int displayAlign) {
this.lm = lm;
this.ipd = ipd;
this.displayAlign = displayAlign;
private class StaticContentBreaker extends LocalBreaker {

public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, int displayAlign) {
super(lm, ipd, displayAlign);
}

/** {@inheritDoc} */
protected void observeElementList(List elementList) {
String elementListID = getStaticContentFO().getFlowName();
String pageSequenceID = ((PageSequence)lm.getParent().getFObj()).getId();
String pageSequenceID = ((PageSequence) lm.getParent().getFObj()).getId();
if (pageSequenceID != null && pageSequenceID.length() > 0) {
elementListID += "-" + pageSequenceID;
}
ElementListObserver.observe(elementList, "static-content", elementListID);
}

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

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

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

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

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

};
}

protected LayoutManager getTopLevelLM() {
return lm;
}

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

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

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

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

protected int getCurrentDisplayAlign() {
return displayAlign;
}

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

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

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

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

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

/**

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

@@ -480,7 +480,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this));
}

addMarkersToPage(
registerMarkers(
true,
!areaCreated,
lastPos == null || isLast(lastPos));
@@ -542,7 +542,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
setTraits(areaCreated, lastPos == null || !isLast(lastPos));
parentLayoutManager.addChildArea(getCurrentArea());

addMarkersToPage(
registerMarkers(
false,
!areaCreated,
lastPos == null || isLast(lastPos));

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

@@ -649,6 +649,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager
log.trace("Restarting line breaking from index " + restartPosition.getIndex());
int parIndex = restartPosition.getLeafPos();
KnuthSequence paragraph = knuthParagraphs.get(parIndex);
if (paragraph instanceof Paragraph) {
((Paragraph) paragraph).ignoreAtStart = 0;
isFirstInBlock = false;
}
paragraph.subList(0, restartPosition.getIndex() + 1).clear();
Iterator<KnuthElement> iter = paragraph.iterator();
while (iter.hasNext() && !iter.next().isBox()) {

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

@@ -171,7 +171,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
}
}

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

PositionIterator childPosIter = new PositionIterator(positionList.listIterator());
while ((childLM = childPosIter.getNextChildLM()) != null) {
@@ -184,7 +184,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
childLM.addAreas(childPosIter, lc);
}

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

// We are done with this area add the background
TraitSetter.addBackground(curBlockArea,

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

@@ -136,7 +136,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp
}
}

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

PositionIterator childPosIter = new PositionIterator(positionList.listIterator());
while ((childLM = childPosIter.getNextChildLM()) != null) {
@@ -149,7 +149,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp
childLM.addAreas(childPosIter, lc);
}

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

flush();


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

@@ -509,7 +509,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements
}
}

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

// use the first and the last ListItemPosition to determine the
// corresponding indexes in the original labelList and bodyList
@@ -563,7 +563,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements
}
curBlockArea.setBPD(itemBPD);

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

// We are done with this area add the background
TraitSetter.addBackground(curBlockArea,

+ 6
- 1
src/java/org/apache/fop/layoutmgr/table/RowPainter.java View File

@@ -303,11 +303,16 @@ class RowPainter {
borderAfterWhich = ConditionalBorder.REST;
}

// when adding the areas for the TableCellLayoutManager this helps with the isLast trait
// if, say, the first cell of a row has content that fits in the page, but the content of
// the second cell does not fit this will assure that the isLast trait for the first cell
// will also be false
lastCellParts[i].pgu.getCellLM().setLastTrait(lastCellParts[i].isLastPart());
addAreasForCell(firstCellParts[i].pgu,
firstCellParts[i].start, lastCellParts[i].end,
actualRowHeight, borderBeforeWhich, borderAfterWhich,
lastOnPage);
firstCellParts[i] = null;
firstCellParts[i] = null; // why? what about the lastCellParts[i]?
Arrays.fill(firstCellOnPage, i, i + currentGU.getCell().getNumberColumnsSpanned(),
false);
}

+ 185
- 2
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java View File

@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -28,19 +29,24 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.Trait;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.flow.table.ConditionalBorder;
import org.apache.fop.fo.flow.table.GridUnit;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
import org.apache.fop.layoutmgr.AbstractLayoutManager;
import org.apache.fop.layoutmgr.AreaAdditionUtil;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBox;
@@ -49,8 +55,10 @@ import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LocalBreaker;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager;
import org.apache.fop.layoutmgr.SpaceResolver;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.traits.BorderProps;
@@ -79,6 +87,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
private int totalHeight;
private int usedBPD;
private boolean emptyCell = true;
private boolean isDescendantOfTableFooter;
private boolean isDescendantOfTableHeader;
private boolean hasRetrieveTableMarker;

// place holder for the addAreas arguments
private boolean savedAddAreasArguments;
private PositionIterator savedParentIter;
private LayoutContext savedLayoutContext;
private int[] savedSpannedGridRowHeights;
private int savedStartRow;
private int savedEndRow;
private int savedBorderBeforeWhich;
private int savedBorderAfterWhich;
private boolean savedFirstOnPage;
private boolean savedLastOnPage;
private RowPainter savedPainter;
private int savedFirstRowHeight;
// this is set to false when the table-cell has a retrieve-table-marker and is in the table-header
private boolean flushArea = true;

// this information is set by the RowPainter
private boolean isLastTrait;

/**
* Create a new Cell layout manager.
@@ -88,6 +118,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) {
super(node);
this.primaryGridUnit = pgu;
this.isDescendantOfTableHeader = node.getParent().getParent() instanceof TableHeader
|| node.getParent() instanceof TableHeader;
this.isDescendantOfTableFooter = node.getParent().getParent() instanceof TableFooter
|| node.getParent() instanceof TableFooter;
this.hasRetrieveTableMarker = node.hasRetrieveTableMarker();
}

/** @return the table-cell FO */
@@ -248,6 +283,84 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
totalHeight = h;
}

private void clearRetrieveTableMarkerChildNodes(List<LayoutManager> childrenLMs) {
if (childrenLMs == null) {
return;
}
int n = childrenLMs.size();
for (int j = 0; j < n; j++) {
LayoutManager lm = (LayoutManager) childrenLMs.get(j);
if (lm == null) {
return;
} else if (lm instanceof RetrieveTableMarkerLayoutManager) {
((AbstractLayoutManager) lm).getFObj().clearChildNodes();
} else {
List<LayoutManager> lms = lm.getChildLMs();
clearRetrieveTableMarkerChildNodes(lms);
}
}
}

/**
* Checks whether the associated table cell of this LM is in a table header or footer.
* @return true if descendant of table header or footer
*/
private boolean isDescendantOfTableHeaderOrFooter() {
return (isDescendantOfTableFooter || isDescendantOfTableHeader);
}

private void saveAddAreasArguments(PositionIterator parentIter, LayoutContext layoutContext,
int[] spannedGridRowHeights, int startRow, int endRow, int borderBeforeWhich,
int borderAfterWhich, boolean firstOnPage, boolean lastOnPage, RowPainter painter,
int firstRowHeight) {
// checks for savedAddAreasArguments and isDescendantOfTableHeader were already made but repeat them
if (savedAddAreasArguments) {
return;
}
if (isDescendantOfTableHeader) {
savedAddAreasArguments = true;
savedParentIter = null /* parentIter */;
savedLayoutContext = null /* layoutContext */;
savedSpannedGridRowHeights = spannedGridRowHeights;
savedStartRow = startRow;
savedEndRow = endRow;
savedBorderBeforeWhich = borderBeforeWhich;
savedBorderAfterWhich = borderAfterWhich;
savedFirstOnPage = firstOnPage;
savedLastOnPage = lastOnPage;
savedPainter = painter;
savedFirstRowHeight = firstRowHeight;
TableLayoutManager parentTableLayoutManager = getTableLayoutManager();
parentTableLayoutManager.saveTableHeaderTableCellLayoutManagers(this);
// this saving is done the first time the addArea() is called; since the retrieve-table-markers
// cannot be resolved at this time we do not want to flush the area; the area needs nevertheless
// be built so that space is allocated for it.
flushArea = false;
}
}

private TableLayoutManager getTableLayoutManager() {
LayoutManager parentLM = getParent();
while (!(parentLM instanceof TableLayoutManager)) {
parentLM = parentLM.getParent();
}
TableLayoutManager tlm = (TableLayoutManager) parentLM;
return tlm;
}

/**
* Calls the addAreas() using the original arguments.
*/
protected void repeatAddAreas() {
if (savedAddAreasArguments) {
addAreas(savedParentIter, savedLayoutContext, savedSpannedGridRowHeights, savedStartRow,
savedEndRow, savedBorderBeforeWhich, savedBorderAfterWhich, savedFirstOnPage,
savedLastOnPage, savedPainter, savedFirstRowHeight);
// so that the arguments of the next table fragment header can be saved
savedAddAreasArguments = false;
}
}

/**
* Add the areas for the break points. The cell contains block stacking layout
* managers that add block areas.
@@ -407,7 +520,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
}

AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
if (isDescendantOfTableHeaderOrFooter()) {
if (hasRetrieveTableMarker) {
if (isDescendantOfTableHeader && !savedAddAreasArguments) {
saveAddAreasArguments(parentIter, layoutContext, spannedGridRowHeights, startRow, endRow,
borderBeforeWhich, borderAfterWhich, firstOnPage, lastOnPage, painter,
firstRowHeight);
}
recreateChildrenLMs();
int displayAlign = ((TableCell) this.getFObj()).getDisplayAlign();
TableCellBreaker breaker = new TableCellBreaker(this, cellIPD, displayAlign);
breaker.doLayout(usedBPD, false);
// this is needed so the next time the LMs are recreated they look like the originals; this
// is due to the fact that during the doLayout() above the FO tree changes when the
// retrieve-table-markers are resolved
clearRetrieveTableMarkerChildNodes(getChildLMs());
}
}

// if hasRetrieveTableMarker == true the areas were already added when the re-layout was done above
if (!hasRetrieveTableMarker) {
AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
}
// Re-adjust the cell's bpd as it may have been modified by the previous call
// for some reason (?)
curBlockArea.setBPD(cellBPD);
@@ -418,7 +552,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
getTableCell().getCommonBorderPaddingBackground(), this);
}

flush();
if (flushArea) {
flush();
} else {
flushArea = true;
}

curBlockArea = null;

@@ -604,4 +742,49 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
return true;
}

private class TableCellBreaker extends LocalBreaker {

public TableCellBreaker(TableCellLayoutManager lm, int ipd, int displayAlign) {
super(lm, ipd, displayAlign);
}

/**
* {@inheritDoc}
*/
protected void observeElementList(List elementList) {
String elementListID = lm.getParent().getFObj().getId() + "-" + lm.getFObj().getId();
ElementListObserver.observe(elementList, "table-cell", elementListID);
}

}

/**
* Registers the FO's markers on the current PageViewport and parent Table.
*
* @param isStarting boolean indicating whether the markers qualify as 'starting'
* @param isFirst boolean indicating whether the markers qualify as 'first'
* @param isLast boolean indicating whether the markers qualify as 'last'
*/
protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) {
Map<String, Marker> markers = getTableCell().getMarkers();
if (markers != null) {
getCurrentPV().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait);
if (!isDescendantOfTableHeaderOrFooter()) {
getTableLayoutManager().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait);
}
}
}

void setLastTrait(boolean isLast) {
isLastTrait = isLast;
}

/** {@inheritDoc} */
public void setParent(LayoutManager lm) {
this.parentLayoutManager = lm;
if (this.hasRetrieveTableMarker) {
this.getTableLayoutManager().flagAsHavingRetrieveTableMarker();
}
}

}

+ 21
- 5
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java View File

@@ -31,9 +31,11 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableBody;
import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ElementListUtils;
@@ -400,9 +402,13 @@ public class TableContentLayoutManager implements PercentBaseContext {
}
}

Map markers = getTableLM().getTable().getMarkers();
// there may be table fragment markers stored; clear them since we are starting a new fragment
tableLM.clearTableFragmentMarkers();

// note: markers at table level are to be retrieved by the page, not by the table itself
Map<String, Marker> markers = getTableLM().getTable().getMarkers();
if (markers != null) {
getTableLM().getCurrentPV().addMarkers(markers,
getTableLM().getCurrentPV().registerMarkers(markers,
true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos));
}

@@ -430,6 +436,10 @@ public class TableContentLayoutManager implements PercentBaseContext {
addBodyAreas(tablePositions.iterator(), painter, footerElements == null);
}

// if there are TCLMs saved because they have a RetrieveTableMarker, we repeat the header areas now;
// this can also be done after the areas for the footer are added but should be the same as here
tableLM.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers();

if (footerElements != null) {
boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact();
layoutContext.setTreatAsArtifact(treatFooterAsArtifact);
@@ -442,7 +452,7 @@ public class TableContentLayoutManager implements PercentBaseContext {
this.usedBPD += painter.getAccumulatedBPD();

if (markers != null) {
getTableLM().getCurrentPV().addMarkers(markers,
getTableLM().getCurrentPV().registerMarkers(markers,
false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos));
}
}
@@ -503,14 +513,20 @@ public class TableContentLayoutManager implements PercentBaseContext {
*/
private void addTablePartAreas(List positions, RowPainter painter, TablePart body,
boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) {
getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
getTableLM().getCurrentPV().registerMarkers(body.getMarkers(),
true, isFirstPos, isLastPos);
if (body instanceof TableBody) {
getTableLM().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos);
}
painter.startTablePart(body);
for (Iterator iter = positions.iterator(); iter.hasNext();) {
painter.handleTableContentPosition((TableContentPosition) iter.next());
}
getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
getTableLM().getCurrentPV().registerMarkers(body.getMarkers(),
false, isFirstPos, isLastPos);
if (body instanceof TableBody) {
getTableLM().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos);
}
painter.endTablePart(lastInBody, lastOnPage);
}


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

@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -33,12 +34,16 @@ import org.apache.fop.datatypes.LengthBase;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.flow.Markers;
import org.apache.fop.fo.flow.RetrieveTableMarker;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockLevelEventProducer;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.BreakOpportunity;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
@@ -62,7 +67,7 @@ import org.apache.fop.util.BreakUtil;
* the render background.
*/
public class TableLayoutManager extends BlockStackingLayoutManager
implements ConditionalElementListener {
implements ConditionalElementListener, BreakOpportunity {

/**
* logging instance
@@ -92,6 +97,15 @@ public class TableLayoutManager extends BlockStackingLayoutManager

private Position auxiliaryPosition;

// this holds a possible list of TCLMs that needed to have their addAreas() repeated
private List<TableCellLayoutManager> savedTCLMs;
private boolean areAllTCLMsSaved;

private Markers tableMarkers;
private Markers tableFragmentMarkers;

private boolean hasRetrieveTableMarker;

/**
* Temporary holder of column background informations for a table-cell's area.
*
@@ -559,4 +573,112 @@ public class TableLayoutManager extends BlockStackingLayoutManager
tableUnit = 0.0;
}

/**
* Saves a TableCellLayoutManager for later use.
*
* @param tclm a TableCellLayoutManager that has a RetrieveTableMarker
*/
protected void saveTableHeaderTableCellLayoutManagers(TableCellLayoutManager tclm) {
if (savedTCLMs == null) {
savedTCLMs = new ArrayList<TableCellLayoutManager>();
}
if (!areAllTCLMsSaved) {
savedTCLMs.add(tclm);
}
}

/**
* Calls addAreas() for each of the saved TableCellLayoutManagers.
*/
protected void repeatAddAreasForSavedTableHeaderTableCellLayoutManagers() {
if (savedTCLMs == null) {
return;
}
// if we get to this stage then we are at the footer of the table fragment; this means that no more
// different TCLM need to be saved (we already have all); we flag the list as being complete then
areAllTCLMsSaved = true;
for (int i = 0; i < savedTCLMs.size(); i++) {
TableCellLayoutManager tclm = savedTCLMs.get(i);
tclm.repeatAddAreas();
}
}

/**
* Resolves a RetrieveTableMarker by finding a qualifying Marker to which it is bound to.
* @param rtm the RetrieveTableMarker to be resolved
* @return a bound RetrieveTableMarker instance or null if no qualifying Marker found
*/
public RetrieveTableMarker resolveRetrieveTableMarker(RetrieveTableMarker rtm) {
String name = rtm.getRetrieveClassName();
int originalPosition = rtm.getPosition();
boolean changedPosition = false;

Marker mark = null;
// try the primary retrieve scope area, which is the same as table-fragment
mark = (tableFragmentMarkers == null) ? null : tableFragmentMarkers.resolve(rtm);
if (mark == null && rtm.getBoundary() != Constants.EN_TABLE_FRAGMENT) {
rtm.changePositionTo(Constants.EN_LAST_ENDING);
changedPosition = true;
// try the page scope area
mark = getCurrentPV().resolveMarker(rtm);
if (mark == null && rtm.getBoundary() != Constants.EN_PAGE) {
// try the table scope area
mark = (tableMarkers == null) ? null : tableMarkers.resolve(rtm);
}
}
if (changedPosition) {
// so that the next time it is called looks unchanged
rtm.changePositionTo(originalPosition);
}
if (mark == null) {
log.debug("found no marker with name: " + name);
return null;
} else {
rtm.bindMarker(mark);
return rtm;
}
}

/**
* Register the markers for this table.
*
* @param marks the map of markers to add
* @param starting if the area being added is starting or ending
* @param isfirst if the area being added has is-first trait
* @param islast if the area being added has is-last trait
*/
public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst,
boolean islast) {
if (tableMarkers == null) {
tableMarkers = new Markers();
}
tableMarkers.register(marks, starting, isfirst, islast);
if (tableFragmentMarkers == null) {
tableFragmentMarkers = new Markers();
}
tableFragmentMarkers.register(marks, starting, isfirst, islast);
}

/**
* Clears the list of markers in the current table fragment. Should be called just before starting a new
* header (that belongs to the next table fragment).
*/
protected void clearTableFragmentMarkers() {
tableFragmentMarkers = null;
}

public void flagAsHavingRetrieveTableMarker() {
hasRetrieveTableMarker = true;
}

protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting,
boolean isFirst, boolean isLast) {
// note: if we allow table-footer after a table-body this check should not be made and the markers
// should be registered regardless because the retrieval may be done only in the footer
if (hasRetrieveTableMarker) {
registerMarkers(markers, isStarting, isFirst, isLast);
}
super.possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast);
}

}

+ 6
- 22
src/java/org/apache/fop/pdf/PDFDocument.java View File

@@ -355,36 +355,20 @@ public class PDFDocument {
}

/**
* Creates and returns a structure element.
*
* @param structureType the structure type of the new element (value for the
* S entry)
* @param parent the parent of the new structure element in the structure
* hierarchy
* @return a dictionary of type StructElem
* Adds the given element to the structure tree.
*/
public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent) {
PDFStructElem structElem = new PDFStructElem(parent, structureType);
public void registerStructureElement(PDFStructElem structElem) {
assignObjectNumber(structElem);
structureTreeElements.add(structElem);
return structElem;
}

/**
* Creates and returns a structure element.
*
* @param structureType the structure type of the new element (value for the
* S entry)
* @param parent the parent of the new structure element in the structure
* hierarchy
* @param scope the scope of the given table header element
* @return a dictionary of type StructElem
* Assigns the given scope to the given element and adds it to the structure tree. The
* scope may not be added if it's not compatible with this document's PDF version.
*/
public PDFStructElem makeStructureElement(StructureType structureType, PDFObject parent,
Scope scope) {
PDFStructElem structElem = makeStructureElement(structureType, parent);
public void registerStructureElement(PDFStructElem structElem, Scope scope) {
registerStructureElement(structElem);
versionController.addTableHeaderScopeAttribute(structElem, scope);
return structElem;
}

/**

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

@@ -23,6 +23,9 @@ package org.apache.fop.pdf;
import java.util.Collections;
import java.util.Set;

import org.apache.fop.fonts.CodePointMapping;
import org.apache.fop.fonts.SingleByteEncoding;

/**
* Class representing an /Encoding object.
*
@@ -73,6 +76,38 @@ public class PDFEncoding extends PDFDictionary {
}
}

/**
* Creates a PDFEncoding instance from a CodePointMapping instance.
* @param encoding the code point mapping (encoding)
* @param fontName ...
* @return the PDF Encoding dictionary (or a String with the predefined encoding)
*/
static Object createPDFEncoding(SingleByteEncoding encoding, String fontName) {
//If encoding type is null, return null which causes /Encoding to be omitted.
if (encoding == null) {
return null;
}
String encodingName = null;
SingleByteEncoding baseEncoding;
if (fontName.indexOf("Symbol") >= 0) {
baseEncoding = CodePointMapping.getMapping(CodePointMapping.SYMBOL_ENCODING);
encodingName = baseEncoding.getName();
} else {
baseEncoding = CodePointMapping.getMapping(CodePointMapping.STANDARD_ENCODING);
}
PDFEncoding pdfEncoding = new PDFEncoding(encodingName);
PDFEncoding.DifferencesBuilder builder = pdfEncoding.createDifferencesBuilder();
PDFArray differences = builder.buildDifferencesArray(baseEncoding, encoding);
// TODO This method should not be returning an Object with two different outcomes
// resulting in subsequent `if (X instanceof Y)` statements.
if (differences.length() > 0) {
pdfEncoding.setDifferences(differences);
return pdfEncoding;
} else {
return encodingName;
}
}

/**
* Indicates whether a given encoding is one of the predefined encodings.
* @param name the encoding name (ex. "StandardEncoding")
@@ -82,6 +117,15 @@ public class PDFEncoding extends PDFDictionary {
return PREDEFINED_ENCODINGS.contains(name);
}

/**
* Indicates whether the given encoding type is that of standard encoding
* @param name The encoding name
* @return Returns true if it is of type standard encoding
*/
static boolean hasStandardEncoding(String encodingName) {
return encodingName.equals(STANDARD_ENCODING);
}

/**
* Creates and returns a new DifferencesBuilder instance for constructing the Differences
* array.
@@ -104,18 +148,44 @@ public class PDFEncoding extends PDFDictionary {
*/
public class DifferencesBuilder {

private PDFArray differences = new PDFArray();
private int currentCode = -1;

/**
* Creates an array containing the differences between two single-byte.
* font encodings.
* @param encodingA The first single-byte encoding
* @param encodingB The second single-byte encoding
* @return The PDFArray of differences between encodings
*/
public PDFArray buildDifferencesArray(SingleByteEncoding encodingA,
SingleByteEncoding encodingB) {
PDFArray differences = new PDFArray();
int start = -1;
String[] baseNames = encodingA.getCharNameMap();
String[] charNameMap = encodingB.getCharNameMap();
for (int i = 0, ci = charNameMap.length; i < ci; i++) {
String basec = baseNames[i];
String c = charNameMap[i];
if (!basec.equals(c)) {
if (start != i) {
addDifference(i, differences);
start = i;
}
addName(c, differences);
start++;
}
}
return differences;
}

/**
* Start a new difference.
* @param code the starting code index inside the encoding
* @return this builder instance
*/
public DifferencesBuilder addDifference(int code) {
private void addDifference(int code, PDFArray differences) {
this.currentCode = code;
this.differences.add(new Integer(code));
return this;
differences.add(Integer.valueOf(code));
}

/**
@@ -123,28 +193,11 @@ public class PDFEncoding extends PDFDictionary {
* @param name the character name
* @return this builder instance
*/
public DifferencesBuilder addName(String name) {
private void addName(String name, PDFArray differences) {
if (this.currentCode < 0) {
throw new IllegalStateException("addDifference(int) must be called first");
}
this.differences.add(new PDFName(name));
return this;
}

/**
* Indicates whether any differences have been recorded.
* @return true if there are differences.
*/
public boolean hasDifferences() {
return (this.differences.length() > 0);
}

/**
* Creates and returns the PDFArray representing the Differences entry.
* @return the Differences entry
*/
public PDFArray toPDFArray() {
return this.differences;
differences.add(new PDFName(name));
}
}


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

@@ -44,9 +44,9 @@ import org.apache.xmlgraphics.java2d.color.NamedColorSpace;
import org.apache.xmlgraphics.xmp.Metadata;

import org.apache.fop.fonts.CIDFont;
import org.apache.fop.fonts.CIDSubset;
import org.apache.fop.fonts.CodePointMapping;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.FontDescriptor;
import org.apache.fop.fonts.FontMetrics;
import org.apache.fop.fonts.FontType;
@@ -1369,23 +1369,14 @@ public class PDFFactory {
} else {
cidMetrics = (CIDFont)metrics;
}
PDFCIDSystemInfo sysInfo
= new PDFCIDSystemInfo(cidMetrics.getRegistry(),
cidMetrics.getOrdering(),
cidMetrics.getSupplement());
PDFCIDFont cidFont = new PDFCIDFont(subsetFontName,
cidMetrics.getCIDType(),
cidMetrics.getDefaultWidth(),
getSubsetWidths(cidMetrics), sysInfo,
(PDFCIDFontDescriptor)pdfdesc);
PDFCIDSystemInfo sysInfo = new PDFCIDSystemInfo(cidMetrics.getRegistry(),
cidMetrics.getOrdering(), cidMetrics.getSupplement());
PDFCIDFont cidFont = new PDFCIDFont(subsetFontName, cidMetrics.getCIDType(),
cidMetrics.getDefaultWidth(), getFontWidths(cidMetrics), sysInfo,
(PDFCIDFontDescriptor) pdfdesc);
getDocument().registerObject(cidFont);

PDFCMap cmap = new PDFToUnicodeCMap(
cidMetrics.getCIDSubset().getSubsetChars(),
"fop-ucs-H",
new PDFCIDSystemInfo("Adobe",
"Identity",
0), false);
PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCIDSet().getChars(), "fop-ucs-H",
new PDFCIDSystemInfo("Adobe", "Identity", 0), false);
getDocument().registerObject(cmap);
((PDFFontType0)font).setCMAP(cmap);
((PDFFontType0)font).setDescendantFonts(cidFont);
@@ -1469,61 +1460,18 @@ public class PDFFactory {
/**
* Creates a PDFEncoding instance from a CodePointMapping instance.
* @param encoding the code point mapping (encoding)
* @param fontNameHint ...
* @param fontName ...
* @return the PDF Encoding dictionary (or a String with the predefined encoding)
*/
public Object createPDFEncoding(SingleByteEncoding encoding, String fontNameHint) {
SingleByteEncoding baseEncoding;
if (fontNameHint.indexOf("Symbol") >= 0) {
baseEncoding = CodePointMapping.getMapping(
CodePointMapping.SYMBOL_ENCODING);
} else {
baseEncoding = CodePointMapping.getMapping(
CodePointMapping.STANDARD_ENCODING);
}
PDFEncoding pdfEncoding = new PDFEncoding(baseEncoding.getName());
PDFEncoding.DifferencesBuilder builder
= pdfEncoding.createDifferencesBuilder();
int start = -1;
String[] baseNames = baseEncoding.getCharNameMap();
String[] charNameMap = encoding.getCharNameMap();
for (int i = 0, ci = charNameMap.length; i < ci; i++) {
String basec = baseNames[i];
String c = charNameMap[i];
if (!basec.equals(c)) {
if (start != i) {
builder.addDifference(i);
start = i;
}
builder.addName(c);
start++;
}
}
if (builder.hasDifferences()) {
pdfEncoding.setDifferences(builder.toPDFArray());
return pdfEncoding;
} else {
return baseEncoding.getName();
}
public Object createPDFEncoding(SingleByteEncoding encoding, String fontName) {
return PDFEncoding.createPDFEncoding(encoding, fontName);
}

/**
* Creates and returns a width array with the widths of all the characters in the subset.
* @param cidFont the font
* @return the width array
*/
public PDFWArray getSubsetWidths(CIDFont cidFont) {
private PDFWArray getFontWidths(CIDFont cidFont) {
// Create widths for reencoded chars
PDFWArray warray = new PDFWArray();
int[] widths = cidFont.getWidths();
CIDSubset subset = cidFont.getCIDSubset();
int[] tmpWidth = new int[subset.getSubsetSize()];

for (int i = 0, c = subset.getSubsetSize(); i < c; i++) {
int nwx = Math.max(0, subset.getGlyphIndexForSubsetIndex(i));
tmpWidth[i] = widths[nwx];
}
warray.addEntry(0, tmpWidth);
int[] widths = cidFont.getCIDSet().getWidths();
warray.addEntry(0, widths);
return warray;
}

@@ -1591,13 +1539,13 @@ public class PDFFactory {
}

private void buildCIDSet(PDFFontDescriptor descriptor, CIDFont cidFont) {
BitSet cidSubset = cidFont.getCIDSubset().getGlyphIndexBitSet();
PDFStream cidSet = makeStream(null, true);
ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSubset.length() / 8 + 1);
BitSet cidSet = cidFont.getCIDSet().getGlyphIndices();
PDFStream pdfStream = makeStream(null, true);
ByteArrayOutputStream baout = new ByteArrayOutputStream(cidSet.length() / 8 + 1);
int value = 0;
for (int i = 0, c = cidSubset.length(); i < c; i++) {
for (int i = 0, c = cidSet.length(); i < c; i++) {
int shift = i % 8;
boolean b = cidSubset.get(i);
boolean b = cidSet.get(i);
if (b) {
value |= 1 << 7 - shift;
}
@@ -1608,8 +1556,8 @@ public class PDFFactory {
}
baout.write(value);
try {
cidSet.setData(baout.toByteArray());
descriptor.setCIDSet(cidSet);
pdfStream.setData(baout.toByteArray());
descriptor.setCIDSet(pdfStream);
} catch (IOException ioe) {
log.error(
"Failed to write CIDSet [" + cidFont + "] "
@@ -1640,14 +1588,16 @@ public class PDFFactory {
if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont) font;
FontFileReader reader = new FontFileReader(in);

TTFSubSetFile subset = new TTFSubSetFile();
subset.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
byte[] subsetFont = subset.getFontSubset();
// Only TrueType CID fonts are supported now

embeddedFont = new PDFTTFStream(subsetFont.length);
((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length);
byte[] fontBytes;
if (font.getEmbeddingMode() == EmbeddingMode.FULL) {
fontBytes = reader.getAllBytes();
} else {
TTFSubSetFile ttfFile = new TTFSubSetFile();
ttfFile.readFont(reader, mbfont.getTTCName(), mbfont.getUsedGlyphs());
fontBytes = ttfFile.getFontSubset();
}
embeddedFont = new PDFTTFStream(fontBytes.length);
((PDFTTFStream) embeddedFont).setData(fontBytes, fontBytes.length);
} else if (desc.getFontType() == FontType.TYPE1) {
PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(in);

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

@@ -70,7 +70,7 @@ public class PDFFont extends PDFDictionary {
* @param encoding the encoding
*/
public void setEncoding(String encoding) {
if (encoding != null) {
if (encoding != null && !PDFEncoding.hasStandardEncoding(encoding)) {
put("Encoding", new PDFName(encoding));
}
}

+ 4
- 2
src/java/org/apache/fop/pdf/PDFStructElem.java View File

@@ -32,7 +32,8 @@ import org.apache.fop.util.LanguageTags;
/**
* Class representing a PDF Structure Element.
*/
public class PDFStructElem extends PDFDictionary implements StructureTreeElement, CompressedObject {
public class PDFStructElem extends StructureHierarchyMember
implements StructureTreeElement, CompressedObject {

private StructureType structureType;

@@ -51,7 +52,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement
* @param parent parent of this element
* @param structureType the structure type of this element
*/
PDFStructElem(PDFObject parent, StructureType structureType) {
public PDFStructElem(PDFObject parent, StructureType structureType) {
this(parent);
this.structureType = structureType;
put("S", structureType.getName());
@@ -86,6 +87,7 @@ public class PDFStructElem extends PDFDictionary implements StructureTreeElement
*
* @param kid element to be added
*/
@Override
public void addKid(PDFObject kid) {
if (kids == null) {
kids = new ArrayList<PDFObject>();

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

@@ -22,7 +22,7 @@ package org.apache.fop.pdf;
/**
* Class representing a PDF /StructTreeRoot dictionary.
*/
public class PDFStructTreeRoot extends PDFDictionary {
public class PDFStructTreeRoot extends StructureHierarchyMember {

/**
* Creates a new /StructTreeRoot dictionary.
@@ -49,6 +49,7 @@ public class PDFStructTreeRoot extends PDFDictionary {
*
* @param kid an object to be added to the K entry
*/
@Override
public void addKid(PDFObject kid) {
getKids().add(kid);
}

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

@@ -111,6 +111,11 @@ public final class StandardStructureTypes {
return name;
}

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

}

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

src/java/org/apache/fop/apps/io/Resource.java → src/java/org/apache/fop/pdf/StructureHierarchyMember.java View File

@@ -17,43 +17,21 @@

/* $Id$ */

package org.apache.fop.apps.io;

import java.io.FilterInputStream;
import java.io.InputStream;
package org.apache.fop.pdf;

/**
* This class represents a resolved resource. The type property is used by FOP to identify the resource
* content.
* An element in the document's structure tree. This can be either the structure tree root
* or a structure element.
*
* @see "Section 10.6, <q>Logical Structure</q> of the PDF Reference, 4th edition (PDF 1.5)"
*/
public class Resource extends FilterInputStream {

private final String type;

/**
* @param type resource type
* @param inputStream input stream of the resource
*/
public Resource(String type, InputStream inputStream) {
super(inputStream);
this.type = type;
}
public abstract class StructureHierarchyMember extends PDFDictionary {

/**
* Constructs a resource of 'unknown' type.
* Adds the given object to the array of kids.
*
* @param inputStream input stream of the resource
*/
public Resource(InputStream inputStream) {
this("unknown", inputStream);
}

/**
* @return the resource type
* @param kid an object to be added to the K entry
*/
public String getType() {
return this.type;
}
public abstract void addKid(PDFObject kid);

}

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

@@ -328,7 +328,8 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
case IN_PAGE_HEADER:
String name = aps.getName();
String value = aps.getValue();
dataStream.createTagLogicalElement(name, value);
int encoding = aps.getEncoding();
dataStream.createTagLogicalElement(name, value, encoding);
break;
default:
throw new IFException(

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


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

Loading…
Cancel
Save