Skip to content

Commit

Permalink
Bugzilla #41831:
Browse files Browse the repository at this point in the history
- Add support font auto-detection (easier font configuration) including a font cache to speed up the auto-detection process.
- Refactoring of the configuration code: All Avalon configuration stuff is extracted into separate "Configurator" classes.
- Refactoring of the FOURIResolver.
Submitted by: Adrian Cumiskey <fop-dev.at.cumiskey.com>

Changes to the patch by jeremias during the review:
- Font cache simplified (Java object serialization instead of XML), functionality fixed and moved to the fonts.package.
- Relocated default cache file location to user directory.
- Fixed the font configuration for PDFDocumentGraphics2D/PDFTranscoder that got lost with the patch.
- Fixed a problem with having a non-file URL as font base URL.
- Simplified RendererContextInfo stuff to make it easier to understand.
- Fixed handling of Type 1 fonts in auto-detection.
- Reduced verbosity of font-related log output.
- Updated Jakarta Commons IO to version 1.3.1 (the patch depends on it)
- Various javadocs improvements

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@542237 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
jmaerki committed May 28, 2007
1 parent ed2ea5e commit 9dc46ab
Show file tree
Hide file tree
Showing 111 changed files with 4,024 additions and 1,462 deletions.
7 changes: 4 additions & 3 deletions fop.bat
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,16 @@ set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\serializer-2.7.0.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\batik-all-1.6.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\xmlgraphics-commons-1.2svn.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\avalon-framework-4.2.0.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\commons-io-1.1.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\commons-io-1.3.1.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\commons-logging-1.0.4.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\jimi-1.0.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\jai_core.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\jai_codec.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%LIBDIR%\fop-hyph.jar
set LOCALCLASSPATH=%LOCALCLASSPATH%;%FOP_HYPHENATION_PATH%

set JAVAOPTS=-Denv.windir=%WINDIR%

if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
if "%JAVACMD%" == "" set JAVACMD=%JAVA_HOME%\bin\java
Expand All @@ -80,5 +82,4 @@ if "%JAVACMD%" == "" set JAVACMD=java

:runFop
rem ECHO "%JAVACMD%"
"%JAVACMD%" %LOGCHOICE% %LOGLEVEL% -cp "%LOCALCLASSPATH%" org.apache.fop.cli.Main %FOP_CMD_LINE_ARGS%

"%JAVACMD%" %JAVAOPTS% %LOGCHOICE% %LOGLEVEL% -cp "%LOCALCLASSPATH%" org.apache.fop.cli.Main %FOP_CMD_LINE_ARGS%
4 changes: 3 additions & 1 deletion fop.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ 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%

if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
if "%JAVACMD%" == "" set JAVACMD=%JAVA_HOME%\bin\java
Expand All @@ -68,6 +70,6 @@ if "%JAVACMD%" == "" set JAVACMD=java

:runFop
rem echo "%JAVACMD%" %LOGCHOICE% %LOGLEVEL% -cp "%LOCALCLASSPATH%" org.apache.fop.cli.Main %FOP_CMD_LINE_ARGS%
"%JAVACMD%" %LOGCHOICE% %LOGLEVEL% -cp "%LOCALCLASSPATH%" org.apache.fop.cli.Main %FOP_CMD_LINE_ARGS%
"%JAVACMD%" %JAVAOPTS% %LOGCHOICE% %LOGLEVEL% -cp "%LOCALCLASSPATH%" org.apache.fop.cli.Main %FOP_CMD_LINE_ARGS%

ENDLOCAL
Binary file removed lib/commons-io-1.1.jar
Binary file not shown.
Binary file added lib/commons-io-1.3.1.jar
Binary file not shown.
3 changes: 3 additions & 0 deletions lib/commons-io.NOTICE.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Apache Jakarta Commons IO
Copyright 2001-2007 The Apache Software Foundation

This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).

18 changes: 18 additions & 0 deletions src/documentation/content/xdocs/trunk/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,24 @@
default-page-settings element to specify the two values.</td>
<td>"height" 11 inches, "width" 8.26 inches</td>
</tr>
<tr>
<td>use-cache</td>
<td>boolean (true, false)</td>
<td>All fonts information that has been gathered as a result of "directory"
or "auto-detect" font configurations will be cached for future rendering runs.
This setting should improve performance on systems where
fonts have been configured using the "directory" or "auto-detect" tag mechanisms.
By default this option is switched on.</td>
<td>true</td>
</tr>
<tr>
<td>cache-file</td>
<td>String</td>
<td>This options specifies the file/directory path of the fop cache file.
This option can also be specified on the command-line using the -cache option.
This file is currently only used to cache font triplet information for future reference.</td>
<td>${base}/conf/fop.cache</td>
</tr>
<tr>
<td>renderers</td>
<td>(see text below)</td>
Expand Down
36 changes: 28 additions & 8 deletions src/documentation/content/xdocs/trunk/fonts.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<authors>
<person name="Jeremias Märki" email=""/>
<person name="Tore Engvig" email=""/>
<person name="Adrian Cumiskey" email=""/>
</authors>
</header>
<body>
Expand Down Expand Up @@ -129,8 +130,7 @@
More information about fonts can be found at:</p>
<ul>
<li><a href="http://partners.adobe.com/asn/developer/type/ftypes.html">Adobe font types</a></li>
<li><a href="http://partners.adobe.com/asn/developer/technotes/fonts.html">Adobe Font Technote</a>
</li>
<li><a href="http://partners.adobe.com/asn/developer/technotes/fonts.html">Adobe Font Technote</a></li>
</ul>
<section id="type1-metrics">
<title>Type 1 Font Metrics</title>
Expand Down Expand Up @@ -236,19 +236,39 @@ It will display all of the font names and exit with an Exception.</p>
<section id="register">
<title>Register Fonts with FOP</title>
<p>You must tell FOP how to find and use the font metrics files by registering them in the <a href="configuration.html">FOP Configuration</a>. Add entries for your custom fonts, regardless of font type, to the configuration file in a manner similar to the following:</p>
<source><![CDATA[<font metrics-url="file:///C:/myfonts/FTL_____.xml" kerning="yes"
<source><![CDATA[
<fonts>
<!-- register a particular font -->
<font metrics-url="file:///C:/myfonts/FTL_____.xml" kerning="yes"
embed-url="file:///C:/myfonts/FTL_____.pfb">
<font-triplet name="FrutigerLight" style="normal" weight="normal"/>
</font>]]></source>
<font-triplet name="FrutigerLight" style="normal" weight="normal"/>
</font>
<!-- register all the fonts found in a directory -->
<directory>C:\MyFonts1</directory>
<!-- register all the fonts found in a directory
and all of its sub directories (use with care) -->
<directory recursive="true">C:\MyFonts2</directory>
<!-- automatically detect operating system installed fonts -->
<auto-detect/>
</fonts>]]></source>
<note>Review the documentation for <a href="configuration.html">FOP Configuration</a> for instructions on making the FOP configuration available to FOP when it runs. Otherwise, FOP has no way of finding your custom font information.</note>
<ul>
<li>
URLs are used to access the font metric and font files.
Relative URLs are resolved relative to the font-base property (or base) if available.
See <a href="configuration.html">FOP: Configuration</a> for more information.
</li>
<li>The "kerning" and "embed-url" attributes are optional. Kerning is currently not used at all. If embedding is off, the output will position the text correctly (from the metrics file), but it will not be displayed or printed correctly unless the viewer has the applicable font available to their local system.</li>
<li>When setting the embed-url attribute for Type 1 fonts, be sure to specify the PFB (actual font data), not PFM (font metrics) file that you used to generate the XML font metrics file.</li>
<li>Either an "embed-url" or a "metrics-url" must be specified for font tag configurations.</li>
<li>The font "kerning" attribute is optional. Kerning is currently not used at all.</li>
<li>If embedding is off, the output will position the text correctly (from the metrics file), but it will not be displayed or printed correctly unless the viewer has the applicable font available to their local system.</li>
<li>When setting the "embed-url" attribute for Type 1 fonts, be sure to specify the PFB (actual font data), not PFM (font metrics) file that you used to generate the XML font metrics file.</li>
<li>The fonts "directory" tag can be used to register fonts contained within a single or list of directory paths. The "recursive" attribute can be specified to recursively add fonts from all sub directories.</li>
<li>The fonts "auto-detect" tag can be used to automatically register fonts that are found to be installed on the native operating system.</li>
<li>Fonts registered with "font" tag configurations override fonts found by means of "directory" tag definitions.</li>
<li>Fonts found as a result of a "directory" tag configuration override fonts found as a result of the "auto-detect" tag being specified.</li>
<li>
If relative URLs are specified, they are evaluated relative to the value of the
"font-base" setting. If there is no "font-base" setting, the fonts are evaluated
Expand Down Expand Up @@ -281,7 +301,7 @@ Characters will be WinAnsi encoded (as specified in the PDF spec), so you lose t
See <a href="#ttf-encoding">Table of TTF Encoding Options</a> for more details.</p>
</section>
<section id="embedding-base14">
<title>Explicitely embedding the base 14 fonts</title>
<title>Explicitly embedding the base 14 fonts</title>
<p>
There are cases where you might want to force the embedding of one or more of the base 14 fonts that
can normally be considered available on the target platform (viewer, printer). One of these cases is
Expand Down
189 changes: 104 additions & 85 deletions src/java/org/apache/fop/apps/FOURIResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.net.URLConnection;

import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamSource;

// commons logging
Expand All @@ -47,8 +48,41 @@
public class FOURIResolver
implements javax.xml.transform.URIResolver {

// log
private Log log = LogFactory.getLog("FOP");

// true if exceptions are to be thrown if the URIs cannot be resolved.
private boolean throwExceptions = false;

/**
* Default constructor
*/
public FOURIResolver() {
this(false);
}

/**
* Additional constructor
* @param throwExceptions true if exceptions are to be thrown if the URIs cannot be
* resolved.
*/
public FOURIResolver(boolean throwExceptions) {
this.throwExceptions = throwExceptions;
}

/**
* Handles resolve exceptions appropriately.
* @param errorStr error string
* @param strict strict user config
*/
private void handleException(Exception e, String errorStr, boolean strict)
throws TransformerException {
if (strict) {
throw new TransformerException(errorStr, e);
}
log.error(e.getMessage());
}

/**
* Called by the processor through {@link FOUserAgent} when it encounters an
* uri in an external-graphic element.
Expand All @@ -70,31 +104,25 @@ public class FOURIResolver
* @throws javax.xml.transform.TransformerException Never thrown by this implementation.
* @see javax.xml.transform.URIResolver#resolve(String, String)
*/
public Source resolve(String href, String base)
throws javax.xml.transform.TransformerException {

//data URLs can be quite long so don't try to build a File (can lead to problems)
public Source resolve(String href, String base) throws TransformerException {
// data URLs can be quite long so don't try to build a File (can lead to problems)
if (href.startsWith("data:")) {
return parseDataURI(href);
}

URL absoluteURL = null;
File f = new File(href);
if (f.exists()) {
File file = new File(href);
if (file.canRead() && file.isFile()) {
try {
absoluteURL = f.toURL();
absoluteURL = file.toURL();
} catch (MalformedURLException mfue) {
log.error("Could not convert filename to URL: " + mfue.getMessage());
handleException(mfue,
"Could not convert filename '" + href + "' to URL", throwExceptions);
}
} else {
URL baseURL = null;
try {
baseURL = toBaseURL(base);
} catch (MalformedURLException mfue) {
log.error("Error with base URL \"" + base + "\"): " + mfue.getMessage());
}
if (baseURL == null) {
// We don't have a valid baseURL just use the URL as given
// no base provided
if (base == null) {
// We don't have a valid file protocol based URL
try {
absoluteURL = new URL(href);
} catch (MalformedURLException mue) {
Expand All @@ -103,64 +131,78 @@ public Source resolve(String href, String base)
// the href contains only a path then file: is assumed
absoluteURL = new URL("file:" + href);
} catch (MalformedURLException mfue) {
log.error("Error with URL '" + href + "': " + mue.getMessage());
return null;
handleException(mfue,
"Error with URL '" + href + "'", throwExceptions);
}
}

// try and resolve from context of base
} else {
URL baseURL = null;
try {
/*
This piece of code is based on the following statement in
RFC2396 section 5.2:
3) If the scheme component is defined, indicating that the reference
starts with a scheme name, then the reference is interpreted as an
absolute URI and we are done. Otherwise, the reference URI's
scheme is inherited from the base URI's scheme component.
Due to a loophole in prior specifications [RFC1630], some parsers
allow the scheme name to be present in a relative URI if it is the
same as the base URI scheme. Unfortunately, this can conflict
with the correct parsing of non-hierarchical URI. For backwards
compatibility, an implementation may work around such references
by removing the scheme if it matches that of the base URI and the
scheme is known to always use the <hier_part> syntax.
The URL class does not implement this work around, so we do.
*/
baseURL = new URL(base);
} catch (MalformedURLException mfue) {
handleException(mfue, "Error with base URL '" + base + "'", throwExceptions);
}

String scheme = baseURL.getProtocol() + ":";
if (href.startsWith(scheme)) {
href = href.substring(scheme.length());
if ("file:".equals(scheme)) {
int colonPos = href.indexOf(':');
int slashPos = href.indexOf('/');
if (slashPos >= 0 && colonPos >= 0 && colonPos < slashPos) {
href = "/" + href; //Absolute file URL doesn't have a leading slash
}
/*
* This piece of code is based on the following statement in
* RFC2396 section 5.2:
*
* 3) If the scheme component is defined, indicating that the
* reference starts with a scheme name, then the reference is
* interpreted as an absolute URI and we are done. Otherwise,
* the reference URI's scheme is inherited from the base URI's
* scheme component.
*
* Due to a loophole in prior specifications [RFC1630], some
* parsers allow the scheme name to be present in a relative URI
* if it is the same as the base URI scheme. Unfortunately, this
* can conflict with the correct parsing of non-hierarchical
* URI. For backwards compatibility, an implementation may work
* around such references by removing the scheme if it matches
* that of the base URI and the scheme is known to always use
* the <hier_part> syntax.
*
* The URL class does not implement this work around, so we do.
*/
String scheme = baseURL.getProtocol() + ":";
if (href.startsWith(scheme)) {
href = href.substring(scheme.length());
if ("file:".equals(scheme)) {
int colonPos = href.indexOf(':');
int slashPos = href.indexOf('/');
if (slashPos >= 0 && colonPos >= 0 && colonPos < slashPos) {
href = "/" + href; // Absolute file URL doesn't
// have a leading slash
}
}
}
try {
absoluteURL = new URL(baseURL, href);
} catch (MalformedURLException mfue) {
log.error("Error with URL '" + href + "': " + mfue.getMessage());
return null;
handleException(mfue,
"Error with URL; base '" + base + "' " + "href '" + href + "'",
throwExceptions);
}
}
}

String effURL = absoluteURL.toExternalForm();
try {
URLConnection connection = absoluteURL.openConnection();
connection.setAllowUserInteraction(false);
connection.setDoInput(true);
updateURLConnection(connection, href);
connection.connect();
return new StreamSource(connection.getInputStream(), effURL);
} catch (FileNotFoundException fnfe) {
//Note: This is on "debug" level since the caller is supposed to handle this
log.debug("File not found: " + effURL);
} catch (java.io.IOException ioe) {
log.error("Error with opening URL '" + effURL + "': " + ioe.getMessage());
if (absoluteURL != null) {
String effURL = absoluteURL.toExternalForm();
try {
URLConnection connection = absoluteURL.openConnection();
connection.setAllowUserInteraction(false);
connection.setDoInput(true);
updateURLConnection(connection, href);
connection.connect();
return new StreamSource(connection.getInputStream(), effURL);
} catch (FileNotFoundException fnfe) {
//Note: This is on "debug" level since the caller is supposed to handle this
log.debug("File not found: " + effURL);
} catch (java.io.IOException ioe) {
log.error("Error with opening URL '" + effURL + "': " + ioe.getMessage());
}
}
return null;
}
Expand Down Expand Up @@ -200,29 +242,6 @@ protected void applyHttpBasicAuthentication(URLConnection connection,
}
}

/**
* Returns the base URL as a java.net.URL.
* If the base URL is not set a default URL pointing to the
* current directory is returned.
* @param baseURL the base URL
* @returns the base URL as java.net.URL
*/
private URL toBaseURL(String base) throws MalformedURLException {
if (base == null) {
return new java.io.File("").toURL();
}
if (!base.endsWith("/")) {
// The behavior described by RFC 3986 regarding resolution of relative
// references may be misleading for normal users:
// file://path/to/resources + myResource.res -> file://path/to/myResource.res
// file://path/to/resources/ + myResource.res -> file://path/to/resources/myResource.res
// We assume that even when the ending slash is missing, users have the second
// example in mind
base += "/";
}
return new URL(base);
}

/**
* Parses inline data URIs as generated by MS Word's XML export and FO stylesheet.
* @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
Expand Down
Loading

0 comments on commit 9dc46ab

Please sign in to comment.