/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.desktop/unix/classes/sun/font/FcFontConfiguration.java
542 строки
20 KB
Sergey Bylokhov
8374310: Update copyright year to 2025 for client-libs in files where it was missed
25 дек 2025, 04:25
25 дек 2025, 04:25
73a8629
Код
Авторство
О чём код?
/* * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.font; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Properties; import java.util.Scanner; import sun.awt.FcFontManager; import sun.awt.FontConfiguration; import sun.awt.FontDescriptor; import sun.awt.SunToolkit; import sun.font.FontConfigManager.FcCompFont; import sun.font.FontConfigManager.FontConfigFont; import sun.font.FontConfigManager.FontConfigInfo; import sun.util.logging.PlatformLogger; import static java.nio.charset.StandardCharsets.ISO_8859_1; public final class FcFontConfiguration extends FontConfiguration { /** Version of the cache file format understood by this code. * Its part of the file name so that we can rev this at * any time, even in a minor JDK update. * It is stored as the value of the "version" property. * This is distinct from the version of "libfontconfig" that generated * the cached results, and which is the "fcversion" property in the file. * {@code FontConfiguration.getVersion()} also returns a version string, * and has meant the version of the fontconfiguration.properties file * that was read. Since this class doesn't use such files, then what * that really means is whether the methods on this class return * values that are compatible with the classes that do directly read * from such files. It is a compatible subset of version "1". */ private static final String fileVersion = "1"; private String fcInfoFileName = null; private FcCompFont[] fcCompFonts = null; public FcFontConfiguration(SunFontManager fm) { super(fm); init(); } /* This isn't called but is needed to satisfy super-class contract. */ public FcFontConfiguration(SunFontManager fm, boolean preferLocaleFonts, boolean preferPropFonts) { super(fm, preferLocaleFonts, preferPropFonts); init(); } @Override public synchronized boolean init() { if (fcCompFonts != null) { return true; } setFontConfiguration(); readFcInfo(); FcFontManager fm = (FcFontManager) fontManager; FontConfigManager fcm = fm.getFontConfigManager(); if (fcCompFonts == null) { fcCompFonts = fcm.loadFontConfig(); if (fcCompFonts != null) { try { writeFcInfo(); } catch (Exception e) { if (FontUtilities.debugFonts()) { warning("Exception writing fcInfo " + e); } } } else if (FontUtilities.debugFonts()) { warning("Failed to get info from libfontconfig"); } } else { fcm.populateFontConfig(fcCompFonts); } if (fcCompFonts == null) { return false; // couldn't load fontconfig. } // NB already in a privileged block from SGE String javaHome = System.getProperty("java.home"); if (javaHome == null) { throw new Error("java.home property not set"); } String javaLib = javaHome + File.separator + "lib"; getInstalledFallbackFonts(javaLib); return true; } @Override public String getFallbackFamilyName(String fontName, String defaultFallback) { // maintain compatibility with old font.properties files, which either // had aliases for TimesRoman & Co. or defined mappings for them. String compatibilityName = getCompatibilityFamilyName(fontName); if (compatibilityName != null) { return compatibilityName; } return defaultFallback; } @Override protected String getFaceNameFromComponentFontName(String componentFontName) { return null; } @Override protected String getFileNameFromComponentFontName(String componentFontName) { return null; } @Override public String getFileNameFromPlatformName(String platformName) { /* Platform name is the file name, but rather than returning * the arg, return null*/ return null; } @Override protected Charset getDefaultFontCharset(String fontName) { return ISO_8859_1; } @Override protected String getEncoding(String awtFontName, String characterSubsetName) { return "default"; } @Override protected void initReorderMap() { reorderMap = new HashMap<>(); } @Override protected FontDescriptor[] buildFontDescriptors(int fontIndex, int styleIndex) { CompositeFontDescriptor[] cfi = get2DCompositeFontInfo(); int idx = fontIndex * NUM_STYLES + styleIndex; String[] componentFaceNames = cfi[idx].getComponentFaceNames(); FontDescriptor[] ret = new FontDescriptor[componentFaceNames.length]; for (int i = 0; i < componentFaceNames.length; i++) { ret[i] = new FontDescriptor(componentFaceNames[i], ISO_8859_1.newEncoder(), new int[0]); } return ret; } @Override public int getNumberCoreFonts() { return 1; } @Override public String[] getPlatformFontNames() { HashSet<String> nameSet = new HashSet<String>(); FcFontManager fm = (FcFontManager) fontManager; FontConfigManager fcm = fm.getFontConfigManager(); FcCompFont[] fcCompFonts = fcm.loadFontConfig(); for (int i=0; i<fcCompFonts.length; i++) { for (int j=0; j<fcCompFonts[i].allFonts.length; j++) { nameSet.add(fcCompFonts[i].allFonts[j].fontFile); } } return nameSet.toArray(new String[0]); } @Override public String getExtraFontPath() { return null; } @Override public boolean needToSearchForFile(String fileName) { return false; } private FontConfigFont[] getFcFontList(FcCompFont[] fcFonts, String fontname, int style) { if (fontname.equals("dialog")) { fontname = "sansserif"; } else if (fontname.equals("dialoginput")) { fontname = "monospaced"; } for (int i=0; i<fcFonts.length; i++) { if (fontname.equals(fcFonts[i].jdkName) && style == fcFonts[i].style) { return fcFonts[i].allFonts; } } return fcFonts[0].allFonts; } @Override public CompositeFontDescriptor[] get2DCompositeFontInfo() { FcFontManager fm = (FcFontManager) fontManager; FontConfigManager fcm = fm.getFontConfigManager(); FcCompFont[] fcCompFonts = fcm.loadFontConfig(); CompositeFontDescriptor[] result = new CompositeFontDescriptor[NUM_FONTS * NUM_STYLES]; for (int fontIndex = 0; fontIndex < NUM_FONTS; fontIndex++) { String fontName = publicFontNames[fontIndex]; for (int styleIndex = 0; styleIndex < NUM_STYLES; styleIndex++) { String faceName = fontName + "." + styleNames[styleIndex]; FontConfigFont[] fcFonts = getFcFontList(fcCompFonts, fontNames[fontIndex], styleIndex); int numFonts = fcFonts.length; // fall back fonts listed in the lib/fonts/fallback directory if (installedFallbackFontFiles != null) { numFonts += installedFallbackFontFiles.length; } String[] fileNames = new String[numFonts]; String[] faceNames = new String[numFonts]; int index; for (index = 0; index < fcFonts.length; index++) { fileNames[index] = fcFonts[index].fontFile; faceNames[index] = fcFonts[index].fullName; } if (installedFallbackFontFiles != null) { System.arraycopy(installedFallbackFontFiles, 0, fileNames, fcFonts.length, installedFallbackFontFiles.length); } result[fontIndex * NUM_STYLES + styleIndex] = new CompositeFontDescriptor( faceName, 1, faceNames, fileNames, null, null); } } return result; } /** * Gets the OS version string from a Linux release-specific file. */ private String getVersionString(File f) { try (Scanner sc = new Scanner(f)) { return sc.findInLine("(\\d)+((\\.)(\\d)+)*"); } catch (Exception e) { } return null; } private String extractInfo(String s) { if (s == null) { return null; } if (s.startsWith("\"")) s = s.substring(1); if (s.endsWith("\"")) s = s.substring(0, s.length()-1); s = s.replace(' ', '_'); return s; } /** * Sets the OS name and version from environment information. */ @Override protected void setOsNameAndVersion() { super.setOsNameAndVersion(); if (!osName.equals("Linux")) { return; } try { File f = new File("/etc/os-release"); if (f.canRead()) { Properties props = new Properties(); try (FileInputStream fis = new FileInputStream(f)) { props.load(fis); } osName = extractInfo(props.getProperty("ID")); osVersion = extractInfo(props.getProperty("VERSION_ID")); } } catch (Exception e) { if (FontUtilities.debugFonts()) { warning("Exception identifying Linux distro."); } } } private File getFcInfoFile() { if (fcInfoFileName == null) { String hostname; try { hostname = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { hostname = "localhost"; } String userDir = System.getProperty("user.home"); String version = System.getProperty("java.version"); String fs = File.separator; String dir = userDir+fs+".java"+fs+"fonts"+fs+version; Locale locale = SunToolkit.getStartupLocale(); String lang = locale.getLanguage(); String country = locale.getCountry(); String name = "fcinfo-"+fileVersion+"-"+hostname+"-"+ osName+"-"+osVersion+"-"+lang+"-"+country+".properties"; fcInfoFileName = dir+fs+name; } return new File(fcInfoFileName); } private void writeFcInfo() { Properties props = new Properties(); props.setProperty("version", fileVersion); FcFontManager fm = (FcFontManager) fontManager; FontConfigManager fcm = fm.getFontConfigManager(); FontConfigInfo fcInfo = fcm.getFontConfigInfo(); props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion)); if (fcInfo.cacheDirs != null) { for (int i=0;i<fcInfo.cacheDirs.length;i++) { if (fcInfo.cacheDirs[i] != null) { props.setProperty("cachedir."+i, fcInfo.cacheDirs[i]); } } } for (int i=0; i<fcCompFonts.length; i++) { FcCompFont fci = fcCompFonts[i]; String styleKey = fci.jdkName+"."+fci.style; props.setProperty(styleKey+".length", Integer.toString(fci.allFonts.length)); for (int j=0; j<fci.allFonts.length; j++) { props.setProperty(styleKey+"."+j+".file", fci.allFonts[j].fontFile); if (fci.allFonts[j].fullName != null) { props.setProperty(styleKey+"."+j+".fullName", fci.allFonts[j].fullName); } } } try { /* This writes into a temp file then renames when done. * Since the rename is an atomic action within the same * directory no client will ever see a partially written file. */ File fcInfoFile = getFcInfoFile(); File dir = fcInfoFile.getParentFile(); dir.mkdirs(); File tempFile = Files.createTempFile(dir.toPath(), "fcinfo", null).toFile(); try (FileOutputStream fos = new FileOutputStream(tempFile)) { props.store(fos, "JDK Font Configuration Generated File: *Do Not Edit*"); } boolean renamed = tempFile.renameTo(fcInfoFile); if (!renamed && FontUtilities.debugFonts()) { System.out.println("rename failed"); warning("Failed renaming file to "+ getFcInfoFile()); } } catch (Exception e) { if (FontUtilities.debugFonts()) { warning("IOException writing to "+ getFcInfoFile()); } } } /* We want to be able to use this cache instead of invoking * fontconfig except when we can detect the system cache has changed. * But there doesn't seem to be a way to find the location of * the system cache. */ private void readFcInfo() { File fcFile = getFcInfoFile(); if (!fcFile.exists()) { if (FontUtilities.debugFonts()) { warning("fontconfig info file " + fcFile.toString() + " does not exist"); } return; } Properties props = new Properties(); try (FileInputStream fis = new FileInputStream(fcFile)) { props.load(fis); } catch (IOException e) { if (FontUtilities.debugFonts()) { warning("IOException (" + e.getCause() + ") reading from " + fcFile.toString()); } return; } String version = (String)props.get("version"); if (version == null || !version.equals(fileVersion)) { if (FontUtilities.debugFonts()) { warning("fontconfig info file version mismatch (found: " + version + ", expected: " + fileVersion + ")"); } return; } // If there's a new, different fontconfig installed on the // system, we invalidate our fontconfig file. String fcVersionStr = (String)props.get("fcversion"); if (fcVersionStr != null) { int fcVersion; try { fcVersion = Integer.parseInt(fcVersionStr); if (fcVersion != 0 && fcVersion != FontConfigManager.getFontConfigVersion()) { if (FontUtilities.debugFonts()) { warning("new, different fontconfig detected"); } return; } } catch (Exception e) { if (FontUtilities.debugFonts()) { warning("Exception parsing version " + fcVersionStr); } return; } } // If we can locate the fontconfig cache dirs, then compare the // time stamp of those with our properties file. If we are out // of date then re-generate. long lastModified = fcFile.lastModified(); int cacheDirIndex = 0; while (cacheDirIndex<4) { // should never be more than 2 anyway. String dir = (String)props.get("cachedir."+cacheDirIndex); if (dir == null) { break; } File dirFile = new File(dir); if (dirFile.exists() && dirFile.lastModified() > lastModified) { if (FontUtilities.debugFonts()) { warning("out of date cache directories detected"); } return; } cacheDirIndex++; } String[] names = { "sansserif", "serif", "monospaced" }; String[] fcnames = { "sans", "serif", "monospace" }; int namesLen = names.length; int numStyles = 4; FcCompFont[] fci = new FcCompFont[namesLen*numStyles]; try { for (int i=0; i<namesLen; i++) { for (int s=0; s<numStyles; s++) { int index = i*numStyles+s; fci[index] = new FcCompFont(); String key = names[i]+"."+s; fci[index].jdkName = names[i]; fci[index].fcFamily = fcnames[i]; fci[index].style = s; String lenStr = (String)props.get(key+".length"); int nfonts = Integer.parseInt(lenStr); if (nfonts <= 0) { if (FontUtilities.debugFonts()) { warning("bad non-positive .length entry in fontconfig file " + fcFile.toString()); } return; // bad file } fci[index].allFonts = new FontConfigFont[nfonts]; for (int f=0; f<nfonts; f++) { fci[index].allFonts[f] = new FontConfigFont(); String fkey = key+"."+f+".fullName"; String fullName = (String)props.get(fkey); fci[index].allFonts[f].fullName = fullName; fkey = key+"."+f+".file"; String file = (String)props.get(fkey); if (file == null) { if (FontUtilities.debugFonts()) { warning("missing file value for key " + fkey + " in fontconfig file " + fcFile.toString()); } return; // bad file } fci[index].allFonts[f].fontFile = file; } fci[index].firstFont = fci[index].allFonts[0]; } } fcCompFonts = fci; } catch (Throwable t) { if (FontUtilities.debugFonts()) { warning(t.toString()); } } if (FontUtilities.debugFonts()) { FontUtilities.logInfo("successfully parsed the fontconfig file at " + fcFile.toString()); } } private static void warning(String msg) { PlatformLogger logger = PlatformLogger.getLogger("sun.awt.FontConfiguration"); logger.warning(msg); } }