1 /* 2 * Copyright (c) 2003, 2006, 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.io.File; 29 import java.awt.Font; 30 import java.util.HashMap; 31 import java.util.concurrent.ConcurrentHashMap; 32 import java.util.Locale; 33 34 public class FontFamily { 35 36 private static ConcurrentHashMap<String, FontFamily> 37 familyNameMap = new ConcurrentHashMap<String, FontFamily>(); 38 private static HashMap<String, FontFamily> allLocaleNames; 39 40 protected String familyName; 41 protected Font2D plain; 42 protected Font2D bold; 43 protected Font2D italic; 44 protected Font2D bolditalic; 45 protected boolean logicalFont = false; 46 protected int familyRank; 47 48 public static FontFamily getFamily(String name) { 49 return familyNameMap.get(name.toLowerCase(Locale.ENGLISH)); 50 } 51 52 public static String[] getAllFamilyNames() { 53 return null; 54 } 55 56 /* Only for use by FontManager.deRegisterBadFont(..). 57 * If this was the only font in the family, the family is removed 58 * from the map 59 */ 60 static void remove(Font2D font2D) { 61 62 String name = font2D.getFamilyName(Locale.ENGLISH); 63 FontFamily family = getFamily(name); 64 if (family == null) { 65 return; 66 } 67 if (family.plain == font2D) { 68 family.plain = null; 69 } 70 if (family.bold == font2D) { 71 family.bold = null; 72 } 73 if (family.italic == font2D) { 74 family.italic = null; 75 } 76 if (family.bolditalic == font2D) { 77 family.bolditalic = null; 78 } 79 if (family.plain == null && family.bold == null && 80 family.plain == null && family.bold == null) { 81 familyNameMap.remove(name); 82 } 83 } 84 85 public FontFamily(String name, boolean isLogFont, int rank) { 86 logicalFont = isLogFont; 87 familyName = name; 88 familyRank = rank; 89 familyNameMap.put(name.toLowerCase(Locale.ENGLISH), this); 90 } 91 92 /* Create a family for created fonts which aren't listed in the 93 * main map. 94 */ 95 FontFamily(String name) { 96 logicalFont = false; 97 familyName = name; 98 familyRank = Font2D.DEFAULT_RANK; 99 } 100 101 public String getFamilyName() { 102 return familyName; 103 } 104 105 public int getRank() { 106 return familyRank; 107 } 108 109 private boolean isFromSameSource(Font2D font) { 110 if (!(font instanceof FileFont)) { 111 return false; 112 } 113 114 FileFont existingFont = null; 115 if (plain instanceof FileFont) { 116 existingFont = (FileFont)plain; 117 } else if (bold instanceof FileFont) { 118 existingFont = (FileFont)bold; 119 } else if (italic instanceof FileFont) { 120 existingFont = (FileFont)italic; 121 } else if (bolditalic instanceof FileFont) { 122 existingFont = (FileFont)bolditalic; 123 } 124 // A family isn't created until there's a font. 125 // So if we didn't find a file font it means this 126 // isn't a file-based family. 127 if (existingFont == null) { 128 return false; 129 } 130 File existDir = (new File(existingFont.platName)).getParentFile(); 131 132 FileFont newFont = (FileFont)font; 133 File newDir = (new File(newFont.platName)).getParentFile(); 134 return java.util.Objects.equals(newDir, existDir); 135 } 136 137 public void setFont(Font2D font, int style) { 138 /* Allow a lower-rank font only if its a file font 139 * from the exact same source as any previous font. 140 */ 141 if ((font.getRank() > familyRank) && !isFromSameSource(font)) { 142 if (FontUtilities.isLogging()) { 143 FontUtilities.getLogger() 144 .warning("Rejecting adding " + font + 145 " of lower rank " + font.getRank() + 146 " to family " + this + 147 " of rank " + familyRank); 148 } 149 return; 150 } 151 152 switch (style) { 153 154 case Font.PLAIN: 155 plain = font; 156 break; 157 158 case Font.BOLD: 159 bold = font; 160 break; 161 162 case Font.ITALIC: 163 italic = font; 164 break; 165 166 case Font.BOLD|Font.ITALIC: 167 bolditalic = font; 168 break; 169 170 default: 171 break; 172 } 173 } 174 175 public Font2D getFontWithExactStyleMatch(int style) { 176 177 switch (style) { 178 179 case Font.PLAIN: 180 return plain; 181 182 case Font.BOLD: 183 return bold; 184 185 case Font.ITALIC: 186 return italic; 187 188 case Font.BOLD|Font.ITALIC: 189 return bolditalic; 190 191 default: 192 return null; 193 } 194 } 195 196 /* REMIND: if the callers of this method are operating in an 197 * environment in which not all fonts are registered, the returned 198 * font may be a algorithmically styled one, where in fact if loadfonts 199 * were executed, a styled font may be located. Our present "solution" 200 * to this is to register all fonts in a directory and assume that this 201 * registered all the styles of a font, since they would all be in the 202 * same location. 203 */ 204 public Font2D getFont(int style) { 205 206 switch (style) { 207 208 case Font.PLAIN: 209 return plain; 210 211 case Font.BOLD: 212 if (bold != null) { 213 return bold; 214 } else if (plain != null && plain.canDoStyle(style)) { 215 return plain; 216 } else { 217 return null; 218 } 219 220 case Font.ITALIC: 221 if (italic != null) { 222 return italic; 223 } else if (plain != null && plain.canDoStyle(style)) { 224 return plain; 225 } else { 226 return null; 227 } 228 229 case Font.BOLD|Font.ITALIC: 230 if (bolditalic != null) { 231 return bolditalic; 232 } else if (italic != null && italic.canDoStyle(style)) { 233 return italic; 234 } else if (bold != null && bold.canDoStyle(style)) { 235 return italic; 236 } else if (plain != null && plain.canDoStyle(style)) { 237 return plain; 238 } else { 239 return null; 240 } 241 default: 242 return null; 243 } 244 } 245 246 /* Only to be called if getFont(style) returns null 247 * This method will only return null if the family is completely empty! 248 * Note that it assumes the font of the style you need isn't in the 249 * family. The logic here is that if we must substitute something 250 * it might as well be from the same family. 251 */ 252 Font2D getClosestStyle(int style) { 253 254 switch (style) { 255 /* if you ask for a plain font try to return a non-italic one, 256 * then a italic one, finally a bold italic one */ 257 case Font.PLAIN: 258 if (bold != null) { 259 return bold; 260 } else if (italic != null) { 261 return italic; 262 } else { 263 return bolditalic; 264 } 265 266 /* if you ask for a bold font try to return a non-italic one, 267 * then a bold italic one, finally an italic one */ 268 case Font.BOLD: 269 if (plain != null) { 270 return plain; 271 } else if (bolditalic != null) { 272 return bolditalic; 273 } else { 274 return italic; 275 } 276 277 /* if you ask for a italic font try to return a bold italic one, 278 * then a plain one, finally an bold one */ 279 case Font.ITALIC: 280 if (bolditalic != null) { 281 return bolditalic; 282 } else if (plain != null) { 283 return plain; 284 } else { 285 return bold; 286 } 287 288 case Font.BOLD|Font.ITALIC: 289 if (italic != null) { 290 return italic; 291 } else if (bold != null) { 292 return bold; 293 } else { 294 return plain; 295 } 296 } 297 return null; 298 } 299 300 /* Font may have localized names. Store these in a separate map, so 301 * that only clients who use these names need be affected. 302 */ 303 static synchronized void addLocaleNames(FontFamily family, String[] names){ 304 if (allLocaleNames == null) { 305 allLocaleNames = new HashMap<String, FontFamily>(); 306 } 307 for (int i=0; i<names.length; i++) { 308 allLocaleNames.put(names[i].toLowerCase(), family); 309 } 310 } 311 312 public static synchronized FontFamily getLocaleFamily(String name) { 313 if (allLocaleNames == null) { 314 return null; 315 } 316 return allLocaleNames.get(name.toLowerCase()); 317 } 318 319 public String toString() { 320 return 321 "Font family: " + familyName + 322 " plain="+plain+ 323 " bold=" + bold + 324 " italic=" + italic + 325 " bolditalic=" + bolditalic; 326 327 } 328 329 }