Showing the changes to java/pkg/sun/font/FontUtilities.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,512 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008, 2011, 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.Font; | ||
| 29 | import java.io.BufferedReader; | ||
| 30 | import java.io.File; | ||
| 31 | import java.io.FileInputStream; | ||
| 32 | import java.io.InputStreamReader; | ||
| 33 | import java.lang.ref.SoftReference; | ||
| 34 | import java.util.concurrent.ConcurrentHashMap; | ||
| 35 | import java.security.AccessController; | ||
| 36 | |||
| 37 | import java.security.PrivilegedAction; | ||
| 38 | import javax.swing.plaf.FontUIResource; | ||
| 39 | |||
| 40 | import sun.util.logging.PlatformLogger; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * A collection of utility methods. | ||
| 44 | */ | ||
| 45 | public final class FontUtilities { | ||
| 46 | |||
| 47 | public static boolean isSolaris; | ||
| 48 | |||
| 49 | public static boolean isLinux; | ||
| 50 | |||
| 51 | public static boolean isSolaris8; | ||
| 52 | |||
| 53 | public static boolean isSolaris9; | ||
| 54 | |||
| 55 | public static boolean isOpenSolaris; | ||
| 56 | |||
| 57 | public static boolean useT2K; | ||
| 58 | |||
| 59 | public static boolean isWindows; | ||
| 60 | |||
| 61 | public static boolean isOpenJDK; | ||
| 62 | |||
| 63 | static final String LUCIDA_FILE_NAME = "LucidaSansRegular.ttf"; | ||
| 64 | |||
| 65 | private static boolean debugFonts = false; | ||
| 66 | private static PlatformLogger logger = null; | ||
| 67 | private static boolean logging; | ||
| 68 | |||
| 69 | // This static initializer block figures out the OS constants. | ||
| 70 | static { | ||
| 71 | |||
| 72 | AccessController.doPrivileged(new PrivilegedAction () { | ||
| 73 | public Object run() { | ||
| 74 | String osName = System.getProperty("os.name", "unknownOS"); | ||
| 75 | isSolaris = osName.startsWith("SunOS"); | ||
| 76 | |||
| 77 | isLinux = osName.startsWith("Linux"); | ||
| 78 | |||
| 79 | String t2kStr = System.getProperty("sun.java2d.font.scaler"); | ||
| 80 | if (t2kStr != null) { | ||
| 81 | useT2K = "t2k".equals(t2kStr); | ||
| 82 | } else { | ||
| 83 | useT2K = false; | ||
| 84 | } | ||
| 85 | if (isSolaris) { | ||
| 86 | String version = System.getProperty("os.version", "0.0"); | ||
| 87 | isSolaris8 = version.startsWith("5.8"); | ||
| 88 | isSolaris9 = version.startsWith("5.9"); | ||
| 89 | float ver = Float.parseFloat(version); | ||
| 90 | if (ver > 5.10f) { | ||
| 91 | File f = new File("/etc/release"); | ||
| 92 | String line = null; | ||
| 93 | try { | ||
| 94 | FileInputStream fis = new FileInputStream(f); | ||
| 95 | InputStreamReader isr = new InputStreamReader( | ||
| 96 | fis, "ISO-8859-1"); | ||
| 97 | BufferedReader br = new BufferedReader(isr); | ||
| 98 | line = br.readLine(); | ||
| 99 | fis.close(); | ||
| 100 | } catch (Exception ex) { | ||
| 101 | // Nothing to do here. | ||
| 102 | } | ||
| 103 | if (line != null && line.indexOf("OpenSolaris") >= 0) { | ||
| 104 | isOpenSolaris = true; | ||
| 105 | } else { | ||
| 106 | isOpenSolaris = false; | ||
| 107 | } | ||
| 108 | } else { | ||
| 109 | isOpenSolaris = false; | ||
| 110 | } | ||
| 111 | } else { | ||
| 112 | isSolaris8 = false; | ||
| 113 | isSolaris9 = false; | ||
| 114 | isOpenSolaris = false; | ||
| 115 | } | ||
| 116 | isWindows = osName.startsWith("Windows"); | ||
| 117 | String jreLibDirName = System.getProperty("java.home", "") | ||
| 118 | + File.separator + "lib"; | ||
| 119 | String jreFontDirName = | ||
| 120 | jreLibDirName + File.separator + "fonts"; | ||
| 121 | File lucidaFile = new File(jreFontDirName + File.separator | ||
| 122 | + LUCIDA_FILE_NAME); | ||
| 123 | isOpenJDK = !lucidaFile.exists(); | ||
| 124 | |||
| 125 | String debugLevel = | ||
| 126 | System.getProperty("sun.java2d.debugfonts"); | ||
| 127 | |||
| 128 | if (debugLevel != null && !debugLevel.equals("false")) { | ||
| 129 | debugFonts = true; | ||
| 130 | logger = PlatformLogger.getLogger("sun.java2d"); | ||
| 131 | if (debugLevel.equals("warning")) { | ||
| 132 | logger.setLevel(PlatformLogger.WARNING); | ||
| 133 | } else if (debugLevel.equals("severe")) { | ||
| 134 | logger.setLevel(PlatformLogger.SEVERE); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | if (debugFonts) { | ||
| 139 | logger = PlatformLogger.getLogger("sun.java2d"); | ||
| 140 | logging = logger.isEnabled(); | ||
| 141 | } | ||
| 142 | |||
| 143 | return null; | ||
| 144 | } | ||
| 145 | }); | ||
| 146 | } | ||
| 147 | |||
| 148 | /** | ||
| 149 | * Referenced by code in the JDK which wants to test for the | ||
| 150 | * minimum char code for which layout may be required. | ||
| 151 | * Note that even basic latin text can benefit from ligatures, | ||
| 152 | * eg "ffi" but we presently apply those only if explicitly | ||
| 153 | * requested with TextAttribute.LIGATURES_ON. | ||
| 154 | * The value here indicates the lowest char code for which failing | ||
| 155 | * to invoke layout would prevent acceptable rendering. | ||
| 156 | */ | ||
| 157 | public static final int MIN_LAYOUT_CHARCODE = 0x0300; | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Referenced by code in the JDK which wants to test for the | ||
| 161 | * maximum char code for which layout may be required. | ||
| 162 | * Note this does not account for supplementary characters | ||
| 163 | * where the caller interprets 'layout' to mean any case where | ||
| 164 | * one 'char' (ie the java type char) does not map to one glyph | ||
| 165 | */ | ||
| 166 | public static final int MAX_LAYOUT_CHARCODE = 0x206F; | ||
| 167 | |||
| 168 | /** | ||
| 169 | * Calls the private getFont2D() method in java.awt.Font objects. | ||
| 170 | * | ||
| 171 | * @param font the font object to call | ||
| 172 | * | ||
| 173 | * @return the Font2D object returned by Font.getFont2D() | ||
| 174 | */ | ||
| 175 | public static Font2D getFont2D(Font font) { | ||
| 176 | return FontAccess.getFontAccess().getFont2D(font); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * If there is anything in the text which triggers a case | ||
| 181 | * where char->glyph does not map 1:1 in straightforward | ||
| 182 | * left->right ordering, then this method returns true. | ||
| 183 | * Scripts which might require it but are not treated as such | ||
| 184 | * due to JDK implementations will not return true. | ||
| 185 | * ie a 'true' return is an indication of the treatment by | ||
| 186 | * the implementation. | ||
| 187 | * Whether supplementary characters should be considered is dependent | ||
| 188 | * on the needs of the caller. Since this method accepts the 'char' type | ||
| 189 | * then such chars are always represented by a pair. From a rendering | ||
| 190 | * perspective these will all (in the cases I know of) still be one | ||
| 191 | * unicode character -> one glyph. But if a caller is using this to | ||
| 192 | * discover any case where it cannot make naive assumptions about | ||
| 193 | * the number of chars, and how to index through them, then it may | ||
| 194 | * need the option to have a 'true' return in such a case. | ||
| 195 | */ | ||
| 196 | public static boolean isComplexText(char [] chs, int start, int limit) { | ||
| 197 | |||
| 198 | for (int i = start; i < limit; i++) { | ||
| 199 | if (chs[i] < MIN_LAYOUT_CHARCODE) { | ||
| 200 | continue; | ||
| 201 | } | ||
| 202 | else if (isNonSimpleChar(chs[i])) { | ||
| 203 | return true; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | return false; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* This is almost the same as the method above, except it takes a | ||
| 210 | * char which means it may include undecoded surrogate pairs. | ||
| 211 | * The distinction is made so that code which needs to identify all | ||
| 212 | * cases in which we do not have a simple mapping from | ||
| 213 | * char->unicode character->glyph can be be identified. | ||
| 214 | * For example measurement cannot simply sum advances of 'chars', | ||
| 215 | * the caret in editable text cannot advance one 'char' at a time, etc. | ||
| 216 | * These callers really are asking for more than whether 'layout' | ||
| 217 | * needs to be run, they need to know if they can assume 1->1 | ||
| 218 | * char->glyph mapping. | ||
| 219 | */ | ||
| 220 | public static boolean isNonSimpleChar(char ch) { | ||
| 221 | return | ||
| 222 | isComplexCharCode(ch) || | ||
| 223 | (ch >= CharToGlyphMapper.HI_SURROGATE_START && | ||
| 224 | ch <= CharToGlyphMapper.LO_SURROGATE_END); | ||
| 225 | } | ||
| 226 | |||
| 227 | /* If the character code falls into any of a number of unicode ranges | ||
| 228 | * where we know that simple left->right layout mapping chars to glyphs | ||
| 229 | * 1:1 and accumulating advances is going to produce incorrect results, | ||
| 230 | * we want to know this so the caller can use a more intelligent layout | ||
| 231 | * approach. A caller who cares about optimum performance may want to | ||
| 232 | * check the first case and skip the method call if its in that range. | ||
| 233 | * Although there's a lot of tests in here, knowing you can skip | ||
| 234 | * CTL saves a great deal more. The rest of the checks are ordered | ||
| 235 | * so that rather than checking explicitly if (>= start & <= end) | ||
| 236 | * which would mean all ranges would need to be checked so be sure | ||
| 237 | * CTL is not needed, the method returns as soon as it recognises | ||
| 238 | * the code point is outside of a CTL ranges. | ||
| 239 | * NOTE: Since this method accepts an 'int' it is asssumed to properly | ||
| 240 | * represent a CHARACTER. ie it assumes the caller has already | ||
| 241 | * converted surrogate pairs into supplementary characters, and so | ||
| 242 | * can handle this case and doesn't need to be told such a case is | ||
| 243 | * 'complex'. | ||
| 244 | */ | ||
| 245 | public static boolean isComplexCharCode(int code) { | ||
| 246 | |||
| 247 | if (code < MIN_LAYOUT_CHARCODE || code > MAX_LAYOUT_CHARCODE) { | ||
| 248 | return false; | ||
| 249 | } | ||
| 250 | else if (code <= 0x036f) { | ||
| 251 | // Trigger layout for combining diacriticals 0x0300->0x036f | ||
| 252 | return true; | ||
| 253 | } | ||
| 254 | else if (code < 0x0590) { | ||
| 255 | // No automatic layout for Greek, Cyrillic, Armenian. | ||
| 256 | return false; | ||
| 257 | } | ||
| 258 | else if (code <= 0x06ff) { | ||
| 259 | // Hebrew 0590 - 05ff | ||
| 260 | // Arabic 0600 - 06ff | ||
| 261 | return true; | ||
| 262 | } | ||
| 263 | else if (code < 0x0900) { | ||
| 264 | return false; // Syriac and Thaana | ||
| 265 | } | ||
| 266 | else if (code <= 0x0e7f) { | ||
| 267 | // if Indic, assume shaping for conjuncts, reordering: | ||
| 268 | // 0900 - 097F Devanagari | ||
| 269 | // 0980 - 09FF Bengali | ||
| 270 | // 0A00 - 0A7F Gurmukhi | ||
| 271 | // 0A80 - 0AFF Gujarati | ||
| 272 | // 0B00 - 0B7F Oriya | ||
| 273 | // 0B80 - 0BFF Tamil | ||
| 274 | // 0C00 - 0C7F Telugu | ||
| 275 | // 0C80 - 0CFF Kannada | ||
| 276 | // 0D00 - 0D7F Malayalam | ||
| 277 | // 0D80 - 0DFF Sinhala | ||
| 278 | // 0E00 - 0E7F if Thai, assume shaping for vowel, tone marks | ||
| 279 | return true; | ||
| 280 | } | ||
| 281 | else if (code < 0x0f00) { | ||
| 282 | return false; | ||
| 283 | } | ||
| 284 | else if (code <= 0x0fff) { // U+0F00 - U+0FFF Tibetan | ||
| 285 | return true; | ||
| 286 | } | ||
| 287 | else if (code < 0x1100) { | ||
| 288 | return false; | ||
| 289 | } | ||
| 290 | else if (code < 0x11ff) { // U+1100 - U+11FF Old Hangul | ||
| 291 | return true; | ||
| 292 | } | ||
| 293 | else if (code < 0x1780) { | ||
| 294 | return false; | ||
| 295 | } | ||
| 296 | else if (code <= 0x17ff) { // 1780 - 17FF Khmer | ||
| 297 | return true; | ||
| 298 | } | ||
| 299 | else if (code < 0x200c) { | ||
| 300 | return false; | ||
| 301 | } | ||
| 302 | else if (code <= 0x200d) { // zwj or zwnj | ||
| 303 | return true; | ||
| 304 | } | ||
| 305 | else if (code >= 0x202a && code <= 0x202e) { // directional control | ||
| 306 | return true; | ||
| 307 | } | ||
| 308 | else if (code >= 0x206a && code <= 0x206f) { // directional control | ||
| 309 | return true; | ||
| 310 | } | ||
| 311 | return false; | ||
| 312 | } | ||
| 313 | |||
| 314 | public static PlatformLogger getLogger() { | ||
| 315 | return logger; | ||
| 316 | } | ||
| 317 | |||
| 318 | public static boolean isLogging() { | ||
| 319 | return logging; | ||
| 320 | } | ||
| 321 | |||
| 322 | public static boolean debugFonts() { | ||
| 323 | return debugFonts; | ||
| 324 | } | ||
| 325 | |||
| 326 | |||
| 327 | // The following methods are used by Swing. | ||
| 328 | |||
| 329 | /* Revise the implementation to in fact mean "font is a composite font. | ||
| 330 | * This ensures that Swing components will always benefit from the | ||
| 331 | * fall back fonts | ||
| 332 | */ | ||
| 333 | public static boolean fontSupportsDefaultEncoding(Font font) { | ||
| 334 | return getFont2D(font) instanceof CompositeFont; | ||
| 335 | } | ||
| 336 | |||
| 337 | /** | ||
| 338 | * This method is provided for internal and exclusive use by Swing. | ||
| 339 | * | ||
| 340 | * It may be used in conjunction with fontSupportsDefaultEncoding(Font) | ||
| 341 | * In the event that a desktop properties font doesn't directly | ||
| 342 | * support the default encoding, (ie because the host OS supports | ||
| 343 | * adding support for the current locale automatically for native apps), | ||
| 344 | * then Swing calls this method to get a font which uses the specified | ||
| 345 | * font for the code points it covers, but also supports this locale | ||
| 346 | * just as the standard composite fonts do. | ||
| 347 | * Note: this will over-ride any setting where an application | ||
| 348 | * specifies it prefers locale specific composite fonts. | ||
| 349 | * The logic for this, is that this method is used only where the user or | ||
| 350 | * application has specified that the native L&F be used, and that | ||
| 351 | * we should honour that request to use the same font as native apps use. | ||
| 352 | * | ||
| 353 | * The behaviour of this method is to construct a new composite | ||
| 354 | * Font object that uses the specified physical font as its first | ||
| 355 | * component, and adds all the components of "dialog" as fall back | ||
| 356 | * components. | ||
| 357 | * The method currently assumes that only the size and style attributes | ||
| 358 | * are set on the specified font. It doesn't copy the font transform or | ||
| 359 | * other attributes because they aren't set on a font created from | ||
| 360 | * the desktop. This will need to be fixed if use is broadened. | ||
| 361 | * | ||
| 362 | * Operations such as Font.deriveFont will work properly on the | ||
| 363 | * font returned by this method for deriving a different point size. | ||
| 364 | * Additionally it tries to support a different style by calling | ||
| 365 | * getNewComposite() below. That also supports replacing slot zero | ||
| 366 | * with a different physical font but that is expected to be "rare". | ||
| 367 | * Deriving with a different style is needed because its been shown | ||
| 368 | * that some applications try to do this for Swing FontUIResources. | ||
| 369 | * Also operations such as new Font(font.getFontName(..), Font.PLAIN, 14); | ||
| 370 | * will NOT yield the same result, as the new underlying CompositeFont | ||
| 371 | * cannot be "looked up" in the font registry. | ||
| 372 | * This returns a FontUIResource as that is the Font sub-class needed | ||
| 373 | * by Swing. | ||
| 374 | * Suggested usage is something like : | ||
| 375 | * FontUIResource fuir; | ||
| 376 | * Font desktopFont = getDesktopFont(..); | ||
| 377 | * // NOTE even if fontSupportsDefaultEncoding returns true because | ||
| 378 | * // you get Tahoma and are running in an English locale, you may | ||
| 379 | * // still want to just call getCompositeFontUIResource() anyway | ||
| 380 | * // as only then will you get fallback fonts - eg for CJK. | ||
| 381 | * if (FontManager.fontSupportsDefaultEncoding(desktopFont)) { | ||
| 382 | * fuir = new FontUIResource(..); | ||
| 383 | * } else { | ||
| 384 | * fuir = FontManager.getCompositeFontUIResource(desktopFont); | ||
| 385 | * } | ||
| 386 | * return fuir; | ||
| 387 | */ | ||
| 388 | private static volatile | ||
| 389 | SoftReference<ConcurrentHashMap<PhysicalFont, CompositeFont>> | ||
| 390 | compMapRef = new SoftReference(null); | ||
| 391 | |||
| 392 | public static FontUIResource getCompositeFontUIResource(Font font) { | ||
| 393 | |||
| 394 | FontUIResource fuir = new FontUIResource(font); | ||
| 395 | Font2D font2D = FontUtilities.getFont2D(font); | ||
| 396 | |||
| 397 | if (!(font2D instanceof PhysicalFont)) { | ||
| 398 | /* Swing should only be calling this when a font is obtained | ||
| 399 | * from desktop properties, so should generally be a physical font, | ||
| 400 | * an exception might be for names like "MS Serif" which are | ||
| 401 | * automatically mapped to "Serif", so there's no need to do | ||
| 402 | * anything special in that case. But note that suggested usage | ||
| 403 | * is first to call fontSupportsDefaultEncoding(Font) and this | ||
| 404 | * method should not be called if that were to return true. | ||
| 405 | */ | ||
| 406 | return fuir; | ||
| 407 | } | ||
| 408 | |||
| 409 | FontManager fm = FontManagerFactory.getInstance(); | ||
| 410 | CompositeFont dialog2D = | ||
| 411 | (CompositeFont) fm.findFont2D("dialog", font.getStyle(), | ||
| 412 | FontManager.NO_FALLBACK); | ||
| 413 | if (dialog2D == null) { /* shouldn't happen */ | ||
| 414 | return fuir; | ||
| 415 | } | ||
| 416 | PhysicalFont physicalFont = (PhysicalFont)font2D; | ||
| 417 | ConcurrentHashMap<PhysicalFont, CompositeFont> compMap = compMapRef.get(); | ||
| 418 | if (compMap == null) { // Its been collected. | ||
| 419 | compMap = new ConcurrentHashMap<PhysicalFont, CompositeFont>(); | ||
| 420 | compMapRef = new SoftReference(compMap); | ||
| 421 | } | ||
| 422 | CompositeFont compFont = compMap.get(physicalFont); | ||
| 423 | if (compFont == null) { | ||
| 424 | compFont = new CompositeFont(physicalFont, dialog2D); | ||
| 425 | compMap.put(physicalFont, compFont); | ||
| 426 | } | ||
| 427 | FontAccess.getFontAccess().setFont2D(fuir, compFont.handle); | ||
| 428 | /* marking this as a created font is needed as only created fonts | ||
| 429 | * copy their creator's handles. | ||
| 430 | */ | ||
| 431 | FontAccess.getFontAccess().setCreatedFont(fuir); | ||
| 432 | return fuir; | ||
| 433 | } | ||
| 434 | |||
| 435 | /* A small "map" from GTK/fontconfig names to the equivalent JDK | ||
| 436 | * logical font name. | ||
| 437 | */ | ||
| 438 | private static final String[][] nameMap = { | ||
| 439 | {"sans", "sansserif"}, | ||
| 440 | {"sans-serif", "sansserif"}, | ||
| 441 | {"serif", "serif"}, | ||
| 442 | {"monospace", "monospaced"} | ||
| 443 | }; | ||
| 444 | |||
| 445 | public static String mapFcName(String name) { | ||
| 446 | for (int i = 0; i < nameMap.length; i++) { | ||
| 447 | if (name.equals(nameMap[i][0])) { | ||
| 448 | return nameMap[i][1]; | ||
| 449 | } | ||
| 450 | } | ||
| 451 | return null; | ||
| 452 | } | ||
| 453 | |||
| 454 | |||
| 455 | /* This is called by Swing passing in a fontconfig family name | ||
| 456 | * such as "sans". In return Swing gets a FontUIResource instance | ||
| 457 | * that has queried fontconfig to resolve the font(s) used for this. | ||
| 458 | * Fontconfig will if asked return a list of fonts to give the largest | ||
| 459 | * possible code point coverage. | ||
| 460 | * For now we use only the first font returned by fontconfig, and | ||
| 461 | * back it up with the most closely matching JDK logical font. | ||
| 462 | * Essentially this means pre-pending what we return now with fontconfig's | ||
| 463 | * preferred physical font. This could lead to some duplication in cases, | ||
| 464 | * if we already included that font later. We probably should remove such | ||
| 465 | * duplicates, but it is not a significant problem. It can be addressed | ||
| 466 | * later as part of creating a Composite which uses more of the | ||
| 467 | * same fonts as fontconfig. At that time we also should pay more | ||
| 468 | * attention to the special rendering instructions fontconfig returns, | ||
| 469 | * such as whether we should prefer embedded bitmaps over antialiasing. | ||
| 470 | * There's no way to express that via a Font at present. | ||
| 471 | */ | ||
| 472 | public static FontUIResource getFontConfigFUIR(String fcFamily, | ||
| 473 | int style, int size) { | ||
| 474 | |||
| 475 | String mapped = mapFcName(fcFamily); | ||
| 476 | if (mapped == null) { | ||
| 477 | mapped = "sansserif"; | ||
| 478 | } | ||
| 479 | |||
| 480 | FontUIResource fuir; | ||
| 481 | FontManager fm = FontManagerFactory.getInstance(); | ||
| 482 | if (fm instanceof SunFontManager) { | ||
| 483 | SunFontManager sfm = (SunFontManager) fm; | ||
| 484 | fuir = sfm.getFontConfigFUIR(mapped, style, size); | ||
| 485 | } else { | ||
| 486 | fuir = new FontUIResource(mapped, style, size); | ||
| 487 | } | ||
| 488 | return fuir; | ||
| 489 | } | ||
| 490 | |||
| 491 | |||
| 492 | /** | ||
| 493 | * Used by windows printing to assess if a font is likely to | ||
| 494 | * be layout compatible with JDK | ||
| 495 | * TrueType fonts should be, but if they have no GPOS table, | ||
| 496 | * but do have a GSUB table, then they are probably older | ||
| 497 | * fonts GDI handles differently. | ||
| 498 | */ | ||
| 499 | public static boolean textLayoutIsCompatible(Font font) { | ||
| 500 | |||
| 501 | Font2D font2D = getFont2D(font); | ||
| 502 | if (font2D instanceof TrueTypeFont) { | ||
| 503 | TrueTypeFont ttf = (TrueTypeFont) font2D; | ||
| 504 | return | ||
| 505 | ttf.getDirectoryEntry(TrueTypeFont.GSUBTag) == null || | ||
| 506 | ttf.getDirectoryEntry(TrueTypeFont.GPOSTag) != null; | ||
| 507 | } else { | ||
| 508 | return false; | ||
| 509 | } | ||
| 510 | } | ||
| 511 | |||
| 512 | } | ||