git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-1_1@1400697 13f79535-47bb-0310-9956-ffa450edef68fop-1_1
@@ -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; |
@@ -1078,6 +1078,15 @@ | |||
<Method name="getExternalAction"/> | |||
<Bug pattern="DM_CONVERT_CASE"/> | |||
</Match> | |||
<Match> | |||
<Class name="org.apache.fop.pdf.PDFPageLabels"/> | |||
<Or> | |||
<Method name="addPageLabel"/> | |||
<Method name="alphabeticToArabic"/> | |||
<Method name="romanToArabic"/> | |||
</Or> | |||
<Bug pattern="DM_CONVERT_CASE"/> | |||
</Match> | |||
<Match> | |||
<Class name="org.apache.fop.render.bitmap.MultiFileRenderingUtil"/> | |||
<Method name="<init>"/> | |||
@@ -3303,6 +3312,11 @@ | |||
<Method name="make"/> | |||
<Bug pattern="BC_UNCONFIRMED_CAST"/> | |||
</Match> | |||
<Match> | |||
<Class name="org.apache.fop.layoutmgr.LayoutManagerMapping$RetrieveTableMarkerLayoutManagerMaker"/> | |||
<Method name="make"/> | |||
<Bug pattern="BC_UNCONFIRMED_CAST"/> | |||
</Match> | |||
<Match> | |||
<Class name="org.apache.fop.layoutmgr.LayoutManagerMapping$WrapperLayoutManagerMaker"/> | |||
<Method name="make"/> |
@@ -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 |
@@ -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 |
@@ -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") + " ":"") |
@@ -97,7 +97,7 @@ To review the archives, you have several options: | |||
<li>The <link href="http://marc.theaimsgroup.com/?l=fop-dev&r=1&w=2">Mailing list ARChives</link> (MARC) at the AIMS group (search).</li> | |||
<li><link href="http://www.mail-archive.com/fop-dev%40xmlgraphics.apache.org/">The Mail Archive</link>.</li> | |||
<li>The <link href="http://dir.gmane.org/gmane.text.xml.fop.devel">GMANE</link> archive.</li> | |||
<li>The <link href="http://www.nabble.com/FOP---Dev-f352.html">Nabble</link> archive.</li> | |||
<li>The <link href="http://apache-fop.1065347.n5.nabble.com/">Nabble</link> archive.</li> | |||
<li>The <link href="http://fop-dev.markmail.org">MarkMail</link> archive.</li> | |||
</ul> | |||
</li> |
@@ -68,6 +68,7 @@ | |||
<li>Tag the source tree with the release ID. For example, if the release is 1.0: | |||
<code>svn copy https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-1_0 https://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-1_0</code></li> | |||
<li>Make a fresh checkout with the just created tag: <code>svn co https://svn.apache.org/repos/asf/xmlgraphics/fop/tags/fop-1_0</code></li> | |||
<li>Copy the <code>jai_core.jar</code> and <code>jai_codec.jar</code> to <code>lib</code>.</li> | |||
<li>Copy the hyphenation patterns jar file <code>fop-hyph.jar</code> to <code>lib</code> (e.g. from <code>http://sourceforge.net/projects/offo</code></li> | |||
<li>Alternatively, create a <code>build-local.properties</code> file that points to the above libraries.</li> | |||
<li>Run <code>build[.sh] dist</code>. Do this using Sun JDK 1.5 or later. A Forrest installation is needed.</li> |
@@ -43,17 +43,17 @@ If you are using Microsoft Outlook, this setting can be found at the "Mail Forma | |||
<title>Archives</title> | |||
<p>To review the archives, you have several options:</p> | |||
<ul> | |||
<li>The <link href="http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-users/">Apache Mailing List archive</link> (mod_mbox archive, no full-text search, yet).</li> | |||
<li>The <link href="http://xmlgraphics.apache.org/mail/fop-users/">Apache Mailing List archive</link> (gzipped mbox files).</li> | |||
<li>The <jump href="http://marc.theaimsgroup.com/?l=fop-user&r=1&w=2">Mailing list ARChives </jump> (MARC) at the AIMS group.</li> | |||
<li><jump href="http://www.mail-archive.com/fop-users%40xmlgraphics.apache.org/">The Mail Archive</jump>.</li> | |||
<li>The <jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE archive</jump>.</li> | |||
<li>The <jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble archive</jump> (only posts after May 2005).</li> | |||
<li>The <jump href="http://apache-fop.1065347.n5.nabble.com/FOP-Users-f3.html">Nabble archive</jump> (only posts after May 2005).</li> | |||
<li>The <jump href="http://fop-users.markmail.org/">MarkMail archive</jump>.</li> | |||
</ul> | |||
<note> | |||
If you don't like mailing lists and prefer a forum-like system, have a look at | |||
If you don't like mailing lists and prefer a forum-like system, have a look at | |||
<jump href="http://dir.gmane.org/gmane.text.xml.fop.user">GMANE</jump> or | |||
<jump href="http://www.nabble.com/FOP---Users-f353.html">Nabble</jump>. They | |||
allow you to post to the mailing list without having to subscribe. |
@@ -38,6 +38,7 @@ | |||
involved in the creation of ISO 8879 (SGML), ISO/IEC 9541 (Font Information Interchange), | |||
ISO/IEC 10179 (DSSSL), ISO/IEC 10180 (SPDL), ISO/IEC 10646 (Universal Coded Character Set), | |||
and, within the W3C, on XSL-FO 1.0.</li> | |||
<li id="lb"><link href="mailto:lmpmbernardo@gmail.com">Luis Bernardo</link> (LB)</li> | |||
<li id="cb"><link href="mailto:bowditch_chris@hotmail.com">Chris Bowditch</link> (CB) | |||
is a Java/VB Programmer from England.</li> | |||
<li id="ac"><link href="mailto:acumiskey AT apache.org">Adrian Cumiskey</link> (AC) | |||
@@ -77,16 +78,15 @@ | |||
<section id="contribute-active"> | |||
<title>Active Contributors</title> | |||
<ul> | |||
<li id="gd">Georg Datterl is a software developer from Austria, currently working for | |||
Geneon media solutions gmbh in Nuremberg, Germany. He needs FOP to wrestle gigabytes of | |||
electronic data into thousands of printed pages.</li> | |||
<li id="ag">Alexios Giotis holds a Ph.D. in the optimization of turbomachinery cascades | |||
using evolutionary algorithms, neural networks and parallel processing. He is one of | |||
the founding members of i-docs (software for enterprises) and he has been leading its | |||
technical design & implementation based on open source libraries since its inception. | |||
He is relying on Apache FOP for generating high volumes of documents on major banks and | |||
telecom operators since FOP's 1.0 release. He lives in Athens, Greece.</li> | |||
<li id="gd">Georg Datterl is a software developer from Austria, currently working for | |||
Geneon media solutions gmbh in Nuremberg, Germany. He needs FOP to wrestle gigabytes of | |||
electronic data into thousands of printed pages.</li> | |||
<li id="lb">Luis Bernardo</li> | |||
</ul> | |||
</section> | |||
<section id="founder"> | |||
@@ -125,4 +125,3 @@ | |||
</section> | |||
</body> | |||
</document> | |||
@@ -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> |
@@ -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(); |
@@ -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); | |||
} | |||
}); | |||
} | |||
} |
@@ -20,8 +20,10 @@ | |||
package org.apache.fop.accessibility.fo; | |||
import java.util.Locale; | |||
import java.util.Stack; | |||
import javax.xml.XMLConstants; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.apache.fop.accessibility.StructureTreeElement; | |||
@@ -30,6 +32,7 @@ import org.apache.fop.fo.FOEventHandler; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.FOText; | |||
import org.apache.fop.fo.extensions.ExtensionElementMapping; | |||
import org.apache.fop.fo.extensions.InternalElementMapping; | |||
import org.apache.fop.fo.flow.AbstractGraphics; | |||
import org.apache.fop.fo.flow.BasicLink; | |||
import org.apache.fop.fo.flow.Block; | |||
@@ -55,9 +58,13 @@ import org.apache.fop.fo.flow.table.TableFooter; | |||
import org.apache.fop.fo.flow.table.TableHeader; | |||
import org.apache.fop.fo.flow.table.TableRow; | |||
import org.apache.fop.fo.pagination.Flow; | |||
import org.apache.fop.fo.pagination.LayoutMasterSet; | |||
import org.apache.fop.fo.pagination.PageSequence; | |||
import org.apache.fop.fo.pagination.Root; | |||
import org.apache.fop.fo.pagination.StaticContent; | |||
import org.apache.fop.fo.properties.CommonAccessibilityHolder; | |||
import org.apache.fop.fo.properties.CommonHyphenation; | |||
import org.apache.fop.util.LanguageTags; | |||
import org.apache.fop.util.XMLUtil; | |||
/** | |||
@@ -67,27 +74,38 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
private StructureTreeEventHandler structureTreeEventHandler; | |||
private LayoutMasterSet layoutMasterSet; | |||
private final Stack<Table> tables = new Stack<Table>(); | |||
private final Stack<Boolean> inTableHeader = new Stack<Boolean>(); | |||
private final Stack<Locale> locales = new Stack<Locale>(); | |||
public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { | |||
this.structureTreeEventHandler = structureTreeEventHandler; | |||
} | |||
@Override | |||
public void startDocument() throws SAXException { | |||
public void startRoot(Root root) { | |||
locales.push(root.getLocale()); | |||
} | |||
@Override | |||
public void endDocument() throws SAXException { | |||
public void endRoot(Root root) { | |||
locales.pop(); | |||
} | |||
@Override | |||
public void startPageSequence(PageSequence pageSeq) { | |||
Locale locale = null; | |||
if (pageSeq.getLanguage() != null) { | |||
if (pageSeq.getCountry() != null) { | |||
locale = new Locale(pageSeq.getLanguage(), pageSeq.getCountry()); | |||
} else { | |||
locale = new Locale(pageSeq.getLanguage()); | |||
} | |||
if (layoutMasterSet == null) { | |||
layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet(); | |||
} | |||
Locale locale = pageSeq.getLocale(); | |||
if (locale != null) { | |||
locales.push(locale); | |||
} else { | |||
locales.push(locales.peek()); | |||
} | |||
String role = pageSeq.getCommonAccessibility().getRole(); | |||
structureTreeEventHandler.startPageSequence(locale, role); | |||
@@ -96,6 +114,7 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
@Override | |||
public void endPageSequence(PageSequence pageSeq) { | |||
structureTreeEventHandler.endPageSequence(); | |||
locales.pop(); | |||
} | |||
@Override | |||
@@ -128,9 +147,28 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
endElement(pageLast); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
AttributesImpl flowName = createFlowNameAttribute(staticContent.getFlowName()); | |||
startElement(staticContent, flowName); | |||
} | |||
private AttributesImpl createFlowNameAttribute(String flowName) { | |||
String regionName = layoutMasterSet.getDefaultRegionNameFor(flowName); | |||
AttributesImpl attribute = new AttributesImpl(); | |||
addNoNamespaceAttribute(attribute, Flow.FLOW_NAME, regionName); | |||
return attribute; | |||
} | |||
@Override | |||
public void endStatic(StaticContent staticContent) { | |||
endElement(staticContent); | |||
} | |||
@Override | |||
public void startFlow(Flow fl) { | |||
startElement(fl); | |||
AttributesImpl flowName = createFlowNameAttribute(fl.getFlowName()); | |||
startElement(fl, flowName); | |||
} | |||
@Override | |||
@@ -140,12 +178,28 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
@Override | |||
public void startBlock(Block bl) { | |||
startElement(bl); | |||
CommonHyphenation hyphProperties = bl.getCommonHyphenation(); | |||
AttributesImpl attributes = createLangAttribute(hyphProperties); | |||
startElement(bl, attributes); | |||
} | |||
private AttributesImpl createLangAttribute(CommonHyphenation hyphProperties) { | |||
Locale locale = hyphProperties.getLocale(); | |||
AttributesImpl attributes = new AttributesImpl(); | |||
if (locale == null || locale.equals(locales.peek())) { | |||
locales.push(locales.peek()); | |||
} else { | |||
locales.push(locale); | |||
addAttribute(attributes, XMLConstants.XML_NS_URI, "lang", "xml", | |||
LanguageTags.toLanguageTag(locale)); | |||
} | |||
return attributes; | |||
} | |||
@Override | |||
public void endBlock(Block bl) { | |||
endElement(bl); | |||
locales.pop(); | |||
} | |||
@Override | |||
@@ -170,42 +224,51 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
@Override | |||
public void startTable(Table tbl) { | |||
tables.push(tbl); | |||
startElement(tbl); | |||
} | |||
@Override | |||
public void endTable(Table tbl) { | |||
endElement(tbl); | |||
tables.pop(); | |||
} | |||
@Override | |||
public void startHeader(TableHeader header) { | |||
inTableHeader.push(Boolean.TRUE); | |||
startElement(header); | |||
} | |||
@Override | |||
public void endHeader(TableHeader header) { | |||
endElement(header); | |||
inTableHeader.pop(); | |||
} | |||
@Override | |||
public void startFooter(TableFooter footer) { | |||
// TODO Shouldn't it be true? | |||
inTableHeader.push(Boolean.FALSE); | |||
startElement(footer); | |||
} | |||
@Override | |||
public void endFooter(TableFooter footer) { | |||
endElement(footer); | |||
inTableHeader.pop(); | |||
} | |||
@Override | |||
public void startBody(TableBody body) { | |||
inTableHeader.push(Boolean.FALSE); | |||
startElement(body); | |||
} | |||
@Override | |||
public void endBody(TableBody body) { | |||
endElement(body); | |||
inTableHeader.pop(); | |||
} | |||
@Override | |||
@@ -221,14 +284,35 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
@Override | |||
public void startCell(TableCell tc) { | |||
AttributesImpl attributes = new AttributesImpl(); | |||
int colSpan = tc.getNumberColumnsSpanned(); | |||
if (colSpan > 1) { | |||
addNoNamespaceAttribute(attributes, "number-columns-spanned", | |||
Integer.toString(colSpan)); | |||
addSpanAttribute(attributes, "number-columns-spanned", tc.getNumberColumnsSpanned()); | |||
addSpanAttribute(attributes, "number-rows-spanned", tc.getNumberRowsSpanned()); | |||
boolean rowHeader = inTableHeader.peek(); | |||
boolean columnHeader = tables.peek().getColumn(tc.getColumnNumber() - 1).isHeader(); | |||
if (rowHeader || columnHeader) { | |||
final String th = "TH"; | |||
String role = tc.getCommonAccessibility().getRole(); | |||
/* Do not override a custom role */ | |||
if (role == null) { | |||
role = th; | |||
addNoNamespaceAttribute(attributes, "role", th); | |||
} | |||
if (role.equals(th)) { | |||
if (columnHeader) { | |||
String scope = rowHeader ? "Both" : "Row"; | |||
addAttribute(attributes, InternalElementMapping.URI, InternalElementMapping.SCOPE, | |||
InternalElementMapping.STANDARD_PREFIX, scope); | |||
} | |||
} | |||
} | |||
startElement(tc, attributes); | |||
} | |||
private void addSpanAttribute(AttributesImpl attributes, String attributeName, int span) { | |||
if (span > 1) { | |||
addNoNamespaceAttribute(attributes, attributeName, Integer.toString(span)); | |||
} | |||
} | |||
@Override | |||
public void endCell(TableCell tc) { | |||
endElement(tc); | |||
@@ -274,16 +358,6 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
endElement(listItemBody); | |||
} | |||
@Override | |||
public void startStatic(StaticContent staticContent) { | |||
startElement(staticContent); | |||
} | |||
@Override | |||
public void endStatic(StaticContent statisContent) { | |||
endElement(statisContent); | |||
} | |||
@Override | |||
public void startLink(BasicLink basicLink) { | |||
startElementWithID(basicLink); | |||
@@ -342,8 +416,10 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
@Override | |||
public void character(Character c) { | |||
startElementWithID(c); | |||
AttributesImpl attributes = createLangAttribute(c.getCommonHyphenation()); | |||
startElementWithID(c, attributes); | |||
endElement(c); | |||
locales.pop(); | |||
} | |||
@Override | |||
@@ -358,7 +434,10 @@ class StructureTreeEventTrigger extends FOEventHandler { | |||
} | |||
private void startElementWithID(FONode node) { | |||
AttributesImpl attributes = new AttributesImpl(); | |||
startElementWithID(node, new AttributesImpl()); | |||
} | |||
private void startElementWithID(FONode node, AttributesImpl attributes) { | |||
String localName = node.getLocalName(); | |||
if (node instanceof CommonAccessibilityHolder) { | |||
addRole((CommonAccessibilityHolder) node, attributes); |
@@ -113,4 +113,13 @@ public interface AFPEventProducer extends EventProducer { | |||
* @event.severity ERROR | |||
*/ | |||
void invalidConfiguration(Object source, Exception e); | |||
/** | |||
* The characterset is missing metric information for the specified character | |||
* @param source the event source | |||
* @param character the character with missing metric information. | |||
* @param charSet the character set containing missing metric information | |||
* @event.severity WARN | |||
*/ | |||
void charactersetMissingMetrics(Object source, char character, String charSet); | |||
} |
@@ -8,4 +8,5 @@ | |||
<message key="fontConfigMissing">The mandatory configuation node: '{missingConfig}' was not found at {location}.</message> | |||
<message key="characterSetNameInvalid">The character set given has an invalid name. [ Reason: {msg} ]</message> | |||
<message key="codePageNotFound">The code page for an AFP font cannot be found.[ Reason: {e}]</message> | |||
<message key="charactersetMissingMetrics">Metric information is missing for the glyph `{character}` in the characterset `{charSet}`. Using space increment width.</message> | |||
</catalogue> |
@@ -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 |
@@ -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; | |||
} |
@@ -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; | |||
} | |||
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.afp.fonts; | |||
import org.apache.fop.afp.AFPEventProducer; | |||
/** | |||
* A font defined as a set of lines and curves as opposed to a bitmap font. An | |||
* outline font can be scaled to any size and otherwise transformed more easily | |||
@@ -29,16 +31,25 @@ public abstract class AbstractOutlineFont extends AFPFont { | |||
/** The character set for this font */ | |||
protected CharacterSet charSet = null; | |||
private final AFPEventProducer eventProducer; | |||
/** | |||
* Constructor for an outline font. | |||
* | |||
* @param name the name of the font | |||
* @param embeddable sets whether or not this font is to be embedded | |||
* @param charSet the chracter set | |||
* @param eventProducer The object to handle any events which occur from the object. | |||
*/ | |||
public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet) { | |||
public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet, | |||
AFPEventProducer eventProducer) { | |||
super(name, embeddable); | |||
this.charSet = charSet; | |||
this.eventProducer = eventProducer; | |||
} | |||
AFPEventProducer getAFPEventProducer() { | |||
return eventProducer; | |||
} | |||
/** |
@@ -363,4 +363,12 @@ public class CharacterSet { | |||
return getCharacterSetOrientation().getEmSpaceIncrement(); | |||
} | |||
/** | |||
* Returns the nominal character increment. | |||
* @return the nominal character increment | |||
*/ | |||
public int getNominalCharIncrement() { | |||
return getCharacterSetOrientation().getNominalCharIncrement(); | |||
} | |||
} |
@@ -236,9 +236,9 @@ public abstract class CharacterSetBuilder { | |||
CharacterSetType charsetType, AFPResourceAccessor accessor, AFPEventProducer eventProducer) | |||
throws IOException { | |||
// check for cached version of the characterset | |||
String descriptor = characterSetName + "_" + encoding + "_" + codePageName; | |||
CharacterSet characterSet = (CharacterSet) characterSetsCache.get(descriptor); | |||
URI charSetURI = accessor.resolveURI(characterSetName); | |||
String cacheKey = charSetURI.toASCIIString() + "_" + characterSetName + "_" + codePageName; | |||
CharacterSet characterSet = (CharacterSet) characterSetsCache.get(cacheKey); | |||
if (characterSet != null) { | |||
return characterSet; | |||
} | |||
@@ -257,6 +257,8 @@ public abstract class CharacterSetBuilder { | |||
* chracter global identifier. | |||
*/ | |||
Map<String, String> codePage; | |||
// TODO: This could have performance implications if several threads want to use the | |||
// codePagesCache to retrieve different codepages. | |||
synchronized (codePagesCache) { | |||
codePage = codePagesCache.get(codePageName); | |||
@@ -308,7 +310,7 @@ public abstract class CharacterSetBuilder { | |||
} finally { | |||
closeInputStream(inputStream); | |||
} | |||
characterSetsCache.put(descriptor, characterSet); | |||
characterSetsCache.put(cacheKey, characterSet); | |||
return characterSet; | |||
} | |||
@@ -446,20 +448,15 @@ public abstract class CharacterSetBuilder { | |||
position++; | |||
if (position == 26) { | |||
position = 0; | |||
int orientation = determineOrientation(fnoData[2]); | |||
// Space Increment | |||
int space = ((fnoData[8] & 0xFF ) << 8) + (fnoData[9] & 0xFF); | |||
// Em-Space Increment | |||
int em = ((fnoData[14] & 0xFF ) << 8) + (fnoData[15] & 0xFF); | |||
CharacterSetOrientation cso = new CharacterSetOrientation(orientation); | |||
cso.setSpaceIncrement(space); | |||
cso.setEmSpaceIncrement(em); | |||
orientations.add(cso); | |||
int spaceIncrement = getUBIN(fnoData, 8); | |||
int emIncrement = getUBIN(fnoData, 14); | |||
int nominalCharacterIncrement = getUBIN(fnoData, 20); | |||
orientations.add(new CharacterSetOrientation(orientation, spaceIncrement, | |||
emIncrement, nominalCharacterIncrement)); | |||
} | |||
} | |||
return orientations.toArray(EMPTY_CSO_ARRAY); |
@@ -60,7 +60,7 @@ public class CharacterSetOrientation { | |||
/** | |||
* The character widths in the character set (indexed using Unicode codepoints) | |||
*/ | |||
private int[] charsWidths = null; | |||
private int[] charsWidths; | |||
/** | |||
* The height of lowercase letters | |||
@@ -77,25 +77,26 @@ public class CharacterSetOrientation { | |||
*/ | |||
private char lastChar; | |||
/** | |||
* The character set orientation | |||
*/ | |||
private int orientation = 0; | |||
/** The character set orientation */ | |||
private final int orientation; | |||
/** space increment */ | |||
private int spaceIncrement; | |||
private final int spaceIncrement; | |||
/** em space increment */ | |||
private int emSpaceIncrement = -1; | |||
private final int emSpaceIncrement; | |||
/** Nominal Character Increment */ | |||
private final int nomCharIncrement; | |||
/** | |||
* Constructor for the CharacterSetOrientation, the orientation is | |||
* expressed as the degrees rotation (i.e 0, 90, 180, 270) | |||
* @param orientation the character set orientation | |||
*/ | |||
public CharacterSetOrientation(int orientation) { | |||
public CharacterSetOrientation(int orientation, int spaceIncrement, int emSpaceIncrement, | |||
int nomCharIncrement) { | |||
this.orientation = orientation; | |||
this.spaceIncrement = spaceIncrement; | |||
this.emSpaceIncrement = emSpaceIncrement; | |||
this.nomCharIncrement = nomCharIncrement; | |||
charsWidths = new int[256]; | |||
Arrays.fill(charsWidths, -1); | |||
} | |||
@@ -283,14 +284,6 @@ public class CharacterSetOrientation { | |||
return this.spaceIncrement; | |||
} | |||
/** | |||
* Sets the space increment. | |||
* @param value the space increment | |||
*/ | |||
public void setSpaceIncrement(int value) { | |||
this.spaceIncrement = value; | |||
} | |||
/** | |||
* Returns the em space increment. | |||
* @return the em space increment | |||
@@ -300,11 +293,10 @@ public class CharacterSetOrientation { | |||
} | |||
/** | |||
* Sets the em space increment. | |||
* @param value the em space increment | |||
* Returns the nominal character increment. | |||
* @return the nominal character increment | |||
*/ | |||
public void setEmSpaceIncrement(int value) { | |||
this.emSpaceIncrement = value; | |||
public int getNominalCharIncrement() { | |||
return this.nomCharIncrement; | |||
} | |||
} |
@@ -23,6 +23,11 @@ import java.lang.Character.UnicodeBlock; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.afp.AFPEventProducer; | |||
/** | |||
* Implementation of AbstractOutlineFont that supports double-byte fonts (CID Keyed font (Type 0)). | |||
* The width of characters that are not prescribed a width metrics in the font resource use | |||
@@ -31,7 +36,9 @@ import java.util.Set; | |||
*/ | |||
public class DoubleByteFont extends AbstractOutlineFont { | |||
//private static final Log LOG = LogFactory.getLog(DoubleByteFont.class); | |||
private static final Log log = LogFactory.getLog(DoubleByteFont.class); | |||
private final Set<Integer> charsProcessed; | |||
//See also http://unicode.org/reports/tr11/ which we've not closely looked at, yet | |||
//TODO the Unicode block listed here is probably not complete (ex. Hiragana, Katakana etc.) | |||
@@ -49,9 +56,12 @@ public class DoubleByteFont extends AbstractOutlineFont { | |||
* @param name the name of the font | |||
* @param embeddable whether or not this font is embeddable | |||
* @param charSet the character set | |||
* @param eventProducer Handles any AFP related events | |||
*/ | |||
public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet) { | |||
super(name, embeddable, charSet); | |||
public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet, | |||
AFPEventProducer eventProducer) { | |||
super(name, embeddable, charSet, eventProducer); | |||
charsProcessed = new HashSet<Integer>(); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -60,16 +70,30 @@ public class DoubleByteFont extends AbstractOutlineFont { | |||
try { | |||
charWidth = charSet.getWidth(toUnicodeCodepoint(character)); | |||
} catch (IllegalArgumentException e) { | |||
if (!charsProcessed.contains(character)) { | |||
charsProcessed.add(character); | |||
getAFPEventProducer().charactersetMissingMetrics(this, (char)character, | |||
charSet.getName().trim()); | |||
} | |||
// We shall try and handle characters that have no mapped width metric in font resource | |||
charWidth = -1; | |||
} | |||
if (charWidth == -1) { | |||
charWidth = inferCharWidth(character); | |||
charWidth = getDefaultCharacterWidth(character); | |||
} | |||
return charWidth * size; | |||
} | |||
private int getDefaultCharacterWidth(int character) { | |||
int nominalCharIncrement = charSet.getNominalCharIncrement(); | |||
if (nominalCharIncrement > 0) { | |||
return nominalCharIncrement; | |||
} else { | |||
return inferCharWidth(character); | |||
} | |||
} | |||
private int inferCharWidth(int character) { | |||
//Is this character an ideograph? |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.afp.fonts; | |||
import org.apache.fop.afp.AFPEventProducer; | |||
/** | |||
* Default implementation of AbstractOutlineFont. | |||
*/ | |||
@@ -29,9 +31,11 @@ public class OutlineFont extends AbstractOutlineFont { | |||
* @param name font's name | |||
* @param embeddable whether or not this font is embeddable | |||
* @param charSet font's character set | |||
* @param eventProducer Handles any AFP related events | |||
*/ | |||
public OutlineFont(String name, boolean embeddable, CharacterSet charSet) { | |||
super(name, embeddable, charSet); | |||
public OutlineFont(String name, boolean embeddable, CharacterSet charSet, | |||
AFPEventProducer eventProducer) { | |||
super(name, embeddable, charSet, eventProducer); | |||
} | |||
} |
@@ -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. | |||
* |
@@ -34,7 +34,7 @@ import org.apache.fop.afp.util.AFPResourceUtil; | |||
*/ | |||
public class IncludedResourceObject extends AbstractNamedAFPObject { | |||
private AFPResourceAccessor resourceAccessor; | |||
private final AFPResourceAccessor resourceAccessor; | |||
private URI uri; | |||
/** |
@@ -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; | |||
} | |||
} |
@@ -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,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; | |||
} | |||
} |
@@ -24,6 +24,9 @@ import java.io.InputStream; | |||
import java.net.URI; | |||
import java.net.URISyntaxException; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
/** | |||
@@ -31,8 +34,11 @@ import org.apache.fop.apps.io.InternalResourceResolver; | |||
*/ | |||
public final class AFPResourceAccessor { | |||
private static final Log log = LogFactory.getLog(AFPResourceAccessor.class); | |||
private final InternalResourceResolver resourceResolver; | |||
private final String baseURI; | |||
private final URI baseURI; | |||
private final URIResolver uriResolver; | |||
/** | |||
* Constructor for resource to be accessed via the {@link org.apache.fop.apps.FOUserAgent}. This | |||
@@ -45,7 +51,23 @@ public final class AFPResourceAccessor { | |||
*/ | |||
public AFPResourceAccessor(InternalResourceResolver resourceResolver, String baseURI) { | |||
this.resourceResolver = resourceResolver; | |||
this.baseURI = baseURI; | |||
URI actualBaseURI = null; | |||
URIResolver uriResolver; | |||
if (baseURI == null) { | |||
actualBaseURI = null; | |||
uriResolver = new NullBaseURIResolver(); | |||
} else { | |||
try { | |||
actualBaseURI = InternalResourceResolver.getBaseURI(baseURI); | |||
uriResolver = new BaseURIResolver(); | |||
} catch (URISyntaxException use) { | |||
log.error("The URI given \"" + baseURI + "\" is invalid: " + use.getMessage()); | |||
actualBaseURI = null; | |||
uriResolver = new NullBaseURIResolver(); | |||
} | |||
} | |||
this.baseURI = actualBaseURI; | |||
this.uriResolver = uriResolver; | |||
} | |||
/** | |||
@@ -57,18 +79,6 @@ public final class AFPResourceAccessor { | |||
this(resourceResolver, null); | |||
} | |||
private URI getResourceURI(URI uri) { | |||
if (baseURI == null) { | |||
return uri; | |||
} | |||
try { | |||
URI baseURI = InternalResourceResolver.getBaseURI(this.baseURI); | |||
return baseURI.resolve(uri); | |||
} catch (URISyntaxException use) { | |||
return uri; | |||
} | |||
} | |||
/** | |||
* Creates an {@link InputStream} given a URI. | |||
* | |||
@@ -77,6 +87,44 @@ public final class AFPResourceAccessor { | |||
* @throws IOException if an I/O error occurs while creating the InputStream. | |||
*/ | |||
public InputStream createInputStream(URI uri) throws IOException { | |||
return resourceResolver.getResource(getResourceURI(uri)); | |||
return resourceResolver.getResource(uriResolver.resolveURI(uri)); | |||
} | |||
/** | |||
* Returns the resolved URI, given the URI of a resource. | |||
* | |||
* @param uri the resource URI | |||
* @return the resolved URI | |||
*/ | |||
public URI resolveURI(String uri) { | |||
return uriResolver.resolveURI(uri); | |||
} | |||
private interface URIResolver { | |||
URI resolveURI(URI uri); | |||
URI resolveURI(String uri); | |||
} | |||
private static final class NullBaseURIResolver implements URIResolver { | |||
public URI resolveURI(URI uri) { | |||
return uri; | |||
} | |||
public URI resolveURI(String uri) { | |||
return URI.create("./" + uri.trim()); | |||
} | |||
} | |||
private final class BaseURIResolver implements URIResolver { | |||
public URI resolveURI(URI uri) { | |||
return baseURI.resolve(uri); | |||
} | |||
public URI resolveURI(String uri) { | |||
return baseURI.resolve(uri.trim()); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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, |
@@ -131,21 +131,7 @@ public class FOUserAgent { | |||
/** Set of keywords applicable to this document. */ | |||
protected String keywords = null; | |||
private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() { | |||
public ImageContext getParentContext() { | |||
return factory; | |||
} | |||
public float getTargetResolution() { | |||
return FOUserAgent.this.getTargetResolution(); | |||
} | |||
public Source resolveURI(String uri) { | |||
return FOUserAgent.this.resolveURI(uri); | |||
} | |||
}; | |||
private final ImageSessionContext imageSessionContext; | |||
/** | |||
* Main constructor. <b>This constructor should not be called directly. Please use the | |||
@@ -154,11 +140,25 @@ public class FOUserAgent { | |||
* @param resourceResolver the resolver used to acquire resources | |||
* @see org.apache.fop.apps.FopFactory | |||
*/ | |||
FOUserAgent(FopFactory factory, InternalResourceResolver resourceResolver) { | |||
FOUserAgent(final FopFactory factory, InternalResourceResolver resourceResolver) { | |||
this.factory = factory; | |||
this.resourceResolver = resourceResolver; | |||
setTargetResolution(factory.getTargetResolution()); | |||
setAccessibility(factory.isAccessibilityEnabled()); | |||
imageSessionContext = new AbstractImageSessionContext(factory.getFallbackResolver()) { | |||
public ImageContext getParentContext() { | |||
return factory; | |||
} | |||
public float getTargetResolution() { | |||
return FOUserAgent.this.getTargetResolution(); | |||
} | |||
public Source resolveURI(String uri) { | |||
return FOUserAgent.this.resolveURI(uri); | |||
} | |||
}; | |||
} | |||
/** | |||
@@ -166,7 +166,7 @@ public class FOUserAgent { | |||
* requires an output stream and you want to configure this very rendering run, | |||
* i.e. if you want to set some metadata like the title and author of the document | |||
* you want to render. In that case, create a new {@link FOUserAgent} instance | |||
* using {@link #newFOUserAgent()}. | |||
* using {@link org.apache.fop.apps.FopFactory#newFOUserAgent() newFOUserAgent()}. | |||
* <p> | |||
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can | |||
* use the constants defined in {@link MimeConstants}. | |||
@@ -184,7 +184,7 @@ public class FOUserAgent { | |||
* Returns a new {@link Fop} instance. Use this factory method if you want to configure this | |||
* very rendering run, i.e. if you want to set some metadata like the title and author of the | |||
* document you want to render. In that case, create a new {@link FOUserAgent} | |||
* instance using {@link #newFOUserAgent()}. | |||
* instance using {@link org.apache.fop.apps.FopFactory#newFOUserAgent() newFOUserAgent()}. | |||
* <p> | |||
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can | |||
* use the constants defined in {@link MimeConstants}. | |||
@@ -791,9 +791,8 @@ public class FOUserAgent { | |||
return factory.getColorSpaceCache(); | |||
} | |||
/** @see {@link FopFactory#getHyphenationPatternNames()} */ | |||
/** @see FopFactory#getHyphenationPatternNames() */ | |||
public Map<String, String> getHyphenationPatternNames() { | |||
return factory.getHyphenationPatternNames(); | |||
} | |||
} | |||
@@ -52,7 +52,7 @@ public class Fop { | |||
private OutputStream stream = null; | |||
// FOUserAgent object to set processing options | |||
private FOUserAgent foUserAgent = null; | |||
private final FOUserAgent foUserAgent; | |||
// FOTreeBuilder object to maintain reference for access to results | |||
private FOTreeBuilder foTreeBuilder = null; | |||
@@ -81,6 +81,10 @@ public class Fop { | |||
/** | |||
* Get the FOUserAgent instance associated with the rendering run represented by this instance. | |||
* @return the user agent | |||
* | |||
* @deprecated this getter doesn't need to exist. By virtue of the fact that the client has | |||
* an instance of this object, it means they also have the {@link FOUserAgent} since this's | |||
* constructor is only used in {@link FOUserAgent} | |||
*/ | |||
public FOUserAgent getUserAgent() { | |||
return foUserAgent; |
@@ -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; |
@@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.image.loader.ImageContext; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; | |||
import org.apache.xmlgraphics.util.UnitConv; | |||
import org.apache.fop.apps.io.InternalResourceResolver; | |||
@@ -325,48 +326,41 @@ public final class FopFactory implements ImageContext { | |||
return config.isAccessibilityEnabled(); | |||
} | |||
/** | |||
* Returns the image manager. | |||
* @return the image manager | |||
*/ | |||
/** @see FopFactoryConfig#getImageManager() */ | |||
public ImageManager getImageManager() { | |||
return config.getImageManager(); | |||
} | |||
/** | |||
* Returns the overriding LayoutManagerMaker instance, if any. | |||
* @return the overriding LayoutManagerMaker or null | |||
*/ | |||
/** @see FopFactoryConfig#getLayoutManagerMakerOverride() */ | |||
public LayoutManagerMaker getLayoutManagerMakerOverride() { | |||
return config.getLayoutManagerMakerOverride(); | |||
} | |||
/** @return the hyphenation pattern names */ | |||
/** @see FopFactoryConfig#getHyphenationPatternNames() */ | |||
public Map<String, String> getHyphenationPatternNames() { | |||
return config.getHyphenationPatternNames(); | |||
} | |||
/** | |||
* Returns whether FOP is strictly validating input XSL | |||
* @return true of strict validation turned on, false otherwise | |||
*/ | |||
/** @see FopFactoryConfig#validateStrictly() */ | |||
public boolean validateStrictly() { | |||
return config.validateStrictly(); | |||
} | |||
/** | |||
* @return true if the indent inheritance should be broken when crossing reference area | |||
* boundaries (for more info, see the javadoc for the relative member variable) | |||
*/ | |||
/** @see FopFactoryConfig#isBreakIndentInheritanceOnReferenceAreaBoundary() */ | |||
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() { | |||
return config.isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
} | |||
/** @return the resolution for resolution-dependent input */ | |||
/** @see FopFactoryConfig#getSourceResolution() */ | |||
public float getSourceResolution() { | |||
return config.getSourceResolution(); | |||
} | |||
/** @see FopFactoryConfig#getTargetResolution() */ | |||
public float getTargetResolution() { | |||
return config.getTargetResolution(); | |||
} | |||
/** | |||
* Returns the conversion factor from pixel units to millimeters. This | |||
* depends on the desired source resolution. | |||
@@ -377,11 +371,6 @@ public final class FopFactory implements ImageContext { | |||
return UnitConv.IN2MM / getSourceResolution(); | |||
} | |||
/** @return the resolution for resolution-dependant output */ | |||
public float getTargetResolution() { | |||
return config.getTargetResolution(); | |||
} | |||
/** | |||
* Returns the conversion factor from pixel units to millimeters. This | |||
* depends on the desired target resolution. | |||
@@ -392,42 +381,26 @@ public final class FopFactory implements ImageContext { | |||
return 25.4f / getTargetResolution(); | |||
} | |||
/** | |||
* Gets the default page-height to use as fallback, | |||
* in case page-height="auto" | |||
* | |||
* @return the page-height, as a String | |||
*/ | |||
/** @see FopFactoryConfig#getPageHeight() */ | |||
public String getPageHeight() { | |||
return config.getPageHeight(); | |||
} | |||
/** | |||
* Gets the default page-width to use as fallback, | |||
* in case page-width="auto" | |||
* | |||
* @return the page-width, as a String | |||
*/ | |||
/** @see FopFactoryConfig#getPageWidth() */ | |||
public String getPageWidth() { | |||
return config.getPageWidth(); | |||
} | |||
/** | |||
* Indicates whether a namespace URI is on the ignored list. | |||
* @param namespaceURI the namespace URI | |||
* @return true if the namespace is ignored by FOP | |||
*/ | |||
/** @see FopFactoryConfig#isNamespaceIgnored(String) */ | |||
public boolean isNamespaceIgnored(String namespaceURI) { | |||
return config.isNamespaceIgnored(namespaceURI); | |||
} | |||
/** @return the set of namespaces that are ignored by FOP */ | |||
/** @see FopFactoryConfig#getIgnoredNamespaces() */ | |||
public Set<String> getIgnoredNamespace() { | |||
return config.getIgnoredNamespaces(); | |||
} | |||
//------------------------------------------- Configuration stuff | |||
/** | |||
* Get the user configuration. | |||
* @return the user configuration | |||
@@ -436,24 +409,21 @@ public final class FopFactory implements ImageContext { | |||
return config.getUserConfig(); | |||
} | |||
/** | |||
* Is the user configuration to be validated? | |||
* @return if the user configuration should be validated | |||
*/ | |||
/** @see FopFactoryConfig#validateUserConfigStrictly() */ | |||
public boolean validateUserConfigStrictly() { | |||
return config.validateUserConfigStrictly(); | |||
} | |||
//------------------------------------------- Font related stuff | |||
/** | |||
* Returns the font manager. | |||
* @return the font manager | |||
*/ | |||
/** @see FopFactoryConfig#getFontManager() */ | |||
public FontManager getFontManager() { | |||
return config.getFontManager(); | |||
} | |||
/** @see FopFactoryConfig#getFallbackResolver() */ | |||
FallbackResolver getFallbackResolver() { | |||
return config.getFallbackResolver(); | |||
} | |||
/** | |||
* Returns the color space cache for this instance. | |||
* <p> |
@@ -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 { |
@@ -26,8 +26,9 @@ import java.util.Set; | |||
import org.apache.avalon.framework.configuration.Configuration; | |||
import org.apache.xmlgraphics.image.loader.ImageManager; | |||
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.FallbackResolver; | |||
import org.apache.xmlgraphics.io.ResourceResolver; | |||
import org.apache.fop.apps.io.ResourceResolver; | |||
import org.apache.fop.fonts.FontManager; | |||
import org.apache.fop.layoutmgr.LayoutManagerMaker; | |||
@@ -67,7 +68,10 @@ public interface FopFactoryConfig { | |||
*/ | |||
boolean isAccessibilityEnabled(); | |||
/** @see {@link FopFactory#getLayoutManagerMakerOverride()} */ | |||
/** | |||
* Returns the overriding LayoutManagerMaker instance, if any. | |||
* @return the overriding LayoutManagerMaker or null | |||
*/ | |||
LayoutManagerMaker getLayoutManagerMakerOverride(); | |||
/** | |||
@@ -84,31 +88,54 @@ public interface FopFactoryConfig { | |||
*/ | |||
URI getBaseURI(); | |||
/** @see {@link FopFactory#validateStrictly()} */ | |||
/** | |||
* Returns whether FOP is strictly validating input XSL | |||
* @return true of strict validation turned on, false otherwise | |||
*/ | |||
boolean validateStrictly(); | |||
/** @see {@link FopFactory#validateUserConfigStrictly()} */ | |||
/** | |||
* Is the user configuration to be validated? | |||
* @return if the user configuration should be validated | |||
*/ | |||
boolean validateUserConfigStrictly(); | |||
/** @see {@link FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()} */ | |||
/** | |||
* @return true if the indent inheritance should be broken when crossing reference area | |||
* boundaries (for more info, see the javadoc for the relative member variable) | |||
*/ | |||
boolean isBreakIndentInheritanceOnReferenceAreaBoundary(); | |||
/** @see {@link FopFactory#getSourceResolution()} */ | |||
/** @return the resolution for resolution-dependent input */ | |||
float getSourceResolution(); | |||
/** @see {@link FopFactory#getTargetResolution()} */ | |||
/** @return the resolution for resolution-dependent output */ | |||
float getTargetResolution(); | |||
/** @see {@link FopFactory#getPageHeight()} */ | |||
/** | |||
* Gets the default page-height to use as fallback, | |||
* in case page-height="auto" | |||
* | |||
* @return the page-height, as a String | |||
*/ | |||
String getPageHeight(); | |||
/** @see {@link FopFactory#getPageWidth()} */ | |||
/** | |||
* Gets the default page-width to use as fallback, | |||
* in case page-width="auto" | |||
* | |||
* @return the page-width, as a String | |||
*/ | |||
String getPageWidth(); | |||
/** @see {@link FopFactory#getIgnoredNamespace()} */ | |||
/** @return the set of namespaces that are ignored by FOP */ | |||
Set<String> getIgnoredNamespaces(); | |||
/** @see {@link FopFactory#isNamespaceIgnored(String)} */ | |||
/** | |||
* Indicates whether a namespace URI is on the ignored list. | |||
* @param namespace the namespace URI | |||
* @return true if the namespace is ignored by FOP | |||
*/ | |||
boolean isNamespaceIgnored(String namespace); | |||
/** | |||
@@ -118,17 +145,30 @@ public interface FopFactoryConfig { | |||
*/ | |||
Configuration getUserConfig(); | |||
/** @see {@link org.apache.fop.render.RendererFactory#isRendererPreferred()} */ | |||
/** @see org.apache.fop.render.RendererFactory#isRendererPreferred() */ | |||
boolean preferRenderer(); | |||
/** @see {@link FopFactory#getFontManager()} */ | |||
/** | |||
* Returns the font manager. | |||
* @return the font manager | |||
*/ | |||
FontManager getFontManager(); | |||
/** @see {@link FopFactory#getImageManager()} */ | |||
/** | |||
* Returns the image manager. | |||
* @return the image manager | |||
*/ | |||
ImageManager getImageManager(); | |||
boolean isComplexScriptFeaturesEnabled(); | |||
/** @see {@link FopFactory#getHyphenationPatternNames()} */ | |||
/** @return the hyphenation pattern names */ | |||
Map<String, String> getHyphenationPatternNames(); | |||
/** | |||
* Controls the mechanisms that are used in the event that {@link javax.xml.transform.Source} | |||
* used for resources couldn't be read. | |||
* @return the fallback resolver | |||
*/ | |||
FallbackResolver getFallbackResolver(); | |||
} |
@@ -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 { |
@@ -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; | |||
} |
@@ -28,6 +28,11 @@ import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.xmlgraphics.io.Resource; | |||
import org.apache.xmlgraphics.io.ResourceResolver; | |||
import org.apache.xmlgraphics.io.TempResourceResolver; | |||
import org.apache.xmlgraphics.io.TempResourceURIGenerator; | |||
/** | |||
* A factory class for {@link ResourceResolver}s. | |||
*/ | |||
@@ -70,10 +75,10 @@ public final class ResourceResolverFactory { | |||
} | |||
/** | |||
* Creates a temporary-resource-schema aware resource resolver. Temporary resource URIs are | |||
* Creates a temporary-resource-scheme aware resource resolver. Temporary resource URIs are | |||
* created by {@link TempResourceURIGenerator}. | |||
* | |||
* @param tempResourceResolver the temporary-resource-schema resolver to use | |||
* @param tempResourceResolver the temporary-resource-scheme resolver to use | |||
* @param defaultResourceResolver the default resource resolver to use | |||
* @return the ressource resolver | |||
*/ | |||
@@ -83,9 +88,18 @@ public final class ResourceResolverFactory { | |||
return new TempAwareResourceResolver(tempResourceResolver, defaultResourceResolver); | |||
} | |||
public static SchemaAwareResourceResolverBuilder createSchemaAwareResourceResolverBuilder( | |||
/** | |||
* This creates the builder class for binding URI schemes to implementations of | |||
* {@link ResourceResolver}. This allows users to define their own URI schemes such that they | |||
* have finer control over the acquisition of resources. | |||
* | |||
* @param defaultResolver the default resource resolver that should be used in the event that | |||
* none of the other registered resolvers match the scheme | |||
* @return the scheme aware {@link ResourceResolver} builder | |||
*/ | |||
public static SchemeAwareResourceResolverBuilder createSchemeAwareResourceResolverBuilder( | |||
ResourceResolver defaultResolver) { | |||
return new SchemaAwareResourceResolverBuilderImpl(defaultResolver); | |||
return new SchemeAwareResourceResolverBuilderImpl(defaultResolver); | |||
} | |||
private static final class DefaultResourceResolver implements ResourceResolver { | |||
@@ -99,10 +113,12 @@ public final class ResourceResolverFactory { | |||
new NormalResourceResolver()); | |||
} | |||
/** {@inheritDoc} */ | |||
public Resource getResource(URI uri) throws IOException { | |||
return delegate.getResource(uri); | |||
} | |||
/** {@inheritDoc} */ | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
return delegate.getOutputStream(uri); | |||
} | |||
@@ -121,26 +137,27 @@ public final class ResourceResolverFactory { | |||
this.defaultResourceResolver = defaultResourceResolver; | |||
} | |||
private static boolean isTempUri(URI uri) { | |||
return TempResourceURIGenerator.isTempUri(uri); | |||
private static boolean isTempURI(URI uri) { | |||
return TempResourceURIGenerator.isTempURI(uri); | |||
} | |||
/** {@inheritDoc} */ | |||
public Resource getResource(URI uri) throws IOException { | |||
if (isTempUri(uri)) { | |||
if (isTempURI(uri)) { | |||
return tempResourceResolver.getResource(uri.getPath()); | |||
} else { | |||
return defaultResourceResolver.getResource(uri); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
if (isTempUri(uri)) { | |||
if (isTempURI(uri)) { | |||
return tempResourceResolver.getOutputStream(uri.getPath()); | |||
} else { | |||
return defaultResourceResolver.getOutputStream(uri); | |||
} | |||
} | |||
} | |||
private static class DefaultTempResourceResolver implements TempResourceResolver { | |||
@@ -150,10 +167,12 @@ public final class ResourceResolverFactory { | |||
return file; | |||
} | |||
/** {@inheritDoc} */ | |||
public Resource getResource(String id) throws IOException { | |||
return new Resource(getTempFile(id).toURI().toURL().openStream()); | |||
} | |||
/** {@inheritDoc} */ | |||
public OutputStream getOutputStream(String id) throws IOException { | |||
File file = getTempFile(id); | |||
if (file.createNewFile()) { | |||
@@ -174,103 +193,141 @@ public final class ResourceResolverFactory { | |||
} | |||
} | |||
private static final class SchemaAwareResourceResolver implements ResourceResolver { | |||
private static final class SchemeAwareResourceResolver implements ResourceResolver { | |||
private final Map<String, ResourceResolver> schemaHandlingResourceResolvers; | |||
private final Map<String, ResourceResolver> schemeHandlingResourceResolvers; | |||
private final ResourceResolver defaultResolver; | |||
private SchemaAwareResourceResolver( | |||
Map<String, ResourceResolver> schemaHandlingResourceResolvers, | |||
private SchemeAwareResourceResolver( | |||
Map<String, ResourceResolver> schemEHandlingResourceResolvers, | |||
ResourceResolver defaultResolver) { | |||
this.schemaHandlingResourceResolvers = schemaHandlingResourceResolvers; | |||
this.schemeHandlingResourceResolvers = schemEHandlingResourceResolvers; | |||
this.defaultResolver = defaultResolver; | |||
} | |||
private ResourceResolver getResourceResolverForSchema(URI uri) { | |||
String schema = uri.getScheme(); | |||
if (schemaHandlingResourceResolvers.containsKey(schema)) { | |||
return schemaHandlingResourceResolvers.get(schema); | |||
private ResourceResolver getResourceResolverForScheme(URI uri) { | |||
String scheme = uri.getScheme(); | |||
if (schemeHandlingResourceResolvers.containsKey(scheme)) { | |||
return schemeHandlingResourceResolvers.get(scheme); | |||
} else { | |||
return defaultResolver; | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public Resource getResource(URI uri) throws IOException { | |||
return getResourceResolverForSchema(uri).getResource(uri); | |||
return getResourceResolverForScheme(uri).getResource(uri); | |||
} | |||
/** {@inheritDoc} */ | |||
public OutputStream getOutputStream(URI uri) throws IOException { | |||
return getResourceResolverForSchema(uri).getOutputStream(uri); | |||
return getResourceResolverForScheme(uri).getOutputStream(uri); | |||
} | |||
} | |||
public interface SchemaAwareResourceResolverBuilder { | |||
void registerResourceResolverForSchema(String schema, ResourceResolver resourceResolver); | |||
/** | |||
* Implementations of this interface will be builders for {@link ResourceResolver}, they bind | |||
* URI schemes to their respective resolver. This gives users more control over the mechanisms | |||
* by which URIs are resolved. | |||
* <p> | |||
* Here is an example of how this could be used: | |||
* </p> | |||
* <p><code> | |||
* SchemeAwareResourceResolverBuilder builder | |||
* = ResourceResolverFactory.createSchemeAwareResourceResolverBuilder(defaultResolver); | |||
* builder.registerResourceResolverForScheme("test", testResolver); | |||
* builder.registerResourceResolverForScheme("anotherTest", test2Resolver); | |||
* ResourceResolver resolver = builder.build(); | |||
* </code></p> | |||
* This will result in all URIs for the form "test:///..." will be resolved using the | |||
* <code>testResolver</code> object; URIs of the form "anotherTest:///..." will be resolved | |||
* using <code>test2Resolver</code>; all other URIs will be resolved from the defaultResolver. | |||
*/ | |||
public interface SchemeAwareResourceResolverBuilder { | |||
/** | |||
* Register a scheme with its respective {@link ResourceResolver}. This resolver will be | |||
* used as the only resolver for the specified scheme. | |||
* | |||
* @param scheme the scheme to be used with the given resolver | |||
* @param resourceResolver the resource resolver | |||
*/ | |||
void registerResourceResolverForScheme(String scheme, ResourceResolver resourceResolver); | |||
/** | |||
* Builds a {@link ResourceResolver} that will delegate to the respective resource resolver | |||
* when a registered URI scheme is given | |||
* | |||
* @return a resolver that delegates to the appropriate scheme resolver | |||
*/ | |||
ResourceResolver build(); | |||
} | |||
private static final class CompletedSchemaAwareResourceResolverBuilder | |||
implements SchemaAwareResourceResolverBuilder { | |||
private static final class CompletedSchemeAwareResourceResolverBuilder | |||
implements SchemeAwareResourceResolverBuilder { | |||
private static final SchemaAwareResourceResolverBuilder INSTANCE | |||
= new CompletedSchemaAwareResourceResolverBuilder(); | |||
private static final SchemeAwareResourceResolverBuilder INSTANCE | |||
= new CompletedSchemeAwareResourceResolverBuilder(); | |||
/** {@inheritDoc} */ | |||
public ResourceResolver build() { | |||
throw new IllegalStateException("Resource resolver already built"); | |||
} | |||
public void registerResourceResolverForSchema(String schema, | |||
/** {@inheritDoc} */ | |||
public void registerResourceResolverForScheme(String scheme, | |||
ResourceResolver resourceResolver) { | |||
throw new IllegalStateException("Resource resolver already built"); | |||
} | |||
} | |||
private static final class ActiveSchemaAwareResourceResolverBuilder | |||
implements SchemaAwareResourceResolverBuilder { | |||
private static final class ActiveSchemeAwareResourceResolverBuilder | |||
implements SchemeAwareResourceResolverBuilder { | |||
private final Map<String, ResourceResolver> schemaHandlingResourceResolvers | |||
private final Map<String, ResourceResolver> schemeHandlingResourceResolvers | |||
= new HashMap<String, ResourceResolver>(); | |||
private final ResourceResolver defaultResolver; | |||
private ActiveSchemaAwareResourceResolverBuilder(ResourceResolver defaultResolver) { | |||
private ActiveSchemeAwareResourceResolverBuilder(ResourceResolver defaultResolver) { | |||
this.defaultResolver = defaultResolver; | |||
} | |||
public void registerResourceResolverForSchema(String schema, | |||
/** {@inheritDoc} */ | |||
public void registerResourceResolverForScheme(String scheme, | |||
ResourceResolver resourceResolver) { | |||
schemaHandlingResourceResolvers.put(schema, resourceResolver); | |||
schemeHandlingResourceResolvers.put(scheme, resourceResolver); | |||
} | |||
/** {@inheritDoc} */ | |||
public ResourceResolver build() { | |||
return new SchemaAwareResourceResolver( | |||
Collections.unmodifiableMap(schemaHandlingResourceResolvers), defaultResolver); | |||
return new SchemeAwareResourceResolver( | |||
Collections.unmodifiableMap(schemeHandlingResourceResolvers), defaultResolver); | |||
} | |||
} | |||
private static final class SchemaAwareResourceResolverBuilderImpl | |||
implements SchemaAwareResourceResolverBuilder { | |||
private static final class SchemeAwareResourceResolverBuilderImpl | |||
implements SchemeAwareResourceResolverBuilder { | |||
private SchemaAwareResourceResolverBuilder delegate; | |||
private SchemeAwareResourceResolverBuilder delegate; | |||
private SchemaAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { | |||
this.delegate = new ActiveSchemaAwareResourceResolverBuilder(defaultResolver); | |||
private SchemeAwareResourceResolverBuilderImpl(ResourceResolver defaultResolver) { | |||
this.delegate = new ActiveSchemeAwareResourceResolverBuilder(defaultResolver); | |||
} | |||
public void registerResourceResolverForSchema(String schema, | |||
/** {@inheritDoc} */ | |||
public void registerResourceResolverForScheme(String scheme, | |||
ResourceResolver resourceResolver) { | |||
delegate.registerResourceResolverForSchema(schema, resourceResolver); | |||
delegate.registerResourceResolverForScheme(scheme, resourceResolver); | |||
} | |||
/** {@inheritDoc} */ | |||
public ResourceResolver build() { | |||
ResourceResolver resourceResolver = delegate.build(); | |||
delegate = CompletedSchemaAwareResourceResolverBuilder.INSTANCE; | |||
delegate = CompletedSchemeAwareResourceResolverBuilder.INSTANCE; | |||
return resourceResolver; | |||
} | |||
} | |||
} |
@@ -1,48 +0,0 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.apps.io; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
/** | |||
* Implementations of this interface resolve URIs for temporary files used by FOP. The temporary- | |||
* resource URI scheme comes from {@link TempResourceURIGenerator#TMP_SCHEMA}. | |||
*/ | |||
public interface TempResourceResolver { | |||
/** | |||
* Get a temporary-resource given the URI pointing to said resource. | |||
* | |||
* @param uri the resource URI | |||
* @return the resource | |||
* @throws IOException if an I/O error occured during resource acquisition | |||
*/ | |||
Resource getResource(String id) throws IOException; | |||
/** | |||
* Gets an temporary-output stream of a given URI. | |||
* | |||
* @param uri the output stream URI | |||
* @return the output stream | |||
* @throws IOException if an I/O error occured while creating an output stream | |||
*/ | |||
OutputStream getOutputStream(String id) throws IOException; | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -84,6 +84,7 @@ import org.apache.fop.util.ContentHandlerFactory; | |||
import org.apache.fop.util.ContentHandlerFactoryRegistry; | |||
import org.apache.fop.util.ConversionUtils; | |||
import org.apache.fop.util.DefaultErrorListener; | |||
import org.apache.fop.util.LanguageTags; | |||
import org.apache.fop.util.XMLConstants; | |||
import org.apache.fop.util.XMLUtil; | |||
@@ -394,10 +395,10 @@ public class AreaTreeParser { | |||
public void startElement(Attributes attributes) { | |||
PageSequence pageSequence = new PageSequence(null); | |||
String lang = attributes.getValue("language"); | |||
pageSequence.setLanguage(lang); | |||
String country = attributes.getValue("country"); | |||
pageSequence.setCountry(country); | |||
String lang = attributes.getValue(javax.xml.XMLConstants.XML_NS_URI, "lang"); | |||
if (lang != null) { | |||
pageSequence.setLocale(LanguageTags.toLocale(lang)); | |||
} | |||
transferForeignObjects(attributes, pageSequence); | |||
areaStack.push(pageSequence); | |||
} |
@@ -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; | |||
/** |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.area; | |||
import java.util.List; | |||
import java.util.Locale; | |||
/** | |||
* Represents a page sequence in the area tree. | |||
@@ -28,8 +29,8 @@ public class PageSequence extends AreaTreeObject { | |||
private List<PageViewport> pages = new java.util.ArrayList<PageViewport>(); | |||
private LineArea title; | |||
private String language; | |||
private String country; | |||
private Locale locale; | |||
/** | |||
* Main constructor | |||
@@ -88,43 +89,21 @@ public class PageSequence extends AreaTreeObject { | |||
} | |||
/** | |||
* Returns the language of the page-sequence. | |||
* @return the language (the value of the language property, "none" is mapped to null) | |||
*/ | |||
public String getLanguage() { | |||
return this.language; | |||
} | |||
/** | |||
* Sets the language that applies to this page-sequence. | |||
* @param language the language to set ("none" is mapped to null) | |||
*/ | |||
public void setLanguage(String language) { | |||
if ("none".equals(language)) { | |||
this.language = null; | |||
} else { | |||
this.language = language; | |||
} | |||
} | |||
/** | |||
* Returns the country of the page-sequence. | |||
* @return the country (the value of the country property, "none" is mapped to null) | |||
* Sets the locale that applies to this page-sequence. | |||
* | |||
* @param locale the locale to set | |||
*/ | |||
public String getCountry() { | |||
return this.country; | |||
public void setLocale(Locale locale) { | |||
this.locale = locale; | |||
} | |||
/** | |||
* Sets the country that applies to this page-sequence. | |||
* @param country the country to set ("none" is mapped to null) | |||
* Returns the locale of this page-sequence. | |||
* | |||
* @return the locale, {@code null} if not set | |||
*/ | |||
public void setCountry(String country) { | |||
if ("none".equals(country)) { | |||
this.country = null; | |||
} else { | |||
this.country = country; | |||
} | |||
public Locale getLocale() { | |||
return locale; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
@@ -43,6 +43,7 @@ import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.apps.FopConfParser; | |||
import org.apache.fop.apps.FopFactory; | |||
import org.apache.fop.apps.FopFactoryBuilder; | |||
import org.apache.fop.apps.FopFactoryConfig; | |||
import org.apache.fop.apps.MimeConstants; | |||
import org.apache.fop.pdf.PDFAMode; | |||
import org.apache.fop.pdf.PDFEncryptionManager; | |||
@@ -117,7 +118,7 @@ public class CommandLineOptions { | |||
/* rendering options (for the user agent) */ | |||
private Map renderingOptions = new java.util.HashMap(); | |||
/* target resolution (for the user agent) */ | |||
private int targetResolution = 0; | |||
private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION; | |||
private boolean strictValidation = true; | |||
/* control memory-conservation policy */ | |||
@@ -138,7 +139,7 @@ public class CommandLineOptions { | |||
private boolean flushCache = false; | |||
private URI baseURI = new File(".").toURI(); | |||
private URI baseURI = new File(".").getAbsoluteFile().toURI(); | |||
/** | |||
* Construct a command line option object. | |||
@@ -420,7 +421,7 @@ public class CommandLineOptions { | |||
throw new FOPException("if you use '-cache', you must specify " | |||
+ "the name of the font cache file"); | |||
} else { | |||
factory.getFontManager().setCacheFile(new File(args[i + 1])); | |||
factory.getFontManager().setCacheFile(URI.create(args[i + 1])); | |||
return 1; | |||
} | |||
} | |||
@@ -468,7 +469,7 @@ public class CommandLineOptions { | |||
this.useStdIn = true; | |||
} else { | |||
fofile = new File(filename); | |||
baseURI = fofile.toURI(); | |||
baseURI = getBaseURI(fofile); | |||
} | |||
return 1; | |||
} | |||
@@ -498,12 +499,16 @@ public class CommandLineOptions { | |||
this.useStdIn = true; | |||
} else { | |||
xmlfile = new File(filename); | |||
baseURI = xmlfile.toURI(); | |||
baseURI = getBaseURI(xmlfile); | |||
} | |||
return 1; | |||
} | |||
} | |||
private URI getBaseURI(File file) { | |||
return file.getAbsoluteFile().getParentFile().toURI(); | |||
} | |||
private int parseAWTOutputOption(String[] args, int i) throws FOPException { | |||
setOutputMode(MimeConstants.MIME_FOP_AWT_PREVIEW); | |||
return 0; | |||
@@ -730,7 +735,7 @@ public class CommandLineOptions { | |||
this.useStdIn = true; | |||
} else { | |||
fofile = new File(filename); | |||
baseURI = fofile.toURI(); | |||
baseURI = getBaseURI(fofile); | |||
} | |||
} else if (outputmode == null) { | |||
outputmode = MimeConstants.MIME_PDF; | |||
@@ -789,7 +794,7 @@ public class CommandLineOptions { | |||
this.useStdIn = true; | |||
} else { | |||
areatreefile = new File(filename); | |||
baseURI = areatreefile.toURI(); | |||
baseURI = getBaseURI(areatreefile); | |||
} | |||
return 1; | |||
} | |||
@@ -806,7 +811,7 @@ public class CommandLineOptions { | |||
this.useStdIn = true; | |||
} else { | |||
iffile = new File(filename); | |||
baseURI = iffile.toURI(); | |||
baseURI = getBaseURI(iffile); | |||
} | |||
return 1; | |||
} | |||
@@ -823,7 +828,7 @@ public class CommandLineOptions { | |||
this.useStdIn = true; | |||
} else { | |||
imagefile = new File(filename); | |||
baseURI = imagefile.toURI(); | |||
baseURI = getBaseURI(imagefile); | |||
} | |||
return 1; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -785,8 +785,11 @@ public interface Constants { | |||
*/ | |||
int PR_X_NUMBER_CONVERSION_FEATURES = 276; | |||
/** Scope for table header */ | |||
int PR_X_HEADER_COLUMN = 277; | |||
/** Number of property constants defined */ | |||
int PROPERTY_COUNT = 276; | |||
int PROPERTY_COUNT = 277; | |||
// compound property constants | |||
@@ -1224,6 +1227,8 @@ public interface Constants { | |||
int EN_BT = 204; // bottom to top | |||
/** Enumeration constant */ | |||
int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode | |||
/** Enumeration constant -- for fo:retrieve-table-marker */ | |||
int EN_FIRST_INCLUDING_CARRYOVER = 206; | |||
/** Number of enumeration constants defined */ | |||
int ENUM_COUNT = 205; | |||
int ENUM_COUNT = 206; | |||
} |
@@ -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(); |
@@ -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. | |||
*/ |
@@ -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 |
@@ -26,6 +26,7 @@ import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.fo.expr.PropertyException; | |||
import org.apache.fop.fo.flow.table.TableFObj.ColumnNumberPropertyMaker; | |||
import org.apache.fop.fo.pagination.Flow; | |||
import org.apache.fop.fo.properties.BackgroundPositionShorthand; | |||
import org.apache.fop.fo.properties.BorderSpacingShorthandParser; | |||
import org.apache.fop.fo.properties.BorderWidthPropertyMaker; | |||
@@ -2177,7 +2178,8 @@ public final class FOPropertyMapping implements Constants { | |||
m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE); | |||
m.setInherited(false); | |||
m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING")); | |||
m.addEnum("first-including-carryover", getEnumProperty(EN_FIC, "FIC")); | |||
m.addEnum("first-including-carryover", | |||
getEnumProperty(EN_FIRST_INCLUDING_CARRYOVER, "FIRST_INCLUDING_CARRYOVER")); | |||
m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING")); | |||
m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING")); | |||
m.setDefault("first-starting"); | |||
@@ -2188,7 +2190,7 @@ public final class FOPropertyMapping implements Constants { | |||
m.setInherited(false); | |||
m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE")); | |||
m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT")); | |||
m.addEnum("page", getEnumProperty(EN_DOCUMENT, "PAGE")); | |||
m.addEnum("page", getEnumProperty(EN_PAGE, "PAGE")); | |||
m.setDefault("table"); | |||
addPropertyMaker("retrieve-boundary-within-table", m); | |||
} | |||
@@ -2267,7 +2269,7 @@ public final class FOPropertyMapping implements Constants { | |||
m = new StringProperty.Maker(PR_FLOW_NAME); | |||
m.setInherited(false); | |||
m.setDefault(""); | |||
addPropertyMaker("flow-name", m); | |||
addPropertyMaker(Flow.FLOW_NAME, m); | |||
// force-page-count | |||
m = new EnumProperty.Maker(PR_FORCE_PAGE_COUNT); | |||
@@ -2512,6 +2514,12 @@ public final class FOPropertyMapping implements Constants { | |||
m.setInherited(false); | |||
m.setDefault("false"); | |||
addPropertyMaker("table-omit-header-at-break", m); | |||
// fox:scope | |||
m = new EnumProperty.Maker(PR_X_HEADER_COLUMN); | |||
m.useGeneric(genericBoolean); | |||
m.setDefault("false"); | |||
addPropertyMaker("fox:header", m); | |||
} | |||
private void createWritingModeProperties() { |
@@ -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 |
@@ -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> |
@@ -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; | |||
} |
@@ -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"); | |||
} | |||
/** |
@@ -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); | |||
} | |||
/** |
@@ -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; | |||
} | |||
} |
@@ -0,0 +1,216 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fo.flow; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.fo.Constants; | |||
/** | |||
* A class to register and resolve markers. | |||
*/ | |||
public final class Markers { | |||
// IsAny means either IsFirst or IsLast | |||
private Map<String, Marker> firstQualifyingIsFirst; | |||
private Map<String, Marker> firstQualifyingIsAny; | |||
private Map<String, Marker> lastQualifyingIsFirst; | |||
private Map<String, Marker> lastQualifyingIsLast; | |||
private Map<String, Marker> lastQualifyingIsAny; | |||
private static Log log = LogFactory.getLog(Markers.class); | |||
/** | |||
* Registers a marker with the position traits set. | |||
* Only the required markers are kept. | |||
* For "first-starting-within-page" it adds the markers | |||
* that are starting only if the marker class name is not | |||
* already added. | |||
* For "first-including-carryover" it adds any starting marker | |||
* if the marker class name is not already added. | |||
* For "last-starting-within-page" it adds all marks that | |||
* are starting, replacing earlier markers. | |||
* For "last-ending-within-page" it adds all markers that | |||
* are ending, replacing earlier markers. | |||
* | |||
* @param marks a map of markers to register | |||
* @param starting whether the registration happens at the start (true) or end (false) the the area | |||
* @param isfirst whether it is the first area of the parent LM | |||
* @param islast whether it is the last area of the parent LM | |||
*/ | |||
public void register(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { | |||
// TODO: find way to put the page number in the log tracing | |||
if (marks == null) { | |||
return; | |||
} | |||
if (log.isDebugEnabled()) { | |||
log.debug("--" + marks.keySet() + ": " + (starting ? "starting" : "ending") | |||
+ (isfirst ? ", first" : "") + (islast ? ", last" : "")); | |||
} | |||
if (starting) { | |||
// at the start of the area, register is-first and any areas | |||
if (firstQualifyingIsAny == null) { | |||
firstQualifyingIsAny = new HashMap<String, Marker>(); | |||
} | |||
if (isfirst) { | |||
if (firstQualifyingIsFirst == null) { | |||
firstQualifyingIsFirst = new HashMap<String, Marker>(); | |||
} | |||
// first on scope: only put in new values, leave current | |||
Set<Map.Entry<String, Marker>> entries = marks.entrySet(); | |||
for (Map.Entry<String, Marker> entry : entries) { | |||
String key = entry.getKey(); | |||
Marker marker = entry.getValue(); | |||
if (!firstQualifyingIsFirst.containsKey(key)) { | |||
firstQualifyingIsFirst.put(key, marker); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Adding marker " + key + " to firstQualifyingIsFirst"); | |||
} | |||
} | |||
if (!firstQualifyingIsAny.containsKey(key)) { | |||
firstQualifyingIsAny.put(key, marker); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Adding marker " + key + " to firstQualifyingIsAny"); | |||
} | |||
} | |||
} | |||
if (lastQualifyingIsFirst == null) { | |||
lastQualifyingIsFirst = new HashMap<String, Marker>(); | |||
} | |||
// last on scope: replace all | |||
lastQualifyingIsFirst.putAll(marks); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Adding all markers to LastStart"); | |||
} | |||
} else { | |||
// first on scope: only put in new values, leave current | |||
Set<Map.Entry<String, Marker>> entries = marks.entrySet(); | |||
for (Map.Entry<String, Marker> entry : entries) { | |||
String key = entry.getKey(); | |||
Marker marker = entry.getValue(); | |||
if (!firstQualifyingIsAny.containsKey(key)) { | |||
firstQualifyingIsAny.put(key, marker); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Adding marker " + key + " to firstQualifyingIsAny"); | |||
} | |||
} | |||
} | |||
} | |||
} else { | |||
// at the end of the area, register is-last and any areas | |||
if (islast) { | |||
if (lastQualifyingIsLast == null) { | |||
lastQualifyingIsLast = new HashMap<String, Marker>(); | |||
} | |||
// last on page: replace all | |||
lastQualifyingIsLast.putAll(marks); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Adding all markers to lastQualifyingIsLast"); | |||
} | |||
} | |||
if (lastQualifyingIsAny == null) { | |||
lastQualifyingIsAny = new HashMap<String, Marker>(); | |||
} | |||
// last on page: replace all | |||
lastQualifyingIsAny.putAll(marks); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Adding all markers to lastQualifyingIsAny"); | |||
} | |||
} | |||
} | |||
/** | |||
* Retrieves the best candidate marker for the given position. | |||
* @param name the key used to register the marker | |||
* @param pos the retrieval scope position | |||
* @return a Marker instance | |||
*/ | |||
public Marker resolve(AbstractRetrieveMarker arm) { | |||
Marker mark = null; | |||
int pos = arm.getPosition(); | |||
String name = arm.getRetrieveClassName(); | |||
String posName = arm.getPositionLabel(); | |||
String localName = arm.getLocalName(); | |||
switch (pos) { | |||
case Constants.EN_FSWP: // retrieve-marker | |||
case Constants.EN_FIRST_STARTING: // retrieve-table-marker | |||
if (firstQualifyingIsFirst != null) { | |||
mark = firstQualifyingIsFirst.get(name); | |||
} | |||
if (mark == null && firstQualifyingIsAny != null) { | |||
mark = firstQualifyingIsAny.get(name); | |||
posName = "FirstAny after " + posName; | |||
} | |||
break; | |||
case Constants.EN_FIC: // retrieve-marker | |||
case Constants.EN_FIRST_INCLUDING_CARRYOVER: // retrieve-table-marker | |||
if (firstQualifyingIsAny != null) { | |||
mark = firstQualifyingIsAny.get(name); | |||
} | |||
break; | |||
case Constants.EN_LSWP: // retrieve-marker | |||
case Constants.EN_LAST_STARTING: // retrieve-table-marker | |||
if (lastQualifyingIsFirst != null) { | |||
mark = lastQualifyingIsFirst.get(name); | |||
} | |||
if (mark == null && lastQualifyingIsAny != null) { | |||
mark = lastQualifyingIsAny.get(name); | |||
posName = "LastAny after " + posName; | |||
} | |||
break; | |||
case Constants.EN_LEWP: // retrieve-marker | |||
case Constants.EN_LAST_ENDING: // retrieve-table-marker | |||
if (lastQualifyingIsLast != null) { | |||
mark = lastQualifyingIsLast.get(name); | |||
} | |||
if (mark == null && lastQualifyingIsAny != null) { | |||
mark = lastQualifyingIsAny.get(name); | |||
posName = "LastAny after " + posName; | |||
} | |||
break; | |||
default: | |||
throw new RuntimeException("Invalid position attribute in " + localName + "."); | |||
} | |||
if (log.isTraceEnabled()) { | |||
// TODO: find way to put the page number here | |||
log.trace(localName + ": name[" + name + "]; position [" + posName + "]"); | |||
} | |||
return mark; | |||
} | |||
/** Dumps the current marker data to the logger. */ | |||
public void dump() { | |||
if (log.isTraceEnabled()) { | |||
log.trace("FirstAny: " + this.firstQualifyingIsAny); | |||
log.trace("FirstStart: " + this.firstQualifyingIsFirst); | |||
log.trace("LastAny: " + this.lastQualifyingIsAny); | |||
log.trace("LastEnd: " + this.lastQualifyingIsLast); | |||
log.trace("LastStart: " + this.lastQualifyingIsFirst); | |||
} | |||
} | |||
} |
@@ -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} */ |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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, |
@@ -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; | |||
} | |||
} | |||
@@ -19,6 +19,7 @@ | |||
package org.apache.fop.fo.pagination; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.Stack; | |||
@@ -30,6 +31,7 @@ import org.apache.fop.datatypes.Numeric; | |||
import org.apache.fop.fo.FONode; | |||
import org.apache.fop.fo.PropertyList; | |||
import org.apache.fop.fo.ValidationException; | |||
import org.apache.fop.fo.properties.CommonHyphenation; | |||
import org.apache.fop.traits.Direction; | |||
import org.apache.fop.traits.WritingMode; | |||
import org.apache.fop.traits.WritingModeTraits; | |||
@@ -41,13 +43,11 @@ import org.apache.fop.traits.WritingModeTraitsGetter; | |||
*/ | |||
public class PageSequence extends AbstractPageSequence implements WritingModeTraitsGetter { | |||
// The value of FO traits (refined properties) that apply to fo:page-sequence. | |||
private String country; | |||
private String language; | |||
private String masterReference; | |||
private Numeric referenceOrientation; | |||
private WritingModeTraits writingModeTraits; | |||
// End of trait values | |||
private Locale locale; | |||
// There doesn't seem to be anything in the spec requiring flows | |||
// to be in the order given, only that they map to the regions | |||
@@ -90,8 +90,9 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra | |||
/** {@inheritDoc} */ | |||
public void bind(PropertyList pList) throws FOPException { | |||
super.bind(pList); | |||
country = pList.get(PR_COUNTRY).getString(); | |||
language = pList.get(PR_LANGUAGE).getString(); | |||
String country = pList.get(PR_COUNTRY).getString(); | |||
String language = pList.get(PR_LANGUAGE).getString(); | |||
locale = CommonHyphenation.toLocale(language, country); | |||
masterReference = pList.get(PR_MASTER_REFERENCE).getString(); | |||
referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); | |||
writingModeTraits = new WritingModeTraits | |||
@@ -320,20 +321,8 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra | |||
return FO_PAGE_SEQUENCE; | |||
} | |||
/** | |||
* Get the value of the <code>country</code> trait. | |||
* @return the country trait value | |||
*/ | |||
public String getCountry() { | |||
return this.country; | |||
} | |||
/** | |||
* Get the value of the <code>language</code> trait. | |||
* @return the language trait value | |||
*/ | |||
public String getLanguage() { | |||
return this.language; | |||
public Locale getLocale() { | |||
return locale; | |||
} | |||
/** |
@@ -36,6 +36,7 @@ import org.apache.fop.fo.extensions.destination.Destination; | |||
import org.apache.fop.fo.pagination.bookmarks.BookmarkTree; | |||
import org.apache.fop.fo.properties.CommonAccessibility; | |||
import org.apache.fop.fo.properties.CommonAccessibilityHolder; | |||
import org.apache.fop.fo.properties.CommonHyphenation; | |||
/** | |||
* Class modeling the <a href="http://www.w3.org/TR/xsl/#fo_root"> | |||
@@ -92,17 +93,7 @@ public class Root extends FObj implements CommonAccessibilityHolder { | |||
mediaUsage = pList.get(PR_MEDIA_USAGE).getEnum(); | |||
String language = pList.get(PR_LANGUAGE).getString(); | |||
String country = pList.get(PR_COUNTRY).getString(); | |||
if (isLocalePropertySet(language)) { | |||
if (isLocalePropertySet(country)) { | |||
locale = new Locale(language, country); | |||
} else { | |||
locale = new Locale(language); | |||
} | |||
} | |||
} | |||
private boolean isLocalePropertySet(String property) { | |||
return property != null && !property.equals("none"); | |||
locale = CommonHyphenation.toLocale(language, country); | |||
} | |||
/** {@inheritDoc} */ |
@@ -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); | |||
} |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.fo.properties; | |||
import java.util.Locale; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -185,6 +187,41 @@ public final class CommonHyphenation { | |||
return font.getCharWidth(hyphChar); | |||
} | |||
/** | |||
* Creates and returns a {@link Locale} representation of the language and country. | |||
* | |||
* @return the language (and the country if set) represented as a locale, {@code null} | |||
* if the language has not been set (i.e., has been left to its initial value of | |||
* "none") | |||
*/ | |||
public Locale getLocale() { | |||
return toLocale(language.getString(), country.getString()); | |||
} | |||
/** | |||
* Creates and returns a {@link Locale} representation of the given language, and the | |||
* given country if set. The country is considered to be set if not {@code null} and | |||
* not set to "none". | |||
* | |||
* @return the language and country represented as a locale, {@code null} if the | |||
* language is null or "none" (case insensitive) | |||
*/ | |||
public static Locale toLocale(String language, String country) { | |||
Locale locale = null; | |||
if (isDefined(language)) { | |||
if (isDefined(country)) { | |||
locale = new Locale(language, country); | |||
} else { | |||
locale = new Locale(language); | |||
} | |||
} | |||
return locale; | |||
} | |||
private static boolean isDefined(String property) { | |||
return !(property == null || property.equalsIgnoreCase("none")); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean equals(Object obj) { | |||
if (obj == this) { |
@@ -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 ---- | |||
/** |
@@ -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(); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/* $Id$ */ | |||
package org.apache.fop.fonts; | |||
import java.util.BitSet; | |||
import java.util.Map; | |||
/** | |||
* Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font. | |||
*/ | |||
public interface CIDSet { | |||
/** | |||
* Returns the original index of the glyph inside the (non-subset) font's glyph list. This | |||
* index can be used to access the character width information, for example. | |||
* @param index the subset index (character selector) to access the glyph | |||
* @return the original index (or -1 if no glyph index is available for the subset index) | |||
*/ | |||
int getOriginalGlyphIndex(int index); | |||
/** | |||
* Returns the Unicode value for a subset index (character selector). If there's no such | |||
* Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. | |||
* @param index the subset index (character selector) | |||
* @return the Unicode value or "NOT A CHARACTER" (0xFFFF) | |||
*/ | |||
char getUnicode(int index); | |||
/** | |||
* Maps a character to a character selector for a font subset. If the character isn't in the | |||
* subset, yet, it is added and a new character selector returned. Otherwise, the already | |||
* allocated character selector is returned from the existing map/subset. | |||
* @param glyphIndex the glyph index of the character | |||
* @param unicode the Unicode index of the character | |||
* @return the subset index | |||
*/ | |||
int mapChar(int glyphIndex, char unicode); | |||
/** | |||
* Returns an unmodifiable Map of the font subset. It maps from glyph index to | |||
* character selector (i.e. the subset index in this case). | |||
* @return Map Map<Integer, Integer> of the font subset | |||
*/ | |||
Map<Integer, Integer> getGlyphs(); | |||
/** | |||
* Returns a char array containing all Unicode characters that are in the subset. | |||
* @return a char array with all used Unicode characters | |||
*/ | |||
char[] getChars(); | |||
/** | |||
* Returns the number of glyphs in the subset. | |||
* @return the number of glyphs in the subset | |||
*/ | |||
int getNumberOfGlyphs(); | |||
/** | |||
* Returns a BitSet with bits set for each available glyph index in the subset. | |||
* @return a BitSet indicating available glyph indices | |||
*/ | |||
BitSet getGlyphIndices(); | |||
/** | |||
* Return the array of widths. | |||
* <p> | |||
* This is used to get an array for inserting in an output format. | |||
* It should not be used for lookup. | |||
* @return an array of widths | |||
*/ | |||
int[] getWidths(); | |||
} |
@@ -26,18 +26,16 @@ import java.util.Map; | |||
import org.apache.fop.util.CharUtilities; | |||
//Naming: | |||
//glyph index: original index of the glyph in the non-subset font (!= unicode index) | |||
//character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For | |||
// non-subset fonts, this is the same as the glyph index. | |||
//Unicode index: The Unicode codepoint of a character. | |||
//Glyph name: the Adobe glyph name (as found in Glyphs.java) | |||
/** | |||
* Keeps track of the glyphs used in a document. This information is later used to build | |||
* a subset of a font. | |||
* Provides methods to get font information. | |||
* Naming: | |||
* glyph index: original index of the glyph in the non-subset font (!= unicode index) | |||
* character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset | |||
* fonts, this is the same as the glyph index. | |||
* Unicode index: The Unicode codepoint of a character. | |||
* Glyph name: the Adobe glyph name (as found in Glyphs.java) | |||
*/ | |||
public class CIDSubset { | |||
public class CIDSubset implements CIDSet { | |||
/** | |||
* usedGlyphs contains orginal, new glyph index (glyph index -> char selector) | |||
@@ -48,51 +46,36 @@ public class CIDSubset { | |||
* usedGlyphsIndex contains new glyph, original index (char selector -> glyph index) | |||
*/ | |||
private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>(); | |||
private int usedGlyphsCount = 0; | |||
private int usedGlyphsCount; | |||
/** | |||
* usedCharsIndex contains new glyph, original char (char selector -> Unicode) | |||
*/ | |||
private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>(); | |||
/** | |||
* Default constructor. | |||
*/ | |||
public CIDSubset() { | |||
} | |||
private final MultiByteFont font; | |||
/** | |||
* Adds the first glyph which is reserved for .notdef for all CID subsets. | |||
*/ | |||
public void setupFirstGlyph() { | |||
usedGlyphs.put(Integer.valueOf(0), Integer.valueOf(0)); | |||
usedGlyphsIndex.put(Integer.valueOf(0), Integer.valueOf(0)); | |||
public CIDSubset(MultiByteFont mbf) { | |||
font = mbf; | |||
// The zeroth value is reserved for .notdef | |||
usedGlyphs.put(0, 0); | |||
usedGlyphsIndex.put(0, 0); | |||
usedGlyphsCount++; | |||
} | |||
/** | |||
* Returns the original index of the glyph inside the (non-subset) font's glyph list. This | |||
* index can be used to access the character width information, for example. | |||
* @param subsetIndex the subset index (character selector) to access the glyph | |||
* @return the original index (or -1 if no glyph index is available for the subset index) | |||
*/ | |||
public int getGlyphIndexForSubsetIndex(int subsetIndex) { | |||
Integer glyphIndex = usedGlyphsIndex.get(Integer.valueOf(subsetIndex)); | |||
/** {@inheritDoc} */ | |||
public int getOriginalGlyphIndex(int index) { | |||
Integer glyphIndex = usedGlyphsIndex.get(index); | |||
if (glyphIndex != null) { | |||
return glyphIndex.intValue(); | |||
return glyphIndex; | |||
} else { | |||
return -1; | |||
} | |||
} | |||
/** | |||
* Returns the Unicode value for a subset index (character selector). If there's no such | |||
* Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. | |||
* @param subsetIndex the subset index (character selector) | |||
* @return the Unicode value or "NOT A CHARACTER" (0xFFFF) | |||
*/ | |||
public char getUnicodeForSubsetIndex(int subsetIndex) { | |||
Character mapValue = usedCharsIndex.get(Integer.valueOf(subsetIndex)); | |||
/** {@inheritDoc} */ | |||
public char getUnicode(int index) { | |||
Character mapValue = usedCharsIndex.get(index); | |||
if (mapValue != null) { | |||
return mapValue.charValue(); | |||
} else { | |||
@@ -100,72 +83,60 @@ public class CIDSubset { | |||
} | |||
} | |||
/** | |||
* Maps a character to a character selector for a font subset. If the character isn't in the | |||
* subset, yet, it is added and a new character selector returned. Otherwise, the already | |||
* allocated character selector is returned from the existing map/subset. | |||
* @param glyphIndex the glyph index of the character | |||
* @param unicode the Unicode index of the character | |||
* @return the subset index | |||
*/ | |||
public int mapSubsetChar(int glyphIndex, char unicode) { | |||
/** {@inheritDoc} */ | |||
public int mapChar(int glyphIndex, char unicode) { | |||
// Reencode to a new subset font or get the reencoded value | |||
// IOW, accumulate the accessed characters and build a character map for them | |||
Integer subsetCharSelector = usedGlyphs.get(Integer.valueOf(glyphIndex)); | |||
Integer subsetCharSelector = usedGlyphs.get(glyphIndex); | |||
if (subsetCharSelector == null) { | |||
int selector = usedGlyphsCount; | |||
usedGlyphs.put(Integer.valueOf(glyphIndex), | |||
Integer.valueOf(selector)); | |||
usedGlyphsIndex.put(Integer.valueOf(selector), | |||
Integer.valueOf(glyphIndex)); | |||
usedCharsIndex.put(Integer.valueOf(selector), | |||
Character.valueOf(unicode)); | |||
usedGlyphs.put(glyphIndex, selector); | |||
usedGlyphsIndex.put(selector, glyphIndex); | |||
usedCharsIndex.put(selector, unicode); | |||
usedGlyphsCount++; | |||
return selector; | |||
} else { | |||
return subsetCharSelector.intValue(); | |||
return subsetCharSelector; | |||
} | |||
} | |||
/** | |||
* Returns an unmodifiable Map of the font subset. It maps from glyph index to | |||
* character selector (i.e. the subset index in this case). | |||
* @return Map Map<Integer, Integer> of the font subset | |||
*/ | |||
public Map<Integer, Integer> getSubsetGlyphs() { | |||
/** {@inheritDoc} */ | |||
public Map<Integer, Integer> getGlyphs() { | |||
return Collections.unmodifiableMap(this.usedGlyphs); | |||
} | |||
/** | |||
* Returns a char array containing all Unicode characters that are in the subset. | |||
* @return a char array with all used Unicode characters | |||
*/ | |||
public char[] getSubsetChars() { | |||
/** {@inheritDoc} */ | |||
public char[] getChars() { | |||
char[] charArray = new char[usedGlyphsCount]; | |||
for (int i = 0; i < usedGlyphsCount; i++) { | |||
charArray[i] = getUnicodeForSubsetIndex(i); | |||
charArray[i] = getUnicode(i); | |||
} | |||
return charArray; | |||
} | |||
/** | |||
* Returns the number of glyphs in the subset. | |||
* @return the number of glyphs in the subset | |||
*/ | |||
public int getSubsetSize() { | |||
/** {@inheritDoc} */ | |||
public int getNumberOfGlyphs() { | |||
return this.usedGlyphsCount; | |||
} | |||
/** | |||
* Returns a BitSet with bits set for each available glyph index in the subset. | |||
* @return a BitSet indicating available glyph indices | |||
*/ | |||
public BitSet getGlyphIndexBitSet() { | |||
/** {@inheritDoc} */ | |||
public BitSet getGlyphIndices() { | |||
BitSet bitset = new BitSet(); | |||
for (Integer cid : usedGlyphs.keySet()) { | |||
bitset.set(cid.intValue()); | |||
bitset.set(cid); | |||
} | |||
return bitset; | |||
} | |||
/** {@inheritDoc} */ | |||
public int[] getWidths() { | |||
int[] widths = font.getWidths(); | |||
int[] tmpWidth = new int[getNumberOfGlyphs()]; | |||
for (int i = 0, c = getNumberOfGlyphs(); i < c; i++) { | |||
int nwx = Math.max(0, getOriginalGlyphIndex(i)); | |||
tmpWidth[i] = widths[nwx]; | |||
} | |||
return tmpWidth; | |||
} | |||
} |
@@ -89,7 +89,7 @@ public final class DefaultFontConfig implements FontConfig { | |||
} else { | |||
this.strict = strict; | |||
this.fontInfoCfg = cfg.getChild("fonts", false); | |||
instance = new DefaultFontConfig(cfg.getChild("auto-detect", false) != null); | |||
instance = new DefaultFontConfig(fontInfoCfg.getChild("auto-detect", false) != null); | |||
parse(); | |||
} | |||
} |
@@ -52,7 +52,6 @@ public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo> | |||
/** | |||
* Main constructor | |||
* @param fontInfoConfig the configuration object | |||
* @param fontManager the font manager | |||
* @param listener the font event listener | |||
* @param strict true if an Exception should be thrown if an error is found. |
@@ -53,7 +53,7 @@ public final class FontCache implements Serializable { | |||
* Serialization Version UID. Change this value if you want to make sure the | |||
* user's cache file is purged after an update. | |||
*/ | |||
private static final long serialVersionUID = 605232520271754719L; | |||
private static final long serialVersionUID = 9129238336422194339L; | |||
/** logging instance */ | |||
private static Log log = LogFactory.getLog(FontCache.class); | |||
@@ -65,7 +65,7 @@ public final class FontCache implements Serializable { | |||
private static final String DEFAULT_CACHE_FILENAME = "fop-fonts.cache"; | |||
/** has this cache been changed since it was last read? */ | |||
private transient boolean changed = false; | |||
private transient boolean changed; | |||
/** change lock */ | |||
private final boolean[] changeLock = new boolean[1]; | |||
@@ -73,12 +73,14 @@ public final class FontCache implements Serializable { | |||
/** | |||
* master mapping of font url -> font info. This needs to be a list, since a | |||
* TTC file may contain more than 1 font. | |||
* @serial | |||
*/ | |||
private Map<String, CachedFontFile> fontfileMap = null; | |||
/** | |||
* mapping of font url -> file modified date (for all fonts that have failed | |||
* to load) | |||
* @serial | |||
*/ | |||
private Map<String, Long> failedFontMap = null; | |||
@@ -139,6 +141,7 @@ public final class FontCache implements Serializable { | |||
* | |||
* @return the font cache deserialized from the file (or null if no cache | |||
* file exists or if it could not be read) | |||
* @deprecated use {@link #loadFrom(File)} instead | |||
*/ | |||
public static FontCache load() { | |||
return loadFrom(getDefaultCacheFile(false)); | |||
@@ -190,8 +193,8 @@ public final class FontCache implements Serializable { | |||
/** | |||
* Writes the font cache to disk. | |||
* | |||
* @throws FOPException | |||
* fop exception | |||
* @throws FOPException fop exception | |||
* @deprecated use {@link #saveTo(File)} instead | |||
*/ | |||
public void save() throws FOPException { | |||
saveTo(getDefaultCacheFile(true)); | |||
@@ -462,10 +465,9 @@ public final class FontCache implements Serializable { | |||
} | |||
/** | |||
* Retrieve the last modified date/time of a URL. | |||
* Retrieve the last modified date/time of a URI. | |||
* | |||
* @param url | |||
* the URL | |||
* @param uri the URI | |||
* @return the last modified date/time | |||
*/ | |||
public static long getLastModified(URI uri) { |
@@ -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; | |||
} |
@@ -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 | |||
} | |||
} | |||
} |
@@ -19,7 +19,7 @@ | |||
package org.apache.fop.fonts; | |||
import java.io.File; | |||
import java.net.URI; | |||
import java.util.List; | |||
import org.apache.fop.apps.FOPException; | |||
@@ -52,9 +52,6 @@ public class FontManager { | |||
/** FontTriplet matcher for fonts that shall be referenced rather than embedded. */ | |||
private FontTriplet.Matcher referencedFontsMatcher; | |||
/** Provides a font cache file path **/ | |||
private File cacheFile; | |||
/** | |||
* Main constructor | |||
* | |||
@@ -115,30 +112,14 @@ public class FontManager { | |||
/** | |||
* Sets the font cache file | |||
* @param cacheFile the font cache file | |||
*/ | |||
public void setCacheFile(File cacheFile) { | |||
this.cacheFile = cacheFile; | |||
} | |||
/** | |||
* Returns the font cache file | |||
* @return the font cache file | |||
* @param cacheFileURI the URI of the font cache file | |||
*/ | |||
public File getCacheFile() { | |||
return getCacheFile(false); | |||
} | |||
private File getCacheFile(boolean writable) { | |||
if (cacheFile != null) { | |||
return cacheFile; | |||
} | |||
return FontCache.getDefaultCacheFile(writable); | |||
public void setCacheFile(URI cacheFileURI) { | |||
fontCacheManager.setCacheFile(resourceResolver.resolveFromBase(cacheFileURI)); | |||
} | |||
/** | |||
* Whether or not to cache results of font triplet detection/auto-config | |||
* @param useCache use cache or not | |||
*/ | |||
public void disableFontCache() { | |||
fontCacheManager = FontCacheManagerFactory.createDisabled(); | |||
@@ -149,7 +130,7 @@ public class FontManager { | |||
* @return the font cache | |||
*/ | |||
public FontCache getFontCache() { | |||
return fontCacheManager.load(getCacheFile()); | |||
return fontCacheManager.load(); | |||
} | |||
/** | |||
@@ -158,16 +139,15 @@ public class FontManager { | |||
* @throws FOPException fop exception | |||
*/ | |||
public void saveCache() throws FOPException { | |||
fontCacheManager.save(getCacheFile()); | |||
fontCacheManager.save(); | |||
} | |||
/** | |||
* Deletes the current FontCache file | |||
* @return Returns true if the font cache file was successfully deleted. | |||
* @throws FOPException - | |||
* @throws FOPException if an error was thrown while deleting the cache | |||
*/ | |||
public void deleteCache() throws FOPException { | |||
fontCacheManager.delete(getCacheFile(true)); | |||
fontCacheManager.delete(); | |||
} | |||
/** |
@@ -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; |
@@ -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); |
@@ -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(); | |||
} | |||
@@ -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(); | |||
} | |||
/** |
@@ -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 { |
@@ -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( |
@@ -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); | |||
@@ -273,4 +273,11 @@ public abstract class AbstractBaseLayoutManager | |||
throw new UnsupportedOperationException("Not implemented"); | |||
} | |||
public void preserveChildrenAtEndOfLayout() { | |||
} | |||
public void recreateChildrenLMs() { | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
@@ -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); |
@@ -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); |
@@ -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 */ |
@@ -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} */ |
@@ -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 | |||
} | |||
} |