/* DefaultTeXFont.java * ========================================================================= * This file is originally part of the JMathTeX Library - http://jmathtex.sourceforge.net * * Copyright (C) 2004-2007 Universiteit Gent * Copyright (C) 2009 DENIZET Calixte * * 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 2 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. * * A copy of the GNU General Public License can be found in the file * LICENSE.txt provided with the source distribution of this program (see * the META-INF directory in the source jar). This license can also be * found on the GNU website at http://www.gnu.org/licenses/gpl.html. * * If you did not receive a copy of the GNU General Public License along * with this program, contact the lead developer, or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * Linking this library statically or dynamically with other modules * is making a combined work based on this library. Thus, the terms * and conditions of the GNU General Public License cover the whole * combination. * * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce * an executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under terms * of your choice, provided that you also meet, for each linked independent * module, the terms and conditions of the license of that module. * An independent module is a module which is not derived from or based * on this library. If you modify this library, you may extend this exception * to your version of the library, but you are not obliged to do so. * If you do not wish to do so, delete this exception statement from your * version. * */ package com.himamis.retex.renderer.share; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.himamis.retex.renderer.share.character.Character; import com.himamis.retex.renderer.share.exception.AlphabetRegistrationException; import com.himamis.retex.renderer.share.exception.FontAlreadyLoadedException; import com.himamis.retex.renderer.share.exception.ResourceParseException; import com.himamis.retex.renderer.share.exception.SymbolMappingNotFoundException; import com.himamis.retex.renderer.share.exception.TextStyleMappingNotFoundException; import com.himamis.retex.renderer.share.exception.XMLResourceParseException; import com.himamis.retex.renderer.share.platform.Resource; import com.himamis.retex.renderer.share.platform.font.Font; /** * The default implementation of the TeXFont-interface. All font information is read from an * xml-file. */ public class DefaultTeXFont implements TeXFont { private static String[] defaultTextStyleMappings; /** * No extension part for that kind (TOP,MID,REP or BOT) */ protected static final int NONE = -1; protected final static int NUMBERS = 0; protected final static int CAPITALS = 1; protected final static int SMALL = 2; protected final static int UNICODE = 3; // Number of font ids in a single font description file. // private static final int NUMBER_OF_FONT_IDS = 256; private static Map<String, CharFont[]> textStyleMappings; private static Map<String, CharFont> symbolMappings; private static FontInfo[] fontInfo = new FontInfo[0]; private static Map<String, Double> parameters; private static Map<String, Number> generalSettings; //private static boolean magnificationEnable = true; protected static final int TOP = 0, MID = 1, REP = 2, BOT = 3; protected static final int WIDTH = 0, HEIGHT = 1, DEPTH = 2, IT = 3; public static List<Character.UnicodeBlock> loadedAlphabets = new ArrayList<Character.UnicodeBlock>(); public static Map<Character.UnicodeBlock, AlphabetRegistration> registeredAlphabets = new HashMap<Character.UnicodeBlock, AlphabetRegistration>(); protected double factor = 1; public boolean isBold = false; public boolean isRoman = false; public boolean isSs = false; public boolean isTt = false; public boolean isIt = false; static { DefaultTeXFontParser parser = new DefaultTeXFontParser(); // load LATIN block loadedAlphabets.add(Character.UnicodeBlock.of('a')); // fonts + font descriptions fontInfo = parser.parseFontDescriptions(fontInfo); // general font parameters parameters = parser.parseParameters(); // text style mappings textStyleMappings = parser.parseTextStyleMappings(); // default text style : style mappings defaultTextStyleMappings = parser.parseDefaultTextStyleMappings(); // symbol mappings symbolMappings = parser.parseSymbolMappings(); // general settings generalSettings = parser.parseGeneralSettings(); generalSettings.put("textfactor", 1); // check if mufontid exists int muFontId = generalSettings.get(DefaultTeXFontParser.MUFONTID_ATTR).intValue(); if (muFontId < 0 || muFontId >= fontInfo.length || fontInfo[muFontId] == null) { throw new XMLResourceParseException(DefaultTeXFontParser.RESOURCE_NAME, DefaultTeXFontParser.GEN_SET_EL, DefaultTeXFontParser.MUFONTID_ATTR, "contains an unknown font id!"); } } private final double size; // standard size public static Font getFont(int fontId) { FontInfo info = fontInfo[fontId]; Font font = info.getFont(); return font; } public DefaultTeXFont(double pointSize) { size = pointSize; } public DefaultTeXFont(double pointSize, boolean b, boolean rm, boolean ss, boolean tt, boolean it) { this(pointSize, 1, b, rm, ss, tt, it); } public DefaultTeXFont(double pointSize, double f, boolean b, boolean rm, boolean ss, boolean tt, boolean it) { size = pointSize; factor = f; isBold = b; isRoman = rm; isSs = ss; isTt = tt; isIt = it; } public static void addTeXFontDescription(String file) throws ResourceParseException { Object in = new Resource().loadResource(file); addTeXFontDescription(in, file); } public static void addTeXFontDescription(Object in, String name) throws ResourceParseException { DefaultTeXFontParser dtfp = new DefaultTeXFontParser(in, name); fontInfo = dtfp.parseFontDescriptions(fontInfo); textStyleMappings.putAll(dtfp.parseTextStyleMappings()); symbolMappings.putAll(dtfp.parseSymbolMappings()); } public static void addTeXFontDescription(Object base, Object in, String name) throws ResourceParseException { DefaultTeXFontParser dtfp = new DefaultTeXFontParser(base, in, name); fontInfo = dtfp.parseFontDescriptions(fontInfo); dtfp.parseExtraPath(); textStyleMappings.putAll(dtfp.parseTextStyleMappings()); symbolMappings.putAll(dtfp.parseSymbolMappings()); } public static void addAlphabet(Character.UnicodeBlock alphabet, Object inlanguage, String language, Object insymbols, String symbols, Object inmappings, String mappings) throws ResourceParseException { if (!loadedAlphabets.contains(alphabet)) { addTeXFontDescription(inlanguage, language); SymbolAtom.addSymbolAtom(insymbols, symbols); TeXFormula.addSymbolMappings(inmappings, mappings); loadedAlphabets.add(alphabet); } } public static void addAlphabet(Object base, Character.UnicodeBlock[] alphabet, String language) throws ResourceParseException { boolean b = false; for (int i = 0; !b && i < alphabet.length; i++) { b = loadedAlphabets.contains(alphabet[i]) || b; } if (!b) { TeXParser.isLoading = true; Object res = new Resource().loadResource(base, language); System.out.println( "ADDING ALPHABET " + language + ":" + res + "," + base); addTeXFontDescription(base, res, language); for (int i = 0; i < alphabet.length; i++) { loadedAlphabets.add(alphabet[i]); } System.out.println("ADDED"); TeXParser.isLoading = false; } } public static void addAlphabet(Character.UnicodeBlock alphabet, String name) { String lg = "fonts/" + name + "/language_" + name + ".xml"; String sym = "fonts/" + name + "/symbols_" + name + ".xml"; String map = "fonts/" + name + "/mappings_" + name + ".xml"; Resource resource = new Resource(); try { DefaultTeXFont.addAlphabet(alphabet, resource.loadResource(TeXFormula.class, lg), lg, resource.loadResource(TeXFormula.class, sym), sym, resource.loadResource(TeXFormula.class, map), map); } catch (FontAlreadyLoadedException e) { } } public static void addAlphabet(AlphabetRegistration reg) { try { if (reg != null) { DefaultTeXFont.addAlphabet(reg.getPackage(), reg.getUnicodeBlock(), reg.getTeXFontFileName()); } } catch (FontAlreadyLoadedException e) { } catch (AlphabetRegistrationException e) { System.err.println(e.toString()); } } public static void registerAlphabet(AlphabetRegistration reg) { Character.UnicodeBlock[] blocks = reg.getUnicodeBlock(); for (int i = 0; i < blocks.length; i++) { registeredAlphabets.put(blocks[i], reg); } } @Override public TeXFont copy() { return new DefaultTeXFont(size, factor, isBold, isRoman, isSs, isTt, isIt); } @Override public TeXFont deriveFont(double size) { return new DefaultTeXFont(size, factor, isBold, isRoman, isSs, isTt, isIt); } @Override public TeXFont scaleFont(double factor) { return new DefaultTeXFont(size, factor, isBold, isRoman, isSs, isTt, isIt); } @Override public double getScaleFactor() { return factor; } @Override public double getAxisHeight(int style) { return getParameter("axisheight") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getBigOpSpacing1(int style) { return getParameter("bigopspacing1") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getBigOpSpacing2(int style) { return getParameter("bigopspacing2") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getBigOpSpacing3(int style) { return getParameter("bigopspacing3") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getBigOpSpacing4(int style) { return getParameter("bigopspacing4") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getBigOpSpacing5(int style) { return getParameter("bigopspacing5") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } private Char getChar(char c, CharFont[] cf, int style) { int kind, offset; if (c >= '0' && c <= '9') { kind = NUMBERS; offset = c - '0'; } else if (c >= 'a' && c <= 'z') { kind = SMALL; offset = c - 'a'; } else if (c >= 'A' && c <= 'Z') { kind = CAPITALS; offset = c - 'A'; } else { kind = UNICODE; offset = c; } // if the mapping for the character's range, then use the default style if (cf[kind] == null) { return getDefaultChar(c, style); } return getChar( new CharFont((char) (cf[kind].c + offset), cf[kind].fontId), style); } @Override public Char getChar(char c, String textStyle, int style) throws TextStyleMappingNotFoundException { Object mapping = textStyleMappings.get(textStyle); if (mapping == null) { throw new TextStyleMappingNotFoundException(textStyle); } return getChar(c, (CharFont[]) mapping, style); } @Override public Char getChar(CharFont cf0, int style) { double fsize = getSizeFactor(style); int id = isBold ? cf0.boldFontId : cf0.fontId; FontInfo info = fontInfo[id]; CharFont cf = cf0; if (isBold && cf.fontId == cf.boldFontId) { id = info.getBoldId(); info = fontInfo[id]; cf = new CharFont(cf.c, id, style); } if (isRoman) { id = info.getRomanId(); info = fontInfo[id]; cf = new CharFont(cf.c, id, style); } if (isSs) { id = info.getSsId(); info = fontInfo[id]; cf = new CharFont(cf.c, id, style); } if (isTt) { id = info.getTtId(); info = fontInfo[id]; cf = new CharFont(cf.c, id, style); } if (isIt) { id = info.getItId(); info = fontInfo[id]; cf = new CharFont(cf.c, id, style); } Font font = info.getFont(); return new Char(cf.c, font, id, getMetrics(cf, factor * fsize)); } @Override public Char getChar(String symbolName, int style) throws SymbolMappingNotFoundException { Object obj = symbolMappings.get(symbolName); if (obj == null) {// no symbol mapping found! for (Entry<String, CharFont> e : symbolMappings.entrySet()) { System.out.println(e.getKey() + " , " + e.getValue()); } throw new SymbolMappingNotFoundException(symbolName); } return getChar((CharFont) obj, style); } @Override public Char getDefaultChar(char c, int style) { // these default text style mappings will allways exist, // because it's checked during parsing if (c >= '0' && c <= '9') { return getChar(c, defaultTextStyleMappings[NUMBERS], style); } else if (c >= 'a' && c <= 'z') { return getChar(c, defaultTextStyleMappings[SMALL], style); } else { return getChar(c, defaultTextStyleMappings[CAPITALS], style); } } @Override public double getDefaultRuleThickness(int style) { return getParameter("defaultrulethickness") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getDenom1(int style) { return getParameter("denom1") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getDenom2(int style) { return getParameter("denom2") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public Extension getExtension(Char c, int style) { Font f = c.getFont(); int fc = c.getFontCode(); double s = getSizeFactor(style); // construct Char for every part FontInfo info = fontInfo[fc]; int[] ext = info.getExtension(c.getChar()); Char[] parts = new Char[ext.length]; for (int i = 0; i < ext.length; i++) { if (ext[i] == NONE) { parts[i] = null; } else { parts[i] = new Char((char) ext[i], f, fc, getMetrics(new CharFont((char) ext[i], fc), s)); } } return new Extension(parts[TOP], parts[MID], parts[REP], parts[BOT]); } @Override public double getKern(CharFont left, CharFont right, int style) { if (left.fontId == right.fontId) { FontInfo info = fontInfo[left.fontId]; return info.getKern(left.c, right.c, getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT); } return 0; } @Override public CharFont getLigature(CharFont left, CharFont right) { if (left.fontId == right.fontId) { FontInfo info = fontInfo[left.fontId]; return info.getLigature(left.c, right.c); } return null; } private static Metrics getMetrics(CharFont cf, double size) { FontInfo info = fontInfo[cf.fontId]; double[] m = info.getMetrics(cf.c); if (m == null) { return new Metrics(1, 1, 0, 0, size * TeXFormula.PIXELS_PER_POINT, size); } return new Metrics(m[WIDTH], m[HEIGHT], m[DEPTH], m[IT], size * TeXFormula.PIXELS_PER_POINT, size); } @Override public int getMuFontId() { return generalSettings.get(DefaultTeXFontParser.MUFONTID_ATTR).intValue(); } @Override public Char getNextLarger(Char c, int style) { FontInfo info = fontInfo[c.getFontCode()]; CharFont ch = info.getNextLarger(c.getChar()); FontInfo newInfo = fontInfo[ch.fontId]; return new Char(ch.c, newInfo.getFont(), ch.fontId, getMetrics(ch, getSizeFactor(style))); } @Override public double getNum1(int style) { return getParameter("num1") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getNum2(int style) { return getParameter("num2") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getNum3(int style) { return getParameter("num3") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getQuad(int style, int fontCode) { FontInfo info = fontInfo[fontCode]; return info.getQuad(getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT); } @Override public double getSize() { return size; } @Override public double getSkew(CharFont cf, int style) { FontInfo info = fontInfo[cf.fontId]; char skew = info.getSkewChar(); if (skew == -1) { return 0; } return getKern(cf, new CharFont(skew, cf.fontId), style); } @Override public double getSpace(int style) { int spaceFontId = generalSettings.get(DefaultTeXFontParser.SPACEFONTID_ATTR).intValue(); FontInfo info = fontInfo[spaceFontId]; return info.getSpace(getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT); } @Override public double getSub1(int style) { return getParameter("sub1") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getSub2(int style) { return getParameter("sub2") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getSubDrop(int style) { return getParameter("subdrop") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getSup1(int style) { return getParameter("sup1") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getSup2(int style) { return getParameter("sup2") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getSup3(int style) { return getParameter("sup3") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getSupDrop(int style) { return getParameter("supdrop") * getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public double getXHeight(int style, int fontCode) { FontInfo info = fontInfo[fontCode]; return info.getXHeight(getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT); } @Override public double getEM(int style) { return getSizeFactor(style) * TeXFormula.PIXELS_PER_POINT; } @Override public boolean hasNextLarger(Char c) { FontInfo info = fontInfo[c.getFontCode()]; return (info.getNextLarger(c.getChar()) != null); } @Override public void setBold(boolean bold) { isBold = bold; } @Override public boolean getBold() { return isBold; } @Override public void setRoman(boolean rm) { isRoman = rm; } @Override public boolean getRoman() { return isRoman; } @Override public void setTt(boolean tt) { isTt = tt; } @Override public boolean getTt() { return isTt; } @Override public void setIt(boolean it) { isIt = it; } @Override public boolean getIt() { return isIt; } @Override public void setSs(boolean ss) { isSs = ss; } @Override public boolean getSs() { return isSs; } @Override public boolean hasSpace(int font) { FontInfo info = fontInfo[font]; return info.hasSpace(); } @Override public boolean isExtensionChar(Char c) { FontInfo info = fontInfo[c.getFontCode()]; return info.getExtension(c.getChar()) != null; } // public static void setMathSizes(double ds, double ts, double ss, double sss) { // if (magnificationEnable) { // generalSettings.put("scriptfactor", Math.abs(ss / ds)); // generalSettings.put("scriptscriptfactor", Math.abs(sss / ds)); // generalSettings.put("textfactor", Math.abs(ts / ds)); // TeXIcon.defaultSize = Math.abs(ds); // } // } // public static void setMagnification(double mag) { // if (magnificationEnable) { // TeXIcon.magFactor = mag / 1000f; // } // } // public static void enableMagnification(boolean b) { // magnificationEnable = b; // } private static double getParameter(String parameterName) { Object param = parameters.get(parameterName); if (param == null) { return 0; } return ((Double) param).doubleValue(); } public static double getSizeFactor(int style) { if (style < TeXConstants.STYLE_TEXT) { return 1; } else if (style < TeXConstants.STYLE_SCRIPT) { return generalSettings.get("textfactor").doubleValue(); } else if (style < TeXConstants.STYLE_SCRIPT_SCRIPT) { return generalSettings.get("scriptfactor").doubleValue(); } else { return generalSettings.get("scriptscriptfactor").doubleValue(); } } }