1 /*
   2  * Copyright (c) 2008, 2016, 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 javafx.scene.text;
  27 
  28 import com.sun.javafx.text.FontHelper;
  29 import java.io.FilePermission;
  30 import java.io.InputStream;
  31 import java.net.URL;
  32 import java.net.URLConnection;
  33 import java.util.List;
  34 
  35 import com.sun.javafx.tk.Toolkit;
  36 import javafx.beans.NamedArg;
  37 
  38 /**
  39  * <p>The {@code Font} class represents fonts, which are used to render text on
  40  * screen.
  41  * <p>
  42  * The size of a {@code Font} is described as being specified in points
  43  * which are a real world measurement of approximately 1/72 inch.
  44  * <p>
  45  * Given that fonts scale with the rendering transform as determined
  46  * by the transform attributes of a {@code Node} using the {@code Font}
  47  * and its ancestors, the size will actually be relative to the local
  48  * coordinate space of the node, which should provide coordinates
  49  * similar to the size of a point if no scaling transforms are present
  50  * in the environment of the node.
  51  * Note that the real world distances specified by the default coordinate
  52  * system only approximate point sizes as a rule of thumb and are typically
  53  * defaulted to screen pixels for most displays.
  54  * <p>
  55  * For more information see {@link javafx.scene.Node} for more information
  56  * on the default coordinate system
  57  * @since JavaFX 2.0
  58  */
  59 public final class Font {
  60 
  61     static {
  62         // This is used by classes in different packages to get access to
  63         // private and package private methods.
  64         FontHelper.setFontAccessor(new FontHelper.FontAccessor() {
  65 
  66             @Override
  67             public Object getNativeFont(Font font) {
  68                 return font.getNativeFont();
  69             }
  70 
  71             @Override
  72             public void setNativeFont(Font font, Object f, String nam, String fam, String styl) {
  73                 font.setNativeFont(f, nam, fam, styl);
  74             }
  75 
  76             @Override
  77             public Font nativeFont(Object f, String name, String family, String style, double size) {
  78                 return Font.nativeFont(f, name, family, style, size);
  79             }
  80 
  81         });
  82     }
  83 
  84     private static final String DEFAULT_FAMILY = "System";
  85     private static final String DEFAULT_FULLNAME = "System Regular";
  86 
  87     /**
  88      * The default font for this platform. This is used whenever a font is not
  89      * specifically set on a Text node or overridden by CSS.
  90      */
  91     private static float defaultSystemFontSize = -1;
  92     private static float getDefaultSystemFontSize() {
  93         if (defaultSystemFontSize == -1) {
  94             defaultSystemFontSize =
  95                 Toolkit.getToolkit().getFontLoader().getSystemFontSize();
  96         }
  97         return defaultSystemFontSize;
  98     }
  99 
 100     private static Font DEFAULT;
 101     /**
 102      * Gets the default font which will be from the family "System",
 103      * and typically the style "Regular", and be of a size consistent
 104      * with the user's desktop environment, to the extent that can
 105      * be determined.
 106      * @return The default font.
 107      */
 108     public static synchronized Font getDefault() {
 109         if (DEFAULT == null) {
 110             DEFAULT = new Font(DEFAULT_FULLNAME, getDefaultSystemFontSize());
 111         }
 112         return DEFAULT;
 113     }
 114 
 115     /**
 116      * Gets all the font families installed on the user's system, including any
 117      * application fonts or SDK fonts. This call has performance considerations
 118      * as looking up all of the fonts may be an expensive operation the
 119      * first time.
 120      * @return The list containing all available font families.
 121      */
 122     public static List<String> getFamilies() {
 123         return Toolkit.getToolkit().getFontLoader().getFamilies();
 124     }
 125 
 126     /**
 127      * Gets the names of all fonts that are installed on the users system,
 128      * including any application fonts and SDK fonts.
 129      * This call has performance considerations as
 130      * looking up all of the fonts may be an expensive operation the first time.
 131      * @return The list containing all available fonts.
 132      */
 133     public static List<String> getFontNames() {
 134         return Toolkit.getToolkit().getFontLoader().getFontNames();
 135     }
 136 
 137     /**
 138      * Gets the names of all fonts in the specified font family that are
 139      * installed on the users system, including any application fonts
 140      * and SDK fonts.
 141      * This call has performance considerations as looking up all of the
 142      * fonts may be an expensive operation the first time.
 143      * @return The list containing the fonts for the given family.
 144      */
 145     public static List<String> getFontNames(String family) {
 146         return Toolkit.getToolkit().getFontLoader().getFontNames(family);
 147     }
 148 
 149     /**
 150      * Searches for an appropriate font based on the font family name and
 151      * weight and posture style. This method is not guaranteed to return
 152      * a specific font, but does its best to find one that fits the
 153      * specified requirements.
 154      * <p>
 155      * A null or empty value for family allows the implementation to
 156      * select any suitable font.
 157      *
 158      * @param family The family of the font
 159      * @param weight The weight of the font
 160      * @param posture The posture or posture of the font
 161      * @param size The point size of the font. This can be a fractional value,
 162      * but must not be negative. If the size is < 0 the default size will be
 163      * used.
 164      * @return The font that best fits the specified requirements.
 165      */
 166     public static Font font(String family, FontWeight weight,
 167                             FontPosture posture, double size) {
 168 
 169         String fam =
 170             (family == null || "".equals(family)) ? DEFAULT_FAMILY : family;
 171         double sz = size < 0 ? getDefaultSystemFontSize() : size;
 172         return Toolkit.getToolkit().getFontLoader().font(fam, weight, posture, (float)sz);
 173     }
 174 
 175     /**
 176      * Searches for an appropriate font based on the font family name and weight
 177      * style. This method is not guaranteed to return a specific font, but does
 178      * its best to find one that fits the specified requirements.
 179      * A null or empty  value for family allows the implementation
 180      * to select any suitable font.
 181      *
 182      * @param family The family of the font
 183      * @param weight The weight of the font
 184      * @param size The point size of the font. This can be a fractional value,
 185      * but must not be negative. If the size is < 0 the default size will be
 186      * used.
 187      * @return The font that best fits the specified requirements.
 188      */
 189     public static Font font(String family, FontWeight weight, double size) {
 190         return font(family, weight, null, size);
 191     }
 192 
 193     /**
 194      * Searches for an appropriate font based on the font family name and posture
 195      * style. This method is not guaranteed to return a specific font, but does
 196      * its best to find one that fits the specified requirements. A null or empty
 197      * value for family allows the implementation to select any suitable font.
 198      *
 199      * @param family The family of the font
 200      * @param posture The posture or posture of the font
 201      * @param size The point size of the font. This can be a fractional value,
 202      * but must not be negative. If the size is < 0 the default size will be
 203      * used.
 204      * @return The font that best fits the specified requirements.
 205      */
 206     public static Font font(String family, FontPosture posture, double size) {
 207         return font(family, null, posture, size);
 208     }
 209 
 210     /**
 211      * Searches for an appropriate font based on the font family name and size.
 212      * This method is not guaranteed to return a specific font, but does
 213      * its best to find one that fits the specified requirements. A null or empty
 214      * value for family allows the implementation to select any suitable font.
 215      *
 216      * @param family The family of the font
 217      * @param size The point size of the font. This can be a fractional value,
 218      * but must not be negative. If the size is < 0 the default size will be
 219      * used.
 220      * @return The font that best fits the specified requirements.
 221      */
 222     public static Font font(String family, double size) {
 223         return font(family, null, null, size);
 224     }
 225 
 226     /**
 227      * Searches for an appropriate font based on the given font family name and
 228      * default font size.
 229      * This method is not guaranteed to return a specific font, but does
 230      * its best to find one that fits the specified requirements. A null or empty
 231      * value for family allows the implementation to select any suitable font.
 232      *
 233      * @param family The family of the font
 234      * @return The font that best fits the specified requirements.
 235      */
 236     public static Font font(String family) {
 237         return font(family, null, null, -1);
 238     }
 239 
 240     /**
 241      * Searches for an appropriate font based on the default font family name and
 242      * given font size.
 243      * This method is not guaranteed to return a specific font, but does
 244      * its best to find one that fits the specified requirements.
 245      *
 246      * @param size The point size of the font. This can be a fractional value,
 247      * but must not be negative. If the size is < 0 the default size will be
 248      * used.
 249      * @return The font that best fits the specified requirements.
 250      */
 251     public static Font font(double size) {
 252         return font(null, null, null, size);
 253     }
 254 
 255     /**
 256      * The full font name. This name includes both the family name
 257      * and the style variant within that family. For example, for a plain
 258      * Arial font this would be "Arial Regular" and for a bolded
 259      * Arial font this would be "Arial Bold". The precise name to use when
 260      * loading a font is defined within each font file as the full font name.
 261      * For example, "Proxima Nova ExtraCondensed Bold Italic" would refer to a
 262      * specific Proxima Nova font.
 263      * A null or empty name allows the implementation to select any suitable
 264      * font.
 265      * <p>
 266      * There is a single unified way to load all of application supplied
 267      * (via <code>Font.loadFont()</code>, JavaFX runtime delivered fonts,
 268      * and system installed fonts. Simply create the font by specifying
 269      * the full name of the font you want to load.
 270      * If the specific font cannot be located, then a fallback or default
 271      * font will be used. The "name" will be updated to reflect the actual name
 272      * of the font being used. A load failure condition can be discovered by
 273      * checking the name of the Font with the name you tried to load.
 274      * <p>
 275      * Note that if you wish to locate a font by font family and style
 276      * then you can use one of the {@link #font} factory methods defined in
 277      * this class.
 278      *
 279      * @defaultValue empty string
 280      */
 281     public final String getName() { return name; }
 282     private String name;
 283 
 284     /**
 285      * Returns the family of this font.
 286      * @return The family of this font.
 287      */
 288     public final String getFamily() { return family; }
 289     private String family;
 290 
 291     /**
 292      * The font specified string describing the style within the font family.
 293      * @return The style name of this font.
 294      */
 295     public final String getStyle() { return style; }
 296     private String style;
 297 
 298     /**
 299      * The point size for this font. This may be a fractional value such as
 300      * {@code 11.5}. If the specified value is < 0 the default size will be
 301      * used.
 302      *
 303      * @defaultValue 12
 304      */
 305     public final double getSize() { return size; }
 306     private double size;
 307 
 308     /**
 309      * The cached hash code, used to improve performance in situations where
 310      * we cache fonts, such as in the CSS routines.
 311      */
 312     private int hash = 0;
 313 
 314     /**
 315      * Constructs a font using the default face "System".
 316      * The underlying font used is determined by the implementation
 317      * based on the typical UI font for the current UI environment.
 318      *
 319      * @param size the font size to use
 320      */
 321     public Font(@NamedArg("size") double size) {
 322         this(null, size);
 323     }
 324 
 325 
 326     /**
 327      * Constructs a font using the specified full face name and size
 328      * @param name full name of the font.
 329      * @param size the font size to use
 330      */
 331     public Font(@NamedArg("name") String name, @NamedArg("size") double size) {
 332         this.name = name;
 333         this.size = size;
 334 
 335         if (name == null || "".equals(name)) this.name = DEFAULT_FULLNAME;
 336         if (size < 0f) this.size = getDefaultSystemFontSize();
 337         // if a search was done based on family + style information, then the
 338         // native font has already been located and specified. Likewise if the
 339         // Font was created based on an existing native font. If however a Font
 340         // was created directly in FX, then we need to find the native font
 341         // to use. This call will also set the family and style by invoking
 342         // the setNativeFont callback method.
 343         Toolkit.getToolkit().getFontLoader().loadFont(this);
 344     }
 345 
 346     /**
 347      * Private constructor for internal implementation
 348      *
 349      * @param f native font
 350      * @param family font family name
 351      * @param name font full name
 352      * @param style style string
 353      * @param size font size
 354      */
 355     private Font(Object f, String family, String name, String style, double size) {
 356         this.nativeFont = f;
 357         this.family = family;
 358         this.name = name;
 359         this.style = style;
 360         this.size = size;
 361     }
 362 
 363     /**
 364      * Loads a font resource from the specified URL. If the load is successful
 365      * such that the location is readable, and it represents a supported
 366      * font format then a <code>Font</code> object will be returned.
 367      * <p>
 368      * If the application does not have the proper permission then this method
 369      * will return the default system font with the specified font size.
 370      * <p>
 371      * Any failure such as a malformed URL being unable to locate or read
 372      * from the resource, or if it doesn't represent a font, will result in
 373      * a <code>null</code> return. It is the application's responsibility
 374      * to check this before use.
 375      * <p>
 376      * On a successful (non-null) return the font will be registered
 377      * with the FX graphics system for creation by available constructors
 378      * and factory methods, and the application should use it in this
 379      * manner rather than calling this method again, which would
 380      * repeat the overhead of downloading and installing the font.
 381      * <p>
 382      * The font <code>size</code> parameter is a convenience so that in
 383      * typical usage the application can directly use the returned (non-null)
 384      * font rather than needing to create one via a constructor. Invalid sizes
 385      * are those <=0 and will result in a default size.
 386      * <p>
 387      * If the URL represents a local disk file, then no copying is performed
 388      * and the font file is required to persist for the lifetime of the
 389      * application. Updating the file in any manner will result
 390      * in unspecified and likely undesired behaviours.
 391      *
 392      * @param urlStr from which to load the font, specified as a String.
 393      * @param size of the returned font.
 394      * @return the Font, or null if the font cannot be created.
 395      */
 396     public static Font loadFont(String urlStr, double size) {
 397         URL url = null;
 398         try {
 399             url = new URL(urlStr); // null string arg. is caught here.
 400         } catch (Exception e) {
 401             return null;
 402         }
 403         if (size <= 0) {
 404             size = getDefaultSystemFontSize();
 405         }
 406         // Now lets parse the URL and decide if its a file,
 407         // or a remote URL from which we need to read.
 408         if (url.getProtocol().equals("file")) {
 409             String path = url.getFile();
 410             // The URL path may have a leading "/", when obtained
 411             // via ClassLoader. This can cause problems on Windows.
 412             // Getting the path from a File fixes this.
 413             path = new java.io.File(path).getPath();
 414             try {
 415                 SecurityManager sm = System.getSecurityManager();
 416                 if (sm != null) {
 417                     FilePermission filePermission =
 418                         new FilePermission(path, "read");
 419                     sm.checkPermission(filePermission);
 420                 }
 421             } catch (Exception e) {
 422                 return null;
 423             }
 424             return Toolkit.getToolkit().getFontLoader().loadFont(path, size);
 425         }
 426         Font font = null;
 427         URLConnection connection = null;
 428         InputStream in = null;
 429         try {
 430             connection = url.openConnection();
 431             in = connection.getInputStream();
 432             font = Toolkit.getToolkit().getFontLoader().loadFont(in, size);
 433         } catch (Exception e) {
 434             return null;
 435         } finally {
 436             try {
 437                 if (in != null) {
 438                     in.close();
 439                 }
 440             } catch (Exception e) {
 441             }
 442         }
 443         return font;
 444     }
 445 
 446     /**
 447      * Loads a font resource from the specified input stream.
 448      * If the load is successful such that the stream can be
 449      * fully read, and it represents a supported font format then a
 450      * <code>Font</code> object will be returned.
 451      * <p>
 452      * If the application does not have the proper permission then this method
 453      * will return the default system font with the specified font size.
 454      * <p>
 455      * Any failure such as abbreviated input, or an unsupported font format
 456      * will result in a <code>null</code> return. It is the application's
 457      * responsibility to check this before use.
 458      * <p>
 459      * On a successful (non-null) return the font will be registered
 460      * with the FX graphics system for creation by available constructors
 461      * and factory methods, and the application should use it in this
 462      * manner rather than calling this method again, which would
 463      * repeat the overhead of re-reading and installing the font.
 464      * <p>
 465      * The font <code>size</code> parameter is a convenience so that in
 466      * typical usage the application can directly use the returned (non-null)
 467      * font rather than needing to create one via a constructor. Invalid sizes
 468      * are those <=0 and will result in a default size.
 469      * <p>
 470      * This method does not close the input stream.
 471      * @param in stream from which to load the font.
 472      * @param size of the returned font.
 473      * @return the Font, or null if the font cannot be created.
 474      */
 475     public static Font loadFont(InputStream in, double size) {
 476         if (size <= 0) {
 477             size = getDefaultSystemFontSize();
 478         }
 479         return Toolkit.getToolkit().getFontLoader().loadFont(in, size);
 480     }
 481 
 482     /**
 483      * Converts this {@code Font} object to a {@code String} representation.
 484      * The String representation is for informational use only and will change.
 485      * Do not use this string representation for any programmatic purpose.
 486      */
 487     @Override public String toString() {
 488         StringBuilder builder = new StringBuilder("Font[name=");
 489         builder = builder.append(name);
 490         builder = builder.append(", family=").append(family);
 491         builder = builder.append(", style=").append(style);
 492         builder = builder.append(", size=").append(size);
 493         builder = builder.append("]");
 494         return builder.toString();
 495     }
 496 
 497     /**
 498      * Indicates whether some other object is "equal to" this one.
 499      * @param obj the reference object with which to compare.
 500      * @return {@code true} if this object is equal to the {@code obj} argument; {@code false} otherwise.
 501      */
 502     @Override public boolean equals(Object obj) {
 503         if (obj == this) return true;
 504         if (obj instanceof Font) {
 505             Font other = (Font)obj;
 506             return (name == null ? other.name == null : name.equals(other.name))
 507                 && size == other.size;
 508         }
 509         return false;
 510     }
 511 
 512     /**
 513      * Returns a hash code for this {@code Font} object.
 514      * @return a hash code for this {@code Font} object.
 515      */
 516     @Override public int hashCode() {
 517         if (hash == 0) {
 518             long bits = 17L;
 519             bits = 37L * bits + name.hashCode();
 520             bits = 37L * bits + Double.doubleToLongBits(size);
 521             hash = (int) (bits ^ (bits >> 32));
 522         }
 523         return hash;
 524     }
 525 
 526     private Object nativeFont;
 527 
 528     private Object getNativeFont() { return nativeFont; }
 529 
 530     private void setNativeFont(Object f, String nam, String fam, String styl) {
 531         nativeFont = f;
 532         name = nam;
 533         family = fam;
 534         style = styl;
 535     }
 536 
 537     private static Font nativeFont(Object f, String name, String family,
 538                                        String style, double size) {
 539         Font retFont = new Font( f, family, name, style, size);
 540         return retFont;
 541     }
 542 }