1 /*
2  * Copyright (c) 2008, 2021, 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 
27 package sun.awt;
28 
29 import java.awt.FontFormatException;
30 import java.awt.GraphicsEnvironment;
31 import java.io.File;
32 import java.security.AccessController;
33 import java.security.PrivilegedAction;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.Locale;
37 import java.util.NoSuchElementException;
38 import java.util.StringTokenizer;
39 
40 import sun.awt.windows.WFontConfiguration;
41 import sun.font.FontManager;
42 import sun.font.SunFontManager;
43 import sun.font.TrueTypeFont;
44 
45 /**
46  * The X11 implementation of {@link FontManager}.
47  */
48 @SuppressWarnings("removal")
49 public final class Win32FontManager extends SunFontManager {
50 
51     private static TrueTypeFont eudcFont;
52 
53     static {
54 
AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { String eudcFile = getEUDCFontFile(); if (eudcFile != null) { try { eudcFont = new TrueTypeFont(eudcFile, null, 0, true, false); } catch (FontFormatException e) { } } return null; } })55         AccessController.doPrivileged(new PrivilegedAction<Object>() {
56 
57                 public Object run() {
58                     String eudcFile = getEUDCFontFile();
59                     if (eudcFile != null) {
60                         try {
61                             /* Must use Java rasteriser since GDI doesn't
62                              * enumerate (allow direct use) of EUDC fonts.
63                              */
64                             eudcFont = new TrueTypeFont(eudcFile, null, 0,
65                                                         true, false);
66                         } catch (FontFormatException e) {
67                         }
68                     }
69                     return null;
70                 }
71 
72             });
73     }
74 
75     /* Used on Windows to obtain from the windows registry the name
76      * of a file containing the system EUFC font. If running in one of
77      * the locales for which this applies, and one is defined, the font
78      * defined by this file is appended to all composite fonts as a
79      * fallback component.
80      */
getEUDCFontFile()81     private static native String getEUDCFontFile();
82 
getEUDCFont()83     public TrueTypeFont getEUDCFont() {
84         return eudcFont;
85     }
86 
Win32FontManager()87     public Win32FontManager() {
88         super();
89         AccessController.doPrivileged(new PrivilegedAction<Object>() {
90                 public Object run() {
91 
92                     /* Register the JRE fonts so that the native platform can
93                      * access them. This is used only on Windows so that when
94                      * printing the printer driver can access the fonts.
95                      */
96                     registerJREFontsWithPlatform(jreFontDirName);
97                     return null;
98                 }
99             });
100     }
101 
102     /**
103      * Whether registerFontFile expects absolute or relative
104      * font file names.
105      */
useAbsoluteFontFileNames()106     protected boolean useAbsoluteFontFileNames() {
107         return false;
108     }
109 
110     /* Unlike the shared code version, this expects a base file name -
111      * not a full path name.
112      * The font configuration file has base file names and the FontConfiguration
113      * class reports these back to the GraphicsEnvironment, so these
114      * are the componentFileNames of CompositeFonts.
115      */
registerFontFile(String fontFileName, String[] nativeNames, int fontRank, boolean defer)116     protected void registerFontFile(String fontFileName, String[] nativeNames,
117                                     int fontRank, boolean defer) {
118 
119         // REMIND: case compare depends on platform
120         if (registeredFontFiles.contains(fontFileName)) {
121             return;
122         }
123         registeredFontFiles.add(fontFileName);
124 
125         int fontFormat;
126         if (getTrueTypeFilter().accept(null, fontFileName)) {
127             fontFormat = SunFontManager.FONTFORMAT_TRUETYPE;
128         } else if (getType1Filter().accept(null, fontFileName)) {
129             fontFormat = SunFontManager.FONTFORMAT_TYPE1;
130         } else {
131             /* on windows we don't use/register native fonts */
132             return;
133         }
134 
135         if (fontPath == null) {
136             fontPath = getPlatformFontPath(noType1Font);
137         }
138 
139         /* Look in the JRE font directory first.
140          * This is playing it safe as we would want to find fonts in the
141          * JRE font directory ahead of those in the system directory
142          */
143         String tmpFontPath = jreFontDirName+File.pathSeparator+fontPath;
144         StringTokenizer parser = new StringTokenizer(tmpFontPath,
145                                                      File.pathSeparator);
146 
147         boolean found = false;
148         try {
149             while (!found && parser.hasMoreTokens()) {
150                 String newPath = parser.nextToken();
151                 boolean isJREFont = newPath.equals(jreFontDirName);
152                 File theFile = new File(newPath, fontFileName);
153                 if (theFile.canRead()) {
154                     found = true;
155                     String path = theFile.getAbsolutePath();
156                     if (defer) {
157                         registerDeferredFont(fontFileName, path,
158                                              nativeNames,
159                                              fontFormat, isJREFont,
160                                              fontRank);
161                     } else {
162                         registerFontFile(path, nativeNames,
163                                          fontFormat, isJREFont,
164                                          fontRank);
165                     }
166                     break;
167                 }
168             }
169         } catch (NoSuchElementException e) {
170             System.err.println(e);
171         }
172         if (!found) {
173             addToMissingFontFileList(fontFileName);
174         }
175     }
176 
177     @Override
createFontConfiguration()178     protected FontConfiguration createFontConfiguration() {
179 
180        FontConfiguration fc = new WFontConfiguration(this);
181        fc.init();
182        return fc;
183     }
184 
185     @Override
createFontConfiguration(boolean preferLocaleFonts, boolean preferPropFonts)186     public FontConfiguration createFontConfiguration(boolean preferLocaleFonts,
187             boolean preferPropFonts) {
188 
189         return new WFontConfiguration(this,
190                                       preferLocaleFonts,preferPropFonts);
191     }
192 
193     protected void
populateFontFileNameMap(HashMap<String,String> fontToFileMap, HashMap<String,String> fontToFamilyNameMap, HashMap<String,ArrayList<String>> familyToFontListMap, Locale locale)194         populateFontFileNameMap(HashMap<String,String> fontToFileMap,
195                                 HashMap<String,String> fontToFamilyNameMap,
196                                 HashMap<String,ArrayList<String>>
197                                 familyToFontListMap,
198                                 Locale locale) {
199 
200         populateFontFileNameMap0(fontToFileMap, fontToFamilyNameMap,
201                                  familyToFontListMap, locale);
202 
203     }
204 
205     private static native void
populateFontFileNameMap0(HashMap<String,String> fontToFileMap, HashMap<String,String> fontToFamilyNameMap, HashMap<String,ArrayList<String>> familyToFontListMap, Locale locale)206         populateFontFileNameMap0(HashMap<String,String> fontToFileMap,
207                                  HashMap<String,String> fontToFamilyNameMap,
208                                  HashMap<String,ArrayList<String>>
209                                      familyToFontListMap,
210                                  Locale locale);
211 
getFontPath(boolean noType1Fonts)212     protected synchronized native String getFontPath(boolean noType1Fonts);
213 
214     @Override
getDefaultPlatformFont()215     protected String[] getDefaultPlatformFont() {
216         String[] info = new String[2];
217         info[0] = "Arial";
218         info[1] = "c:\\windows\\fonts";
219         final String[] dirs = getPlatformFontDirs(true);
220         if (dirs.length > 1) {
221             String dir = (String)
222                 AccessController.doPrivileged(new PrivilegedAction<Object>() {
223                         public Object run() {
224                             for (int i=0; i<dirs.length; i++) {
225                                 String path =
226                                     dirs[i] + File.separator + "arial.ttf";
227                                 File file = new File(path);
228                                 if (file.exists()) {
229                                     return dirs[i];
230                                 }
231                             }
232                             return null;
233                         }
234                     });
235             if (dir != null) {
236                 info[1] = dir;
237             }
238         } else {
239             info[1] = dirs[0];
240         }
241         info[1] = info[1] + File.separator + "arial.ttf";
242         return info;
243     }
244 
245     /* register only TrueType/OpenType fonts
246      * Because these need to be registed just for use when printing,
247      * we defer the actual registration and the static initialiser
248      * for the printing class makes the call to registerJREFontsForPrinting()
249      */
250     static String fontsForPrinting = null;
registerJREFontsWithPlatform(String pathName)251     protected void registerJREFontsWithPlatform(String pathName) {
252         fontsForPrinting = pathName;
253     }
254 
registerJREFontsForPrinting()255     public static void registerJREFontsForPrinting() {
256         final String pathName;
257         synchronized (Win32GraphicsEnvironment.class) {
258             GraphicsEnvironment.getLocalGraphicsEnvironment();
259             if (fontsForPrinting == null) {
260                 return;
261             }
262             pathName = fontsForPrinting;
263             fontsForPrinting = null;
264         }
265         java.security.AccessController.doPrivileged(
266             new java.security.PrivilegedAction<Object>() {
267                 public Object run() {
268                     File f1 = new File(pathName);
269                     String[] ls = f1.list(SunFontManager.getInstance().
270                             getTrueTypeFilter());
271                     if (ls == null) {
272                         return null;
273                     }
274                     for (int i=0; i <ls.length; i++ ) {
275                         File fontFile = new File(f1, ls[i]);
276                         registerFontWithPlatform(fontFile.getAbsolutePath());
277                     }
278                     return null;
279                 }
280          });
281     }
282 
registerFontWithPlatform(String fontName)283     private static native void registerFontWithPlatform(String fontName);
284 
deRegisterFontWithPlatform(String fontName)285     private static native void deRegisterFontWithPlatform(String fontName);
286 
287     /**
288      * populate the map with the most common windows fonts.
289      */
290     @Override
populateHardcodedFileNameMap()291     public HashMap<String, FamilyDescription> populateHardcodedFileNameMap() {
292         HashMap<String, FamilyDescription> platformFontMap
293             = new HashMap<String, FamilyDescription>();
294         FamilyDescription fd;
295 
296         /* Segoe UI is the default UI font for Vista and later, and
297          * is used by the Win L&F which is used by FX too.
298          * Tahoma is used for the Win L&F on XP.
299          * Verdana is used in some FX UI controls.
300          */
301         fd = new FamilyDescription();
302         fd.familyName = "Segoe UI";
303         fd.plainFullName = "Segoe UI";
304         fd.plainFileName = "segoeui.ttf";
305         fd.boldFullName = "Segoe UI Bold";
306         fd.boldFileName = "segoeuib.ttf";
307         fd.italicFullName = "Segoe UI Italic";
308         fd.italicFileName = "segoeuii.ttf";
309         fd.boldItalicFullName = "Segoe UI Bold Italic";
310         fd.boldItalicFileName = "segoeuiz.ttf";
311         platformFontMap.put("segoe", fd);
312 
313         fd = new FamilyDescription();
314         fd.familyName = "Tahoma";
315         fd.plainFullName = "Tahoma";
316         fd.plainFileName = "tahoma.ttf";
317         fd.boldFullName = "Tahoma Bold";
318         fd.boldFileName = "tahomabd.ttf";
319         platformFontMap.put("tahoma", fd);
320 
321         fd = new FamilyDescription();
322         fd.familyName = "Verdana";
323         fd.plainFullName = "Verdana";
324         fd.plainFileName = "verdana.TTF";
325         fd.boldFullName = "Verdana Bold";
326         fd.boldFileName = "verdanab.TTF";
327         fd.italicFullName = "Verdana Italic";
328         fd.italicFileName = "verdanai.TTF";
329         fd.boldItalicFullName = "Verdana Bold Italic";
330         fd.boldItalicFileName = "verdanaz.TTF";
331         platformFontMap.put("verdana", fd);
332 
333         /* The following are important because they are the core
334          * members of the default "Dialog" font.
335          */
336         fd = new FamilyDescription();
337         fd.familyName = "Arial";
338         fd.plainFullName = "Arial";
339         fd.plainFileName = "ARIAL.TTF";
340         fd.boldFullName = "Arial Bold";
341         fd.boldFileName = "ARIALBD.TTF";
342         fd.italicFullName = "Arial Italic";
343         fd.italicFileName = "ARIALI.TTF";
344         fd.boldItalicFullName = "Arial Bold Italic";
345         fd.boldItalicFileName = "ARIALBI.TTF";
346         platformFontMap.put("arial", fd);
347 
348         fd = new FamilyDescription();
349         fd.familyName = "Symbol";
350         fd.plainFullName = "Symbol";
351         fd.plainFileName = "Symbol.TTF";
352         platformFontMap.put("symbol", fd);
353 
354         fd = new FamilyDescription();
355         fd.familyName = "WingDings";
356         fd.plainFullName = "WingDings";
357         fd.plainFileName = "WINGDING.TTF";
358         platformFontMap.put("wingdings", fd);
359 
360         return platformFontMap;
361     }
362 }
363