/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ /* * Created on Apr 17, 2005 */ package org.lobobrowser.util.gui; import java.awt.Font; import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; import java.awt.font.TextAttribute; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.swing.text.StyleContext; /** * A factory for creating Font objects. * * @author J. H. S. */ public class FontFactory { /** The Constant logger. */ private static final Logger logger = LogManager.getLogger(FontFactory.class); /** The Constant loggableFine. */ private static final boolean loggableFine = logger.isInfoEnabled(); /** The Constant instance. */ private static final FontFactory instance = new FontFactory(); /** The font families. */ private final Set<String> fontFamilies = new HashSet<String>(40); /** The font map. */ private final Map<FontKey, Font> fontMap = new HashMap<FontKey, Font>(50); /** The registered fonts. */ private final Map<String, Font> registeredFonts = new HashMap<String, Font>(0); /** The default font name. */ private String defaultFontName = LAFSettings.getInstance().getFont(); /** * Instantiates a new font factory. */ private FontFactory() { boolean liflag = loggableFine; String[] ffns = GraphicsEnvironment.getLocalGraphicsEnvironment() .getAvailableFontFamilyNames(); Set<String> fontFamilies = this.fontFamilies; synchronized (this) { for (int i = 0; i < ffns.length; i++) { String ffn = ffns[i]; if (liflag) { logger.debug("FontFactory(): family=" + ffn); } fontFamilies.add(ffn.toLowerCase()); } } } /** Gets the Constant instance. * * @return the Constant instance */ public static final FontFactory getInstance() { return instance; } /** * Registers a font family. It does not close the stream provided. Fonts * should be registered before the renderer has a chance to cache document * font specifications. * * @param fontName * The name of a font as it would appear in a font-family * specification. * @param fontFormat * Should be {@link Font#TRUETYPE_FONT}. * @param fontStream * the font stream * @throws FontFormatException * the font format exception * @throws IOException * Signals that an I/O exception has occurred. */ public void registerFont(String fontName, int fontFormat, InputStream fontStream) throws FontFormatException, IOException { Font f = Font.createFont(fontFormat, fontStream); synchronized (this) { this.registeredFonts.put(fontName.toLowerCase(), f); } } /** * Unregisters a font previously registered with * {@link #registerFont(String, int, java.io.InputStream)}. * * @param fontName * The font name to be removed. */ public void unregisterFont(String fontName) { synchronized (this) { this.registeredFonts.remove(fontName.toLowerCase()); } } /** * Gets the font. * * @param fontFamily * the font family * @param fontStyle * the font style * @param fontVariant * the font variant * @param fontWeight * the font weight * @param fontSize * the font size * @param locales * the locales * @param superscript * the superscript * @return the font */ public Font getFont(String fontFamily, String fontStyle, String fontVariant, String fontWeight, float fontSize, Set locales, Integer superscript, Integer letterSpacing, boolean strikethrough, Integer underline) { FontKey key = new FontKey(fontFamily, fontStyle, fontVariant, fontWeight, fontSize, locales, superscript,letterSpacing,strikethrough,underline); synchronized (this) { Font font = this.fontMap.get(key); if (font == null) { font = this.createFont(key); this.fontMap.put(key, font); } return font; } } /** Gets the default font name. * * @return the default font name */ public String getDefaultFontName() { return defaultFontName; } /** Sets the default font name. * * @param defaultFontName * the new default font name */ public void setDefaultFontName(String defaultFontName) { if (defaultFontName == null) { throw new IllegalArgumentException( "defaultFontName cannot be null"); } this.defaultFontName = defaultFontName; } /** * Creates a new Font object. * * @param key * the key * @return the font */ private final Font createFont(FontKey key) { Font font = createFont_Impl(key); return scriptFont(font, key); } /** * Script font. * * @param baseFont * the base font * @param newSuperscript * the new superscript * @return the font */ public static Font scriptFont(Font baseFont, FontKey key) { Map<TextAttribute, Object> additionalAttributes = new HashMap<TextAttribute, Object>(); Integer fontSuperScript = (Integer) baseFont.getAttributes().get(TextAttribute.SUPERSCRIPT); if (fontSuperScript == null) { fontSuperScript = key.getSuperscript(); } additionalAttributes.put(TextAttribute.SUPERSCRIPT, fontSuperScript); Integer fontUnderline = (Integer) baseFont.getAttributes().get(TextAttribute.UNDERLINE); if (fontUnderline == null) { fontUnderline = key.getUnderline(); } additionalAttributes.put(TextAttribute.UNDERLINE, fontUnderline); Boolean fontStrikethrough = (Boolean) baseFont.getAttributes().get(TextAttribute.STRIKETHROUGH_ON); if (fontStrikethrough == null) { fontStrikethrough = key.getStrikethrough(); } additionalAttributes.put(TextAttribute.STRIKETHROUGH, fontStrikethrough); return baseFont.deriveFont(additionalAttributes); } /** * Creates a new Font object. * * @param key * the key * @return the font */ private final Font createFont_Impl(FontKey key) { String fontNames = key.getFontFamily(); int letterSpacing = key.getLetterSpacing(); String matchingFace = null; Set fontFamilies = this.fontFamilies; Map<String, Font> registeredFonts = this.registeredFonts; Font baseFont = null; if (fontNames != null) { StringTokenizer tok = new StringTokenizer(fontNames, ","); while (tok.hasMoreTokens()) { String face = tok.nextToken().trim(); String faceTL = face.toLowerCase(); if (registeredFonts.containsKey(faceTL)) { baseFont = registeredFonts.get(faceTL); break; } else if (fontFamilies.contains(faceTL)) { matchingFace = faceTL; break; } } } int fontStyle = Font.PLAIN; if ("italic".equalsIgnoreCase(key.getFontStyle())) { fontStyle |= Font.ITALIC; } if ("bold".equalsIgnoreCase(key.getFontWeight()) || "bolder".equalsIgnoreCase(key.getFontWeight())) { fontStyle |= Font.BOLD; } Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>(); attributes.put(TextAttribute.TRACKING, ((double)letterSpacing/10)/2); if (baseFont != null) { Font f = baseFont.deriveFont(fontStyle, key.getFontSize()); return f.deriveFont(attributes); } else if (matchingFace != null) { Font font = createFont(matchingFace, fontStyle, Math.round(key.getFontSize())); Set locales = key.getLocales(); if (locales == null) { Locale locale = Locale.getDefault(); if (font.canDisplayUpTo(locale.getDisplayLanguage(locale)) == -1) { return font.deriveFont(attributes); } } else { Iterator i = locales.iterator(); boolean allMatch = true; while (i.hasNext()) { Locale locale = (Locale) i.next(); if (font.canDisplayUpTo( locale.getDisplayLanguage(locale)) != -1) { allMatch = false; break; } } if (allMatch) { return font.deriveFont(attributes); } } // Otherwise, fall through. } // Last resort: return createFont(this.defaultFontName, fontStyle, Math.round(key.getFontSize())).deriveFont(attributes); } /** * Creates a new Font object. * * @param name * the name * @param style * the style * @param size * the size * @return the font */ private Font createFont(String name, int style, int size) { return StyleContext.getDefaultStyleContext().getFont(name, style, size); } }