package org.apache.fop.fonts.autodetect;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.apps.io.InternalResourceResolver;
import org.apache.fop.fonts.CustomFont;
import org.apache.fop.fonts.EmbedFontInfo;
import org.apache.fop.fonts.EmbeddingMode;
import org.apache.fop.fonts.EncodingMode;
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.FontTriplet;
import org.apache.fop.fonts.FontUris;
import org.apache.fop.fonts.FontUtil;
import org.apache.fop.fonts.MultiByteFont;
import org.apache.fop.fonts.truetype.FontFileReader;
import org.apache.fop.fonts.truetype.OFFontLoader;
import org.apache.fop.fonts.truetype.TTFFile;
public class FontInfoFinder {
private final Log log = LogFactory.getLog(FontInfoFinder.class);
private FontEventListener eventListener;
public void setEventListener(FontEventListener listener) {
this.eventListener = listener;
}
private void generateTripletsFromFont(CustomFont customFont, Collection<FontTriplet> triplets) {
if (log.isTraceEnabled()) {
log.trace("Font: " + customFont.getFullName()
+ ", family: " + customFont.getFamilyNames()
+ ", PS: " + customFont.getFontName()
+ ", EmbedName: " + customFont.getEmbedFontName());
}
String strippedName = stripQuotes(customFont.getStrippedFontName());
String fullName = stripQuotes(customFont.getFullName());
String searchName = fullName.toLowerCase();
String style = guessStyle(customFont, searchName);
int weight;
int guessedWeight = FontUtil.guessWeight(searchName);
weight = guessedWeight;
triplets.add(new FontTriplet(fullName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL));
if (!fullName.equals(strippedName)) {
triplets.add(new FontTriplet(strippedName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL));
}
Set<String> familyNames = customFont.getFamilyNames();
for (String familyName : familyNames) {
familyName = stripQuotes(familyName);
if (!fullName.equals(familyName)) {
int priority = fullName.startsWith(familyName)
? fullName.length() - familyName.length()
: fullName.length();
triplets.add(new FontTriplet(familyName, style, weight, priority));
}
}
}
private final Pattern quotePattern = Pattern.compile("'");
private String stripQuotes(String name) {
return quotePattern.matcher(name).replaceAll("");
}
private String guessStyle(CustomFont customFont, String fontName) {
String style = Font.STYLE_NORMAL;
if (customFont.getItalicAngle() > 0) {
style = Font.STYLE_ITALIC;
} else {
style = FontUtil.guessStyle(fontName);
}
return style;
}
private EmbedFontInfo getFontInfoFromCustomFont(URI fontUri, CustomFont customFont,
FontCache fontCache, InternalResourceResolver resourceResolver) {
FontUris fontUris = new FontUris(fontUri, null);
List<FontTriplet> fontTripletList = new java.util.ArrayList<FontTriplet>();
generateTripletsFromFont(customFont, fontTripletList);
String subFontName = null;
if (customFont instanceof MultiByteFont) {
subFontName = ((MultiByteFont) customFont).getTTCName();
}
EmbedFontInfo fontInfo = new EmbedFontInfo(fontUris, customFont.isKerningEnabled(),
customFont.isAdvancedEnabled(), fontTripletList, subFontName);
fontInfo.setPostScriptName(customFont.getFontName());
if (fontCache != null) {
fontCache.addFont(fontInfo, resourceResolver);
}
return fontInfo;
}
public EmbedFontInfo[] find(URI fontURI, InternalResourceResolver resourceResolver, FontCache fontCache) {
URI embedUri = resourceResolver.resolveFromBase(fontURI);
String embedStr = embedUri.toASCIIString();
boolean useKerning = true;
boolean useAdvanced = true;
long fileLastModified = -1;
if (fontCache != null) {
fileLastModified = FontCache.getLastModified(fontURI);
if (fontCache.containsFont(embedStr)) {
EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedStr, fileLastModified);
if (fontInfos != null) {
return fontInfos;
}
} else if (fontCache.isFailedFont(embedStr, fileLastModified)) {
if (log.isDebugEnabled()) {
log.debug("Skipping font file that failed to load previously: " + embedUri);
}
return null;
}
}
CustomFont customFont = null;
if (fontURI.toASCIIString().toLowerCase().endsWith(".ttc")) {
List<String> ttcNames = null;
InputStream in = null;
try {
in = resourceResolver.getResource(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,
fontURI.toASCIIString(), e);
}
return null;
} finally {
IOUtils.closeQuietly(in);
}
List<EmbedFontInfo> embedFontInfoList = new java.util.ArrayList<EmbedFontInfo>();
for (String fontName : ttcNames) {
if (log.isDebugEnabled()) {
log.debug("Loading " + fontName);
}
try {
OFFontLoader ttfLoader = new OFFontLoader(fontURI, fontName, true,
EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced,
resourceResolver, false, false);
customFont = ttfLoader.getFont();
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
} catch (Exception e) {
if (fontCache != null) {
fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified);
}
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this,
embedUri.toASCIIString(), e);
}
continue;
}
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache,
resourceResolver);
if (fi != null) {
embedFontInfoList.add(fi);
}
}
return embedFontInfoList.toArray(
new EmbedFontInfo[embedFontInfoList.size()]);
} else {
try {
FontUris fontUris = new FontUris(fontURI, null);
customFont = FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO,
useKerning, useAdvanced, resourceResolver, false, false);
if (this.eventListener != null) {
customFont.setEventListener(this.eventListener);
}
} catch (Exception e) {
if (fontCache != null) {
fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified);
}
if (this.eventListener != null) {
this.eventListener.fontLoadingErrorAtAutoDetection(this,
embedUri.toASCIIString(), e);
}
return null;
}
EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, resourceResolver);
if (fi != null) {
return new EmbedFontInfo[] {fi};
} else {
return null;
}
}
}
}