| /* |
| * Copyright (c) 2002, 2010, 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 com.sun.java.swing.plaf.gtk; |
| |
| import java.awt.*; |
| import java.awt.geom.AffineTransform; |
| import javax.swing.plaf.FontUIResource; |
| import java.util.StringTokenizer; |
| |
| import sun.font.FontConfigManager; |
| import sun.font.FontUtilities; |
| |
| /** |
| * @author Shannon Hickey |
| * @author Leif Samuelsson |
| */ |
| class PangoFonts { |
| |
| public static final String CHARS_DIGITS = "0123456789"; |
| |
| /** |
| * Calculate a default scale factor for fonts in this L&F to match |
| * the reported resolution of the screen. |
| * Java 2D specified a default user-space scale of 72dpi. |
| * This is unlikely to correspond to that of the real screen. |
| * The Xserver reports a value which may be used to adjust for this. |
| * and Java 2D exposes it via a normalizing transform. |
| * However many Xservers report a hard-coded 90dpi whilst others report a |
| * calculated value based on possibly incorrect data. |
| * That is something that must be solved at the X11 level |
| * Note that in an X11 multi-screen environment, the default screen |
| * is the one used by the JRE so it is safe to use it here. |
| */ |
| private static double fontScale; |
| |
| static { |
| fontScale = 1.0d; |
| GraphicsEnvironment ge = |
| GraphicsEnvironment.getLocalGraphicsEnvironment(); |
| |
| if (!ge.isHeadless()) { |
| GraphicsConfiguration gc = |
| ge.getDefaultScreenDevice().getDefaultConfiguration(); |
| AffineTransform at = gc.getNormalizingTransform(); |
| fontScale = at.getScaleY(); |
| } |
| } |
| |
| |
| /** |
| * Parses a String containing a pango font description and returns |
| * a Font object. |
| * |
| * @param pangoName a String describing a pango font |
| * e.g. "Sans Italic 10" |
| * @return a Font object as a FontUIResource |
| * or null if no suitable font could be created. |
| */ |
| static Font lookupFont(String pangoName) { |
| String family = ""; |
| int style = Font.PLAIN; |
| int size = 10; |
| |
| StringTokenizer tok = new StringTokenizer(pangoName); |
| |
| while (tok.hasMoreTokens()) { |
| String word = tok.nextToken(); |
| |
| if (word.equalsIgnoreCase("italic")) { |
| style |= Font.ITALIC; |
| } else if (word.equalsIgnoreCase("bold")) { |
| style |= Font.BOLD; |
| } else if (CHARS_DIGITS.indexOf(word.charAt(0)) != -1) { |
| try { |
| size = Integer.parseInt(word); |
| } catch (NumberFormatException ex) { |
| } |
| } else { |
| if (family.length() > 0) { |
| family += " "; |
| } |
| |
| family += word; |
| } |
| } |
| |
| /* |
| * Java 2D font point sizes are in a user-space scale of 72dpi. |
| * GTK allows a user to configure a "dpi" property used to scale |
| * the fonts used to match a user's preference. |
| * To match the font size of GTK apps we need to obtain this DPI and |
| * adjust as follows: |
| * Some versions of GTK use XSETTINGS if available to dynamically |
| * monitor user-initiated changes in the DPI to be used by GTK |
| * apps. This value is also made available as the Xft.dpi X resource. |
| * This is presumably a function of the font preferences API and/or |
| * the manner in which it requests the toolkit to update the default |
| * for the desktop. This dual approach is probably necessary since |
| * other versions of GTK - or perhaps some apps - determine the size |
| * to use only at start-up from that X resource. |
| * If that resource is not set then GTK scales for the DPI resolution |
| * reported by the Xserver using the formula |
| * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) * 25.4 |
| * (25.4mm == 1 inch). |
| * JDK tracks the Xft.dpi XSETTINGS property directly so it can |
| * dynamically change font size by tracking just that value. |
| * If that resource is not available use the same fall back formula |
| * as GTK (see calculation for fontScale). |
| * |
| * GTK's default setting for Xft.dpi is 96 dpi (and it seems -1 |
| * apparently also can mean that "default"). However this default |
| * isn't used if there's no property set. The real default in the |
| * absence of a resource is the Xserver reported dpi. |
| * Finally this DPI is used to calculate the nearest Java 2D font |
| * 72 dpi font size. |
| * There are cases in which JDK behaviour may not exactly mimic |
| * GTK native app behaviour : |
| * 1) When a GTK app is not able to dynamically track the changes |
| * (does not use XSETTINGS), JDK will resize but other apps will |
| * not. This is OK as JDK is exhibiting preferred behaviour and |
| * this is probably how all later GTK apps will behave |
| * 2) When a GTK app does not use XSETTINGS and for some reason |
| * the XRDB property is not present. JDK will pick up XSETTINGS |
| * and the GTK app will use the Xserver default. Since its |
| * impossible for JDK to know that some other GTK app is not |
| * using XSETTINGS its impossible to account for this and in any |
| * case for it to be a problem the values would have to be different. |
| * It also seems unlikely to arise except when a user explicitly |
| * deletes the X resource database entry. |
| * There also some other issues to be aware of for the future: |
| * GTK specifies the Xft.dpi value as server-wide which when used |
| * on systems with 2 distinct X screens with different physical DPI |
| * the font sizes will inevitably appear different. It would have |
| * been a more user-friendly design to further adjust that one |
| * setting depending on the screen resolution to achieve perceived |
| * equivalent sizes. If such a change were ever to be made in GTK |
| * we would need to update for that. |
| */ |
| double dsize = size; |
| int dpi = 96; |
| Object value = |
| Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/DPI"); |
| if (value instanceof Integer) { |
| dpi = ((Integer)value).intValue() / 1024; |
| if (dpi == -1) { |
| dpi = 96; |
| } |
| if (dpi < 50) { /* 50 dpi is the minimum value gnome allows */ |
| dpi = 50; |
| } |
| /* The Java rasteriser assumes pts are in a user space of |
| * 72 dpi, so we need to adjust for that. |
| */ |
| dsize = ((double)(dpi * size)/ 72.0); |
| } else { |
| /* If there's no property, GTK scales for the resolution |
| * reported by the Xserver using the formula listed above. |
| * fontScale already accounts for the 72 dpi Java 2D space. |
| */ |
| dsize = size * fontScale; |
| } |
| |
| /* Round size to nearest integer pt size */ |
| size = (int)(dsize + 0.5); |
| if (size < 1) { |
| size = 1; |
| } |
| |
| String fcFamilyLC = family.toLowerCase(); |
| if (FontUtilities.mapFcName(fcFamilyLC) != null) { |
| /* family is a Fc/Pango logical font which we need to expand. */ |
| Font font = FontUtilities.getFontConfigFUIR(fcFamilyLC, style, size); |
| font = font.deriveFont(style, (float)dsize); |
| return new FontUIResource(font); |
| } else { |
| /* It's a physical font which we will create with a fallback */ |
| Font font = new Font(family, style, size); |
| /* a roundabout way to set the font size in floating points */ |
| font = font.deriveFont(style, (float)dsize); |
| FontUIResource fuir = new FontUIResource(font); |
| return FontUtilities.getCompositeFontUIResource(fuir); |
| } |
| } |
| |
| /** |
| * Parses a String containing a pango font description and returns |
| * the (unscaled) font size as an integer. |
| * |
| * @param pangoName a String describing a pango font |
| * @return the size of the font described by pangoName (e.g. if |
| * pangoName is "Sans Italic 10", then this method returns 10) |
| */ |
| static int getFontSize(String pangoName) { |
| int size = 10; |
| |
| StringTokenizer tok = new StringTokenizer(pangoName); |
| while (tok.hasMoreTokens()) { |
| String word = tok.nextToken(); |
| |
| if (CHARS_DIGITS.indexOf(word.charAt(0)) != -1) { |
| try { |
| size = Integer.parseInt(word); |
| } catch (NumberFormatException ex) { |
| } |
| } |
| } |
| |
| return size; |
| } |
| } |