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;
public final class DefaultFontConfig implements FontConfig {
private static final 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;
}
public static final class DefaultFontConfigParser implements FontConfig.FontConfigParser {
public DefaultFontConfig parse(Configuration cfg, boolean strict) throws FOPException {
return new ParserHelper(cfg, strict).instance;
}
public DefaultFontConfig parse(Configuration cfg, boolean strict,
FontEventAdapter eventAdapter) throws FOPException {
return new ParserHelper(cfg, strict, eventAdapter).instance;
}
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 config;
private Configuration fontInfoCfg;
private FontEventAdapter eventAdapter;
private DefaultFontConfig instance;
private ParserHelper(Configuration cfg, boolean strict) throws FOPException {
this(cfg, strict, null);
}
private ParserHelper(Configuration cfg, boolean strict, FontEventAdapter eventAdapter)
throws FOPException {
this.eventAdapter = eventAdapter;
if (cfg == null || cfg.getChild("fonts", false) == null) {
instance = null;
} else {
this.strict = strict;
this.config = cfg;
this.fontInfoCfg = cfg.getChild("fonts", false);
instance = new DefaultFontConfig(fontInfoCfg.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("embed-url-afm", null),
fontCfg.getAttribute("embed-url-pfm", null),
fontCfg.getAttribute("sub-font", null),
fontCfg.getAttributeAsBoolean("kerning", true),
fontCfg.getAttributeAsBoolean("advanced", true),
fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()),
fontCfg.getAttribute("embedding-mode", EncodingMode.AUTO.getName()),
fontCfg.getAttributeAsBoolean("simulate-style", false),
fontCfg.getAttributeAsBoolean("embed-as-type1", false));
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;
}
if (!hasTriplets) {
LogUtil.handleError(log, "font without font-triplet", strict);
}
try {
if (eventAdapter != null && font.getSimulateStyle()
&& !config.getAttribute("mime").equals("application/pdf")) {
eventAdapter.fontFeatureNotSuppprted(this, "simulate-style", "PDF");
}
if (eventAdapter != null && font.getEmbedAsType1()
&& !config.getAttribute("mime").equals("application/postscript")) {
throw new FOPException("The embed-as-type1 attribute is only supported in postscript");
}
} catch (ConfigurationException ex) {
LogUtil.handleException(log, ex, true);
}
}
}
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));
}
}
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;
}
}
public List<Font> getFonts() {
return Collections.unmodifiableList(fonts);
}
public List<Directory> getDirectories() {
return Collections.unmodifiableList(directories);
}
public List<String> getReferencedFontFamily() {
return Collections.unmodifiableList(referencedFontFamilies);
}
public boolean isAutoDetectFonts() {
return autoDetectFonts;
}
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;
}
public String getDirectory() {
return directory;
}
public boolean isRecursive() {
return recursive;
}
}
public static final class Font {
private final String metrics;
private final String embedUri;
private String afm;
private String pfm;
private final String subFont;
private final boolean kerning;
private final boolean advanced;
private final String encodingMode;
private final String embeddingMode;
public String getEncodingMode() {
return encodingMode;
}
private final boolean embedAsType1;
private final boolean simulateStyle;
private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>();
public List<FontTriplet> getTripletList() {
return Collections.unmodifiableList(tripletList);
}
private Font(String metrics, String embed, String afm, String pfm, String subFont, boolean kerning,
boolean advanced, String encodingMode, String embeddingMode, boolean simulateStyle,
boolean embedAsType1) {
this.metrics = metrics;
this.embedUri = embed;
this.afm = afm;
this.pfm = pfm;
this.subFont = subFont;
this.kerning = kerning;
this.advanced = advanced;
this.encodingMode = encodingMode;
this.embeddingMode = embeddingMode;
this.simulateStyle = simulateStyle;
this.embedAsType1 = embedAsType1;
}
public boolean isKerning() {
return kerning;
}
public boolean isAdvanced() {
return advanced;
}
public String getMetrics() {
return metrics;
}
public String getEmbedURI() {
return embedUri;
}
public String getSubFont() {
return subFont;
}
public String getEmbeddingMode() {
return embeddingMode;
}
public String getAfm() {
return afm;
}
public String getPfm() {
return pfm;
}
public boolean getSimulateStyle() {
return simulateStyle;
}
public boolean getEmbedAsType1() {
return embedAsType1;
}
}
}