/* * Copyright 2003-2014 JetBrains s.r.o. * * Licensed 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. */ package jetbrains.mps.nodeEditor.cells; import com.intellij.openapi.util.SystemInfo; import jetbrains.mps.logging.Logger; import jetbrains.mps.util.Pair; import org.apache.log4j.LogManager; import org.jetbrains.annotations.NotNull; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GraphicsEnvironment; import java.awt.Toolkit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * User: shatalin * Date: 06/08/14 */ public class FontRegistry { private static final Logger LOG = Logger.wrap(LogManager.getLogger(FontRegistry.class)); private static FontRegistry ourInstance; public static FontRegistry getInstance() { if (ourInstance == null) { ourInstance = new FontRegistry(); } return ourInstance; } private Map<String, FontFamily> myAvailableFonts; private Map<String, Font> myFontsCache = new HashMap<String, Font>(); private Map<Font, FontMetrics> myFontMetricsCache = new HashMap<Font, FontMetrics>(); private FontRegistry() { loadStyledFonts(); } private void loadStyledFonts() { if (!SystemInfo.isMac) { return; } myAvailableFonts = new HashMap<String, FontFamily>(); GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment(); for (Font font : graphicsEnvironment.getAllFonts()) { String fontFamilyName = font.getFamily(); FontFamily fontFamily = myAvailableFonts.get(fontFamilyName); if (fontFamily == null) { fontFamily = new FontFamily(fontFamilyName); myAvailableFonts.put(fontFamilyName, fontFamily); } fontFamily.addFont(font.getName()); } for (String fontFamilyName : myAvailableFonts.keySet().toArray(new String[myAvailableFonts.size()])) { FontFamily fontFamily = myAvailableFonts.get(fontFamilyName); if (!fontFamily.isValid()) { myAvailableFonts.remove(fontFamilyName); } } } public Font getFont(String fontName, int style, int size) { String key = fontName + "#" + style + "#" + size; Font result = myFontsCache.get(key); if (result == null) { Pair<String, Integer> realFontName = getRealFontNameAndStyle(fontName, style); result = new Font(realFontName.o1, realFontName.o2, size); myFontsCache.put(key, result); } return result; } public boolean isFakeItalic(String fontName, int style) { if (!SystemInfo.isMac || (style & Font.ITALIC) == 0) { return false; } FontFamily fontEntry = myAvailableFonts.get(fontName); return fontEntry == null || fontEntry.getFontName(style) == null; } public FontMetrics getFontMetrics(Font font) { FontMetrics result = myFontMetricsCache.get(font); if (result == null) { result = Toolkit.getDefaultToolkit().getFontMetrics(font); myFontMetricsCache.put(font, result); } return result; } private Pair<String, Integer> getRealFontNameAndStyle(String fontName, int style) { if (SystemInfo.isMac && myAvailableFonts.containsKey(fontName)) { FontFamily fontEntry = myAvailableFonts.get(fontName); String styledFontName = fontEntry.getFontName(style); if (styledFontName != null) { return new Pair<String, Integer>(styledFontName, 0); } else { return new Pair<String, Integer>(fontEntry.getRegularFontName(), style); } } return new Pair<String, Integer>(fontName, style); } private class FontFamily { private String myFamilyName; private List<String> myFontNames = new ArrayList<String>(); private String myRegularFontName; private String myBoldFontName; private String myItalicFontName; private String myBoldItalicFontName; public FontFamily(@NotNull String familyName) { myFamilyName = familyName; } public void addFont(String fontName) { myFontNames.add(fontName); } private String getCommonPrefix() { assert myFontNames.size() > 1; String commonPrefix = null; for (String fontName : myFontNames) { if (commonPrefix == null) { commonPrefix = fontName; continue; } while (!fontName.startsWith(commonPrefix) && !commonPrefix.isEmpty()) { commonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1); } } return commonPrefix; } private void loadFontNames() { if (myFontNames.isEmpty()) { return; } if (myFontNames.size() == 1) { myRegularFontName = myFontNames.get(0); return; } String prefix = getCommonPrefix(); if (prefix.isEmpty()) { myRegularFontName = myFontNames.get(0); LOG.error( "Common prefix was not found for font family \"" + myFamilyName + "\" using first available font as regular one: \"" + myRegularFontName + "\""); return; } int prefixLength = prefix.length(); int regularSuffixLen = -1; int italicSuffixLen = -1; int boldSuffixLen = -1; int boldItalicSuffixLen = -1; for (String fontName : myFontNames) { if (fontName.length() < prefixLength) { LOG.error( "Font name \"" + fontName + "\" registered in font family \"" + myFamilyName + "\" is shorter that the length of common prefix \"" + prefix + "\". Skipping it."); continue; } String fontSuffix = fontName.substring(prefixLength); if (fontSuffix.isEmpty() || fontSuffix.contains("Regular") || fontSuffix.contains("Plain")) { if (myRegularFontName == null || fontSuffix.length() < regularSuffixLen) { myRegularFontName = fontName; regularSuffixLen = fontSuffix.length(); } continue; } boolean bold = fontSuffix.contains("Bold"); boolean italic = fontSuffix.contains("Italic") || fontSuffix.contains("Oblique"); if (bold & italic) { if (myBoldItalicFontName == null || fontSuffix.length() < boldItalicSuffixLen) { myBoldItalicFontName = fontName; boldItalicSuffixLen = fontSuffix.length(); } } else if (bold) { if (myBoldFontName == null || fontSuffix.length() < boldSuffixLen) { myBoldFontName = fontName; boldSuffixLen = fontSuffix.length(); } } else if (italic) { if (myItalicFontName == null || fontSuffix.length() < italicSuffixLen) { myItalicFontName = fontName; italicSuffixLen = fontSuffix.length(); } } } if (myRegularFontName == null) { if (myBoldFontName != null) { myRegularFontName = myBoldFontName; } else if (myItalicFontName != null) { myRegularFontName = myItalicFontName; } else if (myBoldItalicFontName != null) { myRegularFontName = myBoldItalicFontName; } else { myRegularFontName = myFontNames.get(0); } } } public boolean isValid() { loadFontNames(); return myRegularFontName != null; } public String getRegularFontName() { return myRegularFontName; } public String getFontName(int style) { boolean bold = (style & Font.BOLD) != 0; boolean italic = (style & Font.ITALIC) != 0; if (bold & italic) { return myBoldItalicFontName; } else if (bold) { return myBoldFontName; } else if (italic) { return myItalicFontName; } return myRegularFontName; } } }