/* * 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 directories = new ArrayList(); private final List fonts = new ArrayList(); private final List referencedFontFamilies = new ArrayList(); 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 getFonts() { return Collections.unmodifiableList(fonts); } /** * Returns a list of directories that were parsed. * @return a list of directories */ public List getDirectories() { return Collections.unmodifiableList(directories); } /** * Returns a list of referenced font families. * @return the referenced font families */ public List 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 tripletList = new ArrayList(); public List 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; } } }