Browse Source

Started unifying URI resolution mechanism, redesigned configuration system and created flexible config testing


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_URI_Unification@1344594 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-2_0
Mehdi Houshmand 12 years ago
parent
commit
eccd73c523
100 changed files with 3550 additions and 2583 deletions
  1. 2
    1
      build.xml
  2. 5
    8
      examples/embedding/java/embedding/ExampleAWTViewer.java
  3. 5
    8
      examples/embedding/java/embedding/ExampleDOM2PDF.java
  4. 1
    1
      examples/embedding/java/embedding/ExampleFO2JPSPrint.java
  5. 1
    1
      examples/embedding/java/embedding/ExampleFO2OldStylePrint.java
  6. 5
    8
      examples/embedding/java/embedding/ExampleFO2PDF.java
  7. 4
    7
      examples/embedding/java/embedding/ExampleFO2PDFUsingSAXParser.java
  8. 5
    7
      examples/embedding/java/embedding/ExampleFO2RTF.java
  9. 7
    9
      examples/embedding/java/embedding/ExampleObj2PDF.java
  10. 4
    6
      examples/embedding/java/embedding/ExampleXML2PDF.java
  11. 6
    8
      examples/embedding/java/embedding/MultipleFO2PDF.java
  12. 1
    1
      examples/embedding/java/embedding/atxml/ExampleConcat.java
  13. 1
    1
      examples/embedding/java/embedding/atxml/ExampleStamp.java
  14. 1
    1
      examples/embedding/java/embedding/events/ExampleEvents.java
  15. 2
    3
      examples/embedding/java/embedding/intermediate/ExampleConcat.java
  16. 1
    1
      examples/embedding/java/embedding/intermediate/ExampleStamp.java
  17. 2
    0
      src/java/org/apache/fop/afp/AFPDataObjectInfo.java
  18. 2
    3
      src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java
  19. 6
    12
      src/java/org/apache/fop/afp/fonts/AFPFont.java
  20. 5
    6
      src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java
  21. 0
    1
      src/java/org/apache/fop/afp/fonts/CharacterSetBuilder.java
  22. 6
    3
      src/java/org/apache/fop/afp/fonts/DoubleByteFont.java
  23. 3
    2
      src/java/org/apache/fop/afp/fonts/OutlineFont.java
  24. 7
    7
      src/java/org/apache/fop/afp/fonts/RasterFont.java
  25. 27
    37
      src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java
  26. 52
    0
      src/java/org/apache/fop/apps/EnvironmentProfile.java
  27. 111
    0
      src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java
  28. 215
    119
      src/java/org/apache/fop/apps/FOUserAgent.java
  29. 3
    3
      src/java/org/apache/fop/apps/Fop.java
  30. 359
    0
      src/java/org/apache/fop/apps/FopConfParser.java
  31. 121
    453
      src/java/org/apache/fop/apps/FopFactory.java
  32. 744
    0
      src/java/org/apache/fop/apps/FopFactoryBuilder.java
  33. 159
    0
      src/java/org/apache/fop/apps/FopFactoryConfig.java
  34. 0
    406
      src/java/org/apache/fop/apps/FopFactoryConfigurator.java
  35. 49
    0
      src/java/org/apache/fop/apps/io/DefaultResourceResolver.java
  36. 2
    1
      src/java/org/apache/fop/apps/io/FOURIResolver.java
  37. 25
    18
      src/java/org/apache/fop/apps/io/Resource.java
  38. 10
    9
      src/java/org/apache/fop/apps/io/ResourceResolver.java
  39. 74
    0
      src/java/org/apache/fop/apps/io/URIResolverWrapper.java
  40. 6
    0
      src/java/org/apache/fop/apps/io/package.html
  41. 1
    1
      src/java/org/apache/fop/area/AreaTreeHandler.java
  42. 3
    3
      src/java/org/apache/fop/area/AreaTreeParser.java
  43. 28
    28
      src/java/org/apache/fop/cli/CommandLineOptions.java
  44. 1
    1
      src/java/org/apache/fop/cli/IFInputHandler.java
  45. 2
    17
      src/java/org/apache/fop/cli/InputHandler.java
  46. 1
    1
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  47. 4
    4
      src/java/org/apache/fop/fo/PropertyList.java
  48. 6
    6
      src/java/org/apache/fop/fo/extensions/svg/SVGElement.java
  49. 1
    1
      src/java/org/apache/fop/fo/flow/ExternalGraphic.java
  50. 1
    1
      src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
  51. 9
    0
      src/java/org/apache/fop/fonts/CIDFont.java
  52. 38
    44
      src/java/org/apache/fop/fonts/CustomFont.java
  53. 10
    18
      src/java/org/apache/fop/fonts/CustomFontCollection.java
  54. 335
    0
      src/java/org/apache/fop/fonts/DefaultFontConfig.java
  55. 190
    0
      src/java/org/apache/fop/fonts/DefaultFontConfigurator.java
  56. 42
    38
      src/java/org/apache/fop/fonts/EmbedFontInfo.java
  57. 8
    4
      src/java/org/apache/fop/fonts/FontAdder.java
  58. 12
    9
      src/java/org/apache/fop/fonts/FontCache.java
  59. 21
    13
      src/java/org/apache/fop/fonts/FontCacheManager.java
  60. 92
    0
      src/java/org/apache/fop/fonts/FontCacheManagerFactory.java
  61. 50
    0
      src/java/org/apache/fop/fonts/FontConfig.java
  62. 39
    0
      src/java/org/apache/fop/fonts/FontConfigurator.java
  63. 5
    77
      src/java/org/apache/fop/fonts/FontDetector.java
  64. 121
    0
      src/java/org/apache/fop/fonts/FontDetectorFactory.java
  65. 0
    324
      src/java/org/apache/fop/fonts/FontInfoConfigurator.java
  66. 10
    85
      src/java/org/apache/fop/fonts/FontLoader.java
  67. 40
    99
      src/java/org/apache/fop/fonts/FontManager.java
  68. 47
    32
      src/java/org/apache/fop/fonts/FontManagerConfigurator.java
  69. 51
    63
      src/java/org/apache/fop/fonts/FontReader.java
  70. 6
    42
      src/java/org/apache/fop/fonts/FontSetup.java
  71. 1
    9
      src/java/org/apache/fop/fonts/FontTriplet.java
  72. 31
    71
      src/java/org/apache/fop/fonts/LazyFont.java
  73. 6
    4
      src/java/org/apache/fop/fonts/MultiByteFont.java
  74. 4
    3
      src/java/org/apache/fop/fonts/MutableFont.java
  75. 6
    3
      src/java/org/apache/fop/fonts/SingleByteFont.java
  76. 14
    7
      src/java/org/apache/fop/fonts/apps/TTFReader.java
  77. 35
    35
      src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
  78. 5
    33
      src/java/org/apache/fop/fonts/truetype/FontFileReader.java
  79. 9
    1
      src/java/org/apache/fop/fonts/truetype/TTFFile.java
  80. 9
    9
      src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
  81. 0
    33
      src/java/org/apache/fop/fonts/type1/PFBParser.java
  82. 13
    12
      src/java/org/apache/fop/fonts/type1/PFMFile.java
  83. 18
    11
      src/java/org/apache/fop/fonts/type1/Type1FontLoader.java
  84. 1
    1
      src/java/org/apache/fop/layoutmgr/ExternalDocumentLayoutManager.java
  85. 2
    2
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  86. 5
    5
      src/java/org/apache/fop/pdf/PDFAMode.java
  87. 13
    0
      src/java/org/apache/fop/pdf/PDFEncryptionParams.java
  88. 34
    70
      src/java/org/apache/fop/pdf/PDFFactory.java
  89. 10
    10
      src/java/org/apache/fop/pdf/PDFResources.java
  90. 4
    4
      src/java/org/apache/fop/pdf/PDFXMode.java
  91. 0
    38
      src/java/org/apache/fop/render/AbstractConfigurator.java
  92. 8
    27
      src/java/org/apache/fop/render/AbstractRendererConfigurator.java
  93. 3
    3
      src/java/org/apache/fop/render/AbstractRendererMaker.java
  94. 5
    16
      src/java/org/apache/fop/render/PrintRenderer.java
  95. 67
    72
      src/java/org/apache/fop/render/PrintRendererConfigurator.java
  96. 14
    10
      src/java/org/apache/fop/render/RendererConfig.java
  97. 3
    10
      src/java/org/apache/fop/render/RendererConfigOptions.java
  98. 16
    21
      src/java/org/apache/fop/render/RendererFactory.java
  99. 1
    1
      src/java/org/apache/fop/render/XMLHandlerConfigurator.java
  100. 0
    0
      src/java/org/apache/fop/render/adobe/AdobeRendererConfigurator.java

+ 2
- 1
build.xml View File

@@ -556,6 +556,7 @@ list of possible build targets.
<include name="org/apache/fop/accessibility/StructureTreeElement.class"/>
<include name="org/apache/fop/apps/Fop.class"/>
<include name="org/apache/fop/apps/FOPException.class"/>
<include name="org/apache/fop/apps/io/**"/>
<include name="org/apache/fop/complexscripts/fonts/*.class"/>
<include name="org/apache/fop/fo/Constants.class"/>
<include name="org/apache/fop/fo/FOTreeBuilder.class"/>
@@ -578,7 +579,7 @@ list of possible build targets.
<exclude name="org/apache/fop/render/pdf/PDFRenderer.class"/>
<exclude name="org/apache/fop/render/pdf/PDFXMLHandler*"/>
<include name="org/apache/fop/render/intermediate/IFDocumentHandlerConfigurator.class"/>
<include name="org/apache/fop/render/**Configurator**"/>
<include name="org/apache/fop/render/**Config**"/>
<include name="org/apache/fop/util/AbstractPaintingState**"/>
<include name="org/apache/fop/pdf/**"/>
</patternset>

+ 5
- 8
examples/embedding/java/embedding/ExampleAWTViewer.java View File

@@ -23,19 +23,16 @@ package embedding;
import java.io.File;
import java.io.IOException;

//JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

//Avalon
import org.apache.avalon.framework.ExceptionUtil;

//FOP
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
@@ -47,7 +44,7 @@ import org.apache.fop.apps.MimeConstants;
public class ExampleAWTViewer {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Display an FO file in the AWT Preview.

+ 5
- 8
examples/embedding/java/embedding/ExampleDOM2PDF.java View File

@@ -22,25 +22,22 @@ package embedding;
// Java
import java.io.File;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
//JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;

// DOM
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

// FOP
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
@@ -54,7 +51,7 @@ import org.apache.fop.apps.MimeConstants;
public class ExampleDOM2PDF {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/** xsl-fo namespace URI */
protected static String foNS = "http://www.w3.org/1999/XSL/Format";

+ 1
- 1
examples/embedding/java/embedding/ExampleFO2JPSPrint.java View File

@@ -53,7 +53,7 @@ import org.apache.fop.render.print.PageableRenderer;
public class ExampleFO2JPSPrint {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

private DocPrintJob createDocPrintJob() {
PrintService[] services = PrintServiceLookup.lookupPrintServices(

+ 1
- 1
examples/embedding/java/embedding/ExampleFO2OldStylePrint.java View File

@@ -43,7 +43,7 @@ import org.apache.fop.apps.MimeConstants;
public class ExampleFO2OldStylePrint {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Prints an FO file using an old-style PrinterJob.

+ 5
- 8
examples/embedding/java/embedding/ExampleFO2PDF.java View File

@@ -26,19 +26,16 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

//JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;


// FOP
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FormattingResults;
import org.apache.fop.apps.MimeConstants;
@@ -50,7 +47,7 @@ import org.apache.fop.apps.PageSequenceResults;
public class ExampleFO2PDF {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Converts an FO file to a PDF file using FOP

+ 4
- 7
examples/embedding/java/embedding/ExampleFO2PDFUsingSAXParser.java View File

@@ -26,17 +26,14 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

//JAXP
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

//SAX
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

// FOP
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
@@ -49,7 +46,7 @@ import org.apache.fop.apps.MimeConstants;
public class ExampleFO2PDFUsingSAXParser {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Converts an FO file to a PDF file using FOP

+ 5
- 7
examples/embedding/java/embedding/ExampleFO2RTF.java View File

@@ -26,18 +26,16 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

//JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

// FOP
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

@@ -50,7 +48,7 @@ import org.apache.fop.apps.MimeConstants;
public class ExampleFO2RTF {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Converts an FO file to a RTF file using FOP

+ 7
- 9
examples/embedding/java/embedding/ExampleObj2PDF.java View File

@@ -21,22 +21,20 @@ package embedding;

// Java
import java.io.File;
import java.io.OutputStream;
import java.io.IOException;
import java.io.OutputStream;

// JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

// FOP
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

@@ -49,7 +47,7 @@ import embedding.model.ProjectTeam;
public class ExampleObj2PDF {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Converts a ProjectTeam object to a PDF file.

+ 4
- 6
examples/embedding/java/embedding/ExampleXML2PDF.java View File

@@ -23,15 +23,13 @@ package embedding;
import java.io.File;
import java.io.OutputStream;

//JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

//FOP
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
@@ -69,7 +67,7 @@ public class ExampleXML2PDF {
System.out.println("Transforming...");

// configure fopFactory as desired
FopFactory fopFactory = FopFactory.newInstance();
final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired

+ 6
- 8
examples/embedding/java/embedding/MultipleFO2PDF.java View File

@@ -27,20 +27,19 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

//JAXP
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

// FOP
import org.apache.commons.io.IOUtils;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FormattingResults;
import org.apache.fop.apps.MimeConstants;
@@ -55,8 +54,6 @@ import org.apache.fop.apps.PageSequenceResults;
public class MultipleFO2PDF {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();

// JAXP TransformerFactory can be reused, too
private TransformerFactory factory = TransformerFactory.newInstance();

@@ -71,6 +68,7 @@ public class MultipleFO2PDF {
*/
public FormattingResults convertFO2PDF(File fo, File pdf)
throws TransformerException, IOException, FOPException {
FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

OutputStream out = null;
Fop fop;

+ 1
- 1
examples/embedding/java/embedding/atxml/ExampleConcat.java View File

@@ -57,7 +57,7 @@ import embedding.model.ProjectTeam;
public class ExampleConcat {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Creates a sample ProjectTeam instance for this demo.

+ 1
- 1
examples/embedding/java/embedding/atxml/ExampleStamp.java View File

@@ -50,7 +50,7 @@ import embedding.model.ProjectTeam;
public class ExampleStamp {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Stamps an area tree XML file and renders it to a PDF file.

+ 1
- 1
examples/embedding/java/embedding/events/ExampleEvents.java View File

@@ -56,7 +56,7 @@ import org.apache.fop.events.model.EventSeverity;
public class ExampleEvents {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Converts an FO file to a PDF file using FOP

+ 2
- 3
examples/embedding/java/embedding/intermediate/ExampleConcat.java View File

@@ -58,7 +58,7 @@ import embedding.model.ProjectTeam;
public class ExampleConcat {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Creates a sample ProjectTeam instance for this demo.
@@ -95,8 +95,7 @@ public class ExampleConcat {
userAgent, MimeConstants.MIME_PDF);

//Create the IFSerializer to write the intermediate format
IFSerializer ifSerializer = new IFSerializer();
ifSerializer.setContext(new IFContext(userAgent));
IFSerializer ifSerializer = new IFSerializer(new IFContext(userAgent));

//Tell the IFSerializer to mimic the target format
ifSerializer.mimicDocumentHandler(targetHandler);

+ 1
- 1
examples/embedding/java/embedding/intermediate/ExampleStamp.java View File

@@ -51,7 +51,7 @@ import embedding.model.ProjectTeam;
public class ExampleStamp {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());

/**
* Stamps an intermediate file and renders it to a PDF file.

+ 2
- 0
src/java/org/apache/fop/afp/AFPDataObjectInfo.java View File

@@ -57,6 +57,8 @@ public class AFPDataObjectInfo {
/** controls the mapping of the image data into the image area */
private byte mappingOption = MappingOptionTriplet.SCALE_TO_FILL;

public static final byte DEFAULT_MAPPING_OPTION = 0x00;

/**
* Default constructor
*/

+ 2
- 3
src/java/org/apache/fop/afp/fonts/AFPBase12FontCollection.java View File

@@ -165,9 +165,8 @@ public class AFPBase12FontCollection implements FontCollection {
}

private RasterFont createReferencedRasterFont(String fontFamily) {
RasterFont font = new RasterFont(fontFamily);
font.setEmbeddable(false); //Font is assumed to be available on the target platform
return font;
boolean embeddable = false; //Font is assumed to be available on the target platform
return new RasterFont(fontFamily, embeddable);
}

}

+ 6
- 12
src/java/org/apache/fop/afp/fonts/AFPFont.java View File

@@ -35,16 +35,18 @@ import org.apache.fop.fonts.Typeface;
public abstract class AFPFont extends Typeface {

/** The font name */
protected String name;
protected final String name;

private boolean embeddable = true;
private final boolean embeddable;

/**
* Constructor for the base font requires the name.
* @param name the name of the font
* @param embeddable whether this font is to be embedded
*/
public AFPFont(String name) {
public AFPFont(String name, boolean embeddable) {
this.name = name;
this.embeddable = embeddable;
}

/** {@inheritDoc} */
@@ -89,7 +91,7 @@ public abstract class AFPFont extends Typeface {
* Returns the kerning map for the font.
* @return the kerning map
*/
public Map getKerningInfo() {
public Map<Integer, Map<Integer, Integer>> getKerningInfo() {
return null;
}

@@ -100,14 +102,6 @@ public abstract class AFPFont extends Typeface {
*/
public abstract CharacterSet getCharacterSet(int size);

/**
* Controls whether this font is embeddable or not.
* @param value true to enable embedding, false otherwise.
*/
public void setEmbeddable(boolean value) {
this.embeddable = value;
}

/**
* Indicates if this font may be embedded.
* @return True, if embedding is possible/permitted

+ 5
- 6
src/java/org/apache/fop/afp/fonts/AbstractOutlineFont.java View File

@@ -32,13 +32,12 @@ public abstract class AbstractOutlineFont extends AFPFont {
/**
* Constructor for an outline font.
*
* @param name
* the name of the font
* @param charSet
* the chracter set
* @param name the name of the font
* @param embeddable sets whether or not this font is to be embedded
* @param charSet the chracter set
*/
public AbstractOutlineFont(String name, CharacterSet charSet) {
super(name);
public AbstractOutlineFont(String name, boolean embeddable, CharacterSet charSet) {
super(name, embeddable);
this.charSet = charSet;
}


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

@@ -464,7 +464,6 @@ public abstract class CharacterSetBuilder {

}
}

return orientations.toArray(EMPTY_CSO_ARRAY);
}


+ 6
- 3
src/java/org/apache/fop/afp/fonts/DoubleByteFont.java View File

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

package org.apache.fop.afp.fonts;

import java.lang.Character.UnicodeBlock;
import java.util.HashSet;
import java.util.Set;

/**
@@ -33,7 +35,7 @@ public class DoubleByteFont extends AbstractOutlineFont {

//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.)
private static final Set IDEOGRAPHIC = new java.util.HashSet();
private static final Set<UnicodeBlock> IDEOGRAPHIC = new HashSet<UnicodeBlock>();
static {
IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS);
//IDEOGRAPHIC.add(Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT);//Java 1.5
@@ -45,10 +47,11 @@ public class DoubleByteFont extends AbstractOutlineFont {
/**
* Constructor for an double-byte outline font.
* @param name the name of the font
* @param embeddable whether or not this font is embeddable
* @param charSet the character set
*/
public DoubleByteFont(String name, CharacterSet charSet) {
super(name, charSet);
public DoubleByteFont(String name, boolean embeddable, CharacterSet charSet) {
super(name, embeddable, charSet);
}

/** {@inheritDoc} */

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

@@ -27,10 +27,11 @@ public class OutlineFont extends AbstractOutlineFont {
/**
* Construct outline font with specified name and character set.
* @param name font's name
* @param embeddable whether or not this font is embeddable
* @param charSet font's character set
*/
public OutlineFont(String name, CharacterSet charSet) {
super(name, charSet);
public OutlineFont(String name, boolean embeddable, CharacterSet charSet) {
super(name, embeddable, charSet);
}

}

+ 7
- 7
src/java/org/apache/fop/afp/fonts/RasterFont.java View File

@@ -52,8 +52,8 @@ public class RasterFont extends AFPFont {
* @param name
* the name of the font
*/
public RasterFont(String name) {
super(name);
public RasterFont(String name, boolean embeddable) {
super(name, embeddable);
}

/**
@@ -76,7 +76,7 @@ public class RasterFont extends AFPFont {
public CharacterSet getCharacterSet(int sizeInMpt) {

Integer requestedSize = Integer.valueOf(sizeInMpt);
CharacterSet csm = (CharacterSet) charSets.get(requestedSize);
CharacterSet csm = charSets.get(requestedSize);
double sizeInPt = sizeInMpt / 1000.0;

if (csm != null) {
@@ -85,7 +85,7 @@ public class RasterFont extends AFPFont {

if (substitutionCharSets != null) {
//Check first if a substitution has already been added
csm = (CharacterSet) substitutionCharSets.get(requestedSize);
csm = substitutionCharSets.get(requestedSize);
}

if (csm == null && !charSets.isEmpty()) {
@@ -95,9 +95,9 @@ public class RasterFont extends AFPFont {
SortedMap<Integer, CharacterSet> smallerSizes = charSets.headMap(requestedSize);
SortedMap<Integer, CharacterSet> largerSizes = charSets.tailMap(requestedSize);
int smallerSize = smallerSizes.isEmpty() ? 0
: ((Integer)smallerSizes.lastKey()).intValue();
: smallerSizes.lastKey().intValue();
int largerSize = largerSizes.isEmpty() ? Integer.MAX_VALUE
: ((Integer)largerSizes.firstKey()).intValue();
: largerSizes.firstKey().intValue();

Integer fontSize;
if (!smallerSizes.isEmpty()
@@ -106,7 +106,7 @@ public class RasterFont extends AFPFont {
} else {
fontSize = Integer.valueOf(largerSize);
}
csm = (CharacterSet) charSets.get(fontSize);
csm = charSets.get(fontSize);

if (csm != null) {
// Add the substitute mapping, so subsequent calls will

+ 27
- 37
src/java/org/apache/fop/afp/util/DefaultFOPResourceAccessor.java View File

@@ -19,26 +19,22 @@

package org.apache.fop.afp.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;

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

import org.apache.commons.io.IOUtils;
import java.net.URISyntaxException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.io.URIResolverWrapper;

/**
* Default implementation of the {@link ResourceAccessor} interface for use inside FOP.
*/
public class DefaultFOPResourceAccessor extends SimpleResourceAccessor {

private FOUserAgent userAgent;
private String categoryBaseURI;
private final URIResolverWrapper resolver;
private final String baseURI;

/**
* Constructor for resource to be accessed via the {@link FOUserAgent}. This contructor
@@ -49,38 +45,32 @@ public class DefaultFOPResourceAccessor extends SimpleResourceAccessor {
* @param categoryBaseURI the category base URI (may be null)
* @param baseURI the custom base URI to resolve relative URIs against (may be null)
*/
public DefaultFOPResourceAccessor(FOUserAgent userAgent, String categoryBaseURI, URI baseURI) {
super(baseURI);
this.userAgent = userAgent;
this.categoryBaseURI = categoryBaseURI;
public DefaultFOPResourceAccessor(URIResolverWrapper resolver, String baseURI) {
super(resolver.getBaseURI());
this.resolver = resolver;
this.baseURI = baseURI;
}

/** {@inheritDoc} */
public InputStream createInputStream(URI uri) throws IOException {
//Step 1: resolve against local base URI --> URI
URI resolved = resolveAgainstBase(uri);

//Step 2: resolve against the user agent --> stream
String base = (this.categoryBaseURI != null
? this.categoryBaseURI
: this.userAgent.getBaseURL());
Source src = userAgent.resolveURI(resolved.toASCIIString(), base);
public DefaultFOPResourceAccessor(URIResolverWrapper resolver) {
super(resolver.getBaseURI());
this.resolver = resolver;
this.baseURI = null;
}

if (src == null) {
throw new FileNotFoundException("Resource not found: " + uri.toASCIIString());
} else if (src instanceof StreamSource) {
StreamSource ss = (StreamSource)src;
InputStream in = ss.getInputStream();
if (in != null) {
return in;
}
if (ss.getReader() != null) {
//Don't support reader, retry using system ID below
IOUtils.closeQuietly(ss.getReader());
}
private URI getResourceURI(URI uri) {
if (baseURI == null) {
return uri;
}
try {
URI baseURI = URIResolverWrapper.getBaseURI(this.baseURI);
return baseURI.resolve(uri);
} catch (URISyntaxException use) {
return uri;
}
URL url = new URL(src.getSystemId());
return url.openStream();
}

/** {@inheritDoc} */
public InputStream createInputStream(URI uri) throws IOException {
return resolver.resolveIn(getResourceURI(uri));
}
}

+ 52
- 0
src/java/org/apache/fop/apps/EnvironmentProfile.java View File

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

import java.net.URI;

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

/**
* The environment profile represents the restrictions and allowances that FOP is
*/
public interface EnvironmentProfile {

/**
* Returns resource resolver for this environment.
*
* @return the resource resolver
*/
ResourceResolver getResourceResolver();

/**
* Returns the font manager with restrictions/allowances set for this environment.
*
* @return the font manager
*/
FontManager getFontManager();

/**
* The default base URI used for resolving URIs.
*
* @return the default base URI
*/
URI getDefaultBaseURI();
}

+ 111
- 0
src/java/org/apache/fop/apps/EnvironmentalProfileFactory.java View File

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

import java.net.URI;

import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.FontCacheManager;
import org.apache.fop.fonts.FontCacheManagerFactory;
import org.apache.fop.fonts.FontDetector;
import org.apache.fop.fonts.FontDetectorFactory;
import org.apache.fop.fonts.FontManager;

/**
* Creates an {@link EnvironmentProfile} that sets the environment in which a FOP instance is run.
*/
public final class EnvironmentalProfileFactory {

private EnvironmentalProfileFactory() {
};

/**
* Creates the default environment that FOP is invoked in. This default profile has no
* operational restrictions for FOP.
*
* @param defaultBaseUri the default base URI for resolving resource URIs
* @param resourceResolver the resource resolver
* @return the environment profile
*/
public static EnvironmentProfile createDefault(URI defaultBaseUri,
ResourceResolver resourceResolver) {
return new Profile(defaultBaseUri, resourceResolver,
createFontManager(defaultBaseUri, resourceResolver,
FontDetectorFactory.createDefault(),
FontCacheManagerFactory.createDefault()));
}

/**
* Creates an IO-restricted environment for FOP by disabling some of the environment-specific
* functionality within FOP.
*
* @param defaultBaseUri the default base URI for resolving resource URIs
* @param resourceResolver the resource resolver
* @return the environment profile
*/
public static EnvironmentProfile createRestrictedIO(URI defaultBaseUri,
ResourceResolver resourceResolver) {
return new Profile(defaultBaseUri, resourceResolver,
createFontManager(defaultBaseUri, resourceResolver,
FontDetectorFactory.createDisabled(),
FontCacheManagerFactory.createDisabled()));
}

private static final class Profile implements EnvironmentProfile {

private final ResourceResolver resourceResolver;

private final FontManager fontManager;

private final URI defaultBaseURI;

private Profile(URI defaultBaseURI, ResourceResolver resourceResolver,
FontManager fontManager) {
if (defaultBaseURI == null) {
throw new IllegalArgumentException("Default base URI must not be null");
}
if (resourceResolver == null) {
throw new IllegalArgumentException("URI Resolver must not be null");
}
this.defaultBaseURI = defaultBaseURI;
this.resourceResolver = resourceResolver;
this.fontManager = fontManager;
}

public ResourceResolver getResourceResolver() {
return resourceResolver;
}

public FontManager getFontManager() {
return fontManager;
}

public URI getDefaultBaseURI() {
return defaultBaseURI;
}
}

private static FontManager createFontManager(URI defaultBaseUri, ResourceResolver resourceResolver,
FontDetector fontDetector, FontCacheManager fontCacheManager) {
return new FontManager(new URIResolverWrapper(defaultBaseUri, resourceResolver), fontDetector,
fontCacheManager);
}
}

+ 215
- 119
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -21,37 +21,54 @@ package org.apache.fop.apps;

// Java
import java.io.File;
import java.net.MalformedURLException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.Map;

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

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
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.ImageSessionContext;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
import org.apache.xmlgraphics.util.UnitConv;
import org.apache.xmlgraphics.util.uri.CommonURIResolver;

import org.apache.fop.Version;
import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.events.DefaultEventBroadcaster;
import org.apache.fop.events.Event;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.events.EventListener;
import org.apache.fop.events.FOPEventListenerProxy;
import org.apache.fop.events.LoggingEventListener;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererConfig;
import org.apache.fop.render.RendererConfig.RendererConfigParser;
import org.apache.fop.render.RendererConfigOptions;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.util.ColorSpaceCache;
import org.apache.fop.util.ContentHandlerFactoryRegistry;

/**
* This is the user agent for FOP.
@@ -75,24 +92,13 @@ import org.apache.fop.render.intermediate.IFDocumentHandler;
*/
public class FOUserAgent {

/** Defines the default target resolution (72dpi) for FOP */
public static final float DEFAULT_TARGET_RESOLUTION
= FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;

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

private FopFactory factory;

/**
* The base URL for all URL resolutions, especially for
* external-graphics.
*/
private String base = null;
private final FopFactory factory;

/** A user settable URI Resolver */
private URIResolver uriResolver = null;
private final URIResolverWrapper newUriResolver;

private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION;
private Map rendererOptions = new java.util.HashMap();
private File outputFile = null;
private IFDocumentHandler documentHandlerOverride = null;
@@ -131,7 +137,7 @@ public class FOUserAgent {
private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() {

public ImageContext getParentContext() {
return getFactory();
return factory;
}

public float getTargetResolution() {
@@ -150,19 +156,56 @@ public class FOUserAgent {
* @param factory the factory that provides environment-level information
* @see org.apache.fop.apps.FopFactory
*/
public FOUserAgent(FopFactory factory) {
if (factory == null) {
throw new NullPointerException("The factory parameter must not be null");
}
FOUserAgent(FopFactory factory, URIResolverWrapper uriResolver) {
this.factory = factory;
setBaseURL(factory.getBaseURL());
this.newUriResolver = uriResolver;
setTargetResolution(factory.getTargetResolution());
setAccessibility(factory.isAccessibilityEnabled());
}

/** @return the associated FopFactory instance */
public FopFactory getFactory() {
return this.factory;
/**
* Returns a new {@link Fop} instance. Use this factory method if your output type
* 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()}.
* <p>
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can
* use the constants defined in {@link MimeConstants}.
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
* @param stream the output stream
* @return the new Fop instance
* @throws FOPException when the constructor fails
*/
public Fop newFop(String outputFormat, OutputStream stream) throws FOPException {
return new Fop(outputFormat, this, stream);
}


/**
* 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()}.
* <p>
* MIME types are used to select the output format (ex. "application/pdf" for PDF). You can
* use the constants defined in {@link MimeConstants}.
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
* @return the new Fop instance
* @throws FOPException when the constructor fails
*/
public Fop newFop(String outputFormat) throws FOPException {
return newFop(outputFormat, null);
}


/**
* Returns the URI Resolver.
*
* @return the URI resolver
*/
public URIResolverWrapper getNewURIResolver() {
return newUriResolver;
}

// ---------------------------------------------- rendering-run dependent stuff
@@ -345,48 +388,13 @@ public class FOUserAgent {
}

/**
* Sets the base URL.
* @param baseUrl base URL
*/
public void setBaseURL(String baseUrl) {
this.base = baseUrl;
}

/**
* Sets font base URL.
* @param fontBaseUrl font base URL
* @deprecated Use {@link FontManager#setFontBaseURL(String)} instead.
*/
public void setFontBaseURL(String fontBaseUrl) {
try {
getFactory().getFontManager().setFontBaseURL(fontBaseUrl);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e.getMessage());
}
}

/**
* Returns the base URL.
* @return the base URL
*/
public String getBaseURL() {
return this.base;
}

/**
* Sets the URI Resolver.
* @param resolver the new URI resolver
*/
public void setURIResolver(URIResolver resolver) {
this.uriResolver = resolver;
}

/**
* Returns the URI Resolver.
* @return the URI Resolver
*/
public URIResolver getURIResolver() {
return this.uriResolver;
* Gets the renderer options given an interface representing renderer configuration options.
*
* @param option the renderer option
* @return the value
*/
public Object getRendererOption(RendererConfigOptions option) {
return rendererOptions.get(option.getName());
}

/**
@@ -396,39 +404,27 @@ public class FOUserAgent {
* @param uri URI to access
* @return A {@link javax.xml.transform.Source} object, or null if the URI
* cannot be resolved.
* @see org.apache.fop.apps.FOURIResolver
* @see org.apache.fop.apps.io.FOURIResolver
*/
public Source resolveURI(String uri) {
return resolveURI(uri, getBaseURL());
}

/**
* Attempts to resolve the given URI.
* Will use the configured resolver and if not successful fall back
* to the default resolver.
* @param href URI to access
* @param base the base URI to resolve against
* @return A {@link javax.xml.transform.Source} object, or null if the URI
* cannot be resolved.
* @see org.apache.fop.apps.FOURIResolver
*/
public Source resolveURI(String href, String base) {
Source source = null;
//RFC 2397 data URLs don't need to be resolved, just decode them through FOP's default
//URIResolver.
boolean bypassURIResolution = href.startsWith("data:");
if (!bypassURIResolution && uriResolver != null) {
try {
source = uriResolver.resolve(href, base);
} catch (TransformerException te) {
log.error("Attempt to resolve URI '" + href + "' failed: ", te);
// TODO: What do we want to do when resources aren't found???
try {
Source src;
// Have to do this so we can resolve data URIs
if (uri.startsWith("data:")) {
CommonURIResolver uriResolver = new CommonURIResolver();
src = uriResolver.resolve(uri, "");
} else {
URI actualUri = URIResolverWrapper.cleanURI(uri);
src = new StreamSource(newUriResolver.resolveIn(actualUri));
src.setSystemId(uri);
}
return src;
} catch (URISyntaxException use) {
return null;
} catch (IOException ioe) {
return null;
}
if (source == null) {
// URI Resolver not configured or returned null, use default resolver from the factory
source = getFactory().resolveURI(href, base);
}
return source;
}

/**
@@ -497,16 +493,6 @@ public class FOUserAgent {
// ---------------------------------------------- environment-level stuff
// (convenience access to FopFactory methods)

/**
* Returns the font base URL.
* @return the font base URL
* @deprecated Use {@link FontManager#getFontBaseURL()} instead. This method is not used by FOP.
*/
public String getFontBaseURL() {
String fontBase = getFactory().getFontManager().getFontBaseURL();
return fontBase != null ? fontBase : getBaseURL();
}

/**
* Returns the conversion factor from pixel units to millimeters. This
* depends on the desired source resolution.
@@ -514,12 +500,12 @@ public class FOUserAgent {
* @see #getSourceResolution()
*/
public float getSourcePixelUnitToMillimeter() {
return getFactory().getSourcePixelUnitToMillimeter();
return factory.getSourcePixelUnitToMillimeter();
}

/** @return the resolution for resolution-dependant input */
public float getSourceResolution() {
return getFactory().getSourceResolution();
return factory.getSourceResolution();
}

/**
@@ -530,7 +516,7 @@ public class FOUserAgent {
* @see FopFactory#getPageHeight()
*/
public String getPageHeight() {
return getFactory().getPageHeight();
return factory.getPageHeight();
}

/**
@@ -541,7 +527,7 @@ public class FOUserAgent {
* @see FopFactory#getPageWidth()
*/
public String getPageWidth() {
return getFactory().getPageWidth();
return factory.getPageWidth();
}

/**
@@ -550,7 +536,7 @@ public class FOUserAgent {
* @see FopFactory#validateStrictly()
*/
public boolean validateStrictly() {
return getFactory().validateStrictly();
return factory.validateStrictly();
}

/**
@@ -559,21 +545,21 @@ public class FOUserAgent {
* @see FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()
*/
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() {
return getFactory().isBreakIndentInheritanceOnReferenceAreaBoundary();
return factory.isBreakIndentInheritanceOnReferenceAreaBoundary();
}

/**
* @return the RendererFactory
*/
public RendererFactory getRendererFactory() {
return getFactory().getRendererFactory();
return factory.getRendererFactory();
}

/**
* @return the XML handler registry
*/
public XMLHandlerRegistry getXMLHandlerRegistry() {
return getFactory().getXMLHandlerRegistry();
return factory.getXMLHandlerRegistry();
}

/**
@@ -662,12 +648,53 @@ public class FOUserAgent {
}

/**
* Control whether complex script features should be enabled
* Returns the renderer configuration object for a particular MIME type.
*
* @param useComplexScriptFeatures true if FOP is to use complex script features
* @param mimeType the config MIME type
* @param configCreator the parser for creating the config for the first run of parsing.
* @return the renderer configuration object
* @throws FOPException if an error occurs when creating the config object
*/
public void setComplexScriptFeaturesEnabled(boolean useComplexScriptFeatures) {
factory.setComplexScriptFeaturesEnabled ( useComplexScriptFeatures );
public RendererConfig getRendererConfig(String mimeType, RendererConfigParser configCreator)
throws FOPException {
return factory.getRendererConfig(this, getRendererConfiguration(mimeType), configCreator);
}

/**
* Returns a {@link Configuration} object for which contains renderer configuration for a given
* MIME type.
*
* @param mimeType the renderer configuration MIME type
* @return the configuration object
*/
public Configuration getRendererConfiguration(String mimeType) {
Configuration cfg = getUserConfig();
String type = "renderer";
String mime = "mime";
if (cfg == null) {
if (log.isDebugEnabled()) {
log.debug("userconfig is null");
}
return null;
}

Configuration userConfig = null;

Configuration[] cfgs = cfg.getChild(type + "s").getChildren(type);
for (int i = 0; i < cfgs.length; ++i) {
Configuration child = cfgs[i];
try {
if (child.getAttribute(mime).equals(mimeType)) {
userConfig = child;
break;
}
} catch (ConfigurationException e) {
// silently pass over configurations without mime type
}
}
log.debug((userConfig == null ? "No u" : "U")
+ "ser configuration found for MIME type " + mimeType);
return userConfig;
}

/**
@@ -713,5 +740,74 @@ public class FOUserAgent {
public StructureTreeEventHandler getStructureTreeEventHandler() {
return this.structureTreeEventHandler;
}

/** @see FopFactory#getLayoutManagerMakerOverride() */
public LayoutManagerMaker getLayoutManagerMakerOverride() {
return factory.getLayoutManagerMakerOverride();
}

/** @see FopFactory#getContentHandlerFactoryRegistry() */
public ContentHandlerFactoryRegistry getContentHandlerFactoryRegistry() {
return factory.getContentHandlerFactoryRegistry();
}

/** @see FopFactory#getImageManager() */
public ImageManager getImageManager() {
return factory.getImageManager();
}

/** @see FopFactory#getElementMappingRegistry() */
public ElementMappingRegistry getElementMappingRegistry() {
return factory.getElementMappingRegistry();
}

/** @see FopFactory#getFontManager() */
public FontManager getFontManager() {
return factory.getFontManager();
}

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

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

/**
* Get the user configuration.
* @return the user configuration
*/
public Configuration getUserConfig() {
return factory.getUserConfig();
}

/** @return the image handler registry */
public ImageHandlerRegistry getImageHandlerRegistry() {
return factory.getImageHandlerRegistry();
}

/** TODO: javadoc*/
public ColorSpaceCache getColorSpaceCache() {
return factory.getColorSpaceCache();
}

/** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */
public HyphenationTreeResolver getHyphenationTreeResolver() {
return factory.getHyphenationTreeResolver();
}

public Map<String, String> getHyphPatNames() {
return factory.getHyphPatNames();
}
}


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

@@ -66,12 +66,12 @@ public class Fop {
* @throws FOPException if setting up the DefaultHandler fails
*/
Fop(String outputFormat, FOUserAgent ua, OutputStream stream) throws FOPException {
if (ua == null) {
throw new FOPException("Cannot create a new Fop instance without a User Agent.");
}
this.outputFormat = outputFormat;

foUserAgent = ua;
if (foUserAgent == null) {
foUserAgent = FopFactory.newInstance().newFOUserAgent();
}

this.stream = stream;


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

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

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.xml.sax.SAXException;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.commons.logging.Log;
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.fop.apps.io.DefaultResourceResolver;
import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.hyphenation.HyphenationTreeCache;
import org.apache.fop.util.LogUtil;

/**
* Parses the FOP configuration file and returns a {@link FopFactoryBuilder} which builds a
* {@link FopFactory}.
*/
public class FopConfParser {

private static final String PREFER_RENDERER = "prefer-renderer";

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

private final FopFactoryBuilder fopFactoryBuilder;

/**
* Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI
* must be given as a fall-back mechanism for URI resolution.
*
* @param fopConfStream the fop conf input stream
* @param enviro the profile of the FOP deployment environment
* @throws SAXException if a SAX error was thrown parsing the FOP conf
* @throws IOException if an I/O error is thrown while parsing the FOP conf
*/
public FopConfParser(InputStream fopConfStream, EnvironmentProfile enviro)
throws SAXException, IOException {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
Configuration cfg;
try {
cfg = cfgBuilder.build(fopConfStream);
} catch (ConfigurationException e) {
throw new FOPException(e);
}
// The default base URI is taken from the directory in which the fopConf resides
fopFactoryBuilder = new FopFactoryBuilder(enviro).setConfiguration(cfg);
configure(enviro.getDefaultBaseURI(), enviro.getResourceResolver(), cfg);
}

/**
* Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI
* must be given as a fall-back mechanism for URI resolution.
*
* @param fopConfStream the fop conf input stream
* @param defaultBaseURI the default base URI
* @param resolver the URI resolver
* @throws SAXException if a SAX error was thrown parsing the FOP conf
* @throws IOException if an I/O error is thrown while parsing the FOP conf
*/
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI,
ResourceResolver resolver) throws SAXException, IOException {
this(fopConfStream, EnvironmentalProfileFactory.createDefault(defaultBaseURI, resolver));
}

/**
* Constructor that takes the FOP conf in the form of an {@link InputStream}. A default base URI
* must be given as a fall-back mechanism for URI resolution. The default URI resolvers is used.
*
* @param fopConfStream the fop conf input stream
* @param defaultBaseURI the default base URI
* @throws SAXException if a SAX error was thrown parsing the FOP conf
* @throws IOException if an I/O error is thrown while parsing the FOP conf
*/
public FopConfParser(InputStream fopConfStream, URI defaultBaseURI) throws SAXException,
IOException {
this(fopConfStream, defaultBaseURI, new DefaultResourceResolver());
}

/**
* Constructor that takes the FOP conf and uses the default URI resolver.
*
* @param fopConfFile the FOP conf file
* @throws SAXException if a SAX error was thrown parsing the FOP conf
* @throws IOException if an I/O error is thrown while parsing the FOP conf
*/
public FopConfParser(File fopConfFile) throws SAXException, IOException {
this(fopConfFile, new DefaultResourceResolver());
}

/**
* Constructor that parses the FOP conf and uses the URI resolver given.
*
* @param fopConfFile the FOP conf file
* @param resolver the URI resolver
* @throws SAXException if a SAX error was thrown parsing the FOP conf
* @throws IOException if an I/O error is thrown while parsing the FOP conf
*/
public FopConfParser(File fopConfFile, ResourceResolver resolver)
throws SAXException, IOException {
this(new FileInputStream(fopConfFile),
fopConfFile.getAbsoluteFile().getParentFile().toURI(), resolver);
}

private void configure(final URI defaultBaseURI, final ResourceResolver resolver,
Configuration cfg) throws FOPException {
if (log.isDebugEnabled()) {
log.debug("Initializing FopFactory Configuration");
}

// TODO: This makes this variable both strict FO and user-config validation, is that right?
boolean strict = false;
// strict fo validation
if (cfg.getChild("strict-validation", false) != null) {
try {
strict = cfg.getChild("strict-validation").getValueAsBoolean();
fopFactoryBuilder.setStrictUserConfigValidation(strict);
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, false);
}
}

if (cfg.getChild("accessibility", false) != null) {
try {
fopFactoryBuilder.setAccessibility(cfg.getChild("accessibility").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, false);
}
}

// base definitions for relative path resolution
if (cfg.getChild("base", false) != null) {
try {
URI confUri = URIResolverWrapper.getBaseURI(cfg.getChild("base").getValue(null));
fopFactoryBuilder.setBaseURI(defaultBaseURI.resolve(confUri));
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, strict);
}
}

if (cfg.getChild("hyphenation-base", false) != null) {
String path = cfg.getChild("hyphenation-base").getValue(null);
if (defaultBaseURI != null) {
try {
URI hyphBaseUri = URIResolverWrapper.getBaseURI(path);
fopFactoryBuilder.setHyphenationBaseURI(defaultBaseURI.resolve(hyphBaseUri));
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, strict);
}
}
}

// renderer options
if (cfg.getChild("source-resolution", false) != null) {
float srcRes = cfg.getChild("source-resolution").getValueAsFloat(
FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION);
fopFactoryBuilder.setSourceResolution(srcRes);
if (log.isDebugEnabled()) {
log.debug("source-resolution set to: " + srcRes + "dpi");
}
}
if (cfg.getChild("target-resolution", false) != null) {
float targetRes = cfg.getChild("target-resolution").getValueAsFloat(
FopFactoryConfig.DEFAULT_TARGET_RESOLUTION);
fopFactoryBuilder.setTargetResolution(targetRes);
if (log.isDebugEnabled()) {
log.debug("target-resolution set to: " + targetRes + "dpi");
}
}
if (cfg.getChild("break-indent-inheritance", false) != null) {
try {
fopFactoryBuilder.setBreakIndentInheritanceOnReferenceAreaBoundary(
cfg.getChild("break-indent-inheritance").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}
Configuration pageConfig = cfg.getChild("default-page-settings");
if (pageConfig.getAttribute("height", null) != null) {
String pageHeight = pageConfig.getAttribute("height",
FopFactoryConfig.DEFAULT_PAGE_HEIGHT);
fopFactoryBuilder.setPageHeight(pageHeight);
if (log.isInfoEnabled()) {
log.info("Default page-height set to: " + pageHeight);
}
}
if (pageConfig.getAttribute("width", null) != null) {
String pageWidth = pageConfig.getAttribute("width",
FopFactoryConfig.DEFAULT_PAGE_WIDTH);
fopFactoryBuilder.setPageWidth(pageWidth);
if (log.isInfoEnabled()) {
log.info("Default page-width set to: " + pageWidth);
}
}

if (cfg.getChild("complex-scripts") != null) {
Configuration csConfig = cfg.getChild("complex-scripts");
fopFactoryBuilder.setComplexScriptFeatures(!csConfig.getAttributeAsBoolean("disabled",
false));
}

setHyphPatNames(cfg, fopFactoryBuilder, strict);

// prefer Renderer over IFDocumentHandler
if (cfg.getChild(PREFER_RENDERER, false) != null) {
try {
fopFactoryBuilder.setPreferRenderer(
cfg.getChild(PREFER_RENDERER).getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}

// configure font manager
new FontManagerConfigurator(cfg, fopFactoryBuilder.getBaseUri(), resolver).configure(
fopFactoryBuilder.getFontManager(), strict);

// configure image loader framework
configureImageLoading(cfg.getChild("image-loading", false), strict);
}

private void setHyphPatNames(Configuration cfg, FopFactoryBuilder builder, boolean strict)
throws FOPException {
Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern");
if (hyphPatConfig.length != 0) {
Map<String, String> hyphPatNames = new HashMap<String, String>();
for (int i = 0; i < hyphPatConfig.length; ++i) {
String lang;
String country;
String filename;
StringBuffer error = new StringBuffer();
String location = hyphPatConfig[i].getLocation();

lang = hyphPatConfig[i].getAttribute("lang", null);
if (lang == null) {
addError("The lang attribute of a hyphenation-pattern configuration"
+ " element must exist (" + location + ")", error);
} else if (!lang.matches("[a-zA-Z]{2}")) {
addError("The lang attribute of a hyphenation-pattern configuration"
+ " element must consist of exactly two letters ("
+ location + ")", error);
}
lang = lang.toLowerCase();

country = hyphPatConfig[i].getAttribute("country", null);
if ("".equals(country)) {
country = null;
}
if (country != null) {
if (!country.matches("[a-zA-Z]{2}")) {
addError("The country attribute of a hyphenation-pattern configuration"
+ " element must consist of exactly two letters ("
+ location + ")", error);
}
country = country.toUpperCase();
}

filename = hyphPatConfig[i].getValue(null);
if (filename == null) {
addError("The value of a hyphenation-pattern configuration"
+ " element may not be empty (" + location + ")", error);
}

if (error.length() != 0) {
LogUtil.handleError(log, error.toString(), strict);
continue;
}

String llccKey = HyphenationTreeCache.constructLlccKey(lang, country);
hyphPatNames.put(llccKey, filename);
if (log.isDebugEnabled()) {
log.debug("Using hyphenation pattern filename " + filename
+ " for lang=\"" + lang + "\""
+ (country != null ? ", country=\"" + country + "\"" : ""));
}
}
builder.setHyphPatNames(hyphPatNames);
}
}

private static void addError(String message, StringBuffer error) {
if (error.length() != 0) {
error.append(". ");
}
error.append(message);
}

private void configureImageLoading(Configuration parent, boolean strict) throws FOPException {
if (parent == null) {
return;
}
ImageImplRegistry registry = fopFactoryBuilder.getImageManager().getRegistry();
Configuration[] penalties = parent.getChildren("penalty");
try {
for (int i = 0, c = penalties.length; i < c; i++) {
Configuration penaltyCfg = penalties[i];
String className = penaltyCfg.getAttribute("class");
String value = penaltyCfg.getAttribute("value");
Penalty p = null;
if (value.toUpperCase().startsWith("INF")) {
p = Penalty.INFINITE_PENALTY;
} else {
try {
p = Penalty.toPenalty(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
LogUtil.handleException(log, nfe, strict);
}
}
if (p != null) {
registry.setAdditionalPenalty(className, p);
}
}
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}

/**
* Returns the {@link FopFactoryBuilder}.
*
* @return the object for configuring the {@link FopFactory}
*/
public FopFactoryBuilder getFopFactoryBuilder() {
return fopFactoryBuilder;
}
}

+ 121
- 453
src/java/org/apache/fop/apps/FopFactory.java View File

@@ -21,18 +21,15 @@ package org.apache.fop.apps;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;

import org.xml.sax.SAXException;

@@ -44,13 +41,15 @@ import org.apache.xmlgraphics.image.loader.ImageContext;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fonts.FontCache;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.layoutmgr.LayoutManagerMaker;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.RendererConfig;
import org.apache.fop.render.RendererConfig.RendererConfigParser;
import org.apache.fop.render.RendererFactory;
import org.apache.fop.render.XMLHandlerRegistry;
import org.apache.fop.util.ColorSpaceCache;
@@ -59,57 +58,48 @@ import org.apache.fop.util.ContentHandlerFactoryRegistry;
/**
* Factory class which instantiates new Fop and FOUserAgent instances. This
* class also holds environmental information and configuration used by FOP.
* Information that may potentially be different for each rendering run can be
* Information that may potentially be different for each renderingq run can be
* found and managed in the FOUserAgent.
*/
public class FopFactory implements ImageContext {
public final class FopFactory implements ImageContext {

/** logger instance */
private static Log log = LogFactory.getLog(FopFactory.class);

/** Factory for Renderers and FOEventHandlers */
private RendererFactory rendererFactory;
private final RendererFactory rendererFactory;

/** Registry for XML handlers */
private XMLHandlerRegistry xmlHandlers;
private final XMLHandlerRegistry xmlHandlers;

/** Registry for image handlers */
private ImageHandlerRegistry imageHandlers;
private final ImageHandlerRegistry imageHandlers;

/** The registry for ElementMapping instances */
private ElementMappingRegistry elementMappingRegistry;
private final ElementMappingRegistry elementMappingRegistry;

/** The registry for ContentHandlerFactory instance */
private ContentHandlerFactoryRegistry contentHandlerFactoryRegistry
= new ContentHandlerFactoryRegistry();
private final ContentHandlerFactoryRegistry contentHandlerFactoryRegistry
= new ContentHandlerFactoryRegistry();

/** The resolver for user-supplied hyphenation patterns */
private HyphenationTreeResolver hyphResolver = null;
private final ColorSpaceCache colorSpaceCache;

private ColorSpaceCache colorSpaceCache = null;
private final FopFactoryConfig config;

/** Image manager for loading and caching image objects */
private ImageManager imageManager;
private final URIResolverWrapper uriResolverWrapper;

/** Font manager for font substitution, autodetection and caching **/
private FontManager fontManager;
private final Map<String, RendererConfig> rendererConfig;

/** Configuration layer used to configure fop */
private FopFactoryConfigurator config = null;

/**
* The base URL for all URL resolutions, especially for
* external-graphics.
*/
private String base = null;

/**
* Controls if accessibility is turned on or off
*/
private boolean accessibility = false;

/** The base URL for all hyphen URL resolutions. */
private String hyphenBase = null;
private FopFactory(FopFactoryConfig config) {
this.config = config;
this.uriResolverWrapper = new URIResolverWrapper(config.getBaseURI(), config.getNewURIResolver());
this.elementMappingRegistry = new ElementMappingRegistry(this);
this.colorSpaceCache = new ColorSpaceCache(config.getURIResolver());
this.rendererFactory = new RendererFactory(config.preferRenderer());
this.xmlHandlers = new XMLHandlerRegistry();
this.imageHandlers = new ImageHandlerRegistry();
rendererConfig = new HashMap<String, RendererConfig>();
}

/**
* Map of configured names of hyphenation pattern file names: ll_CC => name
@@ -121,73 +111,52 @@ public class FopFactory implements ImageContext {
* input XSL violates that FO's content model. This is the default
* behavior for FOP. However, this flag, if set, provides the user the
* ability for FOP to halt on all content model violations if desired.
* Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object.
*
* @param config the fop configuration
* @return the requested FopFactory instance.
*/
private boolean strictFOValidation = FopFactoryConfigurator.DEFAULT_STRICT_FO_VALIDATION;
public static FopFactory newInstance(FopFactoryConfig config) {
return new FopFactory(config);
}

/**
* FOP will validate the contents of the user configuration strictly
* (e.g. base-urls and font urls/paths).
* Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object that
* is created when the fopConf is parsed.
*
* @param fopConf the fop conf configuration file to parse
* @return the requested FopFactory instance.
* @throws IOException
* @throws SAXException
*/
private boolean strictUserConfigValidation
= FopFactoryConfigurator.DEFAULT_STRICT_USERCONFIG_VALIDATION;

/** Source resolution in dpi */
private float sourceResolution = FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION;

/** Target resolution in dpi */
private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;

/** Page height */
private String pageHeight = FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT;

/** Page width */
private String pageWidth = FopFactoryConfigurator.DEFAULT_PAGE_WIDTH;

/** Complex scripts support enabled */
private boolean useComplexScriptFeatures
= FopFactoryConfigurator.DEFAULT_COMPLEX_SCRIPT_FEATURES;

/** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */
private boolean breakIndentInheritanceOnReferenceAreaBoundary
= FopFactoryConfigurator.DEFAULT_BREAK_INDENT_INHERITANCE;

/** Optional overriding LayoutManagerMaker */
private LayoutManagerMaker lmMakerOverride = null;

private Set<String> ignoredNamespaces;

private FOURIResolver foURIResolver;
public static FopFactory newInstance(File fopConf) throws SAXException, IOException {
return new FopConfParser(fopConf).getFopFactoryBuilder().build();
}

/**
* Main constructor.
* Returns a new FopFactory instance that is configured only by the default configuration
* parameters.
*
* @param baseURI the base URI to resolve resource URIs against
* @return the requested FopFactory instance.
*/
protected FopFactory() {
this.config = new FopFactoryConfigurator(this);
this.elementMappingRegistry = new ElementMappingRegistry(this);
this.foURIResolver = new FOURIResolver(validateUserConfigStrictly());
this.fontManager = new FontManager() {

/** {@inheritDoc} */
@Override
public void setFontBaseURL(String fontBase) throws MalformedURLException {
super.setFontBaseURL(getFOURIResolver().checkBaseURL(fontBase));
}

};
this.colorSpaceCache = new ColorSpaceCache(foURIResolver);
this.imageManager = new ImageManager(this);
this.rendererFactory = new RendererFactory();
this.xmlHandlers = new XMLHandlerRegistry();
this.imageHandlers = new ImageHandlerRegistry();
this.ignoredNamespaces = new java.util.HashSet<String>();
public static FopFactory newInstance(URI baseURI) {
return new FopFactoryBuilder(baseURI).build();
}

/**
* Returns a new FopFactory instance.
* Returns a new FopFactory instance that is configured using the {@link FopFactoryConfig} object that
* is created when the fopConf is parsed.
*
* @param baseURI the base URI to resolve resource URIs against
* @param confStream the fop conf configuration stream to parse
* @return the requested FopFactory instance.
* @throws SAXException
* @throws IOException
*/
public static FopFactory newInstance() {
return new FopFactory();
public static FopFactory newInstance(URI baseURI, InputStream confStream) throws SAXException,
IOException {
return new FopConfParser(confStream, baseURI).getFopFactoryBuilder().build();
}

/**
@@ -198,34 +167,12 @@ public class FopFactory implements ImageContext {
* @throws FOPException
*/
public FOUserAgent newFOUserAgent() {
FOUserAgent userAgent = new FOUserAgent(this);
FOUserAgent userAgent = new FOUserAgent(this, uriResolverWrapper);
return userAgent;
}

/**
* Sets accessibility support.
*
* @param value <code>true</code> to enable accessibility, <code>false</code> otherwise
*/
void setAccessibility(boolean value) {
this.accessibility = value;
}

boolean isAccessibilityEnabled() {
return accessibility;
}

/**
* Sets complex script support.
* @param value <code>true</code> to enable complex script features,
* <code>false</code> otherwise
*/
void setComplexScriptFeaturesEnabled(boolean value) {
this.useComplexScriptFeatures = value;
}

boolean isComplexScriptFeaturesEnabled() {
return useComplexScriptFeatures;
return config.isComplexScriptFeaturesEnabled();
}

/**
@@ -239,7 +186,7 @@ public class FopFactory implements ImageContext {
* @throws FOPException when the constructor fails
*/
public Fop newFop(String outputFormat) throws FOPException {
return newFop(outputFormat, newFOUserAgent());
return newFOUserAgent().newFop(outputFormat);
}

/**
@@ -256,7 +203,7 @@ public class FopFactory implements ImageContext {
* @throws FOPException when the constructor fails
*/
public Fop newFop(String outputFormat, FOUserAgent userAgent) throws FOPException {
return newFop(outputFormat, userAgent, null);
return userAgent.newFop(outputFormat, null);
}

/**
@@ -271,7 +218,7 @@ public class FopFactory implements ImageContext {
* @throws FOPException when the constructor fails
*/
public Fop newFop(String outputFormat, OutputStream stream) throws FOPException {
return newFop(outputFormat, newFOUserAgent(), stream);
return newFOUserAgent().newFop(outputFormat, stream);
}

/**
@@ -290,11 +237,8 @@ public class FopFactory implements ImageContext {
* @throws FOPException when the constructor fails
*/
public Fop newFop(String outputFormat, FOUserAgent userAgent, OutputStream stream)
throws FOPException {
if (userAgent == null) {
throw new NullPointerException("The userAgent parameter must not be null!");
}
return new Fop(outputFormat, userAgent, stream);
throws FOPException {
return userAgent.newFop(outputFormat, stream);
}

/**
@@ -343,11 +287,28 @@ public class FopFactory implements ImageContext {
}

/**
* Returns the image manager.
* @return the image manager
*/
public ImageManager getImageManager() {
return this.imageManager;
* Returns the renderer configuration object for a specific renderer given the parser and
* configuration to read. The renderer config is cached such that the {@link Configuration} is
* only parsed once per renderer, per FopFactory instance.
*
* @param userAgent the user agent
* @param cfg the configuration to be parsed
* @param configCreator the parser that creates the config object
* @return the config object
* @throws FOPException when an error occurs while creating the configuration object
*/
public RendererConfig getRendererConfig(FOUserAgent userAgent, Configuration cfg,
RendererConfigParser configCreator) throws FOPException {
RendererConfig config = rendererConfig.get(configCreator.getMimeType());
if (config == null) {
try {
config = configCreator.build(userAgent, cfg);
rendererConfig.put(configCreator.getMimeType(), config);
} catch (Exception e) {
throw new FOPException(e);
}
}
return config;
}

/**
@@ -359,143 +320,41 @@ public class FopFactory implements ImageContext {
}

/**
* Sets an explicit LayoutManagerMaker instance which overrides the one
* defined by the AreaTreeHandler.
* @param lmMaker the LayoutManagerMaker instance
*/
public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) {
this.lmMakerOverride = lmMaker;
}

/**
* Returns the overriding LayoutManagerMaker instance, if any.
* @return the overriding LayoutManagerMaker or null
*/
public LayoutManagerMaker getLayoutManagerMakerOverride() {
return this.lmMakerOverride;
}

/**
* Sets the base URL.
* @param base the base URL
* @throws MalformedURLException if there's a problem with a file URL
* Returns whether accessibility is enabled.
* @return true if accessibility is enabled
*/
public void setBaseURL(String base) throws MalformedURLException {
this.base = foURIResolver.checkBaseURL(base);
}

/**
* Returns the base URL.
* @return the base URL
*/
public String getBaseURL() {
return this.base;
}

/**
* Sets the font base URL.
* @param fontBase font base URL
* @throws MalformedURLException if there's a problem with a file URL
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead
*/
@Deprecated
public void setFontBaseURL(String fontBase) throws MalformedURLException {
getFontManager().setFontBaseURL(fontBase);
}

/**
* @return the font base URL
* @deprecated use getFontManager().setFontBaseURL(fontBase) instead
*/
@Deprecated
public String getFontBaseURL() {
return getFontManager().getFontBaseURL();
}

/** @return the hyphen base URL */
public String getHyphenBaseURL() {
return this.hyphenBase;
}

/**
* Sets the hyphen base URL.
* @param hyphenBase hythen base URL
* @throws MalformedURLException if there's a problem with a file URL
* */
public void setHyphenBaseURL(final String hyphenBase) throws MalformedURLException {
if (hyphenBase != null) {
setHyphenationTreeResolver(
new HyphenationTreeResolver() {
public Source resolve(String href) {
return resolveURI(href, hyphenBase);
}
});
}
this.hyphenBase = foURIResolver.checkBaseURL(hyphenBase);
}

/**
* @return the hyphPatNames
*/
public Map getHyphPatNames() {
return hyphPatNames;
}

/**
* @param hyphPatNames the hyphPatNames to set
*/
public void setHyphPatNames(Map hyphPatNames) {
if (hyphPatNames == null) {
hyphPatNames = new HashMap();
}
this.hyphPatNames = hyphPatNames;
boolean isAccessibilityEnabled() {
return config.isAccessibilityEnabled();
}

/**
* Sets the URI Resolver. It is used for resolving factory-level URIs like hyphenation
* patterns and as backup for URI resolution performed during a rendering run.
* @param uriResolver the new URI resolver
* Returns the image manager.
* @return the image manager
*/
public void setURIResolver(URIResolver uriResolver) {
foURIResolver.setCustomURIResolver(uriResolver);
public ImageManager getImageManager() {
return config.getImageManager();
}

/**
* Returns the URI Resolver.
* @return the URI Resolver
* Returns the overriding LayoutManagerMaker instance, if any.
* @return the overriding LayoutManagerMaker or null
*/
public URIResolver getURIResolver() {
return foURIResolver;
public LayoutManagerMaker getLayoutManagerMakerOverride() {
return config.getLayoutManagerMakerOverride();
}

/**
* Returns the FO URI Resolver.
* @return the FO URI Resolver
*/
public FOURIResolver getFOURIResolver() {
return foURIResolver;
/** @return the hyphen base URI */
public String getHyphenBaseURI() {
return config.getHyphenationBaseURI().toASCIIString();
}

/** @return the HyphenationTreeResolver for resolving user-supplied hyphenation patterns. */
public HyphenationTreeResolver getHyphenationTreeResolver() {
return this.hyphResolver;
}

/**
* Sets the HyphenationTreeResolver to be used for resolving user-supplied hyphenation files.
* @param hyphResolver the HyphenationTreeResolver instance
*/
public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) {
this.hyphResolver = hyphResolver;
return config.getHyphenationTreeResolver();
}

/**
* Activates strict XSL content model validation for FOP
* Default is false (FOP will continue processing where it can)
* @param validateStrictly true to turn on strict validation
*/
public void setStrictValidation(boolean validateStrictly) {
this.strictFOValidation = validateStrictly;
public Map<String, String> getHyphPatNames() {
return config.getHyphPatNames();
}

/**
@@ -503,7 +362,7 @@ public class FopFactory implements ImageContext {
* @return true of strict validation turned on, false otherwise
*/
public boolean validateStrictly() {
return strictFOValidation;
return config.validateStrictly();
}

/**
@@ -511,48 +370,12 @@ public class FopFactory implements ImageContext {
* boundaries (for more info, see the javadoc for the relative member variable)
*/
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() {
return breakIndentInheritanceOnReferenceAreaBoundary;
}

/**
* Controls whether to enable a feature that breaks indent inheritance when crossing
* reference area boundaries.
* <p>
* This flag controls whether FOP will enable special code that breaks property
* inheritance for start-indent and end-indent when the evaluation of the inherited
* value would cross a reference area. This is described under
* http://wiki.apache.org/xmlgraphics-fop/IndentInheritance as is intended to
* improve interoperability with commercial FO implementations and to produce
* results that are more in line with the expectation of unexperienced FO users.
* Note: Enabling this features violates the XSL specification!
* @param value true to enable the feature
*/
public void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value) {
this.breakIndentInheritanceOnReferenceAreaBoundary = value;
return config.isBreakIndentInheritanceOnReferenceAreaBoundary();
}

/**
* @return true if kerning on base 14 fonts is enabled
* @deprecated use getFontManager().isBase14KerningEnabled() instead
*/
@Deprecated
public boolean isBase14KerningEnabled() {
return getFontManager().isBase14KerningEnabled();
}

/**
* Controls whether kerning is activated on base 14 fonts.
* @param value true if kerning should be activated
* @deprecated use getFontManager().setBase14KerningEnabled(boolean) instead
*/
@Deprecated
public void setBase14KerningEnabled(boolean value) {
getFontManager().setBase14KerningEnabled(value);
}

/** @return the resolution for resolution-dependant input */
/** @return the resolution for resolution-dependent input */
public float getSourceResolution() {
return this.sourceResolution;
return config.getSourceResolution();
}

/**
@@ -565,22 +388,9 @@ public class FopFactory implements ImageContext {
return UnitConv.IN2MM / getSourceResolution();
}

/**
* Sets the source resolution in dpi. This value is used to interpret the pixel size
* of source documents like SVG images and bitmap images without resolution information.
* @param dpi resolution in dpi
*/
public void setSourceResolution(float dpi) {
this.sourceResolution = dpi;
if (log.isDebugEnabled()) {
log.debug("source-resolution set to: " + sourceResolution
+ "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")");
}
}

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

/**
@@ -590,25 +400,7 @@ public class FopFactory implements ImageContext {
* @see #getTargetResolution()
*/
public float getTargetPixelUnitToMillimeter() {
return UnitConv.IN2MM / this.targetResolution;
}

/**
* Sets the source resolution in dpi. This value is used to interpret the pixel size
* of source documents like SVG images and bitmap images without resolution information.
* @param dpi resolution in dpi
*/
public void setTargetResolution(float dpi) {
this.targetResolution = dpi;
}

/**
* Sets the source resolution in dpi. This value is used to interpret the pixel size
* of source documents like SVG images and bitmap images without resolution information.
* @param dpi resolution in dpi
*/
public void setSourceResolution(int dpi) {
setSourceResolution((float)dpi);
return 25.4f / getTargetResolution();
}

/**
@@ -618,20 +410,7 @@ public class FopFactory implements ImageContext {
* @return the page-height, as a String
*/
public String getPageHeight() {
return this.pageHeight;
}

/**
* Sets the page-height to use as fallback, in case
* page-height="auto"
*
* @param pageHeight page-height as a String
*/
public void setPageHeight(String pageHeight) {
this.pageHeight = pageHeight;
if (log.isDebugEnabled()) {
log.debug("Default page-height set to: " + pageHeight);
}
return config.getPageHeight();
}

/**
@@ -641,40 +420,7 @@ public class FopFactory implements ImageContext {
* @return the page-width, as a String
*/
public String getPageWidth() {
return this.pageWidth;
}

/**
* Sets the page-width to use as fallback, in case
* page-width="auto"
*
* @param pageWidth page-width as a String
*/
public void setPageWidth(String pageWidth) {
this.pageWidth = pageWidth;
if (log.isDebugEnabled()) {
log.debug("Default page-width set to: " + pageWidth);
}
}

/**
* Adds a namespace to the set of ignored namespaces.
* If FOP encounters a namespace which it cannot handle, it issues a warning except if this
* namespace is in the ignored set.
* @param namespaceURI the namespace URI
*/
public void ignoreNamespace(String namespaceURI) {
this.ignoredNamespaces.add(namespaceURI);
}

/**
* Adds a collection of namespaces to the set of ignored namespaces.
* If FOP encounters a namespace which it cannot handle, it issues a warning except if this
* namespace is in the ignored set.
* @param namespaceURIs the namespace URIs
*/
public void ignoreNamespaces(Collection<String> namespaceURIs) {
this.ignoredNamespaces.addAll(namespaceURIs);
return config.getPageWidth();
}

/**
@@ -683,54 +429,16 @@ public class FopFactory implements ImageContext {
* @return true if the namespace is ignored by FOP
*/
public boolean isNamespaceIgnored(String namespaceURI) {
return this.ignoredNamespaces.contains(namespaceURI);
return config.isNamespaceIgnored(namespaceURI);
}

/** @return the set of namespaces that are ignored by FOP */
public Set<String> getIgnoredNamespace() {
return Collections.unmodifiableSet(this.ignoredNamespaces);
return config.getIgnoredNamespaces();
}

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

/**
* Set the user configuration.
* @param userConfigFile the configuration file
* @throws IOException if an I/O error occurs
* @throws SAXException if a parsing error occurs
*/
public void setUserConfig(File userConfigFile) throws SAXException, IOException {
config.setUserConfig(userConfigFile);
}

/**
* Set the user configuration from an URI.
* @param uri the URI to the configuration file
* @throws IOException if an I/O error occurs
* @throws SAXException if a parsing error occurs
*/
public void setUserConfig(String uri) throws SAXException, IOException {
config.setUserConfig(uri);
}

/**
* Set the user configuration.
* @param userConfig configuration
* @throws FOPException if a configuration problem occurs
*/
public void setUserConfig(Configuration userConfig) throws FOPException {
config.setUserConfig(userConfig);
}

/**
* Set the base URI for the user configuration
* Useful for programmatic configurations
* @param baseURI the base URI
*/
public void setUserConfigBaseURI(URI baseURI) {
config.setBaseURI(baseURI);
}

/**
* Get the user configuration.
* @return the user configuration
@@ -739,61 +447,22 @@ public class FopFactory implements ImageContext {
return config.getUserConfig();
}

/**
* Is the user configuration to be validated?
* @param strictUserConfigValidation strict user config validation
*/
public void setStrictUserConfigValidation(boolean strictUserConfigValidation) {
this.strictUserConfigValidation = strictUserConfigValidation;
this.foURIResolver.setThrowExceptions(strictUserConfigValidation);
}

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

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

/**
* Whether or not to cache results of font triplet detection/auto-config
* @param useCache use cache or not
* @deprecated use getFontManager().setUseCache(boolean) instead
*/
@Deprecated
public void setUseCache(boolean useCache) {
getFontManager().setUseCache(useCache);
}

/**
* Cache results of font triplet detection/auto-config?
* @return whether this factory is uses the cache
* @deprecated use getFontManager().useCache() instead
*/
@Deprecated
public boolean useCache() {
return getFontManager().useCache();
}

/**
* Returns the font cache instance used by this factory.
* @return the font cache
* @deprecated use getFontManager().getFontCache() instead
*/
@Deprecated
public FontCache getFontCache() {
return getFontManager().getFontCache();
}

/**
* Returns the font manager.
* @return the font manager
*/
public FontManager getFontManager() {
return this.fontManager;
return config.getFontManager();
}

/**
@@ -804,12 +473,12 @@ public class FopFactory implements ImageContext {
* @param baseUri the base URI to resolve against
* @return A {@link javax.xml.transform.Source} object, or null if the URI
* cannot be resolved.
* @see org.apache.fop.apps.FOURIResolver
* @see org.apache.fop.apps.io.FOURIResolver
*/
public Source resolveURI(String href, String baseUri) {
Source source = null;
try {
source = foURIResolver.resolve(href, baseUri);
source = config.getURIResolver().resolve(href, baseUri);
} catch (TransformerException e) {
log.error("Attempt to resolve URI '" + href + "' failed: ", e);
}
@@ -825,5 +494,4 @@ public class FopFactory implements ImageContext {
public ColorSpaceCache getColorSpaceCache() {
return this.colorSpaceCache;
}

}

+ 744
- 0
src/java/org/apache/fop/apps/FopFactoryBuilder.java View File

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

import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.URIResolver;

import org.apache.avalon.framework.configuration.Configuration;

import org.apache.xmlgraphics.image.loader.ImageContext;
import org.apache.xmlgraphics.image.loader.ImageManager;

import org.apache.fop.apps.io.DefaultResourceResolver;
import org.apache.fop.apps.io.FOURIResolver;
import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.hyphenation.HyphenationTreeResolver;
import org.apache.fop.layoutmgr.LayoutManagerMaker;

/**
* This is the builder class for {@link FopFactory}. Setters can be chained to
* make building a {@link FopFactory} object more concise and intuitive e.g.
*
* <pre>
* {@code
* FopFactoryBuilder fopFactoryBuilder = new FopFactoryBuilder(<URI>)
* .setURIResolver(<URIResolver>)
* .setPageHeight(<String>)
* .setPageWidth(<String>)
* .setStrictUserConfigValidation(<boolean>)
* ... etc ...
* FopFactory fopFactory = fopFactoryBuilder.build();
* }
* </pre>
*/
public final class FopFactoryBuilder {

private final FopFactoryConfig config;

private FopFactoryConfigBuilder fopFactoryConfigBuilder;

/**
* A builder class for {@link FopFactory} which can be used for setting configuration. This is
* a helper constructor that uses the default URI resolver implementation that FOP packages
* provide ({@link DefaultResourceResolver}).
*
* @param defaultBaseURI the default base URI for resolving URIs against
*/
public FopFactoryBuilder(URI defaultBaseURI) {
this(defaultBaseURI, new DefaultResourceResolver());
}

/**
* A builder class for {@link FopFactory} which can be used for setting configuration.
*
* @param defaultBaseURI the default base URI for resolving URIs against
* @param uriResolver the URI resolver
*/
public FopFactoryBuilder(URI defaultBaseURI, ResourceResolver uriResolver) {
this(EnvironmentalProfileFactory.createDefault(defaultBaseURI, uriResolver));
}

/**
* A builder class for {@link FopFactory} which can be used for setting configuration.
*
* @param enviro the profile of the FOP deployment environment
*/
public FopFactoryBuilder(EnvironmentProfile enviro) {
config = new FopFactoryConfigImpl(enviro);
fopFactoryConfigBuilder = new ActiveFopFactoryConfigBuilder((FopFactoryConfigImpl) config);
}

/**
* Returns the {@link FopFactoryConfig} which is needed to get an instance of
* {@link FopFactory}.
*
* @return build the {@link FopFactoryConfig}
* @deprecated Exposing the {@link FopFactoryConfig} is only to maintain backwards compatibility
*/
public FopFactoryConfig buildConfig() {
fopFactoryConfigBuilder = CompletedFopFactoryConfigBuilder.INSTANCE;
return config;
}

/**
* Builds an instance of the the {@link FopFactory}.
*
* @return the FopFactory instance
*/
public FopFactory build() {
return FopFactory.newInstance(buildConfig());
}

/**
* Gets the base URI used to resolve all URIs within FOP.
*
* @return the base URI
*/
URI getBaseUri() {
return config.getBaseURI();
}

/**
* Returns the {@link FontManager} used for managing the fonts within FOP.
*
* @return the font managing object
*/
public FontManager getFontManager() {
return config.getFontManager();
}

/**
* Return the {@link ImageManager} used for handling images through out FOP.
*
* @return the image manager
*/
public ImageManager getImageManager() {
return config.getImageManager();
}

/**
* Sets whether to include accessibility features in document creation.
*
* @param enableAccessibility true to set accessibility on
* @return <code>this</code>
*/
public FopFactoryBuilder setAccessibility(boolean enableAccessibility) {
fopFactoryConfigBuilder.setAccessibility(enableAccessibility);
return this;
}

/**
* Sets the {@link LayoutManagerMaker} so that users can configure how FOP creates
* {@link LayoutManager}s.
*
* @param lmMaker he layout manager maker
* @return <code>this</code>
*/
public FopFactoryBuilder setLayoutManagerMakerOverride(
LayoutManagerMaker lmMaker) {
fopFactoryConfigBuilder.setLayoutManagerMakerOverride(lmMaker);
return this;
}

/**
* Sets the URI resolver to be used for controlling FOP's file access.
*
* @param resolver the URI resolver
* @return <code>this</code>
* @deprecated this URIResolver will be phased out in favour of a unified URI resolution
* mechanism
*/
public FopFactoryBuilder setURIResolver(URIResolver resolver) {
fopFactoryConfigBuilder.setURIResolver(resolver);
return this;
}

/**
* Sets the base URI, this will be used for resolving all URIs given to FOP.
*
* @param baseURI the base URI
* @return <code>this</code>
*/
public FopFactoryBuilder setBaseURI(URI baseURI) {
fopFactoryConfigBuilder.setBaseURI(baseURI);
return this;
}

/**
* Sets the base URI for hyphenation data.
*
* @param hyphenationBase the hyphenation-base-URI
* @return <code>this</code>
* @deprecated this will be phased out in favour of a unified URI resolution mechanism
*/
public FopFactoryBuilder setHyphenationBaseURI(URI hyphenationBase) {
fopFactoryConfigBuilder.setHyphenationBaseURI(hyphenationBase);
return this;
}

/**
* Sets the URI resolver specific to Hyphenation data.
*
* @param hyphResolver the hyphenation-URI-resolver
* @return <code>this</code>
* @deprecated this will be phased out in favour of a unified URI resolution mechanism
*/
public FopFactoryBuilder setHyphenationTreeResolver(
HyphenationTreeResolver hyphResolver) {
fopFactoryConfigBuilder.setHyphenationTreeResolver(hyphResolver);
return this;

}

/**
* Sets whether to perform strict validation on the FO used.
*
* @param validateStrictly true if the FO is to be strictly validated
* @return <code>this</code>
*/
public FopFactoryBuilder setStrictFOValidation(boolean validateStrictly) {
fopFactoryConfigBuilder.setStrictFOValidation(validateStrictly);
return this;
}

/**
* Sets whether to perform strict alidation on the user-configuration.
*
* @param validateStrictly true if the fop conf is to be strictly validated
* @return <code>this</code>
*/
public FopFactoryBuilder setStrictUserConfigValidation(
boolean validateStrictly) {
fopFactoryConfigBuilder.setStrictUserConfigValidation(validateStrictly);
return this;
}

/**
* Sets whether the indent inheritance should be broken when crossing reference area boundaries.
*
* @param value true to break inheritance when crossing reference area boundaries
* @return <code>this</code>
*/
public FopFactoryBuilder setBreakIndentInheritanceOnReferenceAreaBoundary(
boolean value) {
fopFactoryConfigBuilder.setBreakIndentInheritanceOnReferenceAreaBoundary(value);
return this;
}

/**
* Sets the resolution of resolution-dependent input.
*
* @param dpi the source resolution
* @return <code>this</code>
*/
public FopFactoryBuilder setSourceResolution(float dpi) {
fopFactoryConfigBuilder.setSourceResolution(dpi);
return this;
}

/**
* Sets the resolution of resolution-dependent output.
*
* @param dpi the target resolution
* @return <code>this</code>
*/
public FopFactoryBuilder setTargetResolution(float dpi) {
fopFactoryConfigBuilder.setTargetResolution(dpi);
return this;
}

/**
* Sets the page height of the paginated output.
*
* @param pageHeight the page height
* @return <code>this</code>
*/
public FopFactoryBuilder setPageHeight(String pageHeight) {
fopFactoryConfigBuilder.setPageHeight(pageHeight);
return this;
}

/**
* Sets the page width of the paginated output.
*
* @param pageWidth the page width
* @return <code>this</code>
*/
public FopFactoryBuilder setPageWidth(String pageWidth) {
fopFactoryConfigBuilder.setPageWidth(pageWidth);
return this;
}

/**
* FOP will ignore the specified XML element namespace.
*
* @param namespaceURI the namespace URI to ignore
* @return <code>this</code>
*/
public FopFactoryBuilder ignoreNamespace(String namespaceURI) {
fopFactoryConfigBuilder.ignoreNamespace(namespaceURI);
return this;
}

/**
* FOP will ignore the colletion of XML element namespaces.
*
* @param namespaceURIs a collection of namespace URIs to ignore
* @return <code>this</code>
*/
public FopFactoryBuilder ignoreNamespaces(Collection<String> namespaceURIs) {
fopFactoryConfigBuilder.ignoreNamespaces(namespaceURIs);
return this;
}

/**
* Sets the Avalon configuration if a FOP conf is used.
*
* @param cfg the fop conf configuration
* @return <code>this</code>
*/
public FopFactoryBuilder setConfiguration(Configuration cfg) {
fopFactoryConfigBuilder.setConfiguration(cfg);
return this;
}

/**
* Sets whether to chose a {@link Renderer} in preference to an
* {@link org.apache.fop.render.intermediate.IFDocumentHandler}.
*
* @see {@link RendererFactory}
* @param preferRenderer true to prefer {@link Renderer}
* @return <code>this</code>
*/
public FopFactoryBuilder setPreferRenderer(boolean preferRenderer) {
fopFactoryConfigBuilder.setPreferRenderer(preferRenderer);
return this;
}

public FopFactoryBuilder setComplexScriptFeatures(boolean csf) {
fopFactoryConfigBuilder.setComplexScriptFeaturesEnabled(csf);
return this;
}

public FopFactoryBuilder setHyphPatNames(Map<String, String> hyphPatNames) {
fopFactoryConfigBuilder.setHyphPatNames(hyphPatNames);
return this;
}

public static class FopFactoryConfigImpl implements FopFactoryConfig {

private final EnvironmentProfile enviro;

private final ImageManager imageManager;

private boolean accessibility;

private LayoutManagerMaker layoutManagerMaker;

private URI baseURI;

private URI hyphenationBaseURI;

private HyphenationTreeResolver hyphenationTreeResolver;

private boolean hasStrictFOValidation = true;

private boolean hasStrictUserValidation = FopFactoryConfig.DEFAULT_STRICT_USERCONFIG_VALIDATION;

private boolean breakIndentInheritanceOnReferenceBoundary
= FopFactoryConfig.DEFAULT_BREAK_INDENT_INHERITANCE;

private float sourceResolution = FopFactoryConfig.DEFAULT_SOURCE_RESOLUTION;

private float targetResolution = FopFactoryConfig.DEFAULT_TARGET_RESOLUTION;

private String pageHeight = FopFactoryConfig.DEFAULT_PAGE_HEIGHT;

private String pageWidth = FopFactoryConfig.DEFAULT_PAGE_WIDTH;

private Set<String> ignoredNamespaces = new HashSet<String>();

private URIResolver resolver;

private Configuration cfg;

private boolean preferRenderer;

private boolean isComplexScript = true;

private Map<String, String> hyphPatNames;

private static final class ImageContextImpl implements ImageContext {

private final FopFactoryConfig config;

ImageContextImpl(FopFactoryConfig config) {
this.config = config;
}

public float getSourceResolution() {
return config.getSourceResolution();
}
}

FopFactoryConfigImpl(EnvironmentProfile enviro) {
this.enviro = enviro;
this.baseURI = enviro.getDefaultBaseURI();
this.imageManager = new ImageManager(new ImageContextImpl(this));
this.resolver = new FOURIResolver();
}

/** {@inheritDoc} */
public boolean isAccessibilityEnabled() {
return accessibility;
}

/** {@inheritDoc} */
public LayoutManagerMaker getLayoutManagerMakerOverride() {
return layoutManagerMaker;
}

/** {@inheritDoc} */
public ResourceResolver getNewURIResolver() {
return enviro.getResourceResolver();
}

/** {@inheritDoc} */
public URIResolver getURIResolver() {
return resolver;
}

/** {@inheritDoc} */
public URI getBaseURI() {
return baseURI;
}

/** {@inheritDoc} */
public URI getHyphenationBaseURI() {
return hyphenationBaseURI;
}

/** {@inheritDoc} */
public HyphenationTreeResolver getHyphenationTreeResolver() {
return hyphenationTreeResolver;
}

/** {@inheritDoc} */
public boolean validateStrictly() {
return hasStrictFOValidation;
}

/** {@inheritDoc} */
public boolean validateUserConfigStrictly() {
return hasStrictUserValidation;
}

/** {@inheritDoc} */
public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() {
return breakIndentInheritanceOnReferenceBoundary;
}

/** {@inheritDoc} */
public float getSourceResolution() {
return sourceResolution;
}

/** {@inheritDoc} */
public float getTargetResolution() {
return targetResolution;
}

/** {@inheritDoc} */
public String getPageHeight() {
return pageHeight;
}

/** {@inheritDoc} */
public String getPageWidth() {
return pageWidth;
}

/** {@inheritDoc} */
public Set<String> getIgnoredNamespaces() {
return Collections.unmodifiableSet(ignoredNamespaces);
}

/** {@inheritDoc} */
public boolean isNamespaceIgnored(String namespace) {
return ignoredNamespaces.contains(namespace);
}

/** {@inheritDoc} */
public Configuration getUserConfig() {
return cfg;
}

/** {@inheritDoc} */
public boolean preferRenderer() {
return preferRenderer;
}

/** {@inheritDoc} */
public FontManager getFontManager() {
return enviro.getFontManager();
}

/** {@inheritDoc} */
public ImageManager getImageManager() {
return imageManager;
}

public boolean isComplexScriptFeaturesEnabled() {
return isComplexScript;
}

public Map<String, String> getHyphPatNames() {
return hyphPatNames;
}
}

private interface FopFactoryConfigBuilder {

void setAccessibility(boolean enableAccessibility);

void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker);

void setURIResolver(URIResolver resolver);

void setBaseURI(URI baseURI);

void setHyphenationBaseURI(URI hyphenationBase);

void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver);

void setStrictFOValidation(boolean validateStrictly);

void setStrictUserConfigValidation(boolean validateStrictly);

void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value);

void setSourceResolution(float dpi);

void setTargetResolution(float dpi);

void setPageHeight(String pageHeight);

void setPageWidth(String pageWidth);

void ignoreNamespace(String namespaceURI);

void ignoreNamespaces(Collection<String> namespaceURIs);

void setConfiguration(Configuration cfg);

void setPreferRenderer(boolean preferRenderer);

void setComplexScriptFeaturesEnabled(boolean csf);

void setHyphPatNames(Map<String, String> hyphPatNames);
}

private static final class CompletedFopFactoryConfigBuilder implements FopFactoryConfigBuilder {

private static final CompletedFopFactoryConfigBuilder INSTANCE
= new CompletedFopFactoryConfigBuilder();

private void throwIllegalStateException() {
throw new IllegalStateException("The final FOP Factory configuration has already been built");
}

public void setAccessibility(boolean enableAccessibility) {
throwIllegalStateException();
}

public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) {
throwIllegalStateException();

}

public void setURIResolver(URIResolver resolver) {
throwIllegalStateException();
}

public void setBaseURI(URI baseURI) {
throwIllegalStateException();
}

public void setHyphenationBaseURI(URI hyphenationBase) {
throwIllegalStateException();
}

public void setHyphenationTreeResolver(
HyphenationTreeResolver hyphResolver) {
throwIllegalStateException();
}

public void setStrictFOValidation(boolean validateStrictly) {
throwIllegalStateException();
}

public void setStrictUserConfigValidation(boolean validateStrictly) {
throwIllegalStateException();
}

public void setBreakIndentInheritanceOnReferenceAreaBoundary(
boolean value) {
throwIllegalStateException();
}

public void setSourceResolution(float dpi) {
throwIllegalStateException();
}

public void setTargetResolution(float dpi) {
throwIllegalStateException();
}

public void setPageHeight(String pageHeight) {
throwIllegalStateException();
}

public void setPageWidth(String pageWidth) {
throwIllegalStateException();
}

public void ignoreNamespace(String namespaceURI) {
throwIllegalStateException();
}

public void ignoreNamespaces(Collection<String> namespaceURIs) {
throwIllegalStateException();
}

public void setConfiguration(Configuration cfg) {
throwIllegalStateException();
}

public void setPreferRenderer(boolean preferRenderer) {
throwIllegalStateException();
}

public void setComplexScriptFeaturesEnabled(boolean csf) {
throwIllegalStateException();
}

public void setHyphPatNames(Map<String, String> hyphPatNames) {
throwIllegalStateException();
}

}

private static final class ActiveFopFactoryConfigBuilder implements FopFactoryConfigBuilder {

private final FopFactoryConfigImpl config;

private ActiveFopFactoryConfigBuilder(FopFactoryConfigImpl config) {
this.config = config;
}

public void setAccessibility(boolean enableAccessibility) {
config.accessibility = enableAccessibility;
}

public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) {
config.layoutManagerMaker = lmMaker;
}

public void setURIResolver(URIResolver resolver) {
config.resolver = resolver;
}

public void setBaseURI(URI baseURI) {
config.baseURI = baseURI;
}

public void setHyphenationBaseURI(URI hyphenationBase) {
config.hyphenationBaseURI = hyphenationBase;
}

public void setHyphenationTreeResolver(HyphenationTreeResolver hyphResolver) {
config.hyphenationTreeResolver = hyphResolver;
}

public void setStrictFOValidation(boolean validateStrictly) {
config.hasStrictFOValidation = validateStrictly;
}

public void setStrictUserConfigValidation(
boolean validateStrictly) {
config.hasStrictUserValidation = validateStrictly;
}

public void setBreakIndentInheritanceOnReferenceAreaBoundary(
boolean value) {
config.breakIndentInheritanceOnReferenceBoundary = value;
}

public void setSourceResolution(float dpi) {
config.sourceResolution = dpi;
}

public void setTargetResolution(float dpi) {
config.targetResolution = dpi;
}

public void setPageHeight(String pageHeight) {
config.pageHeight = pageHeight;
}

public void setPageWidth(String pageWidth) {
config.pageWidth = pageWidth;
}

public void ignoreNamespace(String namespaceURI) {
config.ignoredNamespaces.add(namespaceURI);
}

public void ignoreNamespaces(
Collection<String> namespaceURIs) {
config.ignoredNamespaces.addAll(namespaceURIs);
}

public void setConfiguration(Configuration cfg) {
config.cfg = cfg;
}

public void setPreferRenderer(boolean preferRenderer) {
config.preferRenderer = preferRenderer;
}

public void setComplexScriptFeaturesEnabled(boolean csf) {
config.isComplexScript = csf;
}

public void setHyphPatNames(Map<String, String> hyphPatNames) {
config.hyphPatNames = hyphPatNames;
}
}

}

+ 159
- 0
src/java/org/apache/fop/apps/FopFactoryConfig.java View File

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

import java.net.URI;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.URIResolver;

import org.apache.avalon.framework.configuration.Configuration;

import org.apache.xmlgraphics.image.loader.ImageManager;

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

/**
* The configuration data for a {@link FopFactory} instance.
*/
public interface FopFactoryConfig {

/** Defines if FOP should use an alternative rule to determine text indents */
boolean DEFAULT_BREAK_INDENT_INHERITANCE = false;

/** Defines if FOP should validate the user config strictly */
boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true;

/** Defines if FOP should use strict validation for FO and user config */
boolean DEFAULT_STRICT_FO_VALIDATION = true;

/** Defines the default page-width */
String DEFAULT_PAGE_WIDTH = "8.26in";

/** Defines the default page-height */
String DEFAULT_PAGE_HEIGHT = "11in";

/** Defines the default source resolution (72dpi) for FOP */
float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi

/** Defines the default target resolution (72dpi) for FOP */
float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi

/**
* Whether accessibility features are switched on.
*
* @return true if accessibility features have been requested
*/
boolean isAccessibilityEnabled();

/** @see {@link FopFactory#getLayoutManagerMakerOverride()} */
LayoutManagerMaker getLayoutManagerMakerOverride();

/**
* The URI resolver used through-out FOP for controlling all file access.
*
* @return the URI resolver
*/
ResourceResolver getNewURIResolver();

/**
* The URI resolver for controlling file access.
*
* @return the URI resolver
* @deprecated please use the {@link #getNewURIResolver()} method.
*/
URIResolver getURIResolver();

/**
* The base URI from which URIs are resolved against.
*
* @return the base URI
*/
URI getBaseURI();

/**
* The base URI of hyphenation data.
*
* @return the hyphenation-base-URI
* @deprecated this intelligence can be configured in the URI resolver set in
* {@link #getNewURIResolver()}
*/
URI getHyphenationBaseURI();

/**
* The URI resolver for resolving hyphenation data.
*
* @return the hyphenation-URI-resolver
* @deprecated this intelligence can be configured in the URI resolver set in
* {@link #getNewURIResolver()}
*/
HyphenationTreeResolver getHyphenationTreeResolver();

/** @see {@link FopFactory#validateStrictly()} */
boolean validateStrictly();

/** @see {@link FopFactory#validateUserConfigStrictly()} */
boolean validateUserConfigStrictly();

/** @see {@link FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()} */
boolean isBreakIndentInheritanceOnReferenceAreaBoundary();

/** @see {@link FopFactory#getSourceResolution()} */
float getSourceResolution();

/** @see {@link FopFactory#getTargetResolution()} */
float getTargetResolution();

/** @see {@link FopFactory#getPageHeight()} */
String getPageHeight();

/** @see {@link FopFactory#getPageWidth()} */
String getPageWidth();

/** @see {@link FopFactory#getIgnoredNamespace()} */
Set<String> getIgnoredNamespaces();

/** @see {@link FopFactory#isNamespaceIgnored(String)} */
boolean isNamespaceIgnored(String namespace);

/**
* Returns the Avalon {@link Configuration} object.
*
* @return the Avalon config object
*/
Configuration getUserConfig();

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

/** @see {@link FopFactory#getFontManager()} */
FontManager getFontManager();

/** @see {@link FopFactory#getImageManager()} */
ImageManager getImageManager();

boolean isComplexScriptFeaturesEnabled();

Map<String, String> getHyphPatNames();
}

+ 0
- 406
src/java/org/apache/fop/apps/FopFactoryConfigurator.java View File

@@ -1,406 +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;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.xml.sax.SAXException;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

import org.apache.fop.fonts.FontManagerConfigurator;
import org.apache.fop.hyphenation.HyphenationTreeCache;
import org.apache.fop.util.LogUtil;

/**
* FopFactory configurator
*/
public class FopFactoryConfigurator {

/** Defines if FOP should use an alternative rule to determine text indents */
public static final boolean DEFAULT_BREAK_INDENT_INHERITANCE = false;

/** Defines if FOP should validate the user config strictly */
public static final boolean DEFAULT_STRICT_USERCONFIG_VALIDATION = true;

/** Defines if FOP should use strict validation for FO and user config */
public static final boolean DEFAULT_STRICT_FO_VALIDATION = true;

/** Defines the default page-width */
public static final String DEFAULT_PAGE_WIDTH = "8.26in";

/** Defines the default page-height */
public static final String DEFAULT_PAGE_HEIGHT = "11in";

/** Defines the default source resolution (72dpi) for FOP */
public static final float DEFAULT_SOURCE_RESOLUTION = GraphicsConstants.DEFAULT_DPI; //dpi

/** Defines the default target resolution (72dpi) for FOP */
public static final float DEFAULT_TARGET_RESOLUTION = GraphicsConstants.DEFAULT_DPI; //dpi

/** Defines the default complex script support */
public static final boolean DEFAULT_COMPLEX_SCRIPT_FEATURES = true;

private static final String PREFER_RENDERER = "prefer-renderer";

/** logger instance */
private final Log log = LogFactory.getLog(FopFactoryConfigurator.class);

/** Fop factory */
private FopFactory factory = null;

/** Fop factory configuration */
private Configuration cfg = null;

/** The base URI of the configuration file **/
private URI baseURI = null;

/**
* Default constructor
* @param factory fop factory
*/
public FopFactoryConfigurator(FopFactory factory) {
super();
this.factory = factory;
}

/**
* Initializes user agent settings from the user configuration
* file, if present: baseURL, resolution, default page size,...
* @param factory fop factory
* @throws FOPException fop exception
*/
public void configure(FopFactory factory) throws FOPException { // CSOK: MethodLength
// strict configuration
if (cfg.getChild("strict-configuration", false) != null) {
try {
factory.setStrictUserConfigValidation(
cfg.getChild("strict-configuration").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, false);
}
}
boolean strict = factory.validateUserConfigStrictly();
if (log.isDebugEnabled()) {
log.debug("Initializing FopFactory Configuration"
+ "with " + (strict ? "strict" : "permissive") + " validation");
}

if (cfg.getChild("accessibility", false) != null) {
try {
this.factory.setAccessibility(
cfg.getChild("accessibility").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}

// strict fo validation
if (cfg.getChild("strict-validation", false) != null) {
try {
factory.setStrictValidation(
cfg.getChild("strict-validation").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}

// base definitions for relative path resolution
if (cfg.getChild("base", false) != null) {
String path = cfg.getChild("base").getValue(null);
if (baseURI != null) {
path = baseURI.resolve(path).normalize().toString();
}
try {
factory.setBaseURL(path);
} catch (MalformedURLException mfue) {
LogUtil.handleException(log, mfue, strict);
}
}
if (cfg.getChild("hyphenation-base", false) != null) {
String path = cfg.getChild("hyphenation-base").getValue(null);
if (baseURI != null) {
path = baseURI.resolve(path).normalize().toString();
}
try {
factory.setHyphenBaseURL(path);
} catch (MalformedURLException mfue) {
LogUtil.handleException(log, mfue, strict);
}
}

/**
* Read configuration elements hyphenation-pattern,
* construct a map ll_CC => filename, and set it on the factory
*/
Configuration[] hyphPatConfig = cfg.getChildren("hyphenation-pattern");
if (hyphPatConfig.length != 0) {
Map/*<String,String>*/ hyphPatNames = new HashMap/*<String,String>*/();
for (int i = 0; i < hyphPatConfig.length; ++i) {
String lang;
String country;
String filename;
StringBuffer error = new StringBuffer();
String location = hyphPatConfig[i].getLocation();

lang = hyphPatConfig[i].getAttribute("lang", null);
if (lang == null) {
addError("The lang attribute of a hyphenation-pattern configuration"
+ " element must exist (" + location + ")", error);
} else if (!lang.matches("[a-zA-Z]{2}")) {
addError("The lang attribute of a hyphenation-pattern configuration"
+ " element must consist of exactly two letters ("
+ location + ")", error);
}
lang = lang.toLowerCase();

country = hyphPatConfig[i].getAttribute("country", null);
if ("".equals(country)) {
country = null;
}
if (country != null) {
if (!country.matches("[a-zA-Z]{2}")) {
addError("The country attribute of a hyphenation-pattern configuration"
+ " element must consist of exactly two letters ("
+ location + ")", error);
}
country = country.toUpperCase();
}

filename = hyphPatConfig[i].getValue(null);
if (filename == null) {
addError("The value of a hyphenation-pattern configuration"
+ " element may not be empty (" + location + ")", error);
}

if (error.length() != 0) {
LogUtil.handleError(log, error.toString(), strict);
continue;
}

String llccKey = HyphenationTreeCache.constructLlccKey(lang, country);
hyphPatNames.put(llccKey, filename);
if (log.isDebugEnabled()) {
log.debug("Using hyphenation pattern filename " + filename
+ " for lang=\"" + lang + "\""
+ (country != null ? ", country=\"" + country + "\"" : ""));
}
}
factory.setHyphPatNames(hyphPatNames);
}

// renderer options
if (cfg.getChild("source-resolution", false) != null) {
factory.setSourceResolution(
cfg.getChild("source-resolution").getValueAsFloat(
FopFactoryConfigurator.DEFAULT_SOURCE_RESOLUTION));
if (log.isDebugEnabled()) {
log.debug("source-resolution set to: " + factory.getSourceResolution()
+ "dpi (px2mm=" + factory.getSourcePixelUnitToMillimeter() + ")");
}
}
if (cfg.getChild("target-resolution", false) != null) {
factory.setTargetResolution(
cfg.getChild("target-resolution").getValueAsFloat(
FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION));
if (log.isDebugEnabled()) {
log.debug("target-resolution set to: " + factory.getTargetResolution()
+ "dpi (px2mm=" + factory.getTargetPixelUnitToMillimeter()
+ ")");
}
}
if (cfg.getChild("break-indent-inheritance", false) != null) {
try {
factory.setBreakIndentInheritanceOnReferenceAreaBoundary(
cfg.getChild("break-indent-inheritance").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}
Configuration pageConfig = cfg.getChild("default-page-settings");
if (pageConfig.getAttribute("height", null) != null) {
factory.setPageHeight(
pageConfig.getAttribute("height", FopFactoryConfigurator.DEFAULT_PAGE_HEIGHT));
if (log.isInfoEnabled()) {
log.info("Default page-height set to: " + factory.getPageHeight());
}
}
if (pageConfig.getAttribute("width", null) != null) {
factory.setPageWidth(
pageConfig.getAttribute("width", FopFactoryConfigurator.DEFAULT_PAGE_WIDTH));
if (log.isInfoEnabled()) {
log.info("Default page-width set to: " + factory.getPageWidth());
}
}

// prefer Renderer over IFDocumentHandler
if (cfg.getChild(PREFER_RENDERER, false) != null) {
try {
factory.getRendererFactory().setRendererPreferred(
cfg.getChild(PREFER_RENDERER).getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}

// configure complex script support
Configuration csConfig = cfg.getChild("complex-scripts");
if (csConfig != null) {
this.factory.setComplexScriptFeaturesEnabled
(!csConfig.getAttributeAsBoolean ( "disabled", false ));
}

// configure font manager
new FontManagerConfigurator(cfg, baseURI).configure(factory.getFontManager(), strict);

// configure image loader framework
configureImageLoading(cfg.getChild("image-loading", false), strict);
}

private static void addError(String message, StringBuffer error) {
if (error.length() != 0) {
error.append(". ");
}
error.append(message);
}

private void configureImageLoading(Configuration parent, boolean strict) throws FOPException {
if (parent == null) {
return;
}
ImageImplRegistry registry = factory.getImageManager().getRegistry();
Configuration[] penalties = parent.getChildren("penalty");
try {
for (int i = 0, c = penalties.length; i < c; i++) {
Configuration penaltyCfg = penalties[i];
String className = penaltyCfg.getAttribute("class");
String value = penaltyCfg.getAttribute("value");
Penalty p = null;
if (value.toUpperCase().startsWith("INF")) {
p = Penalty.INFINITE_PENALTY;
} else {
try {
p = Penalty.toPenalty(Integer.parseInt(value));
} catch (NumberFormatException nfe) {
LogUtil.handleException(log, nfe, strict);
}
}
if (p != null) {
registry.setAdditionalPenalty(className, p);
}
}
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
}

/**
* Set the user configuration.
* @param userConfigFile the configuration file
* @throws IOException if an I/O error occurs
* @throws SAXException if a parsing error occurs
*/
public void setUserConfig(File userConfigFile) throws SAXException, IOException {
try {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
setUserConfig(cfgBuilder.buildFromFile(userConfigFile));
} catch (ConfigurationException e) {
throw new FOPException(e);
}
}

/**
* Set the user configuration from an URI.
* @param uri the URI to the configuration file
* @throws IOException if an I/O error occurs
* @throws SAXException if a parsing error occurs
*/
public void setUserConfig(String uri) throws SAXException, IOException {
try {
DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
setUserConfig(cfgBuilder.build(uri));
} catch (ConfigurationException e) {
throw new FOPException(e);
}
}

/**
* Set the user configuration.
* @param cfg avalon configuration
* @throws FOPException if a configuration problem occurs
*/
public void setUserConfig(Configuration cfg) throws FOPException {
this.cfg = cfg;
setBaseURI();
configure(this.factory);
}

/**
* Get the avalon user configuration.
* @return the user configuration
*/
public Configuration getUserConfig() {
return this.cfg;
}

/**
* @return the baseURI
*/
public URI getBaseURI() {
return baseURI;
}

/**
* @param baseURI the baseURI to set
*/
public void setBaseURI(URI baseURI) {
this.baseURI = baseURI;
}

private void setBaseURI() throws FOPException {
String loc = cfg.getLocation();
try {
if (loc != null && loc.startsWith("file:")) {
baseURI = new URI(loc);
baseURI = baseURI.resolve(".").normalize();
}
if (baseURI == null) {
baseURI = new File(System.getProperty("user.dir")).toURI();
}
} catch (URISyntaxException e) {
throw new FOPException(e);
}
}

}

+ 49
- 0
src/java/org/apache/fop/apps/io/DefaultResourceResolver.java View File

@@ -0,0 +1,49 @@
/*
* 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.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;


public class DefaultResourceResolver implements ResourceResolver {

public Resource getResource(URI uri) throws IOException {
try {
return new Resource(uri.toURL().openStream());
} catch (MalformedURLException mue) {
throw new RuntimeException(mue);
}
}

public OutputStream getOutputStream(URI uri) throws IOException {
throw new UnsupportedOperationException();
}

public static URIResolverWrapper createDefaultWrapper() {
// Not sure if this is the right place for this, but I don't have any better ideas as of yet
URI thisUri = new File(".").getAbsoluteFile().toURI();
return new URIResolverWrapper(thisUri, new DefaultResourceResolver());
}

}

src/java/org/apache/fop/apps/FOURIResolver.java → src/java/org/apache/fop/apps/io/FOURIResolver.java View File

@@ -17,7 +17,7 @@

/* $Id$ */

package org.apache.fop.apps;
package org.apache.fop.apps.io;

import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -37,6 +37,7 @@ import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.FOUserAgent;

import org.apache.xmlgraphics.util.io.Base64EncodeStream;
import org.apache.xmlgraphics.util.uri.CommonURIResolver;

src/java/org/apache/fop/render/DefaultFontResolver.java → src/java/org/apache/fop/apps/io/Resource.java View File

@@ -17,36 +17,43 @@

/* $Id$ */

package org.apache.fop.render;
package org.apache.fop.apps.io;

import javax.xml.transform.Source;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontResolver;
import java.io.FilterInputStream;
import java.io.InputStream;

/**
* Default FontResolver implementation which uses the FOUserAgent to resolve font URIs.
* This class represents a resolved resource. The type property is used by FOP to identify the resource
* content.
*
*/
public class DefaultFontResolver implements FontResolver {
public class Resource extends FilterInputStream {

private FOUserAgent userAgent;
private final String type;

/**
* Main constructor.
* @param userAgent the user agent
* @param type resource type
* @param inputStream input stream of the resource
*/
public DefaultFontResolver(FOUserAgent userAgent) {
this.userAgent = userAgent;
public Resource(String type, InputStream inputStream) {
super(inputStream);
this.type = type;
}

/** {@inheritDoc} */
public Source resolve(String href) {
return userAgent.resolveURI(href, userAgent.getFactory().getFontManager().getFontBaseURL());
/**
* Constructs a resource of 'unknown' type.
*
* @param inputStream input stream of the resource
*/
public Resource(InputStream inputStream) {
this("unknown", inputStream);
}

/** {@inheritDoc} */
public boolean isComplexScriptFeaturesEnabled() {
return userAgent.isComplexScriptFeaturesEnabled();
/**
* @return the resource type
*/
public String getType() {
return this.type;
}

}

test/java/org/apache/fop/config/FontEmbedUrlMalformedTestCase.java → src/java/org/apache/fop/apps/io/ResourceResolver.java View File

@@ -17,15 +17,16 @@

/* $Id$ */

package org.apache.fop.config;
package org.apache.fop.apps.io;

/**
* this font has a malformed embed-url
*/
public class FontEmbedUrlMalformedTestCase extends BaseDestructiveUserConfigTest {
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;

public interface ResourceResolver {

Resource getResource(URI uri) throws IOException;

OutputStream getOutputStream(URI uri) throws IOException;

@Override
public String getUserConfigFilename() {
return "test_font_embedurl_malformed.xconf";
}
}

+ 74
- 0
src/java/org/apache/fop/apps/io/URIResolverWrapper.java View File

@@ -0,0 +1,74 @@
/*
* 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.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;


public class URIResolverWrapper {
private final URI baseUri;
private final ResourceResolver uriResolver;

public URIResolverWrapper(URI baseUri, ResourceResolver uriResolver) {
this.baseUri = baseUri;
this.uriResolver = uriResolver;
}

public URI getBaseURI() {
return baseUri;
}

public InputStream resolveIn(String stringUri) throws IOException, URISyntaxException {
return resolveIn(cleanURI(stringUri));
}

public InputStream resolveIn(URI uri) throws IOException {
return uriResolver.getResource(resolveFromBase(uri));
}

public OutputStream resolveOut(URI uri) throws IOException {
return uriResolver.getOutputStream(resolveFromBase(uri));
}

private URI resolveFromBase(URI uri) {
return baseUri.resolve(uri);
}

public static URI cleanURI(String base) throws URISyntaxException {
// replace back slash with forward slash to ensure windows file:/// URLS are supported
if (base == null) {
return null;
}
String fixedUri = base.replace('\\', '/');
fixedUri = fixedUri.replace(" ", "%20");
URI baseURI = new URI(fixedUri);
return baseURI;
}

public static URI getBaseURI(String base) throws URISyntaxException {
String path = base + (base.endsWith("/") ? "" : "/");
return cleanURI(path);
}

}

+ 6
- 0
src/java/org/apache/fop/apps/io/package.html View File

@@ -0,0 +1,6 @@
<HTML>
<TITLE>org.apache.fop.io Package</TITLE>
<BODY>
<P>Classes that control all IO in FOP.</P>
</BODY>
</HTML>

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

@@ -104,7 +104,7 @@ public class AreaTreeHandler extends FOEventHandler {

setupModel(userAgent, outputFormat, stream);

this.lmMaker = userAgent.getFactory().getLayoutManagerMakerOverride();
this.lmMaker = userAgent.getLayoutManagerMakerOverride();
if (lmMaker == null) {
lmMaker = new LayoutManagerMapping();
}

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

@@ -132,7 +132,7 @@ public class AreaTreeParser {
*/
public ContentHandler getContentHandler(AreaTreeModel treeModel, FOUserAgent userAgent) {
ElementMappingRegistry elementMappingRegistry
= userAgent.getFactory().getElementMappingRegistry();
= userAgent.getElementMappingRegistry();
return new Handler(treeModel, userAgent, elementMappingRegistry);
}

@@ -292,7 +292,7 @@ public class AreaTreeParser {
}
} else {
ContentHandlerFactoryRegistry registry
= userAgent.getFactory().getContentHandlerFactoryRegistry();
= userAgent.getContentHandlerFactoryRegistry();
ContentHandlerFactory factory = registry.getFactory(uri);
if (factory != null) {
delegate = factory.createContentHandler();
@@ -1102,7 +1102,7 @@ public class AreaTreeParser {
bkg.setURL(uri);

try {
ImageManager manager = userAgent.getFactory().getImageManager();
ImageManager manager = userAgent.getImageManager();
ImageSessionContext sessionContext
= userAgent.getImageSessionContext();
ImageInfo info = manager.getImageInfo(uri, sessionContext);

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

@@ -39,9 +39,10 @@ import org.apache.fop.Version;
import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.apps.FOPException;
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.MimeConstants;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.pdf.PDFAMode;
import org.apache.fop.pdf.PDFEncryptionManager;
import org.apache.fop.pdf.PDFEncryptionParams;
@@ -51,12 +52,13 @@ import org.apache.fop.render.awt.AWTRenderer;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFSerializer;
import org.apache.fop.render.pdf.PDFConfigurationConstants;
import org.apache.fop.render.print.PagesMode;
import org.apache.fop.render.print.PrintRenderer;
import org.apache.fop.render.xml.XMLRenderer;
import org.apache.fop.util.CommandLineLogger;

import static org.apache.fop.render.pdf.PDFRendererConfigOptions.ENCRYPTION_PARAMS;

/**
* Options parses the commandline arguments
*/
@@ -116,12 +118,14 @@ public class CommandLineOptions {
private Map renderingOptions = new java.util.HashMap();
/* target resolution (for the user agent) */
private int targetResolution = 0;

private boolean strictValidation = true;
/* control memory-conservation policy */
private boolean conserveMemoryPolicy = false;
/* true if a complex script features are enabled */
private boolean useComplexScriptFeatures = true;

private FopFactory factory = FopFactory.newInstance();
private FopFactory factory;
private FOUserAgent foUserAgent;

private InputHandler inputHandler;
@@ -183,9 +187,10 @@ public class CommandLineOptions {
addXSLTParameter("fop-output-format", getOutputFormat());
addXSLTParameter("fop-version", Version.getVersion());
foUserAgent.setConserveMemoryPolicy(conserveMemoryPolicy);
if (!useComplexScriptFeatures) {
foUserAgent.setComplexScriptFeaturesEnabled(false);
}
// TODO: Handle this!!
//if (!useComplexScriptFeatures) {
// foUserAgent.setComplexScriptFeaturesEnabled(false);
//}
} else {
return false;
}
@@ -225,9 +230,7 @@ public class CommandLineOptions {
} else if (MimeConstants.MIME_FOP_IF.equals(outputmode)
&& mimicRenderer != null) {
// render from FO to Intermediate Format
IFSerializer serializer = new IFSerializer();
serializer.setContext(new IFContext(foUserAgent));

IFSerializer serializer = new IFSerializer(new IFContext(foUserAgent));
IFDocumentHandler targetHandler
= foUserAgent.getRendererFactory().createDocumentHandler(
foUserAgent, mimicRenderer);
@@ -288,7 +291,7 @@ public class CommandLineOptions {
} else if (args[i].equals("-d")) {
setLogOption("debug", "debug");
} else if (args[i].equals("-r")) {
factory.setStrictValidation(false);
strictValidation = false;
} else if (args[i].equals("-conserve")) {
conserveMemoryPolicy = true;
} else if (args[i].equals("-flush")) {
@@ -819,15 +822,14 @@ public class CommandLineOptions {
}

private PDFEncryptionParams getPDFEncryptionParams() throws FOPException {
PDFEncryptionParams params = (PDFEncryptionParams)renderingOptions.get(
PDFConfigurationConstants.ENCRYPTION_PARAMS);
PDFEncryptionParams params = (PDFEncryptionParams) renderingOptions.get(ENCRYPTION_PARAMS);
if (params == null) {
if (!PDFEncryptionManager.checkAvailableAlgorithms()) {
throw new FOPException("PDF encryption requested but it is not available."
+ " Please make sure MD5 and RC4 algorithms are available.");
}
params = new PDFEncryptionParams();
renderingOptions.put(PDFConfigurationConstants.ENCRYPTION_PARAMS, params);
renderingOptions.put(ENCRYPTION_PARAMS, params);
}
return params;
}
@@ -860,7 +862,7 @@ public class CommandLineOptions {
throw new FOPException("You must specify a PDF profile");
} else {
String profile = args[i + 1];
PDFAMode pdfAMode = PDFAMode.valueOf(profile);
PDFAMode pdfAMode = PDFAMode.getValueOf(profile);
if (pdfAMode != null && pdfAMode != PDFAMode.DISABLED) {
if (renderingOptions.get("pdf-a-mode") != null) {
throw new FOPException("PDF/A mode already set");
@@ -868,7 +870,7 @@ public class CommandLineOptions {
renderingOptions.put("pdf-a-mode", pdfAMode.getName());
return 1;
} else {
PDFXMode pdfXMode = PDFXMode.valueOf(profile);
PDFXMode pdfXMode = PDFXMode.getValueOf(profile);
if (pdfXMode != null && pdfXMode != PDFXMode.DISABLED) {
if (renderingOptions.get("pdf-x-mode") != null) {
throw new FOPException("PDF/X mode already set");
@@ -1027,14 +1029,18 @@ public class CommandLineOptions {
* @throws IOException
*/
private void setUserConfig() throws FOPException, IOException {
FopFactoryBuilder fopFactoryBuilder;
if (userConfigFile == null) {
return;
}
try {
factory.setUserConfig(userConfigFile);
} catch (SAXException e) {
throw new FOPException(e);
fopFactoryBuilder = new FopFactoryBuilder(new File(".").toURI());
} else {
try {
fopFactoryBuilder = new FopConfParser(userConfigFile).getFopFactoryBuilder();
} catch (SAXException e) {
throw new FOPException(e);
}
fopFactoryBuilder.setStrictFOValidation(strictValidation);
}
factory = fopFactoryBuilder.build();
}

/**
@@ -1390,13 +1396,7 @@ public class CommandLineOptions {
}

private void flushCache() throws FOPException {
FontManager fontManager = factory.getFontManager();
File cacheFile = fontManager.getCacheFile();
if (!fontManager.deleteCache()) {
System.err.println("Failed to flush the font cache file '"
+ cacheFile + "'.");
System.exit(1);
}
factory.getFontManager().deleteCache();
}
}


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

@@ -62,7 +62,7 @@ public class IFInputHandler extends InputHandler {
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out)
throws FOPException {
IFDocumentHandler documentHandler
= userAgent.getFactory().getRendererFactory().createDocumentHandler(
= userAgent.getRendererFactory().createDocumentHandler(
userAgent, outputFormat);
try {
documentHandler.setResult(new StreamResult(out));

+ 2
- 17
src/java/org/apache/fop/cli/InputHandler.java View File

@@ -51,7 +51,6 @@ import org.apache.fop.ResourceEventProducer;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.render.awt.viewer.Renderable;

/**
@@ -103,25 +102,11 @@ public class InputHandler implements ErrorListener, Renderable {
public void renderTo(FOUserAgent userAgent, String outputFormat, OutputStream out)
throws FOPException {

FopFactory factory = userAgent.getFactory();
Fop fop;
if (out != null) {
fop = factory.newFop(outputFormat, userAgent, out);
fop = userAgent.newFop(outputFormat, out);
} else {
fop = factory.newFop(outputFormat, userAgent);
}

// if base URL was not explicitly set in FOUserAgent, obtain here
if (fop.getUserAgent().getBaseURL() == null && sourcefile != null) {
String baseURL = null;

try {
baseURL = new File(sourcefile.getAbsolutePath())
.getParentFile().toURI().toURL().toExternalForm();
} catch (Exception e) {
baseURL = "";
}
fop.getUserAgent().setBaseURL(baseURL);
fop = userAgent.newFop(outputFormat);
}

// Resulting SAX events (the generated FO) must be piped through to FOP

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

@@ -99,7 +99,7 @@ public class FOTreeBuilder extends DefaultHandler {
throws FOPException {

this.userAgent = foUserAgent;
this.elementMappingRegistry = userAgent.getFactory().getElementMappingRegistry();
this.elementMappingRegistry = userAgent.getElementMappingRegistry();
//This creates either an AreaTreeHandler and ultimately a Renderer, or
//one of the RTF-, MIF- etc. Handlers.
foEventHandler = foUserAgent.getRendererFactory().createFOEventHandler(

+ 4
- 4
src/java/org/apache/fop/fo/PropertyList.java View File

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

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
import org.apache.fop.fo.properties.CommonAural;
@@ -308,7 +308,7 @@ public abstract class PropertyList {
String attributeNS;
String attributeName;
String attributeValue;
FopFactory factory = getFObj().getUserAgent().getFactory();
FOUserAgent userAgent = getFObj().getUserAgent();
for (int i = 0; i < attributes.getLength(); i++) {
/* convert all attributes with the same namespace as the fo element
* the "xml:lang" and "xml:base" properties are special cases */
@@ -319,8 +319,8 @@ public abstract class PropertyList {
|| "xml:lang".equals(attributeName)
|| "xml:base".equals(attributeName)) {
convertAttributeToProperty(attributes, attributeName, attributeValue);
} else if (!factory.isNamespaceIgnored(attributeNS)) {
ElementMapping mapping = factory.getElementMappingRegistry().getElementMapping(
} else if (!userAgent.isNamespaceIgnored(attributeNS)) {
ElementMapping mapping = userAgent.getElementMappingRegistry().getElementMapping(
attributeNS);
QName attr = new QName(attributeNS, attributeName);
if (mapping != null) {

+ 6
- 6
src/java/org/apache/fop/fo/extensions/svg/SVGElement.java View File

@@ -23,7 +23,8 @@ package org.apache.fop.fo.extensions.svg;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.net.URL;
import java.io.File;
import java.net.URI;

import org.w3c.dom.Element;

@@ -71,12 +72,11 @@ public class SVGElement extends SVGObj {
/* if width and height are zero, get the bounds of the content. */

try {
URL baseURL = new URL(getUserAgent().getBaseURL() == null
? new java.io.File("").toURI().toURL().toExternalForm()
: getUserAgent().getBaseURL());
if (baseURL != null) {
URI baseUri = getUserAgent().getNewURIResolver().getBaseURI();
baseUri = baseUri == null ? new File("").toURI() : baseUri;
if (baseUri != null) {
SVGOMDocument svgdoc = (SVGOMDocument)doc;
svgdoc.setURLObject(baseURL);
svgdoc.setURLObject(baseUri.toURL());
//The following line should not be called to leave FOP compatible to Batik 1.6.
//svgdoc.setDocumentURI(baseURL.toString());
}

+ 1
- 1
src/java/org/apache/fop/fo/flow/ExternalGraphic.java View File

@@ -75,7 +75,7 @@ public class ExternalGraphic extends AbstractGraphics {
//Additional processing: obtain the image's intrinsic size and baseline information
url = URISpecification.getURL(src);
FOUserAgent userAgent = getUserAgent();
ImageManager manager = userAgent.getFactory().getImageManager();
ImageManager manager = userAgent.getImageManager();
ImageInfo info = null;
try {
info = manager.getImageInfo(url, userAgent.getImageSessionContext());

+ 1
- 1
src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java View File

@@ -374,7 +374,7 @@ public class CommonBorderPaddingBackground {
String uri = URISpecification.getURL(newInstance.backgroundImage);
FObj fobj = pList.getFObj();
FOUserAgent userAgent = pList.getFObj().getUserAgent();
ImageManager manager = userAgent.getFactory().getImageManager();
ImageManager manager = userAgent.getImageManager();
ImageSessionContext sessionContext = userAgent.getImageSessionContext();
ImageInfo info;
try {

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

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

package org.apache.fop.fonts;

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

//Java

/**
@@ -29,6 +31,13 @@ public abstract class CIDFont extends CustomFont {
/** Contains the character widths for all characters in the font */
protected int[] width = null;

/**
* @param resolver the URI resolver for controlling file access
*/
public CIDFont(URIResolverWrapper resolver) {
super(resolver);
}

// ---- Required ----
/**
* Returns the type of the CID font.

+ 38
- 44
src/java/org/apache/fop/fonts/CustomFont.java View File

@@ -20,13 +20,15 @@
package org.apache.fop.fonts;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.Source;
import org.apache.fop.apps.io.URIResolverWrapper;


/**
@@ -35,26 +37,26 @@ import javax.xml.transform.Source;
public abstract class CustomFont extends Typeface
implements FontDescriptor, MutableFont {

private String fontName = null;
private String fullName = null;
private Set<String> familyNames = null;
private String fontSubName = null;
private String embedFileName = null;
private String embedResourceName = null;
private FontResolver resolver = null;
private int capHeight = 0;
private int xHeight = 0;
private int ascender = 0;
private int descender = 0;
private String fontName;
private String fullName;
private Set<String> familyNames;
private String fontSubName;
private URI embedFileURI;
private String embedResourceName;
private final URIResolverWrapper resolver;
private int capHeight;
private int xHeight;
private int ascender;
private int descender;
private int[] fontBBox = {0, 0, 0, 0};
private int flags = 4;
private int weight = 0; //0 means unknown weight
private int stemV = 0;
private int italicAngle = 0;
private int missingWidth = 0;
private int weight; //0 means unknown weight
private int stemV;
private int italicAngle;
private int missingWidth;
private FontType fontType = FontType.TYPE1;
private int firstChar = 0;
private int firstChar;
private int lastChar = 255;

private Map<Integer, Map<Integer, Integer>> kerning;
@@ -62,6 +64,13 @@ public abstract class CustomFont extends Typeface
private boolean useKerning = true;
private boolean useAdvanced = true;

/**
* @param resolver the URI resolver for controlling file access
*/
public CustomFont(URIResolverWrapper resolver) {
this.resolver = resolver;
}

/** {@inheritDoc} */
public String getFontName() {
return fontName;
@@ -103,29 +112,22 @@ public abstract class CustomFont extends Typeface
}

/**
* Returns an URI representing an embeddable font file. The URI will often
* be a filename or an URL.
* Returns an URI representing an embeddable font file.
*
* @return URI to an embeddable font file or null if not available.
*/
public String getEmbedFileName() {
return embedFileName;
public URI getEmbedFileURI() {
return embedFileURI;
}

/**
* Returns a Source representing an embeddable font file.
* @return Source for an embeddable font file
* Returns an {@link InputStream} representing an embeddable font file.
*
* @return {@link InputStream} for an embeddable font file
* @throws IOException if embedFileName is not null but Source is not found
*/
public Source getEmbedFileSource() throws IOException {
Source result = null;
if (resolver != null && embedFileName != null) {
result = resolver.resolve(embedFileName);
if (result == null) {
throw new IOException("Unable to resolve Source '"
+ embedFileName + "' for embedded font");
}
}
return result;
public InputStream getInputStream() throws IOException {
return resolver.resolveIn(embedFileURI);
}

/**
@@ -323,8 +325,8 @@ public abstract class CustomFont extends Typeface
/**
* {@inheritDoc}
*/
public void setEmbedFileName(String path) {
this.embedFileName = path;
public void setEmbedURI(URI path) {
this.embedFileURI = path;
}

/**
@@ -444,14 +446,6 @@ public abstract class CustomFont extends Typeface
this.useAdvanced = enabled;
}

/**
* Sets the font resolver. Needed for URI resolution.
* @param resolver the font resolver
*/
public void setResolver(FontResolver resolver) {
this.resolver = resolver;
}

/** {@inheritDoc} */
public void putKerningEntry(Integer key, Map<Integer, Integer> value) {
if (kerning == null) {

+ 10
- 18
src/java/org/apache/fop/fonts/CustomFontCollection.java View File

@@ -21,13 +21,16 @@ package org.apache.fop.fonts;

import java.util.List;

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

/**
* Sets up a set of custom (embedded) fonts
*/
public class CustomFontCollection implements FontCollection {

private FontResolver fontResolver;
private final List<EmbedFontInfo> embedFontInfoList;
private final URIResolverWrapper uriResolver;
private final boolean useComplexScripts;

/**
* Main constructor.
@@ -35,14 +38,11 @@ public class CustomFontCollection implements FontCollection {
* @param customFonts the list of custom fonts
* @param useComplexScriptFeatures true if complex script features enabled
*/
public CustomFontCollection(FontResolver fontResolver,
List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) {
this.fontResolver = fontResolver;
if (this.fontResolver == null) {
//Ensure that we have minimal font resolution capabilities
this.fontResolver = FontManager.createMinimalFontResolver(useComplexScriptFeatures);
}
public CustomFontCollection(URIResolverWrapper fontResolver,
List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) {
this.uriResolver = fontResolver;
this.embedFontInfoList = customFonts;
this.useComplexScripts = useComplexScriptFeatures;
}

/** {@inheritDoc} */
@@ -52,27 +52,19 @@ public class CustomFontCollection implements FontCollection {
}

String internalName = null;
//FontReader reader = null;

for (int i = 0; i < embedFontInfoList.size(); i++) {
EmbedFontInfo embedFontInfo = embedFontInfoList.get(i);

//String metricsFile = configFontInfo.getMetricsFile();
internalName = "F" + num;
num++;
/*
reader = new FontReader(metricsFile);
reader.useKerning(configFontInfo.getKerning());
reader.setFontEmbedPath(configFontInfo.getEmbedFile());
fontInfo.addMetrics(internalName, reader.getFont());
*/

LazyFont font = new LazyFont(embedFontInfo, this.fontResolver);
LazyFont font = new LazyFont(embedFontInfo, this.uriResolver, useComplexScripts);
fontInfo.addMetrics(internalName, font);

List<FontTriplet> triplets = embedFontInfo.getFontTriplets();
for (int tripletIndex = 0; tripletIndex < triplets.size(); tripletIndex++) {
FontTriplet triplet = (FontTriplet) triplets.get(tripletIndex);
FontTriplet triplet = triplets.get(tripletIndex);
fontInfo.addFontProperties(internalName, triplet);
}
}

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

@@ -0,0 +1,335 @@
/*
* 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.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOPException;
import org.apache.fop.events.EventProducer;
import org.apache.fop.util.LogUtil;

/**
* The font configuration data for the more generic fonts such as TTF and Type1, that are used by
* most the renderers.
*/
public final class DefaultFontConfig implements FontConfig {

protected static Log log = LogFactory.getLog(DefaultFontConfig.class);

private final List<Directory> directories = new ArrayList<Directory>();

private final List<Font> fonts = new ArrayList<Font>();

private final List<String> referencedFontFamilies = new ArrayList<String>();

private final boolean autoDetectFonts;

private DefaultFontConfig(boolean autoDetectFonts) {
this.autoDetectFonts = autoDetectFonts;
}

/**
* Parses the morge generic font information.
*/
public static final class DefaultFontConfigParser implements FontConfig.FontConfigParser {
/**
* Parses the font configuration and return the configuration object.
*
* @param cfg the configuration data
* @param strict whether or not to enforce strict validation
* @return the font configuration object
* @throws FOPException if an error occurs when creating the configuration object
*/
public DefaultFontConfig parse(Configuration cfg, boolean strict) throws FOPException {
return new ParserHelper(cfg, strict).instance;
}

/** {@inheritDoc} */
public FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict,
EventProducer eventProducer) throws FOPException {
return parse(cfg, strict);
}
}

private static final class ParserHelper {

private boolean strict;

private Configuration fontInfoCfg;

private DefaultFontConfig instance;

private ParserHelper(Configuration cfg, boolean strict) throws FOPException {
if (cfg == null || cfg.getChild("fonts", false) == null) {
instance = null;
} else {
this.strict = strict;
this.fontInfoCfg = cfg.getChild("fonts", false);
instance = new DefaultFontConfig(cfg.getChild("auto-detect", false) != null);
parse();
}
}

private void parse() throws FOPException {
parseFonts();
parseReferencedFonts();
parseDirectories();
}

private void parseFonts() throws FOPException {
for (Configuration fontCfg : fontInfoCfg.getChildren("font")) {
String embed = fontCfg.getAttribute("embed-url", null);
if (embed == null) {
LogUtil.handleError(log, "Font configuration without embed-url attribute",
strict);
continue;
}
Font font = new Font(fontCfg.getAttribute("metrics-url", null), embed,
fontCfg.getAttribute("sub-font", null), fontCfg.getAttributeAsBoolean(
"kerning", true), fontCfg.getAttributeAsBoolean("advanced", true),
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()));
instance.fonts.add(font);
boolean hasTriplets = false;
for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) {
FontTriplet fontTriplet = getFontTriplet(tripletCfg, strict);
font.tripletList.add(fontTriplet);
hasTriplets = true;
}
// no font triplet info
if (!hasTriplets) {
LogUtil.handleError(log, "font without font-triplet", strict);
}
}
}

private void parseReferencedFonts() throws FOPException {
Configuration referencedFontsCfg = fontInfoCfg.getChild("referenced-fonts", false);
if (referencedFontsCfg != null) {
for (Configuration match : referencedFontsCfg.getChildren("match")) {
try {
instance.referencedFontFamilies.add(match.getAttribute("font-family"));
} catch (ConfigurationException ce) {
LogUtil.handleException(log, ce, strict);
continue;
}
}
}
}

private void parseDirectories() throws FOPException {
for (Configuration directoriesCfg : fontInfoCfg.getChildren("directory")) {
boolean recursive = directoriesCfg.getAttributeAsBoolean("recursive", false);
String directory;
try {
directory = directoriesCfg.getValue();
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
continue;
}
if (directory == null) {
LogUtil.handleException(log,
new FOPException("directory defined without value"), strict);
continue;
}
instance.directories.add(new Directory(directory, recursive));
}
}

/**
* Creates a new FontTriplet given a triple Configuration
*
* @param tripletCfg a triplet configuration
* @return a font triplet font key
* @throws FOPException thrown if a FOP exception occurs
*/
private FontTriplet getFontTriplet(Configuration tripletCfg, boolean strict)
throws FOPException {
try {
String name = tripletCfg.getAttribute("name");
if (name == null) {
LogUtil.handleError(log, "font-triplet without name", strict);
return null;
}
String weightStr = tripletCfg.getAttribute("weight");
if (weightStr == null) {
LogUtil.handleError(log, "font-triplet without weight", strict);
return null;
}
int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr));
String style = tripletCfg.getAttribute("style");
if (style == null) {
LogUtil.handleError(log, "font-triplet without style", strict);
return null;
} else {
style = FontUtil.stripWhiteSpace(style);
}
return FontInfo.createFontKey(name, style, weight);
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
return null;
}

}

/**
* Returns the list of fonts that were parsed.
* @return a list of fonts
*/
public List<Font> getFonts() {
return Collections.unmodifiableList(fonts);
}

/**
* Returns a list of directories that were parsed.
* @return a list of directories
*/
public List<Directory> getDirectories() {
return Collections.unmodifiableList(directories);
}

/**
* Returns a list of referenced font families.
* @return the referenced font families
*/
public List<String> getReferencedFontFamily() {
return Collections.unmodifiableList(referencedFontFamilies);
}

/**
* Whether or not to enable auto-detecting of fonts in the system.
* @return true to enable auto-detect
*/
public boolean isAutoDetectFonts() {
return autoDetectFonts;
}

/**
* The directory to find fonts within.
*/
public static final class Directory {

private final String directory;

private final boolean recursive;

private Directory(String directory, boolean recurse) {
this.directory = directory;
this.recursive = recurse;
}

/**
* Returns a String representing the directory to find fonts within.
* @return the directory
*/
public String getDirectory() {
return directory;
}

/**
* Returns whether or not to recurse through the directory when finding fonts.
* @return true to recurse through the directory and sub-directories
*/
public boolean isRecursive() {
return recursive;
}
}

/**
* Represents a font object within the FOP conf.
*/
public static final class Font {

private final String metrics;

private final String embedUri;

private final String subFont;

private final boolean kerning;

private final boolean advanced;

private final String encodingMode;

public String getEncodingMode() {
return encodingMode;
}

private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>();

public List<FontTriplet> getTripletList() {
return Collections.unmodifiableList(tripletList);
}

private Font(String metrics, String embed, String subFont, boolean kerning,
boolean advanced, String encodingMode) {
this.metrics = metrics;
this.embedUri = embed;
this.subFont = subFont;
this.kerning = kerning;
this.advanced = advanced;
this.encodingMode = encodingMode;
}

/**
* Whether or not to allow kerning of glyphs.
* @return true to allow glyph kerning
*/
public boolean isKerning() {
return kerning;
}
public boolean isAdvanced() {
return advanced;
}

/**
* Gets the String representing the metrics file.
* @return the metrics file
*/
public String getMetrics() {
return metrics;
}

/**
* Gets the URI of the font to embed.
* @return the font URI
*/
public String getEmbedURI() {
return embedUri;
}

/**
* Gets the sub font within, for example, a TTC.
* @return the sub font name
*/
public String getSubFont() {
return subFont;
}
}
}

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

@@ -0,0 +1,190 @@
/*
* 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.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.DefaultFontConfig.Directory;
import org.apache.fop.fonts.autodetect.FontFileFinder;
import org.apache.fop.fonts.autodetect.FontInfoFinder;
import org.apache.fop.util.LogUtil;

/**
* The default configurator for fonts. This configurator can configure the more generic fonts used
* by the renderers i.e. TTF, Type1 etc...
*/
public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo> {
/** logger instance */
protected static Log log = LogFactory.getLog(DefaultFontConfigurator.class);

private final FontManager fontManager;
private final URIResolverWrapper uriResolver;
private final FontEventListener listener;
private final boolean strict;

/**
* 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.
*/
public DefaultFontConfigurator(FontManager fontManager, FontEventListener listener, boolean strict) {
this.fontManager = fontManager;
this.uriResolver = fontManager.getURIResolver();
this.listener = listener;
this.strict = strict;
}

/**
* Initializes font info settings from the user configuration
* @throws FOPException if an exception occurs while processing the configuration
*/
public List<EmbedFontInfo> configure(FontConfig fontInfoConfig)
throws FOPException {
List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>();
DefaultFontConfig adobeFontInfoConfig = (DefaultFontConfig) fontInfoConfig;
if (adobeFontInfoConfig != null) {
long start = 0;
if (log.isDebugEnabled()) {
log.debug("Starting font configuration...");
start = System.currentTimeMillis();
}
FontAdder fontAdder = new FontAdder(fontManager, uriResolver, listener);
// native o/s search (autodetect) configuration
fontManager.autoDetectFonts(adobeFontInfoConfig.isAutoDetectFonts(), fontAdder, strict,
listener, fontInfoList);
// Add configured directories to FontInfo list
addDirectories(adobeFontInfoConfig, fontAdder, fontInfoList);
// Add configured fonts to FontInfo
FontCache fontCache = fontManager.getFontCache();
try {
addFonts(adobeFontInfoConfig, fontCache, fontInfoList);
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, strict);
}
// Update referenced fonts (fonts which are not to be embedded)
fontManager.updateReferencedFonts(fontInfoList);
// Renderer-specific referenced fonts
List<String> referencedFonts = adobeFontInfoConfig.getReferencedFontFamily();
if (referencedFonts.size() > 0) {
FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher(
referencedFonts, strict);
fontManager.updateReferencedFonts(fontInfoList, matcher);
}
// Update font cache if it has changed
fontManager.saveCache();
if (log.isDebugEnabled()) {
log.debug("Finished font configuration in "
+ (System.currentTimeMillis() - start) + "ms");
}
}
return Collections.unmodifiableList(fontInfoList);
}

private void addDirectories(DefaultFontConfig fontInfoConfig, FontAdder fontAdder,
List<EmbedFontInfo> fontInfoList) throws FOPException {
// directory (multiple font) configuration
List<Directory> directories = fontInfoConfig.getDirectories();
for (Directory directory : directories) {
// add fonts found in directory
FontFileFinder fontFileFinder = new FontFileFinder(directory.isRecursive() ? -1 : 1, listener);
List<URL> fontURLList;
try {
fontURLList = fontFileFinder.find(directory.getDirectory());
fontAdder.add(fontURLList, fontInfoList);
} catch (IOException e) {
LogUtil.handleException(log, e, strict);
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, strict);
}
}
}

private void addFonts(DefaultFontConfig fontInfoConfig, FontCache fontCache,
List<EmbedFontInfo> fontInfoList) throws FOPException, URISyntaxException {
// font file (singular) configuration
List<DefaultFontConfig.Font> fonts = fontInfoConfig.getFonts();
for (DefaultFontConfig.Font font : fonts) {
EmbedFontInfo embedFontInfo = getFontInfo(font, fontCache);
if (embedFontInfo != null) {
fontInfoList.add(embedFontInfo);
}
}
}

private EmbedFontInfo getFontInfo(DefaultFontConfig.Font font, FontCache fontCache)
throws FOPException, URISyntaxException {
String embed = font.getEmbedURI();
String metrics = font.getMetrics();
String subFont = font.getSubFont();
URI metricsUri = metrics == null ? null : URIResolverWrapper.cleanURI(metrics);
URI embedUri = URIResolverWrapper.cleanURI(embed);

List<FontTriplet> tripletList = font.getTripletList();

// no font triplet info
if (tripletList.size() == 0) {
//TODO: could be problematic!!
URI fontUri = uriResolver.getBaseURI().resolve(embedUri);
if (fontUri != null) {
FontInfoFinder finder = new FontInfoFinder();
finder.setEventListener(listener);
EmbedFontInfo[] infos = finder.find(fontUri, uriResolver, fontCache);
return infos[0]; //When subFont is set, only one font is returned
} else {
return null;
}
}
EncodingMode encodingMode = EncodingMode.getEncodingMode(font.getEncodingMode());
EmbedFontInfo embedFontInfo = new EmbedFontInfo(metricsUri, font.isKerning(),
font.isAdvanced(), tripletList, embedUri, subFont, encodingMode);
if (fontCache != null) {
if (!fontCache.containsFont(embedFontInfo)) {
fontCache.addFont(embedFontInfo, uriResolver);
}
}

if (log.isDebugEnabled()) {
URI embedFile = embedFontInfo.getEmbedURI();
log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "")
+ "metrics URI " + embedFontInfo.getMetricsURI());
for (int j = 0; j < tripletList.size(); ++j) {
FontTriplet triplet = tripletList.get(j);
log.debug(" Font triplet "
+ triplet.getName() + ", "
+ triplet.getStyle() + ", "
+ triplet.getWeight());
}
}
return embedFontInfo;
}
}

+ 42
- 38
src/java/org/apache/fop/fonts/EmbedFontInfo.java View File

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

import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.util.List;

/**
@@ -31,60 +32,74 @@ public class EmbedFontInfo implements Serializable {
/** Serialization Version UID */
private static final long serialVersionUID = 8755432068669997369L;

/** filename of the metrics file */
protected String metricsFile;
/** filename of the main font file */
protected String embedFile;
protected final URI metricsURI;
protected final URI embedURI;
/** false, to disable kerning */
protected boolean kerning;
protected final boolean kerning;
/** false, to disable advanced typographic features */
protected boolean advanced;
protected final boolean advanced;
/** the requested encoding mode for the font */
protected EncodingMode encodingMode = EncodingMode.AUTO;
private final EncodingMode encodingMode;

/** the PostScript name of the font */
protected String postScriptName = null;
protected String postScriptName;
/** the sub-fontname of the font (used for TrueType Collections, null otherwise) */
protected String subFontName = null;
protected String subFontName;

/** the list of associated font triplets */
private List<FontTriplet> fontTriplets = null;
private List<FontTriplet> fontTriplets;

private transient boolean embedded = true;

/**
* Main constructor
* @param metricsFile path to the xml file containing font metrics
* @param kerning true if kerning should be enabled
* @param metricsURI the URI of the XML resource containing font metrics
* @param kerning True if kerning should be enabled
* @param advanced true if advanced typography features should be enabled
* @param fontTriplets list of font triplets to associate with this font
* @param embedFile path to the embeddable font file (may be null)
* @param fontTriplets List of font triplets to associate with this font
* @param embedURI Path to the embeddable font file (may be null)
* @param subFontName the sub-fontname used for TrueType Collections (null otherwise)
* @param encodingMode the encoding mode to use for this font
*/
public EmbedFontInfo(String metricsFile, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, String embedFile, String subFontName) {
this.metricsFile = metricsFile;
this.embedFile = embedFile;
public EmbedFontInfo(URI metricsURI, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, URI embedURI, String subFontName) {
this.metricsURI = metricsURI;
this.embedURI = embedURI;
this.kerning = kerning;
this.advanced = advanced;
this.fontTriplets = fontTriplets;
this.subFontName = subFontName;
this.encodingMode = EncodingMode.AUTO;
}

public EmbedFontInfo(URI metricsURI, boolean kerning, boolean advanced,
List<FontTriplet> fontTriplets, URI embedURI, String subFontName,
EncodingMode encodingMode) {
this.metricsURI = metricsURI;
this.embedURI = embedURI;
this.kerning = kerning;
this.advanced = advanced;
this.fontTriplets = fontTriplets;
this.subFontName = subFontName;
this.encodingMode = encodingMode;
}

/**
* Returns the path to the metrics file
* Returns the URI of the metrics XML resource
*
* @return the metrics file path
*/
public String getMetricsFile() {
return metricsFile;
public URI getMetricsURI() {
return metricsURI;
}

/**
* Returns the path to the embeddable font file
* @return the font file path
* Returns the URI to the embeddable font resource
*
* @return the font resource URI
*/
public String getEmbedFile() {
return embedFile;
public URI getEmbedURI() {
return embedURI;
}

/**
@@ -141,7 +156,7 @@ public class EmbedFontInfo implements Serializable {
* @return true if the font is embedded, false if it is referenced.
*/
public boolean isEmbedded() {
if (metricsFile != null && embedFile == null) {
if (embedURI == null) {
return false;
} else {
return this.embedded;
@@ -164,17 +179,6 @@ public class EmbedFontInfo implements Serializable {
return this.encodingMode;
}

/**
* Sets the requested encoding mode for this font.
* @param mode the new encoding mode
*/
public void setEncodingMode(EncodingMode mode) {
if (mode == null) {
throw new NullPointerException("mode must not be null");
}
this.encodingMode = mode;
}

private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
@@ -183,7 +187,7 @@ public class EmbedFontInfo implements Serializable {

/** {@inheritDoc} */
public String toString() {
return "metrics-url=" + metricsFile + ", embed-url=" + embedFile
return "metrics-uri=" + metricsURI + ", embed-uri=" + embedURI
+ ", kerning=" + kerning
+ ", advanced=" + advanced
+ ", enc-mode=" + encodingMode

+ 8
- 4
src/java/org/apache/fop/fonts/FontAdder.java View File

@@ -19,9 +19,11 @@

package org.apache.fop.fonts;

import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.autodetect.FontInfoFinder;

/**
@@ -29,7 +31,7 @@ import org.apache.fop.fonts.autodetect.FontInfoFinder;
*/
public class FontAdder {
private final FontEventListener listener;
private final FontResolver resolver;
private final URIResolverWrapper resolver;
private final FontManager manager;

/**
@@ -38,7 +40,7 @@ public class FontAdder {
* @param resolver a font resolver
* @param listener a font event handler
*/
public FontAdder(FontManager manager, FontResolver resolver, FontEventListener listener) {
public FontAdder(FontManager manager, URIResolverWrapper resolver, FontEventListener listener) {
this.manager = manager;
this.resolver = resolver;
this.listener = listener;
@@ -48,14 +50,16 @@ public class FontAdder {
* Iterates over font url list adding to font info list
* @param fontURLList font file list
* @param fontInfoList a configured font info list
* @throws URISyntaxException if a URI syntax error is found
*/
public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList) {
public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList)
throws URISyntaxException {
FontCache cache = manager.getFontCache();
FontInfoFinder finder = new FontInfoFinder();
finder.setEventListener(listener);

for (URL fontURL : fontURLList) {
EmbedFontInfo[] embedFontInfos = finder.find(fontURL, resolver, cache);
EmbedFontInfo[] embedFontInfos = finder.find(fontURL.toURI(), resolver, cache);
if (embedFontInfos == null) {
continue;
}

+ 12
- 9
src/java/org/apache/fop/fonts/FontCache.java View File

@@ -29,6 +29,7 @@ import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
@@ -40,6 +41,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.util.LogUtil;

/**
@@ -234,9 +236,9 @@ public final class FontCache implements Serializable {
*/
protected static String getCacheKey(EmbedFontInfo fontInfo) {
if (fontInfo != null) {
String embedFile = fontInfo.getEmbedFile();
String metricsFile = fontInfo.getMetricsFile();
return (embedFile != null) ? embedFile : metricsFile;
URI embedFile = fontInfo.getEmbedURI();
URI metricsFile = fontInfo.getMetricsURI();
return (embedFile != null) ? embedFile.toASCIIString() : metricsFile.toASCIIString();
}
return null;
}
@@ -318,7 +320,7 @@ public final class FontCache implements Serializable {
* @param fontInfo
* font info
*/
public void addFont(EmbedFontInfo fontInfo) {
public void addFont(EmbedFontInfo fontInfo, URIResolverWrapper resolver) {
String cacheKey = getCacheKey(fontInfo);
synchronized (changeLock) {
CachedFontFile cachedFontFile;
@@ -329,10 +331,10 @@ public final class FontCache implements Serializable {
}
} else {
// try and determine modified date
File fontFile = getFileFromUrls(new String[] {
fontInfo.getEmbedFile(), fontInfo.getMetricsFile() });
long lastModified = (fontFile != null ? fontFile.lastModified()
: -1);
// TODO: This could be problematic?!!?!?!
URI fontUri = resolver.getBaseURI().resolve(fontInfo.getEmbedURI());
File fontFile = new File(fontUri);
long lastModified = (fontFile != null ? fontFile.lastModified() : -1);
cachedFontFile = new CachedFontFile(lastModified);
if (log.isTraceEnabled()) {
log.trace("Font added to cache: " + cacheKey);
@@ -467,8 +469,9 @@ public final class FontCache implements Serializable {
* the URL
* @return the last modified date/time
*/
public static long getLastModified(URL url) {
public static long getLastModified(URI uri) {
try {
URL url = uri.toURL();
URLConnection conn = url.openConnection();
try {
return conn.getLastModified();

src/java/org/apache/fop/fonts/FontResolver.java → src/java/org/apache/fop/fonts/FontCacheManager.java View File

@@ -19,27 +19,35 @@

package org.apache.fop.fonts;

import javax.xml.transform.Source;
import java.io.File;

import org.apache.fop.apps.FOPException;


/**
* This interface is used to resolve absolute and relative font URIs.
* Fop cache (currently only used for font info caching)
*/
public interface FontResolver {
public interface FontCacheManager {

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

/**
* Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's
* resolve() method is defined to be implicitly available in this case. If the URI cannot
* be resolved, null is returned and it is assumed that the FontResolver implementation
* already warned the user about the problem.
* @param href An href attribute, which may be relative or absolute.
* @return A Source object, or null if the href could not resolved.
* 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
*/
Source resolve(String href);
void save(File file) throws FOPException;

/**
* Check whether complex script features are enabled.
* @return true if FOP is to use complex script features
* 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
*/
boolean isComplexScriptFeaturesEnabled();
void delete(File file) throws FOPException;

}

+ 92
- 0
src/java/org/apache/fop/fonts/FontCacheManagerFactory.java View File

@@ -0,0 +1,92 @@
/*
* 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.io.File;

import org.apache.fop.apps.FOPException;

/**
* A factory that provides the font caching manager mechanism.
*
*/
public final class FontCacheManagerFactory {

private FontCacheManagerFactory() {
}

/**
* Create the default font caching mechanism.
* @return the font cache manager
*/
public static FontCacheManager createDefault() {
return new FontCacheManagerImpl();
}

/**
* Create a disabled font caching mechanism which by definition does nothing to cache fonts.
* @return a completely restricted font cache manager
*/
public static FontCacheManager createDisabled() {
return new DisabledFontCacheManager();
}

private static final class FontCacheManagerImpl implements FontCacheManager {

private FontCache fontCache;

public FontCache load(File cacheFile) {
if (fontCache == null) {
fontCache = FontCache.loadFrom(cacheFile);
if (fontCache == null) {
fontCache = new FontCache();
}
}
return fontCache;
}

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

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

private static final class DisabledFontCacheManager implements FontCacheManager {

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

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

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

+ 50
- 0
src/java/org/apache/fop/fonts/FontConfig.java View File

@@ -0,0 +1,50 @@
/*
* 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 org.apache.avalon.framework.configuration.Configuration;

import org.apache.fop.apps.FOPException;
import org.apache.fop.events.EventProducer;

/**
* An interface for font configuration information.
*/
public interface FontConfig {

/**
* An interface for parsing font configuration information.
*/
public interface FontConfigParser {

/**
* Parse the font configuration and return an object containing all the necessary data.
*
* @param cfg the configuration object
* @param fontManager the font manager
* @param strict whether or not to enforce strict validation
* @param eventProducer the event producer for handling font events
* @return the configuration object
* @throws FOPException if an error occurs creating the font configuration object
*/
FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict,
EventProducer eventProducer) throws FOPException;
}
}

+ 39
- 0
src/java/org/apache/fop/fonts/FontConfigurator.java View File

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

import org.apache.fop.apps.FOPException;

/**
* An abstract FontInfo configurator
*/
// TODO: Make T extends some interface to make the font info type explicit
public interface FontConfigurator<T> {

/**
* Initializes font info settings from the user configuration
* @return a font info list
* @throws FOPException if an exception occurs while processing the configuration
*/
List<T> configure(FontConfig fontInfoConfig) throws FOPException;

}

+ 5
- 77
src/java/org/apache/fop/fonts/FontDetector.java View File

@@ -17,90 +17,18 @@

/* $Id$ */


package org.apache.fop.fonts;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.List;

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

import org.apache.xmlgraphics.util.ClasspathResource;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fonts.autodetect.FontFileFinder;
import org.apache.fop.util.LogUtil;

/**
* Detector of operating system and classpath fonts
* An interface for the font detecting mechanism.
*/
public class FontDetector {
private static Log log = LogFactory.getLog(FontDetector.class);

private static final String[] FONT_MIMETYPES = {
"application/x-font", "application/x-font-truetype"
};

private final FontManager fontManager;
private final FontAdder fontAdder;
private final boolean strict;
private final FontEventListener eventListener;

/**
* Main constructor
* @param manager the font manager
* @param adder the font adder
* @param strict true if an Exception should be thrown if an error is found.
* @param listener for throwing font related events
*/
public FontDetector(FontManager manager, FontAdder adder, boolean strict,
FontEventListener listener) {
this.fontManager = manager;
this.fontAdder = adder;
this.strict = strict;
this.eventListener = listener;
}

/**
* Detect installed fonts on the system
* @param fontInfoList a list of fontinfo to populate
* @throws FOPException thrown if a problem occurred during detection
*/
public void detect(List<EmbedFontInfo> fontInfoList) throws FOPException {
// search in font base if it is defined and
// is a directory but don't recurse
FontFileFinder fontFileFinder = new FontFileFinder(eventListener);
String fontBaseURL = fontManager.getFontBaseURL();
if (fontBaseURL != null) {
try {
File fontBase = FileUtils.toFile(new URL(fontBaseURL));
if (fontBase != null) {
List<URL> fontURLList = fontFileFinder.find(fontBase.getAbsolutePath());
fontAdder.add(fontURLList, fontInfoList);

//Can only use the font base URL if it's a file URL
}
} catch (IOException e) {
LogUtil.handleException(log, e, strict);
}
}

// native o/s font directory finding
List<URL> systemFontList;
try {
systemFontList = fontFileFinder.find();
fontAdder.add(systemFontList, fontInfoList);
} catch (IOException e) {
LogUtil.handleException(log, e, strict);
}

// classpath font finding
ClasspathResource resource = ClasspathResource.getInstance();
for (int i = 0; i < FONT_MIMETYPES.length; i++) {
fontAdder.add(resource.listResourcesOfMimeType(FONT_MIMETYPES[i]), fontInfoList);
}
}
public interface FontDetector {
void detect(FontManager fontManager, FontAdder fontAdder, boolean strict,
FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) throws FOPException;
}

+ 121
- 0
src/java/org/apache/fop/fonts/FontDetectorFactory.java View File

@@ -0,0 +1,121 @@
/*
* 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.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;

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

import org.apache.xmlgraphics.util.ClasspathResource;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fonts.autodetect.FontFileFinder;
import org.apache.fop.util.LogUtil;

/**
* A factory that provides the font detecting machanism.
*/
public final class FontDetectorFactory {
private FontDetectorFactory() {
}

/**
* Creates the default font detector
* @return the default font detector
*/
public static FontDetector createDefault() {
return new DefaultFontDetector();
}

/**
* Creates a disabled font detector which, by definition, does nothing to detect fonts.
* @return the completely restricted font detector
*/
public static FontDetector createDisabled() {
return new DisabledFontDetector();
}


private static class DisabledFontDetector implements FontDetector {
public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict,
FontEventListener eventListener, List<EmbedFontInfo> fontInfoList)
throws FOPException {
// nop
}
}

/**
* Detector of operating system and classpath fonts
*/
private static class DefaultFontDetector implements FontDetector {
private static Log log = LogFactory.getLog(DefaultFontDetector.class);

private static final String[] FONT_MIMETYPES = {
"application/x-font", "application/x-font-truetype"
};

/**
* Detect installed fonts on the system
* @param fontInfoList a list of fontinfo to populate
* @throws FOPException thrown if a problem occurred during detection
*/
public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict,
FontEventListener eventListener, List<EmbedFontInfo> fontInfoList)
throws FOPException {
try {
// search in font base if it is defined and
// is a directory but don't recurse
FontFileFinder fontFileFinder = new FontFileFinder(eventListener);
URI fontBaseURI = fontManager.getURIResolver().getBaseURI();
if (fontBaseURI != null) {
File fontBase = FileUtils.toFile(fontBaseURI.toURL());
if (fontBase != null) {
List<URL> fontURLList = fontFileFinder.find(fontBase.getAbsolutePath());
fontAdder.add(fontURLList, fontInfoList);

//Can only use the font base URL if it's a file URL
}
}

// native o/s font directory finding
List<URL> systemFontList;
systemFontList = fontFileFinder.find();
fontAdder.add(systemFontList, fontInfoList);

// classpath font finding
ClasspathResource resource = ClasspathResource.getInstance();
for (String mimeTypes : FONT_MIMETYPES) {
fontAdder.add(resource.listResourcesOfMimeType(mimeTypes), fontInfoList);
}
} catch (IOException e) {
LogUtil.handleException(log, e, strict);
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, strict);
}
}
}
}

+ 0
- 324
src/java/org/apache/fop/fonts/FontInfoConfigurator.java View File

@@ -1,324 +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.fonts;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

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

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fonts.autodetect.FontFileFinder;
import org.apache.fop.fonts.autodetect.FontInfoFinder;
import org.apache.fop.util.LogUtil;

/**
* An abstract FontInfo configurator
*/
public class FontInfoConfigurator {
/** logger instance */
protected static final Log log = LogFactory.getLog(FontInfoConfigurator.class);

private final Configuration cfg;
private final FontManager fontManager;
private final FontResolver fontResolver;
private final FontEventListener listener;
private final boolean strict;

/**
* Main constructor
* @param cfg the configuration object
* @param fontManager the font manager
* @param fontResolver the font resolver
* @param listener the font event listener
* @param strict true if an Exception should be thrown if an error is found.
*/
public FontInfoConfigurator(Configuration cfg, FontManager fontManager,
FontResolver fontResolver, FontEventListener listener, boolean strict) {
this.cfg = cfg;
this.fontManager = fontManager;
this.fontResolver = fontResolver;
this.listener = listener;
this.strict = strict;
}

/**
* Initializes font info settings from the user configuration
* @param fontInfoList a font info list
* @throws FOPException if an exception occurs while processing the configuration
*/
public void configure(List<EmbedFontInfo> fontInfoList)
throws FOPException {
Configuration fontsCfg = cfg.getChild("fonts", false);
if (fontsCfg != null) {
long start = 0;
if (log.isDebugEnabled()) {
log.debug("Starting font configuration...");
start = System.currentTimeMillis();
}

FontAdder fontAdder = new FontAdder(fontManager, fontResolver, listener);

// native o/s search (autodetect) configuration
boolean autodetectFonts = (fontsCfg.getChild("auto-detect", false) != null);
if (autodetectFonts) {
FontDetector fontDetector = new FontDetector(fontManager, fontAdder, strict,
listener);
fontDetector.detect(fontInfoList);
}

// Add configured directories to FontInfo list
addDirectories(fontsCfg, fontAdder, fontInfoList);

// Add fonts from configuration to FontInfo list
addFonts(fontsCfg, fontManager.getFontCache(), fontInfoList);

// Update referenced fonts (fonts which are not to be embedded)
fontManager.updateReferencedFonts(fontInfoList);

// Renderer-specific referenced fonts
Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false);
if (referencedFontsCfg != null) {
FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher(
referencedFontsCfg, strict);
fontManager.updateReferencedFonts(fontInfoList, matcher);
}

// Update font cache if it has changed
fontManager.saveCache();

if (log.isDebugEnabled()) {
log.debug("Finished font configuration in "
+ (System.currentTimeMillis() - start) + "ms");
}
}
}

private void addDirectories(Configuration fontsCfg,
FontAdder fontAdder, List<EmbedFontInfo> fontInfoList) throws FOPException {
// directory (multiple font) configuration
Configuration[] directories = fontsCfg.getChildren("directory");
for (int i = 0; i < directories.length; i++) {
boolean recursive = directories[i].getAttributeAsBoolean("recursive", false);
String directory = null;
try {
directory = directories[i].getValue();
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
continue;
}
if (directory == null) {
LogUtil.handleException(log,
new FOPException("directory defined without value"), strict);
continue;
}

// add fonts found in directory
FontFileFinder fontFileFinder = new FontFileFinder(recursive ? -1 : 1, listener);
List<URL> fontURLList;
try {
fontURLList = fontFileFinder.find(directory);
fontAdder.add(fontURLList, fontInfoList);
} catch (IOException e) {
LogUtil.handleException(log, e, strict);
}
}
}

/**
* Populates the font info list from the fonts configuration
* @param fontsCfg a fonts configuration
* @param fontCache a font cache
* @param fontInfoList a font info list
* @throws FOPException if an exception occurs while processing the configuration
*/
protected void addFonts(Configuration fontsCfg, FontCache fontCache,
List<EmbedFontInfo> fontInfoList) throws FOPException {
// font file (singular) configuration
Configuration[] font = fontsCfg.getChildren("font");
for (int i = 0; i < font.length; i++) {
EmbedFontInfo embedFontInfo = getFontInfo(
font[i], fontCache);
if (embedFontInfo != null) {
fontInfoList.add(embedFontInfo);
}
}
}

private static void closeSource(Source src) {
if (src instanceof StreamSource) {
StreamSource streamSource = (StreamSource)src;
IOUtils.closeQuietly(streamSource.getInputStream());
IOUtils.closeQuietly(streamSource.getReader());
}
}

/**
* Returns a font info from a font node Configuration definition
*
* @param fontCfg Configuration object (font node)
* @param fontCache the font cache (or null if it is disabled)
* @return the embedded font info
* @throws FOPException if something's wrong with the config data
*/
protected EmbedFontInfo getFontInfo(Configuration fontCfg, FontCache fontCache)
throws FOPException {
String metricsUrl = fontCfg.getAttribute("metrics-url", null);
String embedUrl = fontCfg.getAttribute("embed-url", null);
String subFont = fontCfg.getAttribute("sub-font", null);

if (metricsUrl == null && embedUrl == null) {
LogUtil.handleError(log,
"Font configuration without metric-url or embed-url attribute",
strict);
return null;
}
if (strict) {
//This section just checks early whether the URIs can be resolved
//Stream are immediately closed again since they will never be used anyway
if (embedUrl != null) {
Source source = fontResolver.resolve(embedUrl);
closeSource(source);
if (source == null) {
LogUtil.handleError(log,
"Failed to resolve font with embed-url '" + embedUrl + "'", strict);
return null;
}
}
if (metricsUrl != null) {
Source source = fontResolver.resolve(metricsUrl);
closeSource(source);
if (source == null) {
LogUtil.handleError(log,
"Failed to resolve font with metric-url '" + metricsUrl + "'", strict);
return null;
}
}
}

Configuration[] tripletCfg = fontCfg.getChildren("font-triplet");

// no font triplet info
if (tripletCfg.length == 0) {
LogUtil.handleError(log, "font without font-triplet", strict);

File fontFile = FontCache.getFileFromUrls(new String[] {embedUrl, metricsUrl});
URL fontURL = null;
try {
fontURL = fontFile.toURI().toURL();
} catch (MalformedURLException e) {
LogUtil.handleException(log, e, strict);
}
if (fontFile != null) {
FontInfoFinder finder = new FontInfoFinder();
finder.setEventListener(listener);
EmbedFontInfo[] infos = finder.find(fontURL, fontResolver, fontCache);
return infos[0]; //When subFont is set, only one font is returned
} else {
return null;
}
}

List<FontTriplet> tripletList = new java.util.ArrayList<FontTriplet>();
for (int j = 0; j < tripletCfg.length; j++) {
FontTriplet fontTriplet = getFontTriplet(tripletCfg[j]);
tripletList.add(fontTriplet);
}

boolean useKerning = fontCfg.getAttributeAsBoolean("kerning", true);
boolean useAdvanced = fontCfg.getAttributeAsBoolean("advanced", true);
EncodingMode encodingMode = EncodingMode.getEncodingMode(
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()));
EmbedFontInfo embedFontInfo
= new EmbedFontInfo(metricsUrl, useKerning, useAdvanced, tripletList, embedUrl,
subFont);
embedFontInfo.setEncodingMode(encodingMode);
boolean skipCachedFont = false;
if (fontCache != null) {
if (!fontCache.containsFont(embedFontInfo)) {
fontCache.addFont(embedFontInfo);
} else {
skipCachedFont = true;
}
}

if (log.isDebugEnabled()) {
String embedFile = embedFontInfo.getEmbedFile();
log.debug( ( skipCachedFont ? "Skipping (cached) font " : "Adding font " )
+ (embedFile != null ? embedFile + ", " : "")
+ "metric file " + embedFontInfo.getMetricsFile());
for (int j = 0; j < tripletList.size(); ++j) {
FontTriplet triplet = tripletList.get(j);
log.debug(" Font triplet "
+ triplet.getName() + ", "
+ triplet.getStyle() + ", "
+ triplet.getWeight());
}
}
return embedFontInfo;
}

/**
* Creates a new FontTriplet given a triple Configuration
*
* @param tripletCfg a triplet configuration
* @return a font triplet font key
* @throws FOPException thrown if a FOP exception occurs
*/
private FontTriplet getFontTriplet(Configuration tripletCfg) throws FOPException {
try {
String name = tripletCfg.getAttribute("name");
if (name == null) {
LogUtil.handleError(log, "font-triplet without name", strict);
return null;
}

String weightStr = tripletCfg.getAttribute("weight");
if (weightStr == null) {
LogUtil.handleError(log, "font-triplet without weight", strict);
return null;
}
int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr));

String style = tripletCfg.getAttribute("style");
if (style == null) {
LogUtil.handleError(log, "font-triplet without style", strict);
return null;
} else {
style = FontUtil.stripWhiteSpace(style);
}
return FontInfo.createFontKey(name, style, weight);
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, strict);
}
return null;
}

}

+ 10
- 85
src/java/org/apache/fop/fonts/FontLoader.java View File

@@ -19,18 +19,13 @@

package org.apache.fop.fonts;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import java.net.URI;

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

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.truetype.TTFFontLoader;
import org.apache.fop.fonts.type1.Type1FontLoader;

@@ -43,9 +38,9 @@ public abstract class FontLoader {
protected static final Log log = LogFactory.getLog(FontLoader.class);

/** URI representing the font file */
protected String fontFileURI;
protected final URI fontFileURI;
/** the FontResolver to use for font URI resolution */
protected FontResolver resolver;
protected final URIResolverWrapper resolver;
/** the loaded font */
protected CustomFont returnFont;

@@ -67,8 +62,8 @@ public abstract class FontLoader {
* available
* @param resolver the font resolver used to resolve URIs
*/
public FontLoader(String fontFileURI, boolean embedded, boolean useKerning,
boolean useAdvanced, FontResolver resolver) {
public FontLoader(URI fontFileURI, boolean embedded, boolean useKerning,
boolean useAdvanced, URIResolverWrapper resolver) {
this.fontFileURI = fontFileURI;
this.embedded = embedded;
this.useKerning = useKerning;
@@ -76,42 +71,8 @@ public abstract class FontLoader {
this.resolver = resolver;
}

private static boolean isType1(String fontURI) {
return fontURI.toLowerCase().endsWith(".pfb");
}

/**
* Loads a custom font from a File. In the case of Type 1 fonts, the PFB file must be specified.
* @param fontFile the File representation of the font
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
* @param embedded indicates whether the font is embedded or referenced
* @param encodingMode the requested encoding mode
* @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
public static CustomFont loadFont(File fontFile, String subFontName,
boolean embedded, EncodingMode encodingMode, FontResolver resolver) throws IOException {
return loadFont(fontFile.toURI().toURL(), subFontName,
embedded, encodingMode, resolver);
}

/**
* Loads a custom font from an URL. In the case of Type 1 fonts, the PFB file must be specified.
* @param fontUrl the URL representation of the font
* @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise)
* @param embedded indicates whether the font is embedded or referenced
* @param encodingMode the requested encoding mode
* @param resolver the font resolver to use when resolving URIs
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
public static CustomFont loadFont(URL fontUrl, String subFontName,
boolean embedded, EncodingMode encodingMode,
FontResolver resolver) throws IOException {
return loadFont(fontUrl.toExternalForm(), subFontName,
embedded, encodingMode, true, true,
resolver);
private static boolean isType1(URI fontURI) {
return fontURI.toASCIIString().toLowerCase().endsWith(".pfb");
}

/**
@@ -127,10 +88,9 @@ public abstract class FontLoader {
* @return the newly loaded font
* @throws IOException In case of an I/O error
*/
public static CustomFont loadFont(String fontFileURI, String subFontName,
public static CustomFont loadFont(URI fontFileURI, String subFontName,
boolean embedded, EncodingMode encodingMode, boolean useKerning,
boolean useAdvanced, FontResolver resolver) throws IOException {
fontFileURI = fontFileURI.trim();
boolean useAdvanced, URIResolverWrapper resolver) throws IOException {
boolean type1 = isType1(fontFileURI);
FontLoader loader;
if (type1) {
@@ -146,41 +106,6 @@ public abstract class FontLoader {
return loader.getFont();
}

/**
* Opens a font URI and returns an input stream.
* @param resolver the FontResolver to use for font URI resolution
* @param uri the URI representing the font
* @return the InputStream to read the font from.
* @throws IOException In case of an I/O error
* @throws MalformedURLException If an invalid URL is built
*/
public static InputStream openFontUri(FontResolver resolver, String uri)
throws IOException, MalformedURLException {
InputStream in = null;
if (resolver != null) {
Source source = resolver.resolve(uri);
if (source == null) {
String err = "Cannot load font: failed to create Source for font file "
+ uri;
throw new IOException(err);
}
if (source instanceof StreamSource) {
in = ((StreamSource) source).getInputStream();
}
if (in == null && source.getSystemId() != null) {
in = new java.net.URL(source.getSystemId()).openStream();
}
if (in == null) {
String err = "Cannot load font: failed to create InputStream from"
+ " Source for font file " + uri;
throw new IOException(err);
}
} else {
in = new URL(uri).openStream();
}
return in;
}

/**
* Reads/parses the font data.
* @throws IOException In case of an I/O error

+ 40
- 99
src/java/org/apache/fop/fonts/FontManager.java View File

@@ -20,13 +20,10 @@
package org.apache.fop.fonts;

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

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

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.FontTriplet.Matcher;
import org.apache.fop.fonts.substitute.FontSubstitutions;

@@ -38,14 +35,13 @@ import org.apache.fop.fonts.substitute.FontSubstitutions;
* font substitution, referenced fonts and similar.
*/
public class FontManager {
/** Use cache (record previously detected font triplet info) */
public static final boolean DEFAULT_USE_CACHE = true;

/** The base URL for all font URL resolutions. */
private String fontBase = null;
private URIResolverWrapper uriResolver;

private final FontDetector fontDetector;

/** Font cache to speed up auto-font configuration (null if disabled) */
private FontCache fontCache = null;
private FontCacheManager fontCacheManager;

/** Font substitutions */
private FontSubstitutions fontSubstitutions = null;
@@ -56,33 +52,33 @@ public class FontManager {
/** FontTriplet matcher for fonts that shall be referenced rather than embedded. */
private FontTriplet.Matcher referencedFontsMatcher;

/** Enables/disables the use of font caching */
private boolean useCache = DEFAULT_USE_CACHE;

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

/**
* Main constructor
*
* @param uriResolver the URI resolver
* @param fontDetector the font detector
* @param fontCacheManager the font cache manager
*/
public FontManager() {
public FontManager(URIResolverWrapper uriResolver, FontDetector fontDetector,
FontCacheManager fontCacheManager) {
this.uriResolver = uriResolver;
this.fontDetector = fontDetector;
this.fontCacheManager = fontCacheManager;
}

/**
* Sets the font base URL.
* @param fontBase font base URL
* @throws MalformedURLException if there's a problem with a URL
* Sets the font URI resolver
* @param uriResolver font base URI
*/
public void setFontBaseURL(String fontBase) throws MalformedURLException {
this.fontBase = fontBase;
public void setFontURIResolver(URIResolverWrapper uriResolver) {
this.uriResolver = uriResolver;
}

/**
* Returns the font base URL.
* @return the font base URL (or null if none was set)
*/
public String getFontBaseURL() {
return this.fontBase;
public URIResolverWrapper getURIResolver() {
return this.uriResolver;
}

/** @return true if kerning on base 14 fonts is enabled */
@@ -130,29 +126,22 @@ public class FontManager {
* @return the font cache file
*/
public File getCacheFile() {
return getCacheFile(false);
}

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

/**
* Whether or not to cache results of font triplet detection/auto-config
* @param useCache use cache or not
*/
public void setUseCache(boolean useCache) {
this.useCache = useCache;
if (!useCache) {
this.fontCache = null;
}
}

/**
* Cache results of font triplet detection/auto-config?
* @return true if this font manager uses the cache
*/
public boolean useCache() {
return useCache;
public void disableFontCache() {
fontCacheManager = FontCacheManagerFactory.createDisabled();
}

/**
@@ -160,19 +149,7 @@ public class FontManager {
* @return the font cache
*/
public FontCache getFontCache() {
if (fontCache == null) {
if (useCache) {
if (cacheFile != null) {
fontCache = FontCache.loadFrom(cacheFile);
} else {
fontCache = FontCache.load();
}
if (fontCache == null) {
fontCache = new FontCache();
}
}
}
return fontCache;
return fontCacheManager.load(getCacheFile());
}

/**
@@ -181,31 +158,16 @@ public class FontManager {
* @throws FOPException fop exception
*/
public void saveCache() throws FOPException {
if (useCache) {
if (fontCache != null && fontCache.hasChanged()) {
if (cacheFile != null) {
fontCache.saveTo(cacheFile);
} else {
fontCache.save();
}
}
}
fontCacheManager.save(getCacheFile());
}

/**
* Deletes the current FontCache file
* @return Returns true if the font cache file was successfully deleted.
* @throws FOPException -
*/
public boolean deleteCache() {
boolean deleted = false;
if (useCache) {
if (cacheFile != null) {
deleted = cacheFile.delete();
} else {
deleted = FontCache.getDefaultCacheFile(true).delete();
}
}
return deleted;
public void deleteCache() throws FOPException {
fontCacheManager.delete(getCacheFile(true));
}

/**
@@ -224,34 +186,6 @@ public class FontManager {
getFontSubstitutions().adjustFontInfo(fontInfo);
}

/**
* Minimum implemenation of FontResolver.
*/
public static class MinimalFontResolver implements FontResolver {
private boolean useComplexScriptFeatures;
MinimalFontResolver(boolean useComplexScriptFeatures) {
this.useComplexScriptFeatures = useComplexScriptFeatures;
}
/** {@inheritDoc} */
public Source resolve(String href) {
//Minimal functionality here
return new StreamSource(href);
}
/** {@inheritDoc} */
public boolean isComplexScriptFeaturesEnabled() {
return useComplexScriptFeatures;
}
}

/**
* Create minimal font resolver.
* @param useComplexScriptFeatures true if complex script features enabled
* @return a new FontResolver to be used by the font subsystem
*/
public static FontResolver createMinimalFontResolver(boolean useComplexScriptFeatures) {
return new MinimalFontResolver ( useComplexScriptFeatures );
}

/**
* Sets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall
* be referenced rather than embedded.
@@ -298,4 +232,11 @@ public class FontManager {
}
}
}

public void autoDetectFonts(boolean autoDetectFonts, FontAdder fontAdder, boolean strict,
FontEventListener listener, List<EmbedFontInfo> fontInfoList) throws FOPException {
if (autoDetectFonts) {
fontDetector.detect(this, fontAdder, strict, listener, fontInfoList);
}
}
}

+ 47
- 32
src/java/org/apache/fop/fonts/FontManagerConfigurator.java View File

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

import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.regex.Pattern;

@@ -31,6 +31,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.ResourceResolver;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.substitute.FontSubstitutions;
import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator;
import org.apache.fop.util.LogUtil;
@@ -45,24 +47,21 @@ public class FontManagerConfigurator {

private final Configuration cfg;

private URI baseURI = null;
private final URI defaultBaseUri;

/**
* Main constructor
* @param cfg the font manager configuration object
*/
public FontManagerConfigurator(Configuration cfg) {
this.cfg = cfg;
}
private final ResourceResolver uriResolver;

/**
* Main constructor
* @param cfg the font manager configuration object
* @param baseURI the base URI of the configuration
* @param defaultBaseUri the default URI base to use for URI resolution
* @param resolver the URI resolver
*/
public FontManagerConfigurator(Configuration cfg, URI baseURI) {
public FontManagerConfigurator(Configuration cfg, URI defaultBaseUri,
ResourceResolver resolver) {
this.cfg = cfg;
this.baseURI = baseURI;
this.defaultBaseUri = defaultBaseUri;
this.uriResolver = resolver;
}

/**
@@ -75,28 +74,29 @@ public class FontManagerConfigurator {
// caching (fonts)
if (cfg.getChild("use-cache", false) != null) {
try {
fontManager.setUseCache(cfg.getChild("use-cache").getValueAsBoolean());
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, true);
}
}
if (cfg.getChild("cache-file", false) != null) {
try {
fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue()));
} catch (ConfigurationException e) {
LogUtil.handleException(log, e, true);
// TODO: Find some way to deal with this!!
if (!cfg.getChild("use-cache").getValueAsBoolean()) {
fontManager.disableFontCache();
} else {
if (cfg.getChild("cache-file", false) != null) {
fontManager.setCacheFile(new File(cfg.getChild("cache-file").getValue()));
}
}
} catch (ConfigurationException mfue) {
LogUtil.handleException(log, mfue, true);
}
}
if (cfg.getChild("font-base", false) != null) {
String path = cfg.getChild("font-base").getValue(null);
if (baseURI != null) {
path = baseURI.resolve(path).normalize().toString();
}
try {
fontManager.setFontBaseURL(path);
} catch (MalformedURLException mfue) {
LogUtil.handleException(log, mfue, true);
URI fontBase = URIResolverWrapper.getBaseURI(cfg.getChild("font-base").getValue(
null));
fontManager.setFontURIResolver(new URIResolverWrapper(
defaultBaseUri.resolve(fontBase), uriResolver));
} catch (URISyntaxException use) {
LogUtil.handleException(log, use, true);
}
} else {
fontManager.setFontURIResolver(new URIResolverWrapper(defaultBaseUri, uriResolver));
}

// [GA] permit configuration control over base14 kerning; without this,
@@ -114,7 +114,6 @@ public class FontManagerConfigurator {
// global font configuration
Configuration fontsCfg = cfg.getChild("fonts", false);
if (fontsCfg != null) {

// font substitution
Configuration substitutionsCfg = fontsCfg.getChild("substitutions", false);
if (substitutionsCfg != null) {
@@ -122,7 +121,6 @@ public class FontManagerConfigurator {
new FontSubstitutionsConfigurator(substitutionsCfg).configure(substitutions);
fontManager.setFontSubstitutions(substitutions);
}

// referenced fonts (fonts which are not to be embedded)
Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false);
if (referencedFontsCfg != null) {
@@ -130,7 +128,6 @@ public class FontManagerConfigurator {
referencedFontsCfg, strict);
fontManager.setReferencedFontsMatcher(matcher);
}

}
}

@@ -159,6 +156,24 @@ public class FontManagerConfigurator {
return orMatcher;
}

/**
* Creates a font triplet matcher from a configuration object.
* @param fontFamilies the list of font families
* @param strict true for strict configuraton error handling
* @return the font matcher
* @throws FOPException if an error occurs while building the matcher
*/
public static FontTriplet.Matcher createFontsMatcher(
List<String> fontFamilies, boolean strict) throws FOPException {
List<FontTriplet.Matcher> matcherList = new java.util.ArrayList<FontTriplet.Matcher>();
for (String fontFamily : fontFamilies) {
matcherList.add(new FontFamilyRegExFontTripletMatcher(fontFamily));
}
FontTriplet.Matcher orMatcher = new OrFontTripletMatcher(
matcherList.toArray(new FontTriplet.Matcher[matcherList.size()]));
return orMatcher;
}

private static class OrFontTripletMatcher implements FontTriplet.Matcher {

private final FontTriplet.Matcher[] matchers;

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

@@ -21,6 +21,8 @@ package org.apache.fop.fonts;

//Java
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -32,12 +34,12 @@ import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.apps.TTFReader;

/**
@@ -52,19 +54,30 @@ import org.apache.fop.fonts.apps.TTFReader;
*/
public class FontReader extends DefaultHandler {

// private Locator locator = null; // not used at present
private boolean isCID = false;
private CustomFont returnFont = null;
private MultiByteFont multiFont = null;
private SingleByteFont singleFont = null;
private boolean isCID;
private CustomFont returnFont;
private MultiByteFont multiFont;
private SingleByteFont singleFont;
private final URIResolverWrapper resolver;
private StringBuffer text = new StringBuffer();

private List<Integer> cidWidths = null;
private int cidWidthIndex = 0;
private List<Integer> cidWidths;
//private int cidWidthIndex;

private Map<Integer, Integer> currentKerning = null;
private Map<Integer, Integer> currentKerning;

private List<BFEntry> bfranges = null;
private List<BFEntry> bfranges;

/**
* Construct a FontReader object from a path to a metric.xml file
* and read metric data
* @param source Source of the font metric file
* @throws FOPException if loading the font fails
*/
public FontReader(InputSource source, URIResolverWrapper resolver) throws FOPException {
this.resolver = resolver;
createFont(source);
}

private void createFont(InputSource source) throws FOPException {
XMLReader parser = null;
@@ -81,11 +94,9 @@ public class FontReader extends DefaultHandler {
}

try {
parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
false);
parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
} catch (SAXException e) {
throw new FOPException("You need a SAX parser which supports SAX version 2",
e);
throw new FOPException("You need a SAX parser which supports SAX version 2", e);
}

parser.setContentHandler(this);
@@ -104,8 +115,8 @@ public class FontReader extends DefaultHandler {
* Sets the path to embed a font. A null value disables font embedding.
* @param path URI for the embeddable file
*/
public void setFontEmbedPath(String path) {
returnFont.setEmbedFileName(path);
public void setFontEmbedURI(URI path) {
returnFont.setEmbedURI(path);
}

/**
@@ -124,15 +135,6 @@ public class FontReader extends DefaultHandler {
returnFont.setAdvancedEnabled(enabled);
}

/**
* Sets the font resolver. Needed for URI resolution.
* @param resolver the font resolver
*/
public void setResolver(FontResolver resolver) {
returnFont.setResolver(resolver);
}


/**
* Get the generated font object
* @return the font
@@ -141,16 +143,6 @@ public class FontReader extends DefaultHandler {
return returnFont;
}

/**
* Construct a FontReader object from a path to a metric.xml file
* and read metric data
* @param source Source of the font metric file
* @throws FOPException if loading the font fails
*/
public FontReader(InputSource source) throws FOPException {
createFont(source);
}

/**
* {@inheritDoc}
*/
@@ -160,65 +152,62 @@ public class FontReader extends DefaultHandler {
/**
* {@inheritDoc}
*/
public void setDocumentLocator(Locator locator) {
// this.locator = locator; // not used at present
}

/**
* {@inheritDoc}
*/
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (localName.equals("font-metrics")) {
if ("TYPE0".equals(attributes.getValue("type"))) {
multiFont = new MultiByteFont();
multiFont = new MultiByteFont(resolver);
returnFont = multiFont;
isCID = true;
TTFReader.checkMetricsVersion(attributes);
} else if ("TRUETYPE".equals(attributes.getValue("type"))) {
singleFont = new SingleByteFont();
singleFont = new SingleByteFont(resolver);
singleFont.setFontType(FontType.TRUETYPE);
returnFont = singleFont;
isCID = false;
TTFReader.checkMetricsVersion(attributes);
} else {
singleFont = new SingleByteFont();
singleFont = new SingleByteFont(resolver);
singleFont.setFontType(FontType.TYPE1);
returnFont = singleFont;
isCID = false;
}
} else if ("embed".equals(localName)) {
returnFont.setEmbedFileName(attributes.getValue("file"));
try {
returnFont.setEmbedURI(URIResolverWrapper.cleanURI(attributes.getValue("file")));
} catch (URISyntaxException e) {
// TODO: dunno what to do here?!?!
}
returnFont.setEmbedResourceName(attributes.getValue("class"));
} else if ("cid-widths".equals(localName)) {
cidWidthIndex = getInt(attributes.getValue("start-index"));
// This is unused
// cidWidthIndex = getInt(attributes.getValue("start-index"));
cidWidths = new ArrayList<Integer>();
} else if ("kerning".equals(localName)) {
currentKerning = new HashMap<Integer, Integer>();
returnFont.putKerningEntry(new Integer(attributes.getValue("kpx1")),
currentKerning);
returnFont.putKerningEntry(getInt(attributes.getValue("kpx1")),
currentKerning);
} else if ("bfranges".equals(localName)) {
bfranges = new ArrayList<BFEntry>();
} else if ("bf".equals(localName)) {
BFEntry entry = new BFEntry(getInt(attributes.getValue("us")),
getInt(attributes.getValue("ue")),
getInt(attributes.getValue("gi")));
getInt(attributes.getValue("ue")),
getInt(attributes.getValue("gi")));
bfranges.add(entry);
} else if ("wx".equals(localName)) {
cidWidths.add(new Integer(attributes.getValue("w")));
} else if ("widths".equals(localName)) {
//singleFont.width = new int[256];
cidWidths.add(getInt(attributes.getValue("w")));
// } else if ("widths".equals(localName)) {
// singleFont.width = new int[256];
} else if ("char".equals(localName)) {
try {
singleFont.setWidth(Integer.parseInt(attributes.getValue("idx")),
Integer.parseInt(attributes.getValue("wdt")));
singleFont.setWidth(getInt(attributes.getValue("idx")),
getInt(attributes.getValue("wdt")));
} catch (NumberFormatException ne) {
throw new SAXException("Malformed width in metric file: "
+ ne.getMessage(), ne);
throw new SAXException("Malformed width in metric file: " + ne.getMessage(), ne);
}
} else if ("pair".equals(localName)) {
currentKerning.put(new Integer(attributes.getValue("kpx2")),
new Integer(attributes.getValue("kern")));
currentKerning.put(getInt(attributes.getValue("kpx2")),
getInt(attributes.getValue("kern")));
}

}
@@ -314,5 +303,4 @@ public class FontReader extends DefaultHandler {
public void characters(char[] ch, int start, int length) {
text.append(ch, start, length);
}

}

+ 6
- 42
src/java/org/apache/fop/fonts/FontSetup.java View File

@@ -22,9 +22,7 @@ package org.apache.fop.fonts;
// FOP (base 14 fonts)
import java.util.List;

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

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.base14.Courier;
import org.apache.fop.fonts.base14.CourierBold;
import org.apache.fop.fonts.base14.CourierBoldOblique;
@@ -74,8 +72,8 @@ public final class FontSetup {
* @param resolver the font resolver
* @param base14Kerning true if base14 kerning applies
*/
public static void setup(FontInfo fontInfo, List<EmbedFontInfo> embedFontInfoList,
FontResolver resolver, boolean base14Kerning) {
public static void setup(FontInfo fontInfo, List embedFontInfoList,
URIResolverWrapper resolver, boolean base14Kerning) {
fontInfo.addMetrics("F1", new Helvetica(base14Kerning));
fontInfo.addMetrics("F2", new HelveticaOblique(base14Kerning));
fontInfo.addMetrics("F3", new HelveticaBold(base14Kerning));
@@ -192,18 +190,12 @@ public final class FontSetup {
* @param resolver the font resolver
*/
private static void addConfiguredFonts(FontInfo fontInfo,
List<EmbedFontInfo> embedFontInfoList, int num, FontResolver resolver,
List<EmbedFontInfo> embedFontInfoList, int num, URIResolverWrapper resolver,
boolean base14Kerning) {
if (embedFontInfoList == null) {
return; //No fonts to process
}

if (resolver == null) {
//Ensure that we have minimal font resolution capabilities
//None of the built-in base14 fonts have advanced typographic data
boolean useAdvanced = false;
resolver = createMinimalFontResolver(useAdvanced);
}
assert resolver != null;

String internalName = null;

@@ -211,7 +203,7 @@ public final class FontSetup {
internalName = "F" + num;
num++;

LazyFont font = new LazyFont(embedFontInfo, resolver);
LazyFont font = new LazyFont(embedFontInfo, resolver, false);
fontInfo.addMetrics(internalName, font);

List<FontTriplet> triplets = embedFontInfo.getFontTriplets();
@@ -221,32 +213,4 @@ public final class FontSetup {
}
}
}

/**
* Minimum implemenation of FontResolver.
*/
public static class MinimalFontResolver implements FontResolver {
private boolean useComplexScriptFeatures;
MinimalFontResolver(boolean useComplexScriptFeatures) {
this.useComplexScriptFeatures = useComplexScriptFeatures;
}
/** {@inheritDoc} */
public Source resolve(String href) {
//Minimal functionality here
return new StreamSource(href);
}
/** {@inheritDoc} */
public boolean isComplexScriptFeaturesEnabled() {
return useComplexScriptFeatures;
}
}

/**
* Create minimal font resolver.
* @param useComplexScriptFeatures true if complex script features enabled
* @return a new FontResolver to be used by the font subsystem
*/
public static FontResolver createMinimalFontResolver(boolean useComplexScriptFeatures) {
return new MinimalFontResolver ( useComplexScriptFeatures );
}
}

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

@@ -38,14 +38,6 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable {
//This is only a cache
private transient String key;

/**
* Creates a new font triplet (for base14 use).
* @param name font name
*/
public FontTriplet(String name) {
this.name = name;
}

/**
* Creates a new font triplet.
* @param name font name
@@ -64,7 +56,7 @@ public class FontTriplet implements Comparable<FontTriplet>, Serializable {
* @param priority priority of this triplet/font mapping
*/
public FontTriplet(String name, String style, int weight, int priority) {
this(name);
this.name = name;
this.style = style;
this.weight = weight;
this.priority = priority;

+ 31
- 71
src/java/org/apache/fop/fonts/LazyFont.java View File

@@ -20,23 +20,20 @@
package org.apache.fop.fonts;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URI;
import java.util.Map;
import java.util.Set;

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

import org.xml.sax.InputSource;

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

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.complexscripts.fonts.Positionable;
import org.apache.fop.complexscripts.fonts.Substitutable;


/**
* This class is used to defer the loading of a font until it is really used.
*/
@@ -44,36 +41,35 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,

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

private String metricsFileName;
private String fontEmbedPath;
private boolean useKerning;
private boolean useAdvanced;
private EncodingMode encodingMode = EncodingMode.AUTO;
private boolean embedded;
private String subFontName;
private final URI metricsURI;
private final URI fontEmbedURI;
private final boolean useKerning;
private final boolean useAdvanced;
private final EncodingMode encodingMode;
private final boolean embedded;
private final String subFontName;
private final URIResolverWrapper resolver;

private boolean isMetricsLoaded;
private Typeface realFont;
private FontDescriptor realFontDescriptor;

private FontResolver resolver;

/**
* Main constructor
* @param fontInfo the font info to embed
* @param resolver the font resolver to handle font URIs
*/
public LazyFont(EmbedFontInfo fontInfo, FontResolver resolver) {

this.metricsFileName = fontInfo.getMetricsFile();
this.fontEmbedPath = fontInfo.getEmbedFile();
public LazyFont(EmbedFontInfo fontInfo, URIResolverWrapper resolver, boolean useComplexScripts) {
this.metricsURI = fontInfo.getMetricsURI();
this.fontEmbedURI = fontInfo.getEmbedURI();
this.useKerning = fontInfo.getKerning();
if ( resolver != null ) {
this.useAdvanced = resolver.isComplexScriptFeaturesEnabled();
if (resolver != null) {
this.useAdvanced = useComplexScripts;
} else {
this.useAdvanced = fontInfo.getAdvanced();
}
this.encodingMode = fontInfo.getEncodingMode();
this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode()
: EncodingMode.AUTO;
this.subFontName = fontInfo.getSubFontName();
this.embedded = fontInfo.isEmbedded();
this.resolver = resolver;
@@ -83,8 +79,8 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,
public String toString() {
StringBuffer sbuf = new StringBuffer(super.toString());
sbuf.append('{');
sbuf.append("metrics-url=" + metricsFileName);
sbuf.append(",embed-url=" + fontEmbedPath);
sbuf.append("metrics-url=" + metricsURI);
sbuf.append(",embed-url=" + fontEmbedURI);
sbuf.append(",kerning=" + useKerning);
sbuf.append(",advanced=" + useAdvanced);
sbuf.append('}');
@@ -94,74 +90,38 @@ public class LazyFont extends Typeface implements FontDescriptor, Substitutable,
private void load(boolean fail) {
if (!isMetricsLoaded) {
try {
if (metricsFileName != null) {
if (metricsURI != null) {
/**@todo Possible thread problem here */
FontReader reader = null;
if (resolver != null) {
Source source = resolver.resolve(metricsFileName);
if (source == null) {
String err
= "Cannot load font: failed to create Source from metrics file "
+ metricsFileName;
if (fail) {
throw new RuntimeException(err);
} else {
log.error(err);
}
return;
}
InputStream in = null;
if (source instanceof StreamSource) {
in = ((StreamSource) source).getInputStream();
}
if (in == null && source.getSystemId() != null) {
in = new java.net.URL(source.getSystemId()).openStream();
}
if (in == null) {
String err = "Cannot load font: After URI resolution, the returned"
+ " Source object does not contain an InputStream"
+ " or a valid URL (system identifier) for metrics file: "
+ metricsFileName;
if (fail) {
throw new RuntimeException(err);
} else {
log.error(err);
}
return;
}
InputSource src = new InputSource(in);
src.setSystemId(source.getSystemId());
reader = new FontReader(src);
} else {
reader = new FontReader(new InputSource(
new URL(metricsFileName).openStream()));
}
InputStream in = resolver.resolveIn(metricsURI);
InputSource src = new InputSource(in);
src.setSystemId(metricsURI.toASCIIString());
reader = new FontReader(src, resolver);
reader.setKerningEnabled(useKerning);
reader.setAdvancedEnabled(useAdvanced);
if (this.embedded) {
reader.setFontEmbedPath(fontEmbedPath);
reader.setFontEmbedURI(fontEmbedURI);
}
reader.setResolver(resolver);
realFont = reader.getFont();
} else {
if (fontEmbedPath == null) {
if (fontEmbedURI == null) {
throw new RuntimeException("Cannot load font. No font URIs available.");
}
realFont = FontLoader.loadFont(fontEmbedPath, this.subFontName,
realFont = FontLoader.loadFont(fontEmbedURI, this.subFontName,
this.embedded, this.encodingMode, useKerning, useAdvanced, resolver);
}
if (realFont instanceof FontDescriptor) {
realFontDescriptor = (FontDescriptor) realFont;
}
} catch (FOPException fopex) {
log.error("Failed to read font metrics file " + metricsFileName, fopex);
log.error("Failed to read font metrics file " + metricsURI, fopex);
if (fail) {
throw new RuntimeException(fopex.getMessage());
throw new RuntimeException(fopex);
}
} catch (IOException ioex) {
log.error("Failed to read font metrics file " + metricsFileName, ioex);
log.error("Failed to read font metrics file " + metricsURI, ioex);
if (fail) {
throw new RuntimeException(ioex.getMessage());
throw new RuntimeException(ioex);
}
}
realFont.setEventListener(this.eventListener);

+ 6
- 4
src/java/org/apache/fop/fonts/MultiByteFont.java View File

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

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable;
import org.apache.fop.complexscripts.fonts.GlyphPositioningTable;
import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable;
@@ -74,9 +75,10 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
private int lastUnmapped;

/**
* Default constructor
* @param resolver the URI resolver for controlling file access
*/
public MultiByteFont() {
public MultiByteFont(URIResolverWrapper resolver) {
super(resolver);
subset.setupFirstGlyph();
setFontType(FontType.TYPE0);
}
@@ -125,7 +127,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl

/** {@inheritDoc} */
public boolean isEmbeddable() {
return !(getEmbedFileName() == null && getEmbedResourceName() == null);
return !(getEmbedFileURI() == null && getEmbedResourceName() == null);
}

/** {@inheritDoc} */
@@ -561,7 +563,7 @@ public class MultiByteFont extends CIDFont implements Substitutable, Positionabl
}
}
cb.flip();
return (CharSequence) cb;
return cb;
}

}

+ 4
- 3
src/java/org/apache/fop/fonts/MutableFont.java View File

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

package org.apache.fop.fonts;

import java.net.URI;
import java.util.Map;
import java.util.Set;

@@ -49,10 +50,10 @@ public interface MutableFont {
void setFamilyNames(Set<String> names);

/**
* Sets the path to the embeddable font file.
* @param path URI to the file
* Sets the URI to the embeddable font.
* @param path URI to the font
*/
void setEmbedFileName(String path);
void setEmbedURI(URI path);

/**
* Sets the resource name of the embeddable font file.

+ 6
- 3
src/java/org/apache/fop/fonts/SingleByteFont.java View File

@@ -31,6 +31,8 @@ import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.fonts.Glyphs;

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

/**
* Generic SingleByte font
*/
@@ -50,15 +52,16 @@ public class SingleByteFont extends CustomFont {


/**
* Main constructor.
* @param resolver the URI resolver for controlling file access
*/
public SingleByteFont() {
public SingleByteFont(URIResolverWrapper resolver) {
super(resolver);
setEncoding(CodePointMapping.WIN_ANSI_ENCODING);
}

/** {@inheritDoc} */
public boolean isEmbeddable() {
return (!(getEmbedFileName() == null
return (!(getEmbedFileURI() == null
&& getEmbedResourceName() == null));
}


+ 14
- 7
src/java/org/apache/fop/fonts/apps/TTFReader.java View File

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

package org.apache.fop.fonts.apps;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@@ -220,12 +222,17 @@ public class TTFReader extends AbstractFontReader {
public TTFFile loadTTF(String fileName, String fontName, boolean useKerning, boolean useAdvanced) throws IOException {
TTFFile ttfFile = new TTFFile(useKerning, useAdvanced);
log.info("Reading " + fileName + "...");

FontFileReader reader = new FontFileReader(fileName);
boolean supported = ttfFile.readFont(reader, fontName);
if (!supported) {
return null;
InputStream stream = new FileInputStream(fileName);
try {
FontFileReader reader = new FontFileReader(stream);
boolean supported = ttfFile.readFont(reader, fontName);
if (!supported) {
return null;
}
} finally {
stream.close();
}

log.info("Font Family: " + ttfFile.getFamilyNames());
if (ttfFile.isCFF()) {
throw new UnsupportedOperationException(
@@ -460,9 +467,9 @@ public class TTFReader extends AbstractFontReader {

Map h2;
if (isCid) {
h2 = (Map)ttf.getKerning().get(kpx1);
h2 = ttf.getKerning().get(kpx1);
} else {
h2 = (Map)ttf.getAnsiKerning().get(kpx1);
h2 = ttf.getAnsiKerning().get(kpx1);
}

Iterator iter2 = h2.keySet().iterator();

+ 35
- 35
src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java View File

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

import java.io.InputStream;
import java.net.URL;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -30,6 +30,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.EncodingMode;
@@ -37,7 +38,6 @@ import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontCache;
import org.apache.fop.fonts.FontEventListener;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.FontUtil;
import org.apache.fop.fonts.MultiByteFont;
@@ -133,26 +133,24 @@ public class FontInfoFinder {

/**
* Attempts to determine FontInfo from a given custom font
* @param fontURL the font URL
* @param fontUri the font URI
* @param customFont the custom font
* @param fontCache font cache (may be null)
* @return FontInfo from the given custom font
*/
private EmbedFontInfo getFontInfoFromCustomFont(
URL fontURL, CustomFont customFont, FontCache fontCache) {
private EmbedFontInfo getFontInfoFromCustomFont(URI fontUri, CustomFont customFont,
FontCache fontCache, URIResolverWrapper resolver) {
List<FontTriplet> fontTripletList = new java.util.ArrayList<FontTriplet>();
generateTripletsFromFont(customFont, fontTripletList);
String embedUrl;
embedUrl = fontURL.toExternalForm();
String subFontName = null;
if (customFont instanceof MultiByteFont) {
subFontName = ((MultiByteFont)customFont).getTTCName();
subFontName = ((MultiByteFont) customFont).getTTCName();
}
EmbedFontInfo fontInfo = new EmbedFontInfo(null, customFont.isKerningEnabled(),
customFont.isAdvancedEnabled(), fontTripletList, embedUrl, subFontName);
customFont.isAdvancedEnabled(), fontTripletList, fontUri, subFontName);
fontInfo.setPostScriptName(customFont.getFontName());
if (fontCache != null) {
fontCache.addFont(fontInfo);
fontCache.addFont(fontInfo, resolver);
}
return fontInfo;
}
@@ -160,32 +158,31 @@ public class FontInfoFinder {
/**
* Attempts to determine EmbedFontInfo from a given font file.
*
* @param fontURL font URL. Assumed to be local.
* @param fontURI the URI of the font resource
* @param resolver font resolver used to resolve font
* @param fontCache font cache (may be null)
* @return an array of newly created embed font info. Generally, this array
* will have only one entry, unless the fontUrl is a TrueType Collection
*/
public EmbedFontInfo[] find(URL fontURL, FontResolver resolver, FontCache fontCache) {
String embedURL = null;
embedURL = fontURL.toExternalForm();
public EmbedFontInfo[] find(URI fontURI, URIResolverWrapper resolver, FontCache fontCache) {
URI embedUri = resolver.getBaseURI().resolve(fontURI);
String embedStr = embedUri.toASCIIString();
boolean useKerning = true;
boolean useAdvanced = ( resolver != null )
? resolver.isComplexScriptFeaturesEnabled() : true;
boolean useAdvanced = true;

long fileLastModified = -1;
if (fontCache != null) {
fileLastModified = FontCache.getLastModified(fontURL);
fileLastModified = FontCache.getLastModified(fontURI);
// firstly try and fetch it from cache before loading/parsing the font file
if (fontCache.containsFont(embedURL)) {
EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedURL, fileLastModified);
if (fontCache.containsFont(embedStr)) {
EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedStr, fileLastModified);
if (fontInfos != null) {
return fontInfos;
}
// is this a previously failed parsed font?
} else if (fontCache.isFailedFont(embedURL, fileLastModified)) {
} else if (fontCache.isFailedFont(embedStr, fileLastModified)) {
if (log.isDebugEnabled()) {
log.debug("Skipping font file that failed to load previously: " + embedURL);
log.debug("Skipping font file that failed to load previously: " + embedUri);
}
return null;
}
@@ -194,19 +191,19 @@ public class FontInfoFinder {

// try to determine triplet information from font file
CustomFont customFont = null;
if (fontURL.toExternalForm().toLowerCase().endsWith(".ttc")) {
if (fontURI.toASCIIString().toLowerCase().endsWith(".ttc")) {
// Get a list of the TTC Font names
List<String> ttcNames = null;
String fontFileURL = fontURL.toExternalForm().trim();
InputStream in = null;
try {
in = FontLoader.openFontUri(resolver, fontFileURL);
in = resolver.resolveIn(fontURI);
TTFFile ttf = new TTFFile(false, false);
FontFileReader reader = new FontFileReader(in);
ttcNames = ttf.getTTCnames(reader);
} catch (Exception e) {
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, fontFileURL, e);
this.eventListener.fontLoadingErrorAtAutoDetection(this,
fontURI.toASCIIString(), e);
}
return null;
} finally {
@@ -221,23 +218,24 @@ public class FontInfoFinder {
log.debug("Loading " + fontName);
}
try {
TTFFontLoader ttfLoader = new TTFFontLoader(
fontFileURL, fontName, true, EncodingMode.AUTO,
useKerning, useAdvanced, resolver);
TTFFontLoader ttfLoader = new TTFFontLoader(fontURI, fontName, true,
EncodingMode.AUTO, useKerning, useAdvanced, resolver);
customFont = ttfLoader.getFont();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
} catch (Exception e) {
if (fontCache != null) {
fontCache.registerFailedFont(embedURL, fileLastModified);
fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified);
}
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedURL, e);
this.eventListener.fontLoadingErrorAtAutoDetection(this,
embedUri.toASCIIString(), e);
}
continue;
}
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURL, customFont, fontCache);
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache,
resolver);
if (fi != null) {
embedFontInfoList.add(fi);
}
@@ -247,20 +245,22 @@ public class FontInfoFinder {
} else {
// The normal case
try {
customFont = FontLoader.loadFont(fontURL, null, true, EncodingMode.AUTO, resolver);
customFont = FontLoader.loadFont(fontURI, null, true, EncodingMode.AUTO,
useKerning, useAdvanced, resolver);
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
} catch (Exception e) {
if (fontCache != null) {
fontCache.registerFailedFont(embedURL, fileLastModified);
fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified);
}
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this, embedURL, e);
this.eventListener.fontLoadingErrorAtAutoDetection(this,
embedUri.toASCIIString(), e);
}
return null;
}
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURL, customFont, fontCache);
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, resolver);
if (fi != null) {
return new EmbedFontInfo[] {fi};
} else {

+ 5
- 33
src/java/org/apache/fop/fonts/truetype/FontFileReader.java View File

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

package org.apache.fop.fonts.truetype;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@@ -31,38 +30,9 @@ import org.apache.commons.io.IOUtils;
*/
public class FontFileReader {

private int fsize; // file size
private final int fsize; // file size
private int current; // current position in file
private byte[] file;

/**
* Initializes class and reads stream. Init does not close stream.
*
* @param in InputStream to read from new array with size + inc
* @throws IOException In case of an I/O problem
*/
private void init(InputStream in) throws java.io.IOException {
this.file = IOUtils.toByteArray(in);
this.fsize = this.file.length;
this.current = 0;
}

/**
* Constructor
*
* @param fileName filename to read
* @throws IOException In case of an I/O problem
*/
public FontFileReader(String fileName) throws IOException {
final File f = new File(fileName);
InputStream in = new java.io.FileInputStream(f);
try {
init(in);
} finally {
in.close();
}
}

private final byte[] file;

/**
* Constructor
@@ -71,7 +41,9 @@ public class FontFileReader {
* @throws IOException In case of an I/O problem
*/
public FontFileReader(InputStream in) throws IOException {
init(in);
this.file = IOUtils.toByteArray(in);
this.fsize = this.file.length;
this.current = 0;
}



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

@@ -19,13 +19,16 @@

package org.apache.fop.fonts.truetype;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

@@ -1816,12 +1819,14 @@ public class TTFFile {
* @param args The command line arguments
*/
public static void main(String[] args) {
InputStream stream = null;
try {
boolean useKerning = true;
boolean useAdvanced = true;
stream = new FileInputStream(args[0]);
TTFFile ttfFile = new TTFFile(useKerning, useAdvanced);

FontFileReader reader = new FontFileReader(args[0]);
FontFileReader reader = new FontFileReader(stream);

String name = null;
if (args.length >= 2) {
@@ -1834,6 +1839,9 @@ public class TTFFile {
} catch (IOException ioe) {
System.err.println("Problem reading font: " + ioe.toString());
ioe.printStackTrace(System.err);
} finally {
IOUtils.closeQuietly(stream);
}

}
}

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

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

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -30,11 +31,11 @@ import org.apache.commons.io.IOUtils;

import org.apache.xmlgraphics.fonts.Glyphs;

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.BFEntry;
import org.apache.fop.fonts.CIDFontType;
import org.apache.fop.fonts.EncodingMode;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.NamedCharacter;
@@ -55,7 +56,7 @@ public class TTFFontLoader extends FontLoader {
* @param fontFileURI the URI representing the font file
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, FontResolver resolver) {
public TTFFontLoader(URI fontFileURI, URIResolverWrapper resolver) {
this(fontFileURI, null, true, EncodingMode.AUTO, true, true, resolver);
}

@@ -70,9 +71,9 @@ public class TTFFontLoader extends FontLoader {
* @param useAdvanced true to enable loading advanced info if available, false to disable
* @param resolver the FontResolver for font URI resolution
*/
public TTFFontLoader(String fontFileURI, String subFontName,
public TTFFontLoader(URI fontFileURI, String subFontName,
boolean embedded, EncodingMode encodingMode, boolean useKerning,
boolean useAdvanced, FontResolver resolver) {
boolean useAdvanced, URIResolverWrapper resolver) {
super(fontFileURI, embedded, useKerning, useAdvanced, resolver);
this.subFontName = subFontName;
this.encodingMode = encodingMode;
@@ -94,7 +95,7 @@ public class TTFFontLoader extends FontLoader {
* @throws IOException if an I/O error occurs
*/
private void read(String ttcFontName) throws IOException {
InputStream in = openFontUri(resolver, this.fontFileURI);
InputStream in = resolver.resolveIn(this.fontFileURI);
try {
TTFFile ttf = new TTFFile(useKerning, useAdvanced);
FontFileReader reader = new FontFileReader(in);
@@ -122,14 +123,13 @@ public class TTFFontLoader extends FontLoader {
}

if (isCid) {
multiFont = new MultiByteFont();
multiFont = new MultiByteFont(resolver);
returnFont = multiFont;
multiFont.setTTCName(ttcFontName);
} else {
singleFont = new SingleByteFont();
singleFont = new SingleByteFont(resolver);
returnFont = singleFont;
}
returnFont.setResolver(resolver);

returnFont.setFontName(ttf.getPostScriptName());
returnFont.setFullName(ttf.getFullName());
@@ -177,7 +177,7 @@ public class TTFFontLoader extends FontLoader {
}
if (this.embedded) {
if (ttf.isEmbeddable()) {
returnFont.setEmbedFileName(this.fontFileURI);
returnFont.setEmbedURI(this.fontFileURI);
} else {
String msg = "The font " + this.fontFileURI + " is not embeddable due to a"
+ " licensing restriction.";

+ 0
- 33
src/java/org/apache/fop/fonts/type1/PFBParser.java View File

@@ -46,38 +46,6 @@ public class PFBParser {
}


/**
* Parses a PFB file into a PFBData object.
* @param url URL to load the PFB file from
* @return PFBData memory representation of the font
* @throws IOException In case of an I/O problem
*/
public PFBData parsePFB(java.net.URL url) throws IOException {
InputStream in = url.openStream();
try {
return parsePFB(in);
} finally {
in.close();
}
}


/**
* Parses a PFB file into a PFBData object.
* @param pfbFile File to load the PFB file from
* @return PFBData memory representation of the font
* @throws IOException In case of an I/O problem
*/
public PFBData parsePFB(java.io.File pfbFile) throws IOException {
InputStream in = new java.io.FileInputStream(pfbFile);
try {
return parsePFB(in);
} finally {
in.close();
}
}


/**
* Parses a PFB file into a PFBData object.
* @param in InputStream to load the PFB file from
@@ -113,7 +81,6 @@ public class PFBParser {
private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException {
int segmentHead;
int segmentType;
int bytesRead;

//Read first segment
segmentHead = din.readUnsignedByte();

+ 13
- 12
src/java/org/apache/fop/fonts/type1/PFMFile.java View File

@@ -23,6 +23,7 @@ package org.apache.fop.fonts.type1;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
@@ -40,7 +41,7 @@ public class PFMFile {
private String windowsName;
private String postscriptName;
private short dfItalic;
private int dfWeight;
//private int dfWeight;
private short dfCharSet;
private short dfPitchAndFamily;
private int dfAvgWidth;
@@ -61,7 +62,7 @@ public class PFMFile {
// Extent table
private int[] extentTable;

private Map kerningTab = new java.util.HashMap();
private Map<Integer, Map<Integer, Integer>> kerningTab = new HashMap<Integer, Map<Integer, Integer>>();

/**
* logging instance
@@ -119,7 +120,7 @@ public class PFMFile {
inStream.skip(80);
dfItalic = inStream.readByte();
inStream.skip(2);
dfWeight = inStream.readShort();
inStream.readShort(); // dfWeight =
dfCharSet = inStream.readByte();
inStream.skip(4);
dfPitchAndFamily = inStream.readByte();
@@ -192,10 +193,10 @@ public class PFMFile {
log.trace(i + " kerning pairs");
}
while (i > 0) {
int g1 = (int)inStream.readByte();
int g1 = (int) inStream.readByte();
i--;

int g2 = (int)inStream.readByte();
int g2 = (int) inStream.readByte();

int adj = inStream.readShort();
if (adj > 0x8000) {
@@ -209,12 +210,12 @@ public class PFMFile {
log.trace("glyphs: " + glyph1 + ", " + glyph2);
}

Map adjTab = (Map)kerningTab.get(new Integer(g1));
Map<Integer, Integer> adjTab = kerningTab.get(Integer.valueOf(g1));
if (adjTab == null) {
adjTab = new java.util.HashMap();
adjTab = new HashMap<Integer, Integer>();
}
adjTab.put(new Integer(g2), new Integer(adj));
kerningTab.put(new Integer(g1), adjTab);
adjTab.put(Integer.valueOf(g2), Integer.valueOf(adj));
kerningTab.put(Integer.valueOf(g1), adjTab);
}
}

@@ -270,7 +271,7 @@ public class PFMFile {
*
* @return A Map containing the kerning table
*/
public Map getKerning() {
public Map<Integer, Map<Integer, Integer>> getKerning() {
return kerningTab;
}

@@ -453,9 +454,9 @@ public class PFMFile {
public int getStemV() {
// Just guessing....
if (dfItalic != 0) {
return (int)Math.round(dfMinWidth * 0.25);
return (int) Math.round(dfMinWidth * 0.25);
} else {
return (int)Math.round(dfMinWidth * 0.6);
return (int) Math.round(dfMinWidth * 0.6);
}
}


+ 18
- 11
src/java/org/apache/fop/fonts/type1/Type1FontLoader.java View File

@@ -22,15 +22,17 @@ package org.apache.fop.fonts.type1;
import java.awt.geom.RectangularShape;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.IOUtils;

import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.CodePointMapping;
import org.apache.fop.fonts.FontLoader;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontType;
import org.apache.fop.fonts.SingleByteEncoding;
import org.apache.fop.fonts.SingleByteFont;
@@ -50,8 +52,8 @@ public class Type1FontLoader extends FontLoader {
* @param resolver the font resolver used to resolve URIs
* @throws IOException In case of an I/O error
*/
public Type1FontLoader(String fontFileURI, boolean embedded, boolean useKerning,
FontResolver resolver) throws IOException {
public Type1FontLoader(URI fontFileURI, boolean embedded, boolean useKerning,
URIResolverWrapper resolver) throws IOException {
super(fontFileURI, embedded, useKerning, true, resolver);
}

@@ -71,17 +73,21 @@ public class Type1FontLoader extends FontLoader {
PFMFile pfm = null;

InputStream afmIn = null;
String fontFileStr = fontFileURI.toASCIIString();
String partialAfmUri = fontFileStr.substring(0, fontFileStr.length() - 4);
String afmUri = null;
for (int i = 0; i < AFM_EXTENSIONS.length; i++) {
try {
afmUri = this.fontFileURI.substring(0, this.fontFileURI.length() - 4)
+ AFM_EXTENSIONS[i];
afmIn = openFontUri(resolver, afmUri);
afmUri = partialAfmUri + AFM_EXTENSIONS[i];
afmIn = resolver.resolveIn(afmUri);
if (afmIn != null) {
break;
}
} catch (IOException ioe) {
// Ignore, AFM probably not available under the URI
} catch (URISyntaxException e) {
// TODO: Not sure what the best thing to do here is?!?
throw new RuntimeException(e);
}
}
if (afmIn != null) {
@@ -93,12 +99,14 @@ public class Type1FontLoader extends FontLoader {
}
}

String pfmUri = getPFMURI(this.fontFileURI);
String pfmUri = getPFMURI(fontFileStr);
InputStream pfmIn = null;
try {
pfmIn = openFontUri(resolver, pfmUri);
pfmIn = resolver.resolveIn(pfmUri);
} catch (IOException ioe) {
// Ignore, PFM probably not available under the URI
} catch (URISyntaxException e) {
// Ignore, PFM probably not available under the URI
}
if (pfmIn != null) {
try {
@@ -126,11 +134,10 @@ public class Type1FontLoader extends FontLoader {
if (afm == null && pfm == null) {
throw new IllegalArgumentException("Need at least an AFM or a PFM!");
}
singleFont = new SingleByteFont();
singleFont = new SingleByteFont(resolver);
singleFont.setFontType(FontType.TYPE1);
singleFont.setResolver(this.resolver);
if (this.embedded) {
singleFont.setEmbedFileName(this.fontFileURI);
singleFont.setEmbedURI(this.fontFileURI);
}
returnFont = singleFont;


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

@@ -91,7 +91,7 @@ public class ExternalDocumentLayoutManager extends AbstractPageSequenceLayoutMan
initialize();

FOUserAgent userAgent = pageSeq.getUserAgent();
ImageManager imageManager = userAgent.getFactory().getImageManager();
ImageManager imageManager = userAgent.getImageManager();

String uri = URISpecification.getURL(getExternalDocument().getSrc());
Integer firstPageIndex = ImageUtil.getPageIndexFromURI(uri);

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

@@ -1399,8 +1399,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
Hyphenation hyph
= Hyphenator.hyphenate(hyphenationProperties.language.getString(),
hyphenationProperties.country.getString(),
getFObj().getUserAgent().getFactory().getHyphenationTreeResolver(),
getFObj().getUserAgent().getFactory().getHyphPatNames(),
getFObj().getUserAgent().getHyphenationTreeResolver(),
getFObj().getUserAgent().getHyphPatNames(),
sbChars.toString(),
hyphenationProperties.hyphenationRemainCharacterCount.getValue(),
hyphenationProperties.hyphenationPushCharacterCount.getValue());

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

@@ -20,14 +20,14 @@
package org.apache.fop.pdf;

/** Enum class for PDF/A modes. */
public final class PDFAMode {
public enum PDFAMode {

/** PDF/A disabled */
public static final PDFAMode DISABLED = new PDFAMode("PDF/A disabled");
DISABLED("PDF/A disabled"),
/** PDF/A-1a enabled */
public static final PDFAMode PDFA_1A = new PDFAMode("PDF/A-1a");
PDFA_1A("PDF/A-1a"),
/** PDF/A-1b enabled */
public static final PDFAMode PDFA_1B = new PDFAMode("PDF/A-1b");
PDFA_1B("PDF/A-1b");

private String name;

@@ -66,7 +66,7 @@ public final class PDFAMode {
* @param s the string
* @return the PDFAMode enum object (DISABLED will be returned if no match is found)
*/
public static PDFAMode valueOf(String s) {
public static PDFAMode getValueOf(String s) {
if (PDFA_1A.getName().equalsIgnoreCase(s)) {
return PDFA_1A;
} else if (PDFA_1B.getName().equalsIgnoreCase(s)) {

+ 13
- 0
src/java/org/apache/fop/pdf/PDFEncryptionParams.java View File

@@ -273,4 +273,17 @@ public class PDFEncryptionParams {
this.encryptionLengthInBits = encryptionLength;
}

public String toString() {
return "userPassword = " + userPassword + "\n"
+ "ownerPassword = " + ownerPassword + "\n"
+ "allowPrint = " + allowPrint + "\n"
+ "allowCopyContent = " + allowCopyContent + "\n"
+ "allowEditContent = " + allowEditContent + "\n"
+ "allowEditAnnotations = " + allowEditAnnotations + "\n"
+ "allowFillInForms = " + allowFillInForms + "\n"
+ "allowAccessContent = " + allowAccessContent + "\n"
+ "allowAssembleDocument = " + allowAssembleDocument + "\n"
+ "allowPrintHq = " + allowPrintHq;
}

}

+ 34
- 70
src/java/org/apache/fop/pdf/PDFFactory.java View File

@@ -23,10 +23,8 @@ package org.apache.fop.pdf;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -35,9 +33,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
@@ -1636,79 +1631,48 @@ public class PDFFactory {

InputStream in = null;
try {
Source source = font.getEmbedFileSource();
if (source == null && font.getEmbedResourceName() != null) {
source = new StreamSource(this.getClass()
.getResourceAsStream(font.getEmbedResourceName()));
}
if (source == null) {
return null;
}
if (source instanceof StreamSource) {
in = ((StreamSource) source).getInputStream();
}
if (in == null && source.getSystemId() != null) {
try {
in = new java.net.URL(source.getSystemId()).openStream();
} catch (MalformedURLException e) {
//TODO: Why construct a new exception here, when it is not thrown?
new FileNotFoundException(
"File not found. URL could not be resolved: "
+ e.getMessage());
}
}
if (in == null) {
return null;
}
//Make sure the InputStream is decorated with a BufferedInputStream
if (!(in instanceof java.io.BufferedInputStream)) {
in = new java.io.BufferedInputStream(in);
}
in = font.getInputStream();
if (in == null) {
return null;
} else {
try {
AbstractPDFStream embeddedFont;
if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont)font;
FontFileReader reader = new FontFileReader(in);

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

embeddedFont = new PDFTTFStream(subsetFont.length);
((PDFTTFStream)embeddedFont).setData(subsetFont, subsetFont.length);
} else if (desc.getFontType() == FontType.TYPE1) {
PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(in);
embeddedFont = new PDFT1Stream();
((PDFT1Stream)embeddedFont).setData(pfb);
} else {
byte[] file = IOUtils.toByteArray(in);
embeddedFont = new PDFTTFStream(file.length);
((PDFTTFStream)embeddedFont).setData(file, file.length);
}
AbstractPDFStream embeddedFont;
if (desc.getFontType() == FontType.TYPE0) {
MultiByteFont mbfont = (MultiByteFont) font;
FontFileReader reader = new FontFileReader(in);

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

embeddedFont = new PDFTTFStream(subsetFont.length);
((PDFTTFStream) embeddedFont).setData(subsetFont, subsetFont.length);
} else if (desc.getFontType() == FontType.TYPE1) {
PFBParser parser = new PFBParser();
PFBData pfb = parser.parsePFB(in);
embeddedFont = new PDFT1Stream();
((PDFT1Stream) embeddedFont).setData(pfb);
} else {
byte[] file = IOUtils.toByteArray(in);
embeddedFont = new PDFTTFStream(file.length);
((PDFTTFStream) embeddedFont).setData(file, file.length);
}

/*
embeddedFont.getFilterList().addFilter("flate");
if (getDocument().isEncryptionActive()) {
getDocument().applyEncryption(embeddedFont);
} else {
embeddedFont.getFilterList().addFilter("ascii-85");
}*/
/*
embeddedFont.getFilterList().addFilter("flate");
if (getDocument().isEncryptionActive()) {
getDocument().applyEncryption(embeddedFont);
} else {
embeddedFont.getFilterList().addFilter("ascii-85");
}*/

return embeddedFont;
} finally {
in.close();
}
return embeddedFont;
}
} catch (IOException ioe) {
log.error(
"Failed to embed font [" + desc + "] "
+ desc.getEmbedFontName(), ioe);
log.error("Failed to embed font [" + desc + "] " + desc.getEmbedFontName(), ioe);
return null;
} finally {
IOUtils.closeQuietly(in);
}
}


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

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

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

@@ -46,33 +46,33 @@ public class PDFResources extends PDFDictionary {
/**
* /Font objects keyed by their internal name
*/
protected Map fonts = new HashMap();
protected Map fonts = new LinkedHashMap();

/**
* Set of XObjects
*/
protected Set xObjects = new HashSet();
protected Set xObjects = new LinkedHashSet();

/**
* Set of patterns
*/
protected Set patterns = new HashSet();
protected Set patterns = new LinkedHashSet();

/**
* Set of shadings
*/
protected Set shadings = new HashSet();
protected Set shadings = new LinkedHashSet();

/**
* Set of ExtGStates
*/
protected Set gstates = new HashSet();
protected Set gstates = new LinkedHashSet();

/** Map of color spaces (key: color space name) */
protected Map colorSpaces = new HashMap();
protected Map colorSpaces = new LinkedHashMap();

/** Map of ICC color spaces (key: ICC profile description) */
protected Map iccColorSpaces = new HashMap();
protected Map iccColorSpaces = new LinkedHashMap();

/**
* create a /Resources object.
@@ -205,7 +205,7 @@ public class PDFResources extends PDFDictionary {
Iterator fontIterator = this.fonts.keySet().iterator();
while (fontIterator.hasNext()) {
String fontName = (String)fontIterator.next();
dict.put(fontName, (PDFFont)this.fonts.get(fontName));
dict.put(fontName, this.fonts.get(fontName));
}
put("Font", dict);
}

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

@@ -20,12 +20,12 @@
package org.apache.fop.pdf;

/** Enum class for PDF/X modes. */
public final class PDFXMode {
public enum PDFXMode {

/** PDF/X disabled */
public static final PDFXMode DISABLED = new PDFXMode("PDF/X disabled");
DISABLED("PDF/X disabled"),
/** PDF/X-3:2003 enabled */
public static final PDFXMode PDFX_3_2003 = new PDFXMode("PDF/X-3:2003");
PDFX_3_2003("PDF/X-3:2003");

private String name;

@@ -47,7 +47,7 @@ public final class PDFXMode {
* @param s the string
* @return the PDFAMode enum object (DISABLED will be returned if no match is found)
*/
public static PDFXMode valueOf(String s) {
public static PDFXMode getValueOf(String s) {
if (PDFX_3_2003.getName().equalsIgnoreCase(s)) {
return PDFX_3_2003;
} else {

+ 0
- 38
src/java/org/apache/fop/render/AbstractConfigurator.java View File

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

package org.apache.fop.render;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;

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

@@ -48,41 +45,6 @@ public abstract class AbstractConfigurator {
this.userAgent = userAgent;
}

/**
* Returns the configuration subtree for a specific renderer.
* @param mimeType the MIME type of the renderer
* @return the requested configuration subtree, null if there's no configuration
*/
protected Configuration getConfig(String mimeType) {
Configuration cfg = userAgent.getFactory().getUserConfig();
if (cfg == null) {
if (log.isDebugEnabled()) {
log.debug("userconfig is null");
}
return null;
}

Configuration userConfig = null;

String type = getType();
Configuration[] cfgs
= cfg.getChild(type + "s").getChildren(type);
for (int i = 0; i < cfgs.length; ++i) {
Configuration child = cfgs[i];
try {
if (child.getAttribute(MIME).equals(mimeType)) {
userConfig = child;
break;
}
} catch (ConfigurationException e) {
// silently pass over configurations without mime type
}
}
log.debug((userConfig == null ? "No u" : "U")
+ "ser configuration found for MIME type " + mimeType);
return userConfig;
}

/**
* Returns the configurator type
* @return the configurator type

+ 8
- 27
src/java/org/apache/fop/render/AbstractRendererConfigurator.java View File

@@ -19,49 +19,30 @@

package org.apache.fop.render;

import org.apache.avalon.framework.configuration.Configuration;

import org.apache.fop.apps.FOUserAgent;

/**
* Abstract base classes for renderer-related configurator classes. This class basically just
* provides an accessor to the specific renderer configuration object.
*/
public abstract class AbstractRendererConfigurator extends AbstractConfigurator {
public abstract class AbstractRendererConfigurator {

private static final String TYPE = "renderer";
/** fop factory configuration */
protected final FOUserAgent userAgent;

/**
* Default constructor
* @param userAgent user agent
*/
public AbstractRendererConfigurator(FOUserAgent userAgent) {
super(userAgent);
}

/**
* Returns the configuration subtree for a specific renderer.
* @param renderer the renderer
* @return the requested configuration subtree, null if there's no configuration
*/
protected Configuration getRendererConfig(Renderer renderer) {
return super.getConfig(renderer.getMimeType());
this.userAgent = userAgent;
}

/**
* Returns the configuration subtree for a specific renderer.
* @param mimeType the MIME type of the renderer
* @return the requested configuration subtree, null if there's no configuration
* Returns the configurator type
* @return the configurator type
*/
protected Configuration getRendererConfig(String mimeType) {
return super.getConfig(mimeType);
public static String getType() {
return "renderer";
}

/**
* {@inheritDoc}
*/
public String getType() {
return TYPE;
}

}

+ 3
- 3
src/java/org/apache/fop/render/AbstractRendererMaker.java View File

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

package org.apache.fop.render;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;

/**
@@ -50,9 +51,8 @@ public abstract class AbstractRendererMaker {
* @param userAgent user agent
* @return a config object that can be used to configure the renderer
*/
public RendererConfigurator getConfigurator(FOUserAgent userAgent) {
return null;
}
public abstract void configureRenderer(FOUserAgent userAgent, Renderer renderer)
throws FOPException;

/**
* Indicates whether a specific MIME type is supported by this renderer.

+ 5
- 16
src/java/org/apache/fop/render/PrintRenderer.java View File

@@ -36,10 +36,11 @@ import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontCollection;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.fonts.base14.Base14FontCollection;

import sun.font.FontResolver;

/** Abstract base class of "Print" type renderers. */
public abstract class PrintRenderer extends AbstractRenderer {

@@ -88,11 +89,11 @@ public abstract class PrintRenderer extends AbstractRenderer {
/** {@inheritDoc} */
public void setupFontInfo(FontInfo inFontInfo) throws FOPException {
this.fontInfo = inFontInfo;
FontManager fontManager = userAgent.getFactory().getFontManager();
FontManager fontManager = userAgent.getFontManager();
FontCollection[] fontCollections = new FontCollection[] {
new Base14FontCollection(fontManager.isBase14KerningEnabled()),
new CustomFontCollection(getFontResolver(), getFontList(),
userAgent.isComplexScriptFeaturesEnabled())
new CustomFontCollection(fontManager.getURIResolver(), getFontList(),
userAgent.isComplexScriptFeaturesEnabled())
};
fontManager.setup(getFontInfo(), fontCollections);
}
@@ -179,18 +180,6 @@ public abstract class PrintRenderer extends AbstractRenderer {
renderXML(context, doc, ns);
}

/**
* Get FontResolver
*
* @return FontResolver
*/
public FontResolver getFontResolver() {
if (this.fontResolver == null) {
this.fontResolver = new DefaultFontResolver(super.userAgent);
}
return this.fontResolver;
}

/**
* @return the font info
*/

+ 67
- 72
src/java/org/apache/fop/render/PrintRendererConfigurator.java View File

@@ -19,46 +19,74 @@

package org.apache.fop.render;

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

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.io.URIResolverWrapper;
import org.apache.fop.fonts.CustomFontCollection;
import org.apache.fop.fonts.DefaultFontConfigurator;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.FontCollection;
import org.apache.fop.fonts.FontConfigurator;
import org.apache.fop.fonts.FontEventAdapter;
import org.apache.fop.fonts.FontEventListener;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontInfoConfigurator;
import org.apache.fop.fonts.FontManager;
import org.apache.fop.fonts.FontResolver;
import org.apache.fop.fonts.base14.Base14FontCollection;
import org.apache.fop.render.RendererConfig.RendererConfigParser;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;

/**
* Base Print renderer configurator (mostly handles font configuration)
*/
public class PrintRendererConfigurator extends AbstractRendererConfigurator
implements RendererConfigurator, IFDocumentHandlerConfigurator {
public abstract class PrintRendererConfigurator extends AbstractRendererConfigurator
implements IFDocumentHandlerConfigurator {

/** logger instance */
protected static final Log log = LogFactory.getLog(PrintRendererConfigurator.class);
private static Log LOG = LogFactory.getLog(PrintRendererConfigurator.class);

private final RendererConfigParser rendererConfigParser;

private final FontConfigurator<EmbedFontInfo> fontInfoConfigurator;

/**
* Default constructor
* @param userAgent user agent
*/
public PrintRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) {
this(userAgent, rendererConfigParser,
new DefaultFontConfigurator(userAgent.getFontManager(), new FontEventAdapter(
userAgent.getEventBroadcaster()), userAgent.validateUserConfigStrictly()));
}

/**
* Default constructor
* @param userAgent user agent
*/
public PrintRendererConfigurator(FOUserAgent userAgent) {
public PrintRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser,
FontConfigurator<EmbedFontInfo> fontInfoConfigurator) {
super(userAgent);
this.rendererConfigParser = rendererConfigParser;
this.fontInfoConfigurator = fontInfoConfigurator;
}

protected RendererConfig getRendererConfig(IFDocumentHandler documentHandler) throws FOPException {
return getRendererConfig(documentHandler.getMimeType());
}

protected RendererConfig getRendererConfig(String mimeType) throws FOPException {
return userAgent.getRendererConfig(mimeType, rendererConfigParser);
}

protected RendererConfig getRendererConfig(Renderer renderer) throws FOPException {
return getRendererConfig(renderer.getMimeType());
}


/**
* Builds a list of EmbedFontInfo objects for use with the setup() method.
*
@@ -66,77 +94,44 @@ public class PrintRendererConfigurator extends AbstractRendererConfigurator
* @throws FOPException if something's wrong with the config data
*/
public void configure(Renderer renderer) throws FOPException {
Configuration cfg = getRendererConfig(renderer);
if (cfg == null) {
log.trace("no configuration found for " + renderer);
return;
}

PrintRenderer printRenderer = (PrintRenderer)renderer;
FontResolver fontResolver = printRenderer.getFontResolver();

FontEventListener listener = new FontEventAdapter(
renderer.getUserAgent().getEventBroadcaster());
List<EmbedFontInfo> embedFontInfoList = buildFontList(cfg, fontResolver, listener);
PrintRenderer printRenderer = (PrintRenderer) renderer;
List<EmbedFontInfo> embedFontInfoList = buildFontList(renderer.getMimeType());
printRenderer.addFontList(embedFontInfoList);
}

/**
* Builds the font list from configuration.
* @param cfg the configuration object
* @param fontResolver a font resolver
* @param listener the font event listener
* @return the list of {@link EmbedFontInfo} objects
* @throws FOPException if an error occurs while processing the configuration
*/
protected List<EmbedFontInfo> buildFontList(Configuration cfg, FontResolver fontResolver,
FontEventListener listener) throws FOPException {
FopFactory factory = userAgent.getFactory();
FontManager fontManager = factory.getFontManager();
if (fontResolver == null) {
//Ensure that we have minimal font resolution capabilities
fontResolver
= FontManager.createMinimalFontResolver
( userAgent.isComplexScriptFeaturesEnabled() );
}

boolean strict = factory.validateUserConfigStrictly();

//Read font configuration
FontInfoConfigurator fontInfoConfigurator
= new FontInfoConfigurator(cfg, fontManager, fontResolver, listener, strict);
List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>();
fontInfoConfigurator.configure(fontInfoList);
return fontInfoList;
}

// ---=== IFDocumentHandler configuration ===---

/** {@inheritDoc} */
public void configure(IFDocumentHandler documentHandler) throws FOPException {
//nop
}

/** {@inheritDoc} */
public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo)
throws FOPException {
FontManager fontManager = userAgent.getFactory().getFontManager();
List<FontCollection> fontCollections = new ArrayList<FontCollection>();
fontCollections.add(new Base14FontCollection(fontManager.isBase14KerningEnabled()));

Configuration cfg = super.getRendererConfig(documentHandler.getMimeType());
if (cfg != null) {
FontResolver fontResolver = new DefaultFontResolver(userAgent);
FontEventListener listener = new FontEventAdapter(
userAgent.getEventBroadcaster());
List<EmbedFontInfo> fontList = buildFontList(cfg, fontResolver, listener);
fontCollections.add(new CustomFontCollection(fontResolver, fontList,
userAgent.isComplexScriptFeaturesEnabled()));
public void setupFontInfo(String mimeType, FontInfo fontInfo) throws FOPException {
FontManager fontManager = userAgent.getFontManager();
List<FontCollection> fontCollections = getDefaultFontCollection();
fontCollections.add(getCustomFontCollection(fontManager.getURIResolver(), mimeType));
fontManager.setup(fontInfo, fontCollections.toArray(new FontCollection[fontCollections.size()]));
}

protected abstract List<FontCollection> getDefaultFontCollection();

protected FontCollection getCustomFontCollection(URIResolverWrapper uriResolverWrapper, String mimeType)
throws FOPException {
List<EmbedFontInfo> fontList;
if (rendererConfigParser == null) {
fontList = Collections.<EmbedFontInfo>emptyList();
} else {
fontList = fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig());
}
return createCollectionFromFontList(uriResolverWrapper, fontList);
}

protected FontCollection createCollectionFromFontList(URIResolverWrapper uriResolverWrapper,
List<EmbedFontInfo> fontList) {
return new CustomFontCollection(uriResolverWrapper, fontList,
userAgent.isComplexScriptFeaturesEnabled());
}

fontManager.setup(fontInfo,
(FontCollection[])fontCollections.toArray(
new FontCollection[fontCollections.size()]));
documentHandler.setFontInfo(fontInfo);
private List<EmbedFontInfo> buildFontList(String mimeType) throws FOPException {
return fontInfoConfigurator.configure(getRendererConfig(mimeType).getFontInfoConfig());
}
}

src/java/org/apache/fop/render/RendererConfigurator.java → src/java/org/apache/fop/render/RendererConfig.java View File

@@ -19,16 +19,20 @@

package org.apache.fop.render;

import org.apache.avalon.framework.configuration.Configuration;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontConfig;

/**
* Renderer configurator interface
*/
public interface RendererConfigurator {
/**
* Configures a renderer
* @param renderer renderer
* @throws FOPException fop exception
*/
void configure(Renderer renderer) throws FOPException;
public interface RendererConfig {
FontConfig getFontInfoConfig();
public interface RendererConfigParser {
RendererConfig build(FOUserAgent userAgent, Configuration rendererConfiguration) throws FOPException;
String getMimeType();
}
}

test/java/org/apache/fop/config/FontBaseBadTestCase.java → src/java/org/apache/fop/render/RendererConfigOptions.java View File

@@ -17,15 +17,8 @@

/* $Id$ */

package org.apache.fop.config;
package org.apache.fop.render;

/**
* This font base does not exist and a relative font path is used.
*/
public class FontBaseBadTestCase extends BaseDestructiveUserConfigTest {

@Override
public String getUserConfigFilename() {
return "test_fontbase_bad.xconf";
}
public interface RendererConfigOptions {
String getName();
}

+ 16
- 21
src/java/org/apache/fop/render/RendererFactory.java View File

@@ -36,6 +36,7 @@ import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.render.intermediate.AbstractIFDocumentHandlerMaker;
import org.apache.fop.render.intermediate.EventProducingFilter;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
import org.apache.fop.render.intermediate.IFRenderer;
@@ -52,25 +53,19 @@ public class RendererFactory {
private Map eventHandlerMakerMapping = new java.util.HashMap();
private Map documentHandlerMakerMapping = new java.util.HashMap();

private boolean rendererPreferred = false;
private final boolean rendererPreferred;

/**
* Main constructor.
* @param rendererPreferred Controls whether a {@link Renderer} is preferred over a
* {@link IFDocumentHandler} if both are available for the same MIME type. True to prefer the
* {@link Renderer}, false to prefer the {@link IFDocumentHandler}.
*/
public RendererFactory() {
public RendererFactory(boolean rendererPreferred) {
discoverRenderers();
discoverFOEventHandlers();
discoverDocumentHandlers();
}

/**
* Controls whether a {@link Renderer} is preferred over a {@link IFDocumentHandler} if
* both are available for the same MIME type.
* @param value true to prefer the {@link Renderer},
* false to prefer the {@link IFDocumentHandler}.
*/
public void setRendererPreferred(boolean value) {
this.rendererPreferred = value;
this.rendererPreferred = rendererPreferred;
}

/**
@@ -239,7 +234,7 @@ public class RendererFactory {
* @param mime the requested output format
* @return the requested RendererMaker or null if none is available
*/
public AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) {
private AbstractIFDocumentHandlerMaker getDocumentHandlerMaker(String mime) {
AbstractIFDocumentHandlerMaker maker
= (AbstractIFDocumentHandlerMaker)documentHandlerMakerMapping.get(mime);
return maker;
@@ -299,10 +294,7 @@ public class RendererFactory {
AbstractRendererMaker maker = getRendererMaker(outputFormat);
if (maker != null) {
Renderer rend = maker.makeRenderer(userAgent);
RendererConfigurator configurator = maker.getConfigurator(userAgent);
if (configurator != null) {
configurator.configure(rend);
}
maker.configureRenderer(userAgent, rend);
return rend;
} else {
return null;
@@ -383,7 +375,10 @@ public class RendererFactory {
throw new UnsupportedOperationException(
"No IF document handler for the requested format available: " + outputFormat);
}
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(userAgent);
IFDocumentHandler documentHandler = maker.makeIFDocumentHandler(new IFContext(userAgent));
// TODO: do all the configuration in the makeIfDocumentHandler method, that would beam when
// you ask for a document handler, a configured one is returned to you. Getting it and
// configuring it in two steps doesn't make sense.
IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator();
if (configurator != null) {
configurator.configure(documentHandler);
@@ -398,15 +393,15 @@ public class RendererFactory {
List lst = new java.util.ArrayList();
Iterator iter = this.rendererMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
lst.add(iter.next());
}
iter = this.eventHandlerMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
lst.add(iter.next());
}
iter = this.documentHandlerMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
lst.add(iter.next());
}
Collections.sort(lst);
return (String[])lst.toArray(new String[lst.size()]);

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

@@ -83,7 +83,7 @@ public class XMLHandlerConfigurator extends AbstractRendererConfigurator {
*/
public void configure(RendererContext context, String ns) throws FOPException {
//Optional XML handler configuration
Configuration cfg = getRendererConfig(context.getRenderer());
Configuration cfg = userAgent.getRendererConfiguration(context.getRenderer().getMimeType());
if (cfg != null) {
cfg = getHandlerConfig(cfg, ns);
if (cfg != null) {

+ 0
- 0
src/java/org/apache/fop/render/adobe/AdobeRendererConfigurator.java View File


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

Loading…
Cancel
Save