Ignore:
Timestamp:
2016-10-24T12:42:06+02:00 (9 years ago)
Author:
bastiK
Message:

rework/simplify inheritance structure of PlatformHook

PlatformHookUnixoid is no longer base class of PlatformHookWindows
and PlatformHookOsx; move common methods to PlatformHook

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java

    r10627 r11156  
    2929
    3030import java.awt.GraphicsEnvironment;
     31import java.io.BufferedWriter;
    3132import java.io.File;
     33import java.io.FileInputStream;
    3234import java.io.IOException;
     35import java.io.OutputStream;
     36import java.io.OutputStreamWriter;
     37import java.io.Writer;
     38import java.nio.charset.StandardCharsets;
    3339import java.nio.file.DirectoryStream;
    3440import java.nio.file.FileSystems;
     
    5157import java.util.List;
    5258import java.util.Locale;
     59import java.util.Properties;
    5360
    5461import javax.swing.JOptionPane;
    5562
    5663import org.openstreetmap.josm.Main;
     64import org.openstreetmap.josm.data.Preferences;
    5765
    5866/**
     
    6068  * @since 1023
    6169  */
    62 public class PlatformHookWindows extends PlatformHookUnixoid {
    63 
    64     @Override
    65     public void startupHook() {
    66         // Do nothing
     70public class PlatformHookWindows implements PlatformHook {
     71
     72    /**
     73     * Simple data class to hold information about a font.
     74     *
     75     * Used for fontconfig.properties files.
     76     */
     77    public static class FontEntry {
     78        /**
     79         * The character subset. Basically a free identifier, but should be unique.
     80         */
     81        @Preferences.pref
     82        public String charset;
     83
     84        /**
     85         * Platform font name.
     86         */
     87        @Preferences.pref
     88        @Preferences.writeExplicitly
     89        public String name = "";
     90
     91        /**
     92         * File name.
     93         */
     94        @Preferences.pref
     95        @Preferences.writeExplicitly
     96        public String file = "";
     97
     98        /**
     99         * Constructs a new {@code FontEntry}.
     100         */
     101        public FontEntry() {
     102        }
     103
     104        /**
     105         * Constructs a new {@code FontEntry}.
     106         * @param charset The character subset. Basically a free identifier, but should be unique
     107         * @param name Platform font name
     108         * @param file File name
     109         */
     110        public FontEntry(String charset, String name, String file) {
     111            this.charset = charset;
     112            this.name = name;
     113            this.file = file;
     114        }
    67115    }
    68116
     
    319367
    320368    @Override
    321     public Collection<String> getInstalledFonts() {
     369    public File getDefaultUserDataDirectory() {
     370        // Use preferences directory by default
     371        return Main.pref.getPreferencesDirectory();
     372    }
     373
     374    /**
     375     * <p>Add more fallback fonts to the Java runtime, in order to get
     376     * support for more scripts.</p>
     377     *
     378     * <p>The font configuration in Java doesn't include some Indic scripts,
     379     * even though MS Windows ships with fonts that cover these unicode ranges.</p>
     380     *
     381     * <p>To fix this, the fontconfig.properties template is copied to the JOSM
     382     * cache folder. Then, the additional entries are added to the font
     383     * configuration. Finally the system property "sun.awt.fontconfig" is set
     384     * to the customized fontconfig.properties file.</p>
     385     *
     386     * <p>This is a crude hack, but better than no font display at all for these languages.
     387     * There is no guarantee, that the template file
     388     * ($JAVA_HOME/lib/fontconfig.properties.src) matches the default
     389     * configuration (which is in a binary format).
     390     * Furthermore, the system property "sun.awt.fontconfig" is undocumented and
     391     * may no longer work in future versions of Java.</p>
     392     *
     393     * <p>Related Java bug: <a href="https://bugs.openjdk.java.net/browse/JDK-8008572">JDK-8008572</a></p>
     394     *
     395     * @param templateFileName file name of the fontconfig.properties template file
     396     */
     397    protected void extendFontconfig(String templateFileName) {
     398        String customFontconfigFile = Main.pref.get("fontconfig.properties", null);
     399        if (customFontconfigFile != null) {
     400            Utils.updateSystemProperty("sun.awt.fontconfig", customFontconfigFile);
     401            return;
     402        }
     403        if (!Main.pref.getBoolean("font.extended-unicode", true))
     404            return;
     405
     406        String javaLibPath = System.getProperty("java.home") + File.separator + "lib";
     407        Path templateFile = FileSystems.getDefault().getPath(javaLibPath, templateFileName);
     408        if (!Files.isReadable(templateFile)) {
     409            Main.warn("extended font config - unable to find font config template file "+templateFile.toString());
     410            return;
     411        }
     412        try (FileInputStream fis = new FileInputStream(templateFile.toFile())) {
     413            Properties props = new Properties();
     414            props.load(fis);
     415            byte[] content = Files.readAllBytes(templateFile);
     416            File cachePath = Main.pref.getCacheDirectory();
     417            Path fontconfigFile = cachePath.toPath().resolve("fontconfig.properties");
     418            OutputStream os = Files.newOutputStream(fontconfigFile);
     419            os.write(content);
     420            try (Writer w = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
     421                Collection<FontEntry> extrasPref = Main.pref.getListOfStructs(
     422                        "font.extended-unicode.extra-items", getAdditionalFonts(), FontEntry.class);
     423                Collection<FontEntry> extras = new ArrayList<>();
     424                w.append("\n\n# Added by JOSM to extend unicode coverage of Java font support:\n\n");
     425                List<String> allCharSubsets = new ArrayList<>();
     426                for (FontEntry entry: extrasPref) {
     427                    Collection<String> fontsAvail = getInstalledFonts();
     428                    if (fontsAvail != null && fontsAvail.contains(entry.file.toUpperCase(Locale.ENGLISH))) {
     429                        if (!allCharSubsets.contains(entry.charset)) {
     430                            allCharSubsets.add(entry.charset);
     431                            extras.add(entry);
     432                        } else {
     433                            Main.trace("extended font config - already registered font for charset ''{0}'' - skipping ''{1}''",
     434                                    entry.charset, entry.name);
     435                        }
     436                    } else {
     437                        Main.trace("extended font config - Font ''{0}'' not found on system - skipping", entry.name);
     438                    }
     439                }
     440                for (FontEntry entry: extras) {
     441                    allCharSubsets.add(entry.charset);
     442                    if ("".equals(entry.name)) {
     443                        continue;
     444                    }
     445                    String key = "allfonts." + entry.charset;
     446                    String value = entry.name;
     447                    String prevValue = props.getProperty(key);
     448                    if (prevValue != null && !prevValue.equals(value)) {
     449                        Main.warn("extended font config - overriding ''{0}={1}'' with ''{2}''", key, prevValue, value);
     450                    }
     451                    w.append(key + '=' + value + '\n');
     452                }
     453                w.append('\n');
     454                for (FontEntry entry: extras) {
     455                    if ("".equals(entry.name) || "".equals(entry.file)) {
     456                        continue;
     457                    }
     458                    String key = "filename." + entry.name.replace(' ', '_');
     459                    String value = entry.file;
     460                    String prevValue = props.getProperty(key);
     461                    if (prevValue != null && !prevValue.equals(value)) {
     462                        Main.warn("extended font config - overriding ''{0}={1}'' with ''{2}''", key, prevValue, value);
     463                    }
     464                    w.append(key + '=' + value + '\n');
     465                }
     466                w.append('\n');
     467                String fallback = props.getProperty("sequence.fallback");
     468                if (fallback != null) {
     469                    w.append("sequence.fallback=" + fallback + ',' + Utils.join(",", allCharSubsets) + '\n');
     470                } else {
     471                    w.append("sequence.fallback=" + Utils.join(",", allCharSubsets) + '\n');
     472                }
     473            }
     474            Utils.updateSystemProperty("sun.awt.fontconfig", fontconfigFile.toString());
     475        } catch (IOException ex) {
     476            Main.error(ex);
     477        }
     478    }
     479
     480    /**
     481     * Get a list of fonts that are installed on the system.
     482     *
     483     * Must be done without triggering the Java Font initialization.
     484     * (See {@link #extendFontconfig(java.lang.String)}, have to set system
     485     * property first, which is then read by sun.awt.FontConfiguration upon initialization.)
     486     *
     487     * @return list of file names
     488     */
     489    protected Collection<String> getInstalledFonts() {
    322490        // Cannot use GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()
    323491        // because we have to set the system property before Java initializes its fonts.
     
    341509    }
    342510
    343     @Override
    344     public Collection<FontEntry> getAdditionalFonts() {
     511    /**
     512     * Get default list of additional fonts to add to the configuration.
     513     *
     514     * Java will choose thee first font in the list that can render a certain character.
     515     *
     516     * @return list of FontEntry objects
     517     */
     518    protected Collection<FontEntry> getAdditionalFonts() {
    345519        Collection<FontEntry> def = new ArrayList<>(33);
    346520        def.add(new FontEntry("devanagari", "", "")); // just include in fallback list font already defined in template
Note: See TracChangeset for help on using the changeset viewer.