Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java
41153 views
1
/*
2
* Copyright (c) 2008, 2020, 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.io.FileInputStream;
30
import java.io.FileOutputStream;
31
import java.io.IOException;
32
import java.net.InetAddress;
33
import java.net.UnknownHostException;
34
import java.nio.charset.Charset;
35
import java.nio.charset.StandardCharsets;
36
import java.nio.file.Files;
37
import java.util.HashMap;
38
import java.util.HashSet;
39
import java.util.Locale;
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.FontConfigManager.FontConfigInfo;
48
import sun.font.FontConfigManager.FcCompFont;
49
import sun.font.FontConfigManager.FontConfigFont;
50
import sun.util.logging.PlatformLogger;
51
52
public class FcFontConfiguration extends FontConfiguration {
53
54
/** Version of the cache file format understood by this code.
55
* Its part of the file name so that we can rev this at
56
* any time, even in a minor JDK update.
57
* It is stored as the value of the "version" property.
58
* This is distinct from the version of "libfontconfig" that generated
59
* the cached results, and which is the "fcversion" property in the file.
60
* {@code FontConfiguration.getVersion()} also returns a version string,
61
* and has meant the version of the fontconfiguration.properties file
62
* that was read. Since this class doesn't use such files, then what
63
* that really means is whether the methods on this class return
64
* values that are compatible with the classes that do directly read
65
* from such files. It is a compatible subset of version "1".
66
*/
67
private static final String fileVersion = "1";
68
private String fcInfoFileName = null;
69
70
private FcCompFont[] fcCompFonts = null;
71
72
public FcFontConfiguration(SunFontManager fm) {
73
super(fm);
74
init();
75
}
76
77
/* This isn't called but is needed to satisfy super-class contract. */
78
public FcFontConfiguration(SunFontManager fm,
79
boolean preferLocaleFonts,
80
boolean preferPropFonts) {
81
super(fm, preferLocaleFonts, preferPropFonts);
82
init();
83
}
84
85
@Override
86
public synchronized boolean init() {
87
if (fcCompFonts != null) {
88
return true;
89
}
90
91
setFontConfiguration();
92
readFcInfo();
93
FcFontManager fm = (FcFontManager) fontManager;
94
FontConfigManager fcm = fm.getFontConfigManager();
95
if (fcCompFonts == null) {
96
fcCompFonts = fcm.loadFontConfig();
97
if (fcCompFonts != null) {
98
try {
99
writeFcInfo();
100
} catch (Exception e) {
101
if (FontUtilities.debugFonts()) {
102
warning("Exception writing fcInfo " + e);
103
}
104
}
105
} else if (FontUtilities.debugFonts()) {
106
warning("Failed to get info from libfontconfig");
107
}
108
} else {
109
fcm.populateFontConfig(fcCompFonts);
110
}
111
112
if (fcCompFonts == null) {
113
return false; // couldn't load fontconfig.
114
}
115
116
// NB already in a privileged block from SGE
117
String javaHome = System.getProperty("java.home");
118
if (javaHome == null) {
119
throw new Error("java.home property not set");
120
}
121
String javaLib = javaHome + File.separator + "lib";
122
getInstalledFallbackFonts(javaLib);
123
124
return true;
125
}
126
127
@Override
128
public String getFallbackFamilyName(String fontName,
129
String defaultFallback) {
130
// maintain compatibility with old font.properties files, which either
131
// had aliases for TimesRoman & Co. or defined mappings for them.
132
String compatibilityName = getCompatibilityFamilyName(fontName);
133
if (compatibilityName != null) {
134
return compatibilityName;
135
}
136
return defaultFallback;
137
}
138
139
@Override
140
protected String
141
getFaceNameFromComponentFontName(String componentFontName) {
142
return null;
143
}
144
145
@Override
146
protected String
147
getFileNameFromComponentFontName(String componentFontName) {
148
return null;
149
}
150
151
@Override
152
public String getFileNameFromPlatformName(String platformName) {
153
/* Platform name is the file name, but rather than returning
154
* the arg, return null*/
155
return null;
156
}
157
158
@Override
159
protected Charset getDefaultFontCharset(String fontName) {
160
return Charset.forName("ISO8859_1");
161
}
162
163
@Override
164
protected String getEncoding(String awtFontName,
165
String characterSubsetName) {
166
return "default";
167
}
168
169
@Override
170
protected void initReorderMap() {
171
reorderMap = new HashMap<>();
172
}
173
174
@Override
175
protected FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) {
176
CompositeFontDescriptor[] cfi = get2DCompositeFontInfo();
177
int idx = fontIndex * NUM_STYLES + styleIndex;
178
String[] componentFaceNames = cfi[idx].getComponentFaceNames();
179
FontDescriptor[] ret = new FontDescriptor[componentFaceNames.length];
180
for (int i = 0; i < componentFaceNames.length; i++) {
181
ret[i] = new FontDescriptor(componentFaceNames[i], StandardCharsets.ISO_8859_1.newEncoder(), new int[0]);
182
}
183
184
return ret;
185
}
186
187
@Override
188
public int getNumberCoreFonts() {
189
return 1;
190
}
191
192
@Override
193
public String[] getPlatformFontNames() {
194
HashSet<String> nameSet = new HashSet<String>();
195
FcFontManager fm = (FcFontManager) fontManager;
196
FontConfigManager fcm = fm.getFontConfigManager();
197
FcCompFont[] fcCompFonts = fcm.loadFontConfig();
198
for (int i=0; i<fcCompFonts.length; i++) {
199
for (int j=0; j<fcCompFonts[i].allFonts.length; j++) {
200
nameSet.add(fcCompFonts[i].allFonts[j].fontFile);
201
}
202
}
203
return nameSet.toArray(new String[0]);
204
}
205
206
@Override
207
public String getExtraFontPath() {
208
return null;
209
}
210
211
@Override
212
public boolean needToSearchForFile(String fileName) {
213
return false;
214
}
215
216
private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts,
217
String fontname, int style) {
218
219
if (fontname.equals("dialog")) {
220
fontname = "sansserif";
221
} else if (fontname.equals("dialoginput")) {
222
fontname = "monospaced";
223
}
224
for (int i=0; i<fcFonts.length; i++) {
225
if (fontname.equals(fcFonts[i].jdkName) &&
226
style == fcFonts[i].style) {
227
return fcFonts[i].allFonts;
228
}
229
}
230
return fcFonts[0].allFonts;
231
}
232
233
@Override
234
public CompositeFontDescriptor[] get2DCompositeFontInfo() {
235
236
FcFontManager fm = (FcFontManager) fontManager;
237
FontConfigManager fcm = fm.getFontConfigManager();
238
FcCompFont[] fcCompFonts = fcm.loadFontConfig();
239
240
CompositeFontDescriptor[] result =
241
new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES];
242
243
for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) {
244
String fontName = publicFontNames[fontIndex];
245
246
for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) {
247
248
String faceName = fontName + "." + styleNames[styleIndex];
249
FontConfigFont[] fcFonts =
250
getFcFontList(fcCompFonts,
251
fontNames[fontIndex], styleIndex);
252
253
int numFonts = fcFonts.length;
254
// fall back fonts listed in the lib/fonts/fallback directory
255
if (installedFallbackFontFiles != null) {
256
numFonts += installedFallbackFontFiles.length;
257
}
258
259
String[] fileNames = new String[numFonts];
260
String[] faceNames = new String[numFonts];
261
262
int index;
263
for (index = 0; index < fcFonts.length; index++) {
264
fileNames[index] = fcFonts[index].fontFile;
265
faceNames[index] = fcFonts[index].fullName;
266
}
267
268
if (installedFallbackFontFiles != null) {
269
System.arraycopy(installedFallbackFontFiles, 0,
270
fileNames, fcFonts.length,
271
installedFallbackFontFiles.length);
272
}
273
274
result[fontIndex * NUM_STYLES + styleIndex]
275
= new CompositeFontDescriptor(
276
faceName,
277
1,
278
faceNames,
279
fileNames,
280
null, null);
281
}
282
}
283
return result;
284
}
285
286
/**
287
* Gets the OS version string from a Linux release-specific file.
288
*/
289
private String getVersionString(File f) {
290
try (Scanner sc = new Scanner(f)) {
291
return sc.findInLine("(\\d)+((\\.)(\\d)+)*");
292
} catch (Exception e) {
293
}
294
return null;
295
}
296
297
/**
298
* Sets the OS name and version from environment information.
299
*/
300
@Override
301
protected void setOsNameAndVersion() {
302
303
super.setOsNameAndVersion();
304
305
if (!osName.equals("Linux")) {
306
return;
307
}
308
try {
309
File f;
310
if ((f = new File("/etc/lsb-release")).canRead()) {
311
/* Ubuntu and (perhaps others) use only lsb-release.
312
* Syntax and encoding is compatible with java properties.
313
* For Ubuntu the ID is "Ubuntu".
314
*/
315
Properties props = new Properties();
316
props.load(new FileInputStream(f));
317
osName = props.getProperty("DISTRIB_ID");
318
osVersion = props.getProperty("DISTRIB_RELEASE");
319
} else if ((f = new File("/etc/redhat-release")).canRead()) {
320
osName = "RedHat";
321
osVersion = getVersionString(f);
322
} else if ((f = new File("/etc/SuSE-release")).canRead()) {
323
osName = "SuSE";
324
osVersion = getVersionString(f);
325
} else if ((f = new File("/etc/turbolinux-release")).canRead()) {
326
osName = "Turbo";
327
osVersion = getVersionString(f);
328
} else if ((f = new File("/etc/fedora-release")).canRead()) {
329
osName = "Fedora";
330
osVersion = getVersionString(f);
331
}
332
} catch (Exception e) {
333
if (FontUtilities.debugFonts()) {
334
warning("Exception identifying Linux distro.");
335
}
336
}
337
}
338
339
private File getFcInfoFile() {
340
if (fcInfoFileName == null) {
341
// NB need security permissions to get true IP address, and
342
// we should have those as the whole initialisation is in a
343
// doPrivileged block. But in this case no exception is thrown,
344
// and it returns the loop back address, and so we end up with
345
// "localhost"
346
String hostname;
347
try {
348
hostname = InetAddress.getLocalHost().getHostName();
349
} catch (UnknownHostException e) {
350
hostname = "localhost";
351
}
352
String userDir = System.getProperty("user.home");
353
String version = System.getProperty("java.version");
354
String fs = File.separator;
355
String dir = userDir+fs+".java"+fs+"fonts"+fs+version;
356
Locale locale = SunToolkit.getStartupLocale();
357
String lang = locale.getLanguage();
358
String country = locale.getCountry();
359
String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+
360
osName+"-"+osVersion+"-"+lang+"-"+country+".properties";
361
fcInfoFileName = dir+fs+name;
362
}
363
return new File(fcInfoFileName);
364
}
365
366
private void writeFcInfo() {
367
Properties props = new Properties();
368
props.setProperty("version", fileVersion);
369
FcFontManager fm = (FcFontManager) fontManager;
370
FontConfigManager fcm = fm.getFontConfigManager();
371
FontConfigInfo fcInfo = fcm.getFontConfigInfo();
372
props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
373
if (fcInfo.cacheDirs != null) {
374
for (int i=0;i<fcInfo.cacheDirs.length;i++) {
375
if (fcInfo.cacheDirs[i] != null) {
376
props.setProperty("cachedir."+i, fcInfo.cacheDirs[i]);
377
}
378
}
379
}
380
for (int i=0; i<fcCompFonts.length; i++) {
381
FcCompFont fci = fcCompFonts[i];
382
String styleKey = fci.jdkName+"."+fci.style;
383
props.setProperty(styleKey+".length",
384
Integer.toString(fci.allFonts.length));
385
for (int j=0; j<fci.allFonts.length; j++) {
386
props.setProperty(styleKey+"."+j+".file",
387
fci.allFonts[j].fontFile);
388
if (fci.allFonts[j].fullName != null) {
389
props.setProperty(styleKey+"."+j+".fullName",
390
fci.allFonts[j].fullName);
391
}
392
}
393
}
394
try {
395
/* This writes into a temp file then renames when done.
396
* Since the rename is an atomic action within the same
397
* directory no client will ever see a partially written file.
398
*/
399
File fcInfoFile = getFcInfoFile();
400
File dir = fcInfoFile.getParentFile();
401
dir.mkdirs();
402
File tempFile = Files.createTempFile(dir.toPath(), "fcinfo", null).toFile();
403
FileOutputStream fos = new FileOutputStream(tempFile);
404
props.store(fos,
405
"JDK Font Configuration Generated File: *Do Not Edit*");
406
fos.close();
407
boolean renamed = tempFile.renameTo(fcInfoFile);
408
if (!renamed && FontUtilities.debugFonts()) {
409
System.out.println("rename failed");
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
if (FontUtilities.debugFonts()) {
428
warning("fontconfig info file " + fcFile.toString() + " does not exist");
429
}
430
return;
431
}
432
Properties props = new Properties();
433
try (FileInputStream fis = new FileInputStream(fcFile)) {
434
props.load(fis);
435
} catch (IOException e) {
436
if (FontUtilities.debugFonts()) {
437
warning("IOException (" + e.getCause() + ") reading from " + fcFile.toString());
438
}
439
return;
440
}
441
String version = (String)props.get("version");
442
if (version == null || !version.equals(fileVersion)) {
443
if (FontUtilities.debugFonts()) {
444
warning("fontconfig info file version mismatch (found: " + version +
445
", expected: " + fileVersion + ")");
446
}
447
return;
448
}
449
450
// If there's a new, different fontconfig installed on the
451
// system, we invalidate our fontconfig file.
452
String fcVersionStr = (String)props.get("fcversion");
453
if (fcVersionStr != null) {
454
int fcVersion;
455
try {
456
fcVersion = Integer.parseInt(fcVersionStr);
457
if (fcVersion != 0 &&
458
fcVersion != FontConfigManager.getFontConfigVersion()) {
459
if (FontUtilities.debugFonts()) {
460
warning("new, different fontconfig detected");
461
}
462
return;
463
}
464
} catch (Exception e) {
465
if (FontUtilities.debugFonts()) {
466
warning("Exception parsing version " + fcVersionStr);
467
}
468
return;
469
}
470
}
471
472
// If we can locate the fontconfig cache dirs, then compare the
473
// time stamp of those with our properties file. If we are out
474
// of date then re-generate.
475
long lastModified = fcFile.lastModified();
476
int cacheDirIndex = 0;
477
while (cacheDirIndex<4) { // should never be more than 2 anyway.
478
String dir = (String)props.get("cachedir."+cacheDirIndex);
479
if (dir == null) {
480
break;
481
}
482
File dirFile = new File(dir);
483
if (dirFile.exists() && dirFile.lastModified() > lastModified) {
484
if (FontUtilities.debugFonts()) {
485
warning("out of date cache directories detected");
486
}
487
return;
488
}
489
cacheDirIndex++;
490
}
491
492
String[] names = { "sansserif", "serif", "monospaced" };
493
String[] fcnames = { "sans", "serif", "monospace" };
494
int namesLen = names.length;
495
int numStyles = 4;
496
FcCompFont[] fci = new FcCompFont[namesLen*numStyles];
497
498
try {
499
for (int i=0; i<namesLen; i++) {
500
for (int s=0; s<numStyles; s++) {
501
int index = i*numStyles+s;
502
fci[index] = new FcCompFont();
503
String key = names[i]+"."+s;
504
fci[index].jdkName = names[i];
505
fci[index].fcFamily = fcnames[i];
506
fci[index].style = s;
507
String lenStr = (String)props.get(key+".length");
508
int nfonts = Integer.parseInt(lenStr);
509
if (nfonts <= 0) {
510
if (FontUtilities.debugFonts()) {
511
warning("bad non-positive .length entry in fontconfig file " + fcFile.toString());
512
}
513
return; // bad file
514
}
515
fci[index].allFonts = new FontConfigFont[nfonts];
516
for (int f=0; f<nfonts; f++) {
517
fci[index].allFonts[f] = new FontConfigFont();
518
String fkey = key+"."+f+".fullName";
519
String fullName = (String)props.get(fkey);
520
fci[index].allFonts[f].fullName = fullName;
521
fkey = key+"."+f+".file";
522
String file = (String)props.get(fkey);
523
if (file == null) {
524
if (FontUtilities.debugFonts()) {
525
warning("missing file value for key " + fkey + " in fontconfig file " + fcFile.toString());
526
}
527
return; // bad file
528
}
529
fci[index].allFonts[f].fontFile = file;
530
}
531
fci[index].firstFont = fci[index].allFonts[0];
532
533
}
534
}
535
fcCompFonts = fci;
536
} catch (Throwable t) {
537
if (FontUtilities.debugFonts()) {
538
warning(t.toString());
539
}
540
}
541
542
if (FontUtilities.debugFonts()) {
543
FontUtilities.logInfo("successfully parsed the fontconfig file at " + fcFile.toString());
544
}
545
}
546
547
private static void warning(String msg) {
548
PlatformLogger logger = PlatformLogger.getLogger("sun.awt.FontConfiguration");
549
logger.warning(msg);
550
}
551
}
552
553