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.File;
30 import java.io.FileInputStream;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.net.InetAddress;
34 import java.net.UnknownHostException;
35 import java.nio.charset.Charset;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Files;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Properties;
41 import java.util.Scanner;
42 import sun.awt.FontConfiguration;
43 import sun.awt.FontDescriptor;
44 import sun.awt.SunToolkit;
45 import sun.awt.X11FontManager;
46 import sun.font.CompositeFontDescriptor;
47 import sun.font.FontManager;
48 import sun.font.FontConfigManager.FontConfigInfo;
49 import sun.font.FontConfigManager.FcCompFont;
50 import sun.font.FontConfigManager.FontConfigFont;
51 import sun.java2d.SunGraphicsEnvironment;
52 import sun.util.logging.PlatformLogger;
53
54 public class FcFontConfiguration extends FontConfiguration {
55
56 /** Version of the cache file format understood by this code.
57 * Its part of the file name so that we can rev this at
58 * any time, even in a minor JDK update.
59 * It is stored as the value of the "version" property.
60 * This is distinct from the version of "libfontconfig" that generated
61 * the cached results, and which is the "fcversion" property in the file.
62 * {@code FontConfiguration.getVersion()} also returns a version string,
63 * and has meant the version of the fontconfiguration.properties file
64 * that was read. Since this class doesn't use such files, then what
65 * that really means is whether the methods on this class return
75 super(fm);
76 init();
77 }
78
79 /* This isn't called but is needed to satisfy super-class contract. */
80 public FcFontConfiguration(SunFontManager fm,
81 boolean preferLocaleFonts,
82 boolean preferPropFonts) {
83 super(fm, preferLocaleFonts, preferPropFonts);
84 init();
85 }
86
87 @Override
88 public synchronized boolean init() {
89 if (fcCompFonts != null) {
90 return true;
91 }
92
93 setFontConfiguration();
94 readFcInfo();
95 X11FontManager fm = (X11FontManager) fontManager;
96 FontConfigManager fcm = fm.getFontConfigManager();
97 if (fcCompFonts == null) {
98 fcCompFonts = fcm.loadFontConfig();
99 if (fcCompFonts != null) {
100 try {
101 writeFcInfo();
102 } catch (Exception e) {
103 if (FontUtilities.debugFonts()) {
104 warning("Exception writing fcInfo " + e);
105 }
106 }
107 } else if (FontUtilities.debugFonts()) {
108 warning("Failed to get info from libfontconfig");
109 }
110 } else {
111 fcm.populateFontConfig(fcCompFonts);
112 }
113
114 if (fcCompFonts == null) {
115 return false; // couldn't load fontconfig.
177 protected FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {
178 CompositeFontDescriptor[] cfi = get2DCompositeFontInfo();
179 int idx = fontIndex * NUM_STYLES + styleIndex;
180 String[] componentFaceNames = cfi[idx].getComponentFaceNames();
181 FontDescriptor[] ret = new FontDescriptor[componentFaceNames.length];
182 for (int i = 0; i < componentFaceNames.length; i++) {
183 ret[i] = new FontDescriptor(componentFaceNames[i], StandardCharsets.ISO_8859_1.newEncoder(), new int[0]);
184 }
185
186 return ret;
187 }
188
189 @Override
190 public int getNumberCoreFonts() {
191 return 1;
192 }
193
194 @Override
195 public String[] getPlatformFontNames() {
196 HashSet<String> nameSet = new HashSet<String>();
197 X11FontManager fm = (X11FontManager) fontManager;
198 FontConfigManager fcm = fm.getFontConfigManager();
199 FcCompFont[] fcCompFonts = fcm.loadFontConfig();
200 for (int i=0; i<fcCompFonts.length; i++) {
201 for (int j=0; j<fcCompFonts[i].allFonts.length; j++) {
202 nameSet.add(fcCompFonts[i].allFonts[j].fontFile);
203 }
204 }
205 return nameSet.toArray(new String[0]);
206 }
207
208 @Override
209 public String getExtraFontPath() {
210 return null;
211 }
212
213 @Override
214 public boolean needToSearchForFile(String fileName) {
215 return false;
216 }
217
218 private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
219 String fontname, int style) {
220
221 if (fontname.equals("dialog")) {
222 fontname = "sansserif";
223 } else if (fontname.equals("dialoginput")) {
224 fontname = "monospaced";
225 }
226 for (int i=0; i<fcFonts.length; i++) {
227 if (fontname.equals(fcFonts[i].jdkName) &&
228 style == fcFonts[i].style) {
229 return fcFonts[i].allFonts;
230 }
231 }
232 return fcFonts[0].allFonts;
233 }
234
235 @Override
236 public CompositeFontDescriptor[] get2DCompositeFontInfo() {
237
238 X11FontManager fm = (X11FontManager) fontManager;
239 FontConfigManager fcm = fm.getFontConfigManager();
240 FcCompFont[] fcCompFonts = fcm.loadFontConfig();
241
242 CompositeFontDescriptor[] result =
243 new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
244
245 for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
246 String fontName = publicFontNames[fontIndex];
247
248 for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
249
250 String faceName = fontName + "." + styleNames[styleIndex];
251 FontConfigFont[] fcFonts =
252 getFcFontList(fcCompFonts,
253 fontNames[fontIndex], styleIndex);
254
255 int numFonts = fcFonts.length;
256 // fall back fonts listed in the lib/fonts/fallback directory
257 if (installedFallbackFontFiles != null) {
258 numFonts += installedFallbackFontFiles.length;
351 try {
352 hostname = InetAddress.getLocalHost().getHostName();
353 } catch (UnknownHostException e) {
354 hostname = "localhost";
355 }
356 String userDir = System.getProperty("user.home");
357 String version = System.getProperty("java.version");
358 String fs = File.separator;
359 String dir = userDir+fs+".java"+fs+"fonts"+fs+version;
360 String lang = SunToolkit.getStartupLocale().getLanguage();
361 String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+
362 osName+"-"+osVersion+"-"+lang+".properties";
363 fcInfoFileName = dir+fs+name;
364 }
365 return new File(fcInfoFileName);
366 }
367
368 private void writeFcInfo() {
369 Properties props = new Properties();
370 props.setProperty("version", fileVersion);
371 X11FontManager fm = (X11FontManager) fontManager;
372 FontConfigManager fcm = fm.getFontConfigManager();
373 FontConfigInfo fcInfo = fcm.getFontConfigInfo();
374 props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
375 if (fcInfo.cacheDirs != null) {
376 for (int i=0;i<fcInfo.cacheDirs.length;i++) {
377 if (fcInfo.cacheDirs[i] != null) {
378 props.setProperty("cachedir."+i, fcInfo.cacheDirs[i]);
379 }
380 }
381 }
382 for (int i=0; i<fcCompFonts.length; i++) {
383 FcCompFont fci = fcCompFonts[i];
384 String styleKey = fci.jdkName+"."+fci.style;
385 props.setProperty(styleKey+".length",
386 Integer.toString(fci.allFonts.length));
387 for (int j=0; j<fci.allFonts.length; j++) {
388 props.setProperty(styleKey+"."+j+".family",
389 fci.allFonts[j].familyName);
390 props.setProperty(styleKey+"."+j+".file",
391 fci.allFonts[j].fontFile);
410 warning("Failed renaming file to "+ getFcInfoFile());
411 }
412 } catch (Exception e) {
413 if (FontUtilities.debugFonts()) {
414 warning("IOException writing to "+ getFcInfoFile());
415 }
416 }
417 }
418
419 /* We want to be able to use this cache instead of invoking
420 * fontconfig except when we can detect the system cache has changed.
421 * But there doesn't seem to be a way to find the location of
422 * the system cache.
423 */
424 private void readFcInfo() {
425 File fcFile = getFcInfoFile();
426 if (!fcFile.exists()) {
427 return;
428 }
429 Properties props = new Properties();
430 X11FontManager fm = (X11FontManager) fontManager;
431 FontConfigManager fcm = fm.getFontConfigManager();
432 try {
433 FileInputStream fis = new FileInputStream(fcFile);
434 props.load(fis);
435 fis.close();
436 } catch (IOException e) {
437 if (FontUtilities.debugFonts()) {
438 warning("IOException reading from "+fcFile.toString());
439 }
440 return;
441 }
442 String version = (String)props.get("version");
443 if (version == null || !version.equals(fileVersion)) {
444 return;
445 }
446
447 // If there's a new, different fontconfig installed on the
448 // system, we invalidate our fontconfig file.
449 String fcVersionStr = (String)props.get("fcversion");
450 if (fcVersionStr != null) {
|
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.File;
30 import java.io.FileInputStream;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.net.InetAddress;
34 import java.net.UnknownHostException;
35 import java.nio.charset.Charset;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Files;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Properties;
41 import java.util.Scanner;
42 import sun.awt.FcFontManager;
43 import sun.awt.FontConfiguration;
44 import sun.awt.FontDescriptor;
45 import sun.awt.SunToolkit;
46 import sun.font.CompositeFontDescriptor;
47 import sun.font.FontManager;
48 import sun.font.FontConfigManager.FontConfigInfo;
49 import sun.font.FontConfigManager.FcCompFont;
50 import sun.font.FontConfigManager.FontConfigFont;
51 import sun.java2d.SunGraphicsEnvironment;
52 import sun.util.logging.PlatformLogger;
53
54 public class FcFontConfiguration extends FontConfiguration {
55
56 /** Version of the cache file format understood by this code.
57 * Its part of the file name so that we can rev this at
58 * any time, even in a minor JDK update.
59 * It is stored as the value of the "version" property.
60 * This is distinct from the version of "libfontconfig" that generated
61 * the cached results, and which is the "fcversion" property in the file.
62 * {@code FontConfiguration.getVersion()} also returns a version string,
63 * and has meant the version of the fontconfiguration.properties file
64 * that was read. Since this class doesn't use such files, then what
65 * that really means is whether the methods on this class return
75 super(fm);
76 init();
77 }
78
79 /* This isn't called but is needed to satisfy super-class contract. */
80 public FcFontConfiguration(SunFontManager fm,
81 boolean preferLocaleFonts,
82 boolean preferPropFonts) {
83 super(fm, preferLocaleFonts, preferPropFonts);
84 init();
85 }
86
87 @Override
88 public synchronized boolean init() {
89 if (fcCompFonts != null) {
90 return true;
91 }
92
93 setFontConfiguration();
94 readFcInfo();
95 FcFontManager fm = (FcFontManager) fontManager;
96 FontConfigManager fcm = fm.getFontConfigManager();
97 if (fcCompFonts == null) {
98 fcCompFonts = fcm.loadFontConfig();
99 if (fcCompFonts != null) {
100 try {
101 writeFcInfo();
102 } catch (Exception e) {
103 if (FontUtilities.debugFonts()) {
104 warning("Exception writing fcInfo " + e);
105 }
106 }
107 } else if (FontUtilities.debugFonts()) {
108 warning("Failed to get info from libfontconfig");
109 }
110 } else {
111 fcm.populateFontConfig(fcCompFonts);
112 }
113
114 if (fcCompFonts == null) {
115 return false; // couldn't load fontconfig.
177 protected FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {
178 CompositeFontDescriptor[] cfi = get2DCompositeFontInfo();
179 int idx = fontIndex * NUM_STYLES + styleIndex;
180 String[] componentFaceNames = cfi[idx].getComponentFaceNames();
181 FontDescriptor[] ret = new FontDescriptor[componentFaceNames.length];
182 for (int i = 0; i < componentFaceNames.length; i++) {
183 ret[i] = new FontDescriptor(componentFaceNames[i], StandardCharsets.ISO_8859_1.newEncoder(), new int[0]);
184 }
185
186 return ret;
187 }
188
189 @Override
190 public int getNumberCoreFonts() {
191 return 1;
192 }
193
194 @Override
195 public String[] getPlatformFontNames() {
196 HashSet<String> nameSet = new HashSet<String>();
197 FcFontManager fm = (FcFontManager) fontManager;
198 FontConfigManager fcm = fm.getFontConfigManager();
199 FcCompFont[] fcCompFonts = fcm.loadFontConfig();
200 for (int i=0; i<fcCompFonts.length; i++) {
201 for (int j=0; j<fcCompFonts[i].allFonts.length; j++) {
202 nameSet.add(fcCompFonts[i].allFonts[j].fontFile);
203 }
204 }
205 return nameSet.toArray(new String[0]);
206 }
207
208 @Override
209 public String getExtraFontPath() {
210 return null;
211 }
212
213 @Override
214 public boolean needToSearchForFile(String fileName) {
215 return false;
216 }
217
218 private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
219 String fontname, int style) {
220
221 if (fontname.equals("dialog")) {
222 fontname = "sansserif";
223 } else if (fontname.equals("dialoginput")) {
224 fontname = "monospaced";
225 }
226 for (int i=0; i<fcFonts.length; i++) {
227 if (fontname.equals(fcFonts[i].jdkName) &&
228 style == fcFonts[i].style) {
229 return fcFonts[i].allFonts;
230 }
231 }
232 return fcFonts[0].allFonts;
233 }
234
235 @Override
236 public CompositeFontDescriptor[] get2DCompositeFontInfo() {
237
238 FcFontManager fm = (FcFontManager) fontManager;
239 FontConfigManager fcm = fm.getFontConfigManager();
240 FcCompFont[] fcCompFonts = fcm.loadFontConfig();
241
242 CompositeFontDescriptor[] result =
243 new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
244
245 for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
246 String fontName = publicFontNames[fontIndex];
247
248 for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
249
250 String faceName = fontName + "." + styleNames[styleIndex];
251 FontConfigFont[] fcFonts =
252 getFcFontList(fcCompFonts,
253 fontNames[fontIndex], styleIndex);
254
255 int numFonts = fcFonts.length;
256 // fall back fonts listed in the lib/fonts/fallback directory
257 if (installedFallbackFontFiles != null) {
258 numFonts += installedFallbackFontFiles.length;
351 try {
352 hostname = InetAddress.getLocalHost().getHostName();
353 } catch (UnknownHostException e) {
354 hostname = "localhost";
355 }
356 String userDir = System.getProperty("user.home");
357 String version = System.getProperty("java.version");
358 String fs = File.separator;
359 String dir = userDir+fs+".java"+fs+"fonts"+fs+version;
360 String lang = SunToolkit.getStartupLocale().getLanguage();
361 String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+
362 osName+"-"+osVersion+"-"+lang+".properties";
363 fcInfoFileName = dir+fs+name;
364 }
365 return new File(fcInfoFileName);
366 }
367
368 private void writeFcInfo() {
369 Properties props = new Properties();
370 props.setProperty("version", fileVersion);
371 FcFontManager fm = (FcFontManager) fontManager;
372 FontConfigManager fcm = fm.getFontConfigManager();
373 FontConfigInfo fcInfo = fcm.getFontConfigInfo();
374 props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
375 if (fcInfo.cacheDirs != null) {
376 for (int i=0;i<fcInfo.cacheDirs.length;i++) {
377 if (fcInfo.cacheDirs[i] != null) {
378 props.setProperty("cachedir."+i, fcInfo.cacheDirs[i]);
379 }
380 }
381 }
382 for (int i=0; i<fcCompFonts.length; i++) {
383 FcCompFont fci = fcCompFonts[i];
384 String styleKey = fci.jdkName+"."+fci.style;
385 props.setProperty(styleKey+".length",
386 Integer.toString(fci.allFonts.length));
387 for (int j=0; j<fci.allFonts.length; j++) {
388 props.setProperty(styleKey+"."+j+".family",
389 fci.allFonts[j].familyName);
390 props.setProperty(styleKey+"."+j+".file",
391 fci.allFonts[j].fontFile);
410 warning("Failed renaming file to "+ getFcInfoFile());
411 }
412 } catch (Exception e) {
413 if (FontUtilities.debugFonts()) {
414 warning("IOException writing to "+ getFcInfoFile());
415 }
416 }
417 }
418
419 /* We want to be able to use this cache instead of invoking
420 * fontconfig except when we can detect the system cache has changed.
421 * But there doesn't seem to be a way to find the location of
422 * the system cache.
423 */
424 private void readFcInfo() {
425 File fcFile = getFcInfoFile();
426 if (!fcFile.exists()) {
427 return;
428 }
429 Properties props = new Properties();
430 FcFontManager fm = (FcFontManager) fontManager;
431 FontConfigManager fcm = fm.getFontConfigManager();
432 try {
433 FileInputStream fis = new FileInputStream(fcFile);
434 props.load(fis);
435 fis.close();
436 } catch (IOException e) {
437 if (FontUtilities.debugFonts()) {
438 warning("IOException reading from "+fcFile.toString());
439 }
440 return;
441 }
442 String version = (String)props.get("version");
443 if (version == null || !version.equals(fileVersion)) {
444 return;
445 }
446
447 // If there's a new, different fontconfig installed on the
448 // system, we invalidate our fontconfig file.
449 String fcVersionStr = (String)props.get("fcversion");
450 if (fcVersionStr != null) {
|