1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.font; 27 28 import java.awt.*; 29 import java.io.File; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.Hashtable; 33 import java.util.Locale; 34 import java.util.TreeMap; 35 import java.util.Vector; 36 37 import javax.swing.plaf.FontUIResource; 38 39 import sun.awt.FontConfiguration; 40 import sun.awt.HeadlessToolkit; 41 import sun.lwawt.macosx.*; 42 43 public class CFontManager extends SunFontManager { 44 private FontConfigManager fcManager = null; 45 private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>(); 46 47 @Override 48 protected FontConfiguration createFontConfiguration() { 49 FontConfiguration fc = new CFontConfiguration(this); 50 fc.init(); 51 return fc; 52 } 53 54 @Override 55 public FontConfiguration createFontConfiguration(boolean preferLocaleFonts, 56 boolean preferPropFonts) 57 { 58 return new CFontConfiguration(this, preferLocaleFonts, preferPropFonts); 59 } 60 61 private static String[] defaultPlatformFont = null; 62 63 /* 64 * Returns an array of two strings. The first element is the 65 * name of the font. The second element is the file name. 66 */ 67 @Override 68 public synchronized String[] getDefaultPlatformFont() { 69 if (defaultPlatformFont == null) { 70 defaultPlatformFont = new String[2]; 71 defaultPlatformFont[0] = "Lucida Grande"; 72 defaultPlatformFont[1] = "/System/Library/Fonts/LucidaGrande.ttc"; 73 } 74 return defaultPlatformFont; 75 } 76 77 // This is a way to register any kind of Font2D, not just files and composites. 78 public static Font2D[] getGenericFonts() { 79 return genericFonts.values().toArray(new Font2D[0]); 80 } 81 82 public Font2D registerGenericFont(Font2D f) 83 { 84 return registerGenericFont(f, false); 85 } 86 public Font2D registerGenericFont(Font2D f, boolean logicalFont) 87 { 88 int rank = 4; 89 90 String fontName = f.fullName; 91 String familyName = f.familyName; 92 93 if (fontName == null || "".equals(fontName)) { 94 return null; 95 } 96 97 // logical fonts always need to be added to the family 98 // plus they never need to be added to the generic font list 99 // or the fullNameToFont table since they are covers for 100 // already existing fonts in this list 101 if (logicalFont || !genericFonts.containsKey(fontName)) { 102 if (FontUtilities.debugFonts()) { 103 FontUtilities.getLogger().info("Add to Family "+familyName + 104 ", Font " + fontName + " rank="+rank); 105 } 106 FontFamily family = FontFamily.getFamily(familyName); 107 if (family == null) { 108 family = new FontFamily(familyName, false, rank); 109 family.setFont(f, f.style); 110 } else if (family.getRank() >= rank) { 111 family.setFont(f, f.style); 112 } 113 if (!logicalFont) 114 { 115 genericFonts.put(fontName, f); 116 fullNameToFont.put(fontName.toLowerCase(Locale.ENGLISH), f); 117 } 118 return f; 119 } else { 120 return genericFonts.get(fontName); 121 } 122 } 123 124 @Override 125 public Font2D[] getRegisteredFonts() { 126 Font2D[] regFonts = super.getRegisteredFonts(); 127 128 // Add in the Mac OS X native fonts 129 Font2D[] genericFonts = getGenericFonts(); 130 Font2D[] allFonts = new Font2D[regFonts.length+genericFonts.length]; 131 System.arraycopy(regFonts, 0, allFonts, 0, regFonts.length); 132 System.arraycopy(genericFonts, 0, allFonts, regFonts.length, genericFonts.length); 133 134 return allFonts; 135 } 136 137 @Override 138 protected void addNativeFontFamilyNames(TreeMap<String, String> familyNames, Locale requestedLocale) { 139 Font2D[] genericfonts = getGenericFonts(); 140 for (int i=0; i < genericfonts.length; i++) { 141 if (!(genericfonts[i] instanceof NativeFont)) { 142 String name = genericfonts[i].getFamilyName(requestedLocale); 143 familyNames.put(name.toLowerCase(requestedLocale), name); 144 } 145 } 146 } 147 148 @Override 149 public Font2D createFont2D(File fontFile, int fontFormat, boolean isCopy, CreatedFontTracker tracker) throws FontFormatException { 150 151 String fontFilePath = fontFile.getPath(); 152 Font2D font2D = null; 153 final File fFile = fontFile; 154 final CreatedFontTracker _tracker = tracker; 155 try { 156 switch (fontFormat) { 157 case Font.TRUETYPE_FONT: 158 font2D = new TrueTypeFont(fontFilePath, null, 0, true); 159 break; 160 case Font.TYPE1_FONT: 161 font2D = new Type1Font(fontFilePath, null, isCopy); 162 break; 163 default: 164 throw new FontFormatException("Unrecognised Font Format"); 165 } 166 } catch (FontFormatException e) { 167 if (isCopy) { 168 java.security.AccessController.doPrivileged( 169 new java.security.PrivilegedAction<Object>() { 170 public Object run() { 171 if (_tracker != null) { 172 _tracker.subBytes((int)fFile.length()); 173 } 174 fFile.delete(); 175 return null; 176 } 177 }); 178 } 179 throw(e); 180 } 181 if (isCopy) { 182 FileFont.setFileToRemove(font2D, fontFile, tracker); 183 synchronized (FontManager.class) { 184 185 if (tmpFontFiles == null) { 186 tmpFontFiles = new Vector<File>(); 187 } 188 tmpFontFiles.add(fontFile); 189 190 if (fileCloser == null) { 191 final Runnable fileCloserRunnable = new Runnable() { 192 public void run() { 193 java.security.AccessController.doPrivileged( 194 new java.security.PrivilegedAction<Object>() { 195 public Object run() { 196 197 for (int i=0;i<CHANNELPOOLSIZE;i++) { 198 if (fontFileCache[i] != null) { 199 try { 200 fontFileCache[i].close(); 201 } catch (Exception e) {} 202 } 203 } 204 if (tmpFontFiles != null) { 205 File[] files = new File[tmpFontFiles.size()]; 206 files = tmpFontFiles.toArray(files); 207 for (int f=0; f<files.length;f++) { 208 try { 209 files[f].delete(); 210 } catch (Exception e) {} 211 } 212 } 213 return null; 214 } 215 }); 216 } 217 }; 218 java.security.AccessController.doPrivileged( 219 new java.security.PrivilegedAction<Object>() { 220 public Object run() { 221 /* The thread must be a member of a thread group 222 * which will not get GCed before VM exit. 223 * Make its parent the top-level thread group. 224 */ 225 ThreadGroup tg = 226 Thread.currentThread().getThreadGroup(); 227 for (ThreadGroup tgn = tg; 228 tgn != null; 229 tg = tgn, tgn = tg.getParent()); 230 fileCloser = new Thread(tg, fileCloserRunnable); 231 fileCloser.setContextClassLoader(null); 232 Runtime.getRuntime().addShutdownHook(fileCloser); 233 return null; 234 } 235 }); 236 } 237 } 238 } 239 return font2D; 240 } 241 242 /* 243 public synchronized FontConfigManager getFontConfigManager() { 244 if (fcManager == null) { 245 fcManager = new FontConfigManager(); 246 } 247 return fcManager; 248 } 249 */ 250 251 protected void registerFontsInDir(String dirName, boolean useJavaRasterizer, int fontRank, boolean defer, boolean resolveSymLinks) { 252 loadNativeDirFonts(dirName); 253 super.registerFontsInDir(dirName, useJavaRasterizer, fontRank, defer, resolveSymLinks); 254 } 255 256 private native void loadNativeDirFonts(String dirName); 257 private native void loadNativeFonts(); 258 259 void registerFont(String fontName, String fontFamilyName) { 260 final CFont font = new CFont(fontName, fontFamilyName); 261 262 registerGenericFont(font); 263 264 if ((font.getStyle() & Font.ITALIC) == 0) { 265 registerGenericFont(font.createItalicVariant(), true); 266 } 267 } 268 269 Object waitForFontsToBeLoaded = new Object(); 270 public void loadFonts() 271 { 272 synchronized(waitForFontsToBeLoaded) 273 { 274 super.loadFonts(); 275 java.security.AccessController.doPrivileged( 276 new java.security.PrivilegedAction<Object>() { 277 public Object run() { 278 loadNativeFonts(); 279 return null; 280 } 281 } 282 ); 283 284 String defaultFont = "Lucida Grande"; 285 String defaultFallback = "Lucida Sans"; 286 287 setupLogicalFonts("Dialog", defaultFont, defaultFallback); 288 setupLogicalFonts("Serif", "Times", "Lucida Bright"); 289 setupLogicalFonts("SansSerif", defaultFont, defaultFallback); 290 setupLogicalFonts("Monospaced", "Menlo", "Lucida Sans Typewriter"); 291 setupLogicalFonts("DialogInput", defaultFont, defaultFallback); 292 } 293 } 294 295 protected void setupLogicalFonts(String logicalName, String realName, String fallbackName) { 296 FontFamily realFamily = getFontFamilyWithExtraTry(logicalName, realName, fallbackName); 297 298 cloneStyledFont(realFamily, logicalName, Font.PLAIN); 299 cloneStyledFont(realFamily, logicalName, Font.BOLD); 300 cloneStyledFont(realFamily, logicalName, Font.ITALIC); 301 cloneStyledFont(realFamily, logicalName, Font.BOLD | Font.ITALIC); 302 } 303 304 protected FontFamily getFontFamilyWithExtraTry(String logicalName, String realName, String fallbackName){ 305 FontFamily family = getFontFamily(realName, fallbackName); 306 if (family != null) return family; 307 308 // at this point, we recognize that we probably needed a fallback font 309 super.loadFonts(); 310 311 family = getFontFamily(realName, fallbackName); 312 if (family != null) return family; 313 314 System.err.println("Warning: the fonts \"" + realName + "\" and \"" + fallbackName + "\" are not available for the Java logical font \"" + logicalName + "\", which may have unexpected appearance or behavior. Re-enable the \""+ realName +"\" font to remove this warning."); 315 return null; 316 } 317 318 protected FontFamily getFontFamily(String realName, String fallbackName){ 319 FontFamily family = FontFamily.getFamily(realName); 320 if (family != null) return family; 321 322 family = FontFamily.getFamily(fallbackName); 323 if (family != null){ 324 System.err.println("Warning: the font \"" + realName + "\" is not available, so \"" + fallbackName + "\" has been substituted, but may have unexpected appearance or behavor. Re-enable the \""+ realName +"\" font to remove this warning."); 325 return family; 326 } 327 328 return null; 329 } 330 331 protected boolean cloneStyledFont(FontFamily realFamily, String logicalFamilyName, int style) { 332 if (realFamily == null) return false; 333 334 Font2D realFont = realFamily.getFontWithExactStyleMatch(style); 335 if (realFont == null || !(realFont instanceof CFont)) return false; 336 337 CFont newFont = new CFont((CFont)realFont, logicalFamilyName); 338 registerGenericFont(newFont, true); 339 340 return true; 341 } 342 343 @Override 344 public String getFontPath(boolean noType1Fonts) { 345 // In the case of the Cocoa toolkit, since we go through NSFont, we don't need to register /Library/Fonts 346 Toolkit tk = Toolkit.getDefaultToolkit(); 347 if (tk instanceof HeadlessToolkit) { 348 tk = ((HeadlessToolkit)tk).getUnderlyingToolkit(); 349 } 350 if (tk instanceof LWCToolkit) { 351 return ""; 352 } 353 354 // X11 case 355 return "/Library/Fonts"; 356 } 357 358 @Override 359 protected FontUIResource getFontConfigFUIR( 360 String family, int style, int size) 361 { 362 String mappedName = FontUtilities.mapFcName(family); 363 if (mappedName == null) { 364 mappedName = "sansserif"; 365 } 366 return new FontUIResource(mappedName, style, size); 367 } 368 369 // Only implemented on Windows 370 @Override 371 protected void populateFontFileNameMap(HashMap<String, String> fontToFileMap, HashMap<String, String> fontToFamilyNameMap, 372 HashMap<String, ArrayList<String>> familyToFontListMap, Locale locale) {} 373 }