123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /*
- * 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);
- EncodingMode encodingMode = EncodingMode.getEncodingMode(
- fontCfg.getAttribute("encoding-mode", EncodingMode.AUTO.getName()));
- EmbedFontInfo embedFontInfo
- = new EmbedFontInfo(metricsUrl, useKerning, tripletList, embedUrl, subFont);
- embedFontInfo.setEncodingMode(encodingMode);
- if (fontCache != null) {
- if (!fontCache.containsFont(embedFontInfo)) {
- fontCache.addFont(embedFontInfo);
- }
- }
-
- if (log.isDebugEnabled()) {
- String embedFile = embedFontInfo.getEmbedFile();
- log.debug("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;
- }
-
- }
|