/*********************************************************************** * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved. * * 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 version 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 Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***********************************************************************/ package org.mt4j.components.visibleComponents.font; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import org.mt4j.components.visibleComponents.font.fontFactories.BitmapFontFactory; import org.mt4j.components.visibleComponents.font.fontFactories.IFontFactory; import org.mt4j.components.visibleComponents.font.fontFactories.SvgFontFactory; import org.mt4j.components.visibleComponents.font.fontFactories.TTFontFactory; import org.mt4j.util.MT4jSettings; import org.mt4j.util.MTColor; import processing.core.PApplet; /** * Manager for creating fonts. Manages a set of IFontFactory classes. * * @author Christopher Ruff */ public class FontManager { /** The font manager. */ private static FontManager fontManager; /** The fonts. */ private ArrayList<IFont> fonts; /** The suffix to factory. */ private HashMap<String, IFontFactory> suffixToFactory; private static final int CACHE_MAX_SIZE = 10; public static String DEFAULT_FONT = "SansSerif"; public static int DEFAULT_FONT_SIZE = 16; public static MTColor DEFAULT_FONT_FILL_COLOR = MTColor.BLACK; public static MTColor DEFAULT_FONT_STROKE_COLOR = MTColor.BLACK; public static boolean DEFAULT_FONT_ANTIALIASING = true; //TODO fonts seem to be one of the main memory eaters in MT4j! //somehow the fontmanager seems to grow bigger and bigger (at least it seems at profiling //although the same cached(!) fonts are used /** * Instantiates a new font manager. */ private FontManager(){ fonts = new ArrayList<IFont>(); suffixToFactory = new HashMap<String, IFontFactory>(); //Register default font factories this.registerFontFactory(".ttf", new TTFontFactory()); this.registerFontFactory(".svg", new SvgFontFactory()); BitmapFontFactory bitmapFontFactory = new BitmapFontFactory(); // this.registerFontFactory(".ttf", bitmapFontFactory); // TEST this.registerFontFactory("", bitmapFontFactory); this.registerFontFactory(".vlw", bitmapFontFactory); this.registerFontFactory(".otf", bitmapFontFactory); this.registerFontFactory(".bold", bitmapFontFactory); this.registerFontFactory(".bolditalic", bitmapFontFactory); this.registerFontFactory(".italic", bitmapFontFactory); this.registerFontFactory(".plain", bitmapFontFactory); } /** * Gets the instance. * * @return the instance * * this VectorFontManager, use <code>createFont</code> to create a font with it */ public static FontManager getInstance(){ if (fontManager == null){ fontManager = new FontManager(); return fontManager; }else{ return fontManager; } } /** * Gets the default font. * * @param app the app * @return the default font */ public IFont getDefaultFont(PApplet app){ return createFont(app, DEFAULT_FONT, DEFAULT_FONT_SIZE, new MTColor(DEFAULT_FONT_FILL_COLOR), new MTColor(DEFAULT_FONT_STROKE_COLOR), DEFAULT_FONT_ANTIALIASING); } /** * Creates the font. * * @param pa the pa * @param fontFileName the font file name * @param fontSize the font size * @param antiAliased the anti aliased * @return the i font */ public IFont createFont(PApplet pa, String fontFileName, int fontSize, boolean antiAliased){ return createFont(pa, fontFileName,fontSize, new MTColor(0,0,0,255), new MTColor(0,0,0,255), antiAliased); } /** * Loads and returns a font from a file. * <br>The file has to be located in the ./data/ directory of the program. * <br>Example: "IFont font = FontManager.createFont(papplet, "Pakenham.svg", 100);" * * @param pa the pa * @param fontFileName the font file name * @param fontSize the font size * * @return the i font */ public IFont createFont(PApplet pa, String fontFileName, int fontSize){ //// String fontAbsoultePath = System.getProperty("user.dir") + File.separator + "data" + /*File.separator + "fonts" + */ File.separator + IVectorFontFileName; // String fontAbsoultePath = MT4jSettings.getInstance().getDefaultFontPath() + fontFileName; // IFont font = this.getCachedFont(fontAbsoultePath, fontSize, new MTColor(0,0,0,255), new MTColor(0,0,0,255), true); // if (font != null){ // return font; // } return createFont(pa, fontFileName,fontSize, new MTColor(0,0,0,255), new MTColor(0,0,0,255)); } /** * Loads and returns a vector font from a file. * <br>The file has to be located in the ./data/ directory of the program. * * @param pa the pa * @param fontFileName the font file name * @param fontSize the font size * @param fillColor the fill color * @param strokeColor the stroke color * * @return the i font */ public IFont createFont(PApplet pa, String fontFileName, int fontSize, MTColor fillColor, MTColor strokeColor) { return this.createFont(pa, fontFileName, fontSize, fillColor, strokeColor, true); } /** * Loads and returns a vector font from a file. * <br>The file has to be located in the ./data/ directory of the program. * * @param pa the pa * @param fontFileName the font file name * @param fontSize the font size * @param fillColor the fill color * @param strokeColor the stroke color * @param antiAliased the anti aliased * @return the i font */ public IFont createFont(PApplet pa, String fontFileName, int fontSize, MTColor fillColor, MTColor strokeColor, boolean antiAliased) { // String fontAbsoultePath = System.getProperty("user.dir") + File.separator + "data" + File.separator + "fonts"+ File.separator + fontFileName; String fontAbsoultePath = MT4jSettings.getInstance().getDefaultFontPath() + fontFileName; //Return cached font if there IFont font = this.getCachedFont(fontAbsoultePath, fontSize, fillColor, strokeColor, antiAliased); if (font != null){ return font; } IFont loadedFont = null; // if (new File(fontAbsoultePath).exists()){ try { int indexOfPoint = fontFileName.lastIndexOf("."); String suffix; if (indexOfPoint != -1){ suffix = fontFileName.substring(indexOfPoint, fontFileName.length()); suffix = suffix.toLowerCase(); }else{ suffix = ""; } //Check which factory to use for this file type IFontFactory factoryToUse = this.getFactoryForFileSuffix(suffix); //Create the font if we have a factory if (factoryToUse != null){ System.out.println("Loading new font \"" + fontFileName + "\" with factory: " + factoryToUse.getClass().getName()); // loadedFont = factoryToUse.createFont(pa, fontAbsoultePath, fontSize, fillColor, strokeColor); loadedFont = factoryToUse.createFont(pa, fontAbsoultePath, fontSize, fillColor, strokeColor, antiAliased); fonts.add(loadedFont); if (fonts.size() > CACHE_MAX_SIZE && !fonts.isEmpty()){ IFont removedFont = fonts.remove(0); //FIXME destroy font, too! if (removedFont != null){ removedFont.destroy(); } } }else{ System.err.println("Couldnt find a appropriate font factory for: " + fontFileName + " Suffix: " + suffix); // loadedFont = new VectorFont(new VectorFontCharacter[0]); } }catch (Exception e) { System.err.println("Error while trying to create the font: " + fontFileName); e.printStackTrace(); } // } // else{ // System.err.println("Couldnt find font: " + fontAbsoultePath); // loadedFont = new VectorFont(new VectorFontCharacter[0]); // } return (loadedFont); } /** * Register a new fontfactory for a file type. * * @param factory the factory * @param fileSuffix the file suffix to use with that factory. ".ttf" for example. */ public void registerFontFactory(String fileSuffix, IFontFactory factory){ fileSuffix = fileSuffix.toLowerCase(); this.suffixToFactory.put(fileSuffix, factory); } /** * Unregister a fontfactory for a file type. * * @param factory the factory */ public void unregisterFontFactory(IFontFactory factory){ Set<String> suffixesInHashMap = this.suffixToFactory.keySet(); for (Iterator<String> iter = suffixesInHashMap.iterator(); iter.hasNext();) { String suffix = (String) iter.next(); if (this.getFactoryForFileSuffix(suffix).equals(factory)){ this.suffixToFactory.remove(suffix); } } } /** * Gets the registered factories. * @return the registered factories */ public IFontFactory[] getRegisteredFactories(){ Collection<IFontFactory> factoryCollection = this.suffixToFactory.values(); return factoryCollection.toArray(new IFontFactory[factoryCollection.size()]); } /** * Gets the factory for file suffix. * @param suffix the suffix * @return the factory for file suffix */ public IFontFactory getFactoryForFileSuffix(String suffix){ return this.suffixToFactory.get(suffix); } /** * Gets the cached font. * * @param fontAbsoultePath the font absoulte path * @param fontSize the font size * @param fillColor the fill color * @param strokeColor the stroke color * * @return the cached font */ public IFont getCachedFont(String fontAbsoultePath, int fontSize, MTColor fillColor, MTColor strokeColor, boolean antiAliased){ for (IFont font : fonts){ if (fontsAreEqual(font, fontAbsoultePath, fontSize, fillColor, strokeColor, antiAliased) ){ System.out.println("Using cached font: " + fontAbsoultePath + " Fontsize: " + Math.round(fontSize) + " FillColor: " + fillColor + " StrokeColor: " + strokeColor); return font; } } return null; } //TODO should take fontcolor into acount, too /** * Fonts are equal. * * @param font the font * @param IVectorFontFileName the i vector font file name * @param fontSize the font size * @param fillColor the fill color * @param strokeColor the stroke color * * @return true, if successful */ public static boolean fontsAreEqual(IFont font, String IVectorFontFileName, int fontSize, MTColor fillColor, MTColor strokeColor, boolean antiAliased){ return ( font.getFontFileName().equalsIgnoreCase(IVectorFontFileName) && font.getOriginalFontSize() == fontSize && // font.getFillRed() == fillRed // && font.getFillGreen() == fillGreen // && font.getFillBlue() == fillBlue // && font.getFillAlpha() == fillAlpha font.getFillColor().equals(fillColor) && font.getStrokeColor().equals(strokeColor) && (font.isAntiAliased() == antiAliased) // font.getStrokeRed() == strokeRed // && font.getStrokeGreen() == strokeGreen // && font.getStrokeBlue() == strokeBlue // && font.getStrokeAlpha() == strokeAlpha ); } /** * Checks if is fonts are equal. * * @param font1 the font1 * @param font2 the font2 * * @return true, if is fonts are equal */ public static boolean isFontsAreEqual(IFont font1, IFont font2){ return ( //font1.getFontFileName().equalsIgnoreCase(font2.getFontFileName()) //&& font1.getOriginalFontSize() == font2.getOriginalFontSize() && font1.getFontFamily().equalsIgnoreCase(font2.getFontFamily()) && // font1.getFillRed() == font2.getFillRed() // && font1.getFillGreen() == font2.getFillGreen() // && font1.getFillBlue() == font2.getFillBlue() // && font1.getFillAlpha() == font2.getFillAlpha() font1.getFillColor().equals(font2.getFillColor()) && font1.getStrokeColor().equals(font2.getStrokeColor()) // font1.getStrokeRed() == font2.getStrokeRed() // && font1.getStrokeGreen() == font2.getStrokeGreen() // && font1.getStrokeBlue() == font2.getStrokeBlue() // && font1.getStrokeAlpha() == font2.getStrokeAlpha() ); } /** * Removes the font from the cache. * <br><b>NOTE:</b> doesent destroy the font! To cleanly destroy a font AND remove it from * the fontmanager cache call <code>font.destroy()</code>. * * @param font the font * @return true, if successful */ public boolean removeFromCache(IFont font) { int in = this.fonts.indexOf(font); if (in != -1){ IFont removedFont = fonts.remove(in); // if (removedFont != null){ //DOESENT DESTROY THE FONT, font would get destroyed 2 times if font.destroy is called, which calls removeFromCache // removedFont.destroy(); // } return true; }else{ return false; } } }