PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/share/classes/sun/awt/FontConfiguration.java

https://bitbucket.org/chegar/jigsaw_jigsaw_jdk
Java | 2287 lines | 1648 code | 191 blank | 448 comment | 394 complexity | c0db8511952cfa658829a0b8f321d1ba MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 1996, 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. package sun.awt;
  26. import java.awt.Font;
  27. import java.io.DataInputStream;
  28. import java.io.DataOutputStream;
  29. import java.io.File;
  30. import java.io.FileInputStream;
  31. import java.io.InputStream;
  32. import java.io.IOException;
  33. import java.io.OutputStream;
  34. import java.nio.charset.Charset;
  35. import java.nio.charset.CharsetEncoder;
  36. import java.security.AccessController;
  37. import java.security.PrivilegedAction;
  38. import java.util.Arrays;
  39. import java.util.HashMap;
  40. import java.util.HashSet;
  41. import java.util.Hashtable;
  42. import java.util.Locale;
  43. import java.util.Map.Entry;
  44. import java.util.Properties;
  45. import java.util.Set;
  46. import java.util.Vector;
  47. import sun.font.CompositeFontDescriptor;
  48. import sun.font.SunFontManager;
  49. import sun.font.FontManagerFactory;
  50. import sun.font.FontUtilities;
  51. import sun.util.logging.PlatformLogger;
  52. /**
  53. * Provides the definitions of the five logical fonts: Serif, SansSerif,
  54. * Monospaced, Dialog, and DialogInput. The necessary information
  55. * is obtained from fontconfig files.
  56. */
  57. public abstract class FontConfiguration {
  58. //static global runtime env
  59. protected static String osVersion;
  60. protected static String osName;
  61. protected static String encoding; // canonical name of default nio charset
  62. protected static Locale startupLocale = null;
  63. protected static Hashtable localeMap = null;
  64. private static FontConfiguration fontConfig;
  65. private static PlatformLogger logger;
  66. protected static boolean isProperties = true;
  67. protected SunFontManager fontManager;
  68. protected boolean preferLocaleFonts;
  69. protected boolean preferPropFonts;
  70. private File fontConfigFile;
  71. private boolean foundOsSpecificFile;
  72. private boolean inited;
  73. private String javaLib;
  74. /* A default FontConfiguration must be created before an alternate
  75. * one to ensure proper static initialisation takes place.
  76. */
  77. public FontConfiguration(SunFontManager fm) {
  78. if (FontUtilities.debugFonts()) {
  79. FontUtilities.getLogger()
  80. .info("Creating standard Font Configuration");
  81. }
  82. if (FontUtilities.debugFonts() && logger == null) {
  83. logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
  84. }
  85. fontManager = fm;
  86. setOsNameAndVersion(); /* static initialization */
  87. setEncoding(); /* static initialization */
  88. /* Separating out the file location from the rest of the
  89. * initialisation, so the caller has the option of doing
  90. * something else if a suitable file isn't found.
  91. */
  92. findFontConfigFile();
  93. }
  94. public synchronized boolean init() {
  95. if (!inited) {
  96. this.preferLocaleFonts = false;
  97. this.preferPropFonts = false;
  98. setFontConfiguration();
  99. readFontConfigFile(fontConfigFile);
  100. initFontConfig();
  101. inited = true;
  102. }
  103. return true;
  104. }
  105. public FontConfiguration(SunFontManager fm,
  106. boolean preferLocaleFonts,
  107. boolean preferPropFonts) {
  108. fontManager = fm;
  109. if (FontUtilities.debugFonts()) {
  110. FontUtilities.getLogger()
  111. .info("Creating alternate Font Configuration");
  112. }
  113. this.preferLocaleFonts = preferLocaleFonts;
  114. this.preferPropFonts = preferPropFonts;
  115. /* fontConfig should be initialised by default constructor, and
  116. * its data tables can be shared, since readFontConfigFile doesn't
  117. * update any other state. Also avoid a doPrivileged block.
  118. */
  119. initFontConfig();
  120. }
  121. /**
  122. * Fills in this instance's osVersion and osName members. By
  123. * default uses the system properties os.name and os.version;
  124. * subclasses may override.
  125. */
  126. protected void setOsNameAndVersion() {
  127. osName = System.getProperty("os.name");
  128. osVersion = System.getProperty("os.version");
  129. }
  130. private void setEncoding() {
  131. encoding = Charset.defaultCharset().name();
  132. startupLocale = SunToolkit.getStartupLocale();
  133. }
  134. /////////////////////////////////////////////////////////////////////
  135. // methods for loading the FontConfig file //
  136. /////////////////////////////////////////////////////////////////////
  137. public boolean foundOsSpecificFile() {
  138. return foundOsSpecificFile;
  139. }
  140. /* Smoke test to see if we can trust this configuration by testing if
  141. * the first slot of a composite font maps to an installed file.
  142. */
  143. public boolean fontFilesArePresent() {
  144. init();
  145. short fontNameID = compFontNameIDs[0][0][0];
  146. short fileNameID = getComponentFileID(fontNameID);
  147. final String fileName = mapFileName(getComponentFileName(fileNameID));
  148. Boolean exists = (Boolean)java.security.AccessController.doPrivileged(
  149. new java.security.PrivilegedAction() {
  150. public Object run() {
  151. try {
  152. File f = new File(fileName);
  153. return Boolean.valueOf(f.exists());
  154. }
  155. catch (Exception e) {
  156. return false;
  157. }
  158. }
  159. });
  160. return exists.booleanValue();
  161. }
  162. private void findFontConfigFile() {
  163. foundOsSpecificFile = true; // default assumption.
  164. String javaHome = System.getProperty("java.home");
  165. if (javaHome == null) {
  166. throw new Error("java.home property not set");
  167. }
  168. javaLib = javaHome + File.separator + "lib";
  169. String userConfigFile = System.getProperty("sun.awt.fontconfig");
  170. if (userConfigFile != null) {
  171. fontConfigFile = new File(userConfigFile);
  172. } else {
  173. fontConfigFile = findFontConfigFile(javaLib);
  174. }
  175. }
  176. private void readFontConfigFile(File f) {
  177. /* This is invoked here as readFontConfigFile is only invoked
  178. * once per VM, and always in a privileged context, thus the
  179. * directory containing installed fall back fonts is accessed
  180. * from this context
  181. */
  182. getInstalledFallbackFonts(javaLib);
  183. if (f != null) {
  184. try {
  185. FileInputStream in = new FileInputStream(f.getPath());
  186. if (isProperties) {
  187. loadProperties(in);
  188. } else {
  189. loadBinary(in);
  190. }
  191. in.close();
  192. if (FontUtilities.debugFonts()) {
  193. logger.config("Read logical font configuration from " + f);
  194. }
  195. } catch (IOException e) {
  196. if (FontUtilities.debugFonts()) {
  197. logger.config("Failed to read logical font configuration from " + f);
  198. }
  199. }
  200. }
  201. String version = getVersion();
  202. if (!"1".equals(version) && FontUtilities.debugFonts()) {
  203. logger.config("Unsupported fontconfig version: " + version);
  204. }
  205. }
  206. protected void getInstalledFallbackFonts(String javaLib) {
  207. String fallbackDirName = javaLib + File.separator +
  208. "fonts" + File.separator + "fallback";
  209. File fallbackDir = new File(fallbackDirName);
  210. if (fallbackDir.exists() && fallbackDir.isDirectory()) {
  211. String[] ttfs = fallbackDir.list(fontManager.getTrueTypeFilter());
  212. String[] t1s = fallbackDir.list(fontManager.getType1Filter());
  213. int numTTFs = (ttfs == null) ? 0 : ttfs.length;
  214. int numT1s = (t1s == null) ? 0 : t1s.length;
  215. int len = numTTFs + numT1s;
  216. if (numTTFs + numT1s == 0) {
  217. return;
  218. }
  219. installedFallbackFontFiles = new String[len];
  220. for (int i=0; i<numTTFs; i++) {
  221. installedFallbackFontFiles[i] =
  222. fallbackDir + File.separator + ttfs[i];
  223. }
  224. for (int i=0; i<numT1s; i++) {
  225. installedFallbackFontFiles[i+numTTFs] =
  226. fallbackDir + File.separator + t1s[i];
  227. }
  228. fontManager.registerFontsInDir(fallbackDirName);
  229. }
  230. }
  231. private File findImpl(String fname) {
  232. File f = new File(fname + ".properties");
  233. if (f.canRead()) {
  234. isProperties = true;
  235. return f;
  236. }
  237. f = new File(fname + ".bfc");
  238. if (f.canRead()) {
  239. isProperties = false;
  240. return f;
  241. }
  242. return null;
  243. }
  244. private File findFontConfigFile(String javaLib) {
  245. String baseName = javaLib + File.separator + "fontconfig";
  246. File configFile;
  247. String osMajorVersion = null;
  248. if (osVersion != null && osName != null) {
  249. configFile = findImpl(baseName + "." + osName + "." + osVersion);
  250. if (configFile != null) {
  251. return configFile;
  252. }
  253. int decimalPointIndex = osVersion.indexOf(".");
  254. if (decimalPointIndex != -1) {
  255. osMajorVersion = osVersion.substring(0, osVersion.indexOf("."));
  256. configFile = findImpl(baseName + "." + osName + "." + osMajorVersion);
  257. if (configFile != null) {
  258. return configFile;
  259. }
  260. }
  261. }
  262. if (osName != null) {
  263. configFile = findImpl(baseName + "." + osName);
  264. if (configFile != null) {
  265. return configFile;
  266. }
  267. }
  268. if (osVersion != null) {
  269. configFile = findImpl(baseName + "." + osVersion);
  270. if (configFile != null) {
  271. return configFile;
  272. }
  273. if (osMajorVersion != null) {
  274. configFile = findImpl(baseName + "." + osMajorVersion);
  275. if (configFile != null) {
  276. return configFile;
  277. }
  278. }
  279. }
  280. foundOsSpecificFile = false;
  281. configFile = findImpl(baseName);
  282. if (configFile != null) {
  283. return configFile;
  284. }
  285. return null;
  286. }
  287. /* Initialize the internal data tables from binary format font
  288. * configuration file.
  289. */
  290. public static void loadBinary(InputStream inStream) throws IOException {
  291. DataInputStream in = new DataInputStream(inStream);
  292. head = readShortTable(in, HEAD_LENGTH);
  293. int[] tableSizes = new int[INDEX_TABLEEND];
  294. for (int i = 0; i < INDEX_TABLEEND; i++) {
  295. tableSizes[i] = head[i + 1] - head[i];
  296. }
  297. table_scriptIDs = readShortTable(in, tableSizes[INDEX_scriptIDs]);
  298. table_scriptFonts = readShortTable(in, tableSizes[INDEX_scriptFonts]);
  299. table_elcIDs = readShortTable(in, tableSizes[INDEX_elcIDs]);
  300. table_sequences = readShortTable(in, tableSizes[INDEX_sequences]);
  301. table_fontfileNameIDs = readShortTable(in, tableSizes[INDEX_fontfileNameIDs]);
  302. table_componentFontNameIDs = readShortTable(in, tableSizes[INDEX_componentFontNameIDs]);
  303. table_filenames = readShortTable(in, tableSizes[INDEX_filenames]);
  304. table_awtfontpaths = readShortTable(in, tableSizes[INDEX_awtfontpaths]);
  305. table_exclusions = readShortTable(in, tableSizes[INDEX_exclusions]);
  306. table_proportionals = readShortTable(in, tableSizes[INDEX_proportionals]);
  307. table_scriptFontsMotif = readShortTable(in, tableSizes[INDEX_scriptFontsMotif]);
  308. table_alphabeticSuffix = readShortTable(in, tableSizes[INDEX_alphabeticSuffix]);
  309. table_stringIDs = readShortTable(in, tableSizes[INDEX_stringIDs]);
  310. //StringTable cache
  311. stringCache = new String[table_stringIDs.length + 1];
  312. int len = tableSizes[INDEX_stringTable];
  313. byte[] bb = new byte[len * 2];
  314. table_stringTable = new char[len];
  315. in.read(bb);
  316. int i = 0, j = 0;
  317. while (i < len) {
  318. table_stringTable[i++] = (char)(bb[j++] << 8 | (bb[j++] & 0xff));
  319. }
  320. if (verbose) {
  321. dump();
  322. }
  323. }
  324. /* Generate a binary format font configuration from internal data
  325. * tables.
  326. */
  327. public static void saveBinary(OutputStream out) throws IOException {
  328. sanityCheck();
  329. DataOutputStream dataOut = new DataOutputStream(out);
  330. writeShortTable(dataOut, head);
  331. writeShortTable(dataOut, table_scriptIDs);
  332. writeShortTable(dataOut, table_scriptFonts);
  333. writeShortTable(dataOut, table_elcIDs);
  334. writeShortTable(dataOut, table_sequences);
  335. writeShortTable(dataOut, table_fontfileNameIDs);
  336. writeShortTable(dataOut, table_componentFontNameIDs);
  337. writeShortTable(dataOut, table_filenames);
  338. writeShortTable(dataOut, table_awtfontpaths);
  339. writeShortTable(dataOut, table_exclusions);
  340. writeShortTable(dataOut, table_proportionals);
  341. writeShortTable(dataOut, table_scriptFontsMotif);
  342. writeShortTable(dataOut, table_alphabeticSuffix);
  343. writeShortTable(dataOut, table_stringIDs);
  344. //stringTable
  345. dataOut.writeChars(new String(table_stringTable));
  346. out.close();
  347. if (verbose) {
  348. dump();
  349. }
  350. }
  351. //private static boolean loadingProperties;
  352. private static short stringIDNum;
  353. private static short[] stringIDs;
  354. private static StringBuilder stringTable;
  355. public static void loadProperties(InputStream in) throws IOException {
  356. //loadingProperties = true;
  357. //StringID starts from "1", "0" is reserved for "not defined"
  358. stringIDNum = 1;
  359. stringIDs = new short[1000];
  360. stringTable = new StringBuilder(4096);
  361. if (verbose && logger == null) {
  362. logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
  363. }
  364. new PropertiesHandler().load(in);
  365. //loadingProperties = false;
  366. stringIDs = null;
  367. stringTable = null;
  368. }
  369. /////////////////////////////////////////////////////////////////////
  370. // methods for initializing the FontConfig //
  371. /////////////////////////////////////////////////////////////////////
  372. /**
  373. * set initLocale, initEncoding and initELC for this FontConfig object
  374. * currently we just simply use the startup locale and encoding
  375. */
  376. private void initFontConfig() {
  377. initLocale = startupLocale;
  378. initEncoding = encoding;
  379. if (preferLocaleFonts && !willReorderForStartupLocale()) {
  380. preferLocaleFonts = false;
  381. }
  382. initELC = getInitELC();
  383. initAllComponentFonts();
  384. }
  385. //"ELC" stands for "Encoding.Language.Country". This method returns
  386. //the ID of the matched elc setting of "initLocale" in elcIDs table.
  387. //If no match is found, it returns the default ID, which is
  388. //"NULL.NULL.NULL" in elcIDs table.
  389. private short getInitELC() {
  390. if (initELC != -1) {
  391. return initELC;
  392. }
  393. HashMap <String, Integer> elcIDs = new HashMap<String, Integer>();
  394. for (int i = 0; i < table_elcIDs.length; i++) {
  395. elcIDs.put(getString(table_elcIDs[i]), i);
  396. }
  397. String language = initLocale.getLanguage();
  398. String country = initLocale.getCountry();
  399. String elc;
  400. if (elcIDs.containsKey(elc=initEncoding + "." + language + "." + country)
  401. || elcIDs.containsKey(elc=initEncoding + "." + language)
  402. || elcIDs.containsKey(elc=initEncoding)) {
  403. initELC = elcIDs.get(elc).shortValue();
  404. } else {
  405. initELC = elcIDs.get("NULL.NULL.NULL").shortValue();
  406. }
  407. int i = 0;
  408. while (i < table_alphabeticSuffix.length) {
  409. if (initELC == table_alphabeticSuffix[i]) {
  410. alphabeticSuffix = getString(table_alphabeticSuffix[i + 1]);
  411. return initELC;
  412. }
  413. i += 2;
  414. }
  415. return initELC;
  416. }
  417. public static boolean verbose;
  418. private short initELC = -1;
  419. private Locale initLocale;
  420. private String initEncoding;
  421. private String alphabeticSuffix;
  422. private short[][][] compFontNameIDs = new short[NUM_FONTS][NUM_STYLES][];
  423. private int[][][] compExclusions = new int[NUM_FONTS][][];
  424. private int[] compCoreNum = new int[NUM_FONTS];
  425. private Set<Short> coreFontNameIDs = new HashSet<Short>();
  426. private Set<Short> fallbackFontNameIDs = new HashSet<Short>();
  427. private void initAllComponentFonts() {
  428. short[] fallbackScripts = getFallbackScripts();
  429. for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
  430. short[] coreScripts = getCoreScripts(fontIndex);
  431. compCoreNum[fontIndex] = coreScripts.length;
  432. /*
  433. System.out.println("coreScriptID=" + table_sequences[initELC * 5 + fontIndex]);
  434. for (int i = 0; i < coreScripts.length; i++) {
  435. System.out.println(" " + i + " :" + getString(table_scriptIDs[coreScripts[i]]));
  436. }
  437. */
  438. //init exclusionRanges
  439. int[][] exclusions = new int[coreScripts.length][];
  440. for (int i = 0; i < coreScripts.length; i++) {
  441. exclusions[i] = getExclusionRanges(coreScripts[i]);
  442. }
  443. compExclusions[fontIndex] = exclusions;
  444. //init componentFontNames
  445. for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
  446. int index;
  447. short[] nameIDs = new short[coreScripts.length + fallbackScripts.length];
  448. //core
  449. for (index = 0; index < coreScripts.length; index++) {
  450. nameIDs[index] = getComponentFontID(coreScripts[index],
  451. fontIndex, styleIndex);
  452. if (preferLocaleFonts && localeMap != null &&
  453. fontManager.usingAlternateFontforJALocales()) {
  454. nameIDs[index] = remapLocaleMap(fontIndex, styleIndex,
  455. coreScripts[index], nameIDs[index]);
  456. }
  457. if (preferPropFonts) {
  458. nameIDs[index] = remapProportional(fontIndex, nameIDs[index]);
  459. }
  460. //System.out.println("nameid=" + nameIDs[index]);
  461. coreFontNameIDs.add(nameIDs[index]);
  462. }
  463. //fallback
  464. for (int i = 0; i < fallbackScripts.length; i++) {
  465. short id = getComponentFontID(fallbackScripts[i],
  466. fontIndex, styleIndex);
  467. if (preferLocaleFonts && localeMap != null &&
  468. fontManager.usingAlternateFontforJALocales()) {
  469. id = remapLocaleMap(fontIndex, styleIndex, fallbackScripts[i], id);
  470. }
  471. if (preferPropFonts) {
  472. id = remapProportional(fontIndex, id);
  473. }
  474. if (contains(nameIDs, id, index)) {
  475. continue;
  476. }
  477. /*
  478. System.out.println("fontIndex=" + fontIndex + ", styleIndex=" + styleIndex
  479. + ", fbIndex=" + i + ",fbS=" + fallbackScripts[i] + ", id=" + id);
  480. */
  481. fallbackFontNameIDs.add(id);
  482. nameIDs[index++] = id;
  483. }
  484. if (index < nameIDs.length) {
  485. short[] newNameIDs = new short[index];
  486. System.arraycopy(nameIDs, 0, newNameIDs, 0, index);
  487. nameIDs = newNameIDs;
  488. }
  489. compFontNameIDs[fontIndex][styleIndex] = nameIDs;
  490. }
  491. }
  492. }
  493. private short remapLocaleMap(int fontIndex, int styleIndex, short scriptID, short fontID) {
  494. String scriptName = getString(table_scriptIDs[scriptID]);
  495. String value = (String)localeMap.get(scriptName);
  496. if (value == null) {
  497. String fontName = fontNames[fontIndex];
  498. String styleName = styleNames[styleIndex];
  499. value = (String)localeMap.get(fontName + "." + styleName + "." + scriptName);
  500. }
  501. if (value == null) {
  502. return fontID;
  503. }
  504. for (int i = 0; i < table_componentFontNameIDs.length; i++) {
  505. String name = getString(table_componentFontNameIDs[i]);
  506. if (value.equalsIgnoreCase(name)) {
  507. fontID = (short)i;
  508. break;
  509. }
  510. }
  511. return fontID;
  512. }
  513. public static boolean hasMonoToPropMap() {
  514. return table_proportionals != null && table_proportionals.length != 0;
  515. }
  516. private short remapProportional(int fontIndex, short id) {
  517. if (preferPropFonts &&
  518. table_proportionals.length != 0 &&
  519. fontIndex != 2 && //"monospaced"
  520. fontIndex != 4) { //"dialoginput"
  521. int i = 0;
  522. while (i < table_proportionals.length) {
  523. if (table_proportionals[i] == id) {
  524. return table_proportionals[i + 1];
  525. }
  526. i += 2;
  527. }
  528. }
  529. return id;
  530. }
  531. /////////////////////////////////////////////////////////////////////
  532. // Methods for handling font and style names //
  533. /////////////////////////////////////////////////////////////////////
  534. protected static final int NUM_FONTS = 5;
  535. protected static final int NUM_STYLES = 4;
  536. protected static final String[] fontNames
  537. = {"serif", "sansserif", "monospaced", "dialog", "dialoginput"};
  538. protected static final String[] publicFontNames
  539. = {Font.SERIF, Font.SANS_SERIF, Font.MONOSPACED, Font.DIALOG,
  540. Font.DIALOG_INPUT};
  541. protected static final String[] styleNames
  542. = {"plain", "bold", "italic", "bolditalic"};
  543. /**
  544. * Checks whether the given font family name is a valid logical font name.
  545. * The check is case insensitive.
  546. */
  547. public static boolean isLogicalFontFamilyName(String fontName) {
  548. return isLogicalFontFamilyNameLC(fontName.toLowerCase(Locale.ENGLISH));
  549. }
  550. /**
  551. * Checks whether the given font family name is a valid logical font name.
  552. * The check is case sensitive.
  553. */
  554. public static boolean isLogicalFontFamilyNameLC(String fontName) {
  555. for (int i = 0; i < fontNames.length; i++) {
  556. if (fontName.equals(fontNames[i])) {
  557. return true;
  558. }
  559. }
  560. return false;
  561. }
  562. /**
  563. * Checks whether the given style name is a valid logical font style name.
  564. */
  565. private static boolean isLogicalFontStyleName(String styleName) {
  566. for (int i = 0; i < styleNames.length; i++) {
  567. if (styleName.equals(styleNames[i])) {
  568. return true;
  569. }
  570. }
  571. return false;
  572. }
  573. /**
  574. * Checks whether the given font face name is a valid logical font name.
  575. * The check is case insensitive.
  576. */
  577. public static boolean isLogicalFontFaceName(String fontName) {
  578. return isLogicalFontFaceNameLC(fontName.toLowerCase(Locale.ENGLISH));
  579. }
  580. /**
  581. * Checks whether the given font face name is a valid logical font name.
  582. * The check is case sensitive.
  583. */
  584. public static boolean isLogicalFontFaceNameLC(String fontName) {
  585. int period = fontName.indexOf('.');
  586. if (period >= 0) {
  587. String familyName = fontName.substring(0, period);
  588. String styleName = fontName.substring(period + 1);
  589. return isLogicalFontFamilyName(familyName) &&
  590. isLogicalFontStyleName(styleName);
  591. } else {
  592. return isLogicalFontFamilyName(fontName);
  593. }
  594. }
  595. protected static int getFontIndex(String fontName) {
  596. return getArrayIndex(fontNames, fontName);
  597. }
  598. protected static int getStyleIndex(String styleName) {
  599. return getArrayIndex(styleNames, styleName);
  600. }
  601. private static int getArrayIndex(String[] names, String name) {
  602. for (int i = 0; i < names.length; i++) {
  603. if (name.equals(names[i])) {
  604. return i;
  605. }
  606. }
  607. assert false;
  608. return 0;
  609. }
  610. protected static int getStyleIndex(int style) {
  611. switch (style) {
  612. case Font.PLAIN:
  613. return 0;
  614. case Font.BOLD:
  615. return 1;
  616. case Font.ITALIC:
  617. return 2;
  618. case Font.BOLD | Font.ITALIC:
  619. return 3;
  620. default:
  621. return 0;
  622. }
  623. }
  624. protected static String getFontName(int fontIndex) {
  625. return fontNames[fontIndex];
  626. }
  627. protected static String getStyleName(int styleIndex) {
  628. return styleNames[styleIndex];
  629. }
  630. /**
  631. * Returns the font face name for the given logical font
  632. * family name and style.
  633. * The style argument is interpreted as in java.awt.Font.Font.
  634. */
  635. public static String getLogicalFontFaceName(String familyName, int style) {
  636. assert isLogicalFontFamilyName(familyName);
  637. return familyName.toLowerCase(Locale.ENGLISH) + "." + getStyleString(style);
  638. }
  639. /**
  640. * Returns the string typically used in properties files
  641. * for the given style.
  642. * The style argument is interpreted as in java.awt.Font.Font.
  643. */
  644. public static String getStyleString(int style) {
  645. return getStyleName(getStyleIndex(style));
  646. }
  647. /**
  648. * Returns a fallback name for the given font name. For a few known
  649. * font names, matching logical font names are returned. For all
  650. * other font names, defaultFallback is returned.
  651. * defaultFallback differs between AWT and 2D.
  652. */
  653. public abstract String getFallbackFamilyName(String fontName, String defaultFallback);
  654. /**
  655. * Returns the 1.1 equivalent for some old 1.0 font family names for
  656. * which we need to maintain compatibility in some configurations.
  657. * Returns null for other font names.
  658. */
  659. protected String getCompatibilityFamilyName(String fontName) {
  660. fontName = fontName.toLowerCase(Locale.ENGLISH);
  661. if (fontName.equals("timesroman")) {
  662. return "serif";
  663. } else if (fontName.equals("helvetica")) {
  664. return "sansserif";
  665. } else if (fontName.equals("courier")) {
  666. return "monospaced";
  667. }
  668. return null;
  669. }
  670. protected static String[] installedFallbackFontFiles = null;
  671. /**
  672. * Maps a file name given in the font configuration file
  673. * to a format appropriate for the platform.
  674. */
  675. protected String mapFileName(String fileName) {
  676. return fileName;
  677. }
  678. //////////////////////////////////////////////////////////////////////
  679. // reordering //
  680. //////////////////////////////////////////////////////////////////////
  681. /* Mappings from file encoding to font config name for font supporting
  682. * the corresponding language. This is filled in by initReorderMap()
  683. */
  684. protected HashMap reorderMap = null;
  685. /* Platform-specific mappings */
  686. protected abstract void initReorderMap();
  687. /* Move item at index "src" to "dst", shuffling all values in
  688. * between down
  689. */
  690. private void shuffle(String[] seq, int src, int dst) {
  691. if (dst >= src) {
  692. return;
  693. }
  694. String tmp = seq[src];
  695. for (int i=src; i>dst; i--) {
  696. seq[i] = seq[i-1];
  697. }
  698. seq[dst] = tmp;
  699. }
  700. /* Called to determine if there's a re-order sequence for this locale/
  701. * encoding. If there's none then the caller can "bail" and avoid
  702. * unnecessary work
  703. */
  704. public static boolean willReorderForStartupLocale() {
  705. return getReorderSequence() != null;
  706. }
  707. private static Object getReorderSequence() {
  708. if (fontConfig.reorderMap == null) {
  709. fontConfig.initReorderMap();
  710. }
  711. HashMap reorderMap = fontConfig.reorderMap;
  712. /* Find the most specific mapping */
  713. String language = startupLocale.getLanguage();
  714. String country = startupLocale.getCountry();
  715. Object val = reorderMap.get(encoding + "." + language + "." + country);
  716. if (val == null) {
  717. val = reorderMap.get(encoding + "." + language);
  718. }
  719. if (val == null) {
  720. val = reorderMap.get(encoding);
  721. }
  722. return val;
  723. }
  724. /* This method reorders the sequence such that the matches for the
  725. * file encoding are moved ahead of other elements.
  726. * If an encoding uses more than one font, they are all moved up.
  727. */
  728. private void reorderSequenceForLocale(String[] seq) {
  729. Object val = getReorderSequence();
  730. if (val instanceof String) {
  731. for (int i=0; i< seq.length; i++) {
  732. if (seq[i].equals(val)) {
  733. shuffle(seq, i, 0);
  734. return;
  735. }
  736. }
  737. } else if (val instanceof String[]) {
  738. String[] fontLangs = (String[])val;
  739. for (int l=0; l<fontLangs.length;l++) {
  740. for (int i=0; i<seq.length;i++) {
  741. if (seq[i].equals(fontLangs[l])) {
  742. shuffle(seq, i, l);
  743. }
  744. }
  745. }
  746. }
  747. }
  748. private static Vector splitSequence(String sequence) {
  749. //String.split would be more convenient, but incurs big performance penalty
  750. Vector parts = new Vector();
  751. int start = 0;
  752. int end;
  753. while ((end = sequence.indexOf(',', start)) >= 0) {
  754. parts.add(sequence.substring(start, end));
  755. start = end + 1;
  756. }
  757. if (sequence.length() > start) {
  758. parts.add(sequence.substring(start, sequence.length()));
  759. }
  760. return parts;
  761. }
  762. protected String[] split(String sequence) {
  763. Vector v = splitSequence(sequence);
  764. return (String[])v.toArray(new String[0]);
  765. }
  766. ////////////////////////////////////////////////////////////////////////
  767. // Methods for extracting information from the fontconfig data for AWT//
  768. ////////////////////////////////////////////////////////////////////////
  769. private Hashtable charsetRegistry = new Hashtable(5);
  770. /**
  771. * Returns FontDescriptors describing the physical fonts used for the
  772. * given logical font name and style. The font name is interpreted
  773. * in a case insensitive way.
  774. * The style argument is interpreted as in java.awt.Font.Font.
  775. */
  776. public FontDescriptor[] getFontDescriptors(String fontName, int style) {
  777. assert isLogicalFontFamilyName(fontName);
  778. fontName = fontName.toLowerCase(Locale.ENGLISH);
  779. int fontIndex = getFontIndex(fontName);
  780. int styleIndex = getStyleIndex(style);
  781. return getFontDescriptors(fontIndex, styleIndex);
  782. }
  783. private FontDescriptor[][][] fontDescriptors =
  784. new FontDescriptor[NUM_FONTS][NUM_STYLES][];
  785. private FontDescriptor[] getFontDescriptors(int fontIndex, int styleIndex) {
  786. FontDescriptor[] descriptors = fontDescriptors[fontIndex][styleIndex];
  787. if (descriptors == null) {
  788. descriptors = buildFontDescriptors(fontIndex, styleIndex);
  789. fontDescriptors[fontIndex][styleIndex] = descriptors;
  790. }
  791. return descriptors;
  792. }
  793. private FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {
  794. String fontName = fontNames[fontIndex];
  795. String styleName = styleNames[styleIndex];
  796. short[] scriptIDs = getCoreScripts(fontIndex);
  797. short[] nameIDs = compFontNameIDs[fontIndex][styleIndex];
  798. String[] sequence = new String[scriptIDs.length];
  799. String[] names = new String[scriptIDs.length];
  800. for (int i = 0; i < sequence.length; i++) {
  801. names[i] = getComponentFontName(nameIDs[i]);
  802. sequence[i] = getScriptName(scriptIDs[i]);
  803. if (alphabeticSuffix != null && "alphabetic".equals(sequence[i])) {
  804. sequence[i] = sequence[i] + "/" + alphabeticSuffix;
  805. }
  806. }
  807. int[][] fontExclusionRanges = compExclusions[fontIndex];
  808. FontDescriptor[] descriptors = new FontDescriptor[names.length];
  809. for (int i = 0; i < names.length; i++) {
  810. String awtFontName;
  811. String encoding;
  812. awtFontName = makeAWTFontName(names[i], sequence[i]);
  813. // look up character encoding
  814. encoding = getEncoding(names[i], sequence[i]);
  815. if (encoding == null) {
  816. encoding = "default";
  817. }
  818. CharsetEncoder enc
  819. = getFontCharsetEncoder(encoding.trim(), awtFontName);
  820. // we already have the exclusion ranges
  821. int[] exclusionRanges = fontExclusionRanges[i];
  822. // create descriptor
  823. descriptors[i] = new FontDescriptor(awtFontName, enc, exclusionRanges);
  824. }
  825. return descriptors;
  826. }
  827. /**
  828. * Returns the AWT font name for the given platform font name and
  829. * character subset.
  830. */
  831. protected String makeAWTFontName(String platformFontName,
  832. String characterSubsetName) {
  833. return platformFontName;
  834. }
  835. /**
  836. * Returns the java.io name of the platform character encoding for the
  837. * given AWT font name and character subset. May return "default"
  838. * to indicate that getDefaultFontCharset should be called to obtain
  839. * a charset encoder.
  840. */
  841. protected abstract String getEncoding(String awtFontName,
  842. String characterSubsetName);
  843. private CharsetEncoder getFontCharsetEncoder(final String charsetName,
  844. String fontName) {
  845. Charset fc = null;
  846. if (charsetName.equals("default")) {
  847. fc = (Charset) charsetRegistry.get(fontName);
  848. } else {
  849. fc = (Charset) charsetRegistry.get(charsetName);
  850. }
  851. if (fc != null) {
  852. return fc.newEncoder();
  853. }
  854. if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) {
  855. fc = Charset.forName(charsetName);
  856. } else {
  857. Class fcc = (Class) AccessController.doPrivileged(new PrivilegedAction() {
  858. public Object run() {
  859. try {
  860. return Class.forName(charsetName, true,
  861. Thread.currentThread().getContextClassLoader());
  862. } catch (ClassNotFoundException e) {
  863. }
  864. return null;
  865. }
  866. });
  867. if (fcc != null) {
  868. try {
  869. fc = (Charset) fcc.newInstance();
  870. } catch (Exception e) {
  871. }
  872. }
  873. }
  874. if (fc == null) {
  875. fc = getDefaultFontCharset(fontName);
  876. }
  877. if (charsetName.equals("default")){
  878. charsetRegistry.put(fontName, fc);
  879. } else {
  880. charsetRegistry.put(charsetName, fc);
  881. }
  882. return fc.newEncoder();
  883. }
  884. protected abstract Charset getDefaultFontCharset(
  885. String fontName);
  886. /* This retrieves the platform font directories (path) calculated
  887. * by setAWTFontPathSequence(String[]). The default implementation
  888. * returns null, its expected that X11 platforms may return
  889. * non-null.
  890. */
  891. public HashSet<String> getAWTFontPathSet() {
  892. return null;
  893. }
  894. ////////////////////////////////////////////////////////////////////////
  895. // methods for extracting information from the fontconfig data for 2D //
  896. ////////////////////////////////////////////////////////////////////////
  897. /**
  898. * Returns an array of composite font descriptors for all logical font
  899. * faces.
  900. * If the font configuration file doesn't specify Lucida Sans Regular
  901. * or the given fallback font as component fonts, they are added here.
  902. */
  903. public CompositeFontDescriptor[] get2DCompositeFontInfo() {
  904. CompositeFontDescriptor[] result =
  905. new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
  906. String defaultFontFile = fontManager.getDefaultFontFile();
  907. String defaultFontFaceName = fontManager.getDefaultFontFaceName();
  908. for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
  909. String fontName = publicFontNames[fontIndex];
  910. // determine exclusion ranges for font
  911. // AWT uses separate exclusion range array per component font.
  912. // 2D packs all range boundaries into one array.
  913. // Both use separate entries for lower and upper boundary.
  914. int[][] exclusions = compExclusions[fontIndex];
  915. int numExclusionRanges = 0;
  916. for (int i = 0; i < exclusions.length; i++) {
  917. numExclusionRanges += exclusions[i].length;
  918. }
  919. int[] exclusionRanges = new int[numExclusionRanges];
  920. int[] exclusionRangeLimits = new int[exclusions.length];
  921. int exclusionRangeIndex = 0;
  922. int exclusionRangeLimitIndex = 0;
  923. for (int i = 0; i < exclusions.length; i++) {
  924. int[] componentRanges = exclusions[i];
  925. for (int j = 0; j < componentRanges.length; ) {
  926. int value = componentRanges[j];
  927. exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];
  928. exclusionRanges[exclusionRangeIndex++] = componentRanges[j++];
  929. }
  930. exclusionRangeLimits[i] = exclusionRangeIndex;
  931. }
  932. // other info is per style
  933. for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
  934. int maxComponentFontCount = compFontNameIDs[fontIndex][styleIndex].length;
  935. boolean sawDefaultFontFile = false;
  936. // fall back fonts listed in the lib/fonts/fallback directory
  937. if (installedFallbackFontFiles != null) {
  938. maxComponentFontCount += installedFallbackFontFiles.length;
  939. }
  940. String faceName = fontName + "." + styleNames[styleIndex];
  941. // determine face names and file names of component fonts
  942. String[] componentFaceNames = new String[maxComponentFontCount];
  943. String[] componentFileNames = new String[maxComponentFontCount];
  944. int index;
  945. for (index = 0; index < compFontNameIDs[fontIndex][styleIndex].length; index++) {
  946. short fontNameID = compFontNameIDs[fontIndex][styleIndex][index];
  947. short fileNameID = getComponentFileID(fontNameID);
  948. componentFaceNames[index] = getFaceNameFromComponentFontName(getComponentFontName(fontNameID));
  949. componentFileNames[index] = mapFileName(getComponentFileName(fileNameID));
  950. if (componentFileNames[index] == null ||
  951. needToSearchForFile(componentFileNames[index])) {
  952. componentFileNames[index] = getFileNameFromComponentFontName(getComponentFontName(fontNameID));
  953. }
  954. if (!sawDefaultFontFile &&
  955. defaultFontFile.equals(componentFileNames[index])) {
  956. sawDefaultFontFile = true;
  957. }
  958. /*
  959. System.out.println(publicFontNames[fontIndex] + "." + styleNames[styleIndex] + "."
  960. + getString(table_scriptIDs[coreScripts[index]]) + "=" + componentFileNames[index]);
  961. */
  962. }
  963. //"Lucida Sans Regular" is not in the list, we add it here
  964. if (!sawDefaultFontFile) {
  965. int len = 0;
  966. if (installedFallbackFontFiles != null) {
  967. len = installedFallbackFontFiles.length;
  968. }
  969. if (index + len == maxComponentFontCount) {
  970. String[] newComponentFaceNames = new String[maxComponentFontCount + 1];
  971. System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);
  972. componentFaceNames = newComponentFaceNames;
  973. String[] newComponentFileNames = new String[maxComponentFontCount + 1];
  974. System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);
  975. componentFileNames = newComponentFileNames;
  976. }
  977. componentFaceNames[index] = defaultFontFaceName;
  978. componentFileNames[index] = defaultFontFile;
  979. index++;
  980. }
  981. if (installedFallbackFontFiles != null) {
  982. for (int ifb=0; ifb<installedFallbackFontFiles.length; ifb++) {
  983. componentFaceNames[index] = null;
  984. componentFileNames[index] = installedFallbackFontFiles[ifb];
  985. index++;
  986. }
  987. }
  988. if (index < maxComponentFontCount) {
  989. String[] newComponentFaceNames = new String[index];
  990. System.arraycopy(componentFaceNames, 0, newComponentFaceNames, 0, index);
  991. componentFaceNames = newComponentFaceNames;
  992. String[] newComponentFileNames = new String[index];
  993. System.arraycopy(componentFileNames, 0, newComponentFileNames, 0, index);
  994. componentFileNames = newComponentFileNames;
  995. }
  996. // exclusion range limit array length must match component face name
  997. // array length - native code relies on this
  998. int[] clippedExclusionRangeLimits = exclusionRangeLimits;
  999. if (index != clippedExclusionRangeLimits.length) {
  1000. int len = exclusionRangeLimits.length;
  1001. clippedExclusionRangeLimits = new int[index];
  1002. System.arraycopy(exclusionRangeLimits, 0, clippedExclusionRangeLimits, 0, len);
  1003. //padding for various fallback fonts
  1004. for (int i = len; i < index; i++) {
  1005. clippedExclusionRangeLimits[i] = exclusionRanges.length;
  1006. }
  1007. }
  1008. /*
  1009. System.out.println(faceName + ":");
  1010. for (int i = 0; i < componentFileNames.length; i++) {
  1011. System.out.println(" " + componentFaceNames[i]
  1012. + " -> " + componentFileNames[i]);
  1013. }
  1014. */
  1015. result[fontIndex * NUM_STYLES + styleIndex]
  1016. = new CompositeFontDescriptor(
  1017. faceName,
  1018. compCoreNum[fontIndex],
  1019. componentFaceNames,
  1020. componentFileNames,
  1021. exclusionRanges,
  1022. clippedExclusionRangeLimits);
  1023. }
  1024. }
  1025. return result;
  1026. }
  1027. protected abstract String getFaceNameFromComponentFontName(String componentFontName);
  1028. protected abstract String getFileNameFromComponentFontName(String componentFontName);
  1029. /*
  1030. public class 2dFont {
  1031. public String platformName;
  1032. public String fontfileName;
  1033. }
  1034. private 2dFont [] componentFonts = null;
  1035. */
  1036. /* Used on Linux to test if a file referenced in a font configuration
  1037. * file exists in the location that is expected. If it does, no need
  1038. * to search for it. If it doesn't then unless its a fallback font,
  1039. * return that expensive code should be invoked to search for the font.
  1040. */
  1041. HashMap<String, Boolean> existsMap;
  1042. public boolean needToSearchForFile(String fileName) {
  1043. if (!FontUtilities.isLinux) {
  1044. return false;
  1045. } else if (existsMap == null) {
  1046. existsMap = new HashMap<String, Boolean>();
  1047. }
  1048. Boolean exists = existsMap.get(fileName);
  1049. if (exists == null) {
  1050. /* call getNumberCoreFonts() to ensure these are initialised, and
  1051. * if this file isn't for a core component, ie, is a for a fallback
  1052. * font which very typically isn't available, then can't afford
  1053. * to take the start-up penalty to search for it.
  1054. */
  1055. getNumberCoreFonts();
  1056. if (!coreFontFileNames.contains(fileName)) {
  1057. exists = Boolean.TRUE;
  1058. } else {
  1059. exists = Boolean.valueOf((new File(fileName)).exists());
  1060. existsMap.put(fileName, exists);
  1061. if (FontUtilities.debugFonts() &&
  1062. exists == Boolean.FALSE) {
  1063. logger.warning("Couldn't locate font file " + fileName);
  1064. }
  1065. }
  1066. }
  1067. return exists == Boolean.FALSE;
  1068. }
  1069. private int numCoreFonts = -1;
  1070. private String[] componentFonts = null;
  1071. HashMap <String, String> filenamesMap = new HashMap<String, String>();
  1072. HashSet <String> coreFontFileNames = new HashSet<String>();
  1073. /* Return the number of core fonts. Note this isn't thread safe but
  1074. * a calling thread can call this and getPlatformFontNames() in either
  1075. * order.
  1076. */
  1077. public int getNumberCoreFonts() {
  1078. if (numCoreFonts == -1) {
  1079. numCoreFonts = coreFontNameIDs.size();
  1080. Short[] emptyShortArray = new Short[0];
  1081. Short[] core = coreFontNameIDs.toArray(emptyShortArray);
  1082. Short[] fallback = fallbackFontNameIDs.toArray(emptyShortArray);
  1083. int numFallbackFonts = 0;
  1084. int i;
  1085. for (i = 0; i < fallback.length; i++) {
  1086. if (coreFontNameIDs.contains(fallback[i])) {
  1087. fallback[i] = null;
  1088. continue;
  1089. }
  1090. numFallbackFonts++;
  1091. }
  1092. componentFonts = new String[numCoreFonts + numFallbackFonts];
  1093. String filename = null;
  1094. for (i = 0; i < core.length; i++) {
  1095. short fontid = core[i];
  1096. short fileid = getComponentFileID(fontid);
  1097. componentFonts[i] = getComponentFontName(fontid);
  1098. String compFileName = getComponentFileName(fileid);
  1099. if (compFileName != null) {
  1100. coreFontFileNames.add(compFileName);
  1101. }
  1102. filenamesMap.put(componentFonts[i], mapFileName(compFileName));
  1103. }
  1104. for (int j = 0; j < fallback.length; j++) {
  1105. if (fallback[j] != null) {
  1106. short fontid = fallback[j];
  1107. short fileid = getComponentFileID(fontid);
  1108. componentFonts[i] = getComponentFontName(fontid);
  1109. filenamesMap.put(componentFonts[i],
  1110. mapFileName(getComponentFileName(fileid)));
  1111. i++;
  1112. }
  1113. }
  1114. }
  1115. return numCoreFonts;
  1116. }
  1117. /* Return all platform font names used by this font configuration.
  1118. * The first getNumberCoreFonts() entries are guaranteed to be the
  1119. * core fonts - ie no fall back only fonts.
  1120. */
  1121. public String[] getPlatformFontNames() {
  1122. if (numCoreFonts == -1) {
  1123. getNumberCoreFonts();
  1124. }
  1125. return componentFonts;
  1126. }
  1127. /**
  1128. * Returns a file name for the physical font represented by this platform font name,
  1129. * if the font configuration has such information available, or null if the
  1130. * information is unavailable. The file name returned is just a hint; a null return
  1131. * value doesn't necessarily mean that the font is unavailable, nor does a non-null
  1132. * return value guarantee that the file exists and contains the physical font.
  1133. * The file name can be an absolute or a relative path name.
  1134. */
  1135. public String getFileNameFromPlatformName(String platformName) {
  1136. // get2DCompositeFontInfo
  1137. // -> getFileNameFromComponentfontName() (W/M)
  1138. // -> getFileNameFromPlatformName()
  1139. // it's a waste of time on Win32, but I have to give X11 a chance to
  1140. // call getFileNameFromXLF…

Large files files are truncated, but you can click here to view the full file