From d1ba259469737eeef63947418147db63afdcd412 Mon Sep 17 00:00:00 2001 From: Jakub Valtar Date: Thu, 3 Sep 2015 17:51:10 -0400 Subject: [PATCH] FX - support for fonts from TTF and OTF lands --- core/src/processing/core/PApplet.java | 32 +----- core/src/processing/core/PGraphics.java | 35 +++++++ core/src/processing/javafx/PGraphicsFX2D.java | 98 ++++++++++++++----- 3 files changed, 109 insertions(+), 56 deletions(-) diff --git a/core/src/processing/core/PApplet.java b/core/src/processing/core/PApplet.java index c928899e7..64d823730 100644 --- a/core/src/processing/core/PApplet.java +++ b/core/src/processing/core/PApplet.java @@ -29,7 +29,6 @@ import java.awt.Desktop; import java.awt.DisplayMode; import java.awt.EventQueue; import java.awt.FileDialog; -import java.awt.Font; import java.awt.Frame; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; @@ -6140,39 +6139,12 @@ public class PApplet implements PConstants { * @param charset array containing characters to be generated * @see PFont * @see PGraphics#textFont(PFont, float) - * @see PGraphics#text(String, float, float, float, float, float) + * @see PGraphics#text(String, float, float, float, float) * @see PApplet#loadFont(String) */ public PFont createFont(String name, float size, boolean smooth, char[] charset) { - String lowerName = name.toLowerCase(); - Font baseFont = null; - - try { - InputStream stream = null; - if (lowerName.endsWith(".otf") || lowerName.endsWith(".ttf")) { - stream = createInput(name); - if (stream == null) { - System.err.println("The font \"" + name + "\" " + - "is missing or inaccessible, make sure " + - "the URL is valid or that the file has been " + - "added to your sketch and is readable."); - return null; - } - baseFont = Font.createFont(Font.TRUETYPE_FONT, createInput(name)); - - } else { - baseFont = PFont.findFont(name); - } - return new PFont(baseFont.deriveFont(size * pixelDensity), - smooth, charset, stream != null, - pixelDensity); - - } catch (Exception e) { - System.err.println("Problem with createFont(\"" + name + "\")"); - e.printStackTrace(); - return null; - } + return g.createFont(name, size, smooth, charset); } diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 720ff3e17..8b4325b27 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -29,8 +29,10 @@ package processing.core; import java.awt.Color; // Used for the 'image' object that's been here forever +import java.awt.Font; import java.awt.Image; +import java.io.InputStream; import java.util.Map; import java.util.HashMap; import java.util.WeakHashMap; @@ -4013,6 +4015,39 @@ public class PGraphics extends PImage implements PConstants { // TEXT/FONTS + protected PFont createFont(String name, float size, + boolean smooth, char[] charset) { + String lowerName = name.toLowerCase(); + Font baseFont = null; + + try { + InputStream stream = null; + if (lowerName.endsWith(".otf") || lowerName.endsWith(".ttf")) { + stream = parent.createInput(name); + if (stream == null) { + System.err.println("The font \"" + name + "\" " + + "is missing or inaccessible, make sure " + + "the URL is valid or that the file has been " + + "added to your sketch and is readable."); + return null; + } + baseFont = Font.createFont(Font.TRUETYPE_FONT, parent.createInput(name)); + + } else { + baseFont = PFont.findFont(name); + } + return new PFont(baseFont.deriveFont(size * parent.pixelDensity), + smooth, charset, stream != null, + parent.pixelDensity); + + } catch (Exception e) { + System.err.println("Problem with createFont(\"" + name + "\")"); + e.printStackTrace(); + return null; + } + } + + public void textAlign(int alignX) { textAlign(alignX, BASELINE); } diff --git a/core/src/processing/javafx/PGraphicsFX2D.java b/core/src/processing/javafx/PGraphicsFX2D.java index 576171834..a9534fdaa 100644 --- a/core/src/processing/javafx/PGraphicsFX2D.java +++ b/core/src/processing/javafx/PGraphicsFX2D.java @@ -1282,7 +1282,23 @@ public class PGraphicsFX2D extends PGraphics { // and mirrors PGraphics.textFont field protected FontInfo textFontInfo; - protected Text measuringText = new Text(); + + @Override + protected PFont createFont(String name, float size, + boolean smooth, char[] charset) { + PFont font = super.createFont(name, size, smooth, charset); + if (font.isStream()) { + Font fxFont = Font.loadFont(parent.createInput(name), size); + if (fxFont != null) { + String fontName = font.getName(); + fontCache.nameToFilename.put(fontName, name); + FontInfo fontInfo = fontCache.createFontInfo(fxFont, false); + fontCache.put(fontName, size, fontInfo); + } + } + return font; + } + @Override protected void defaultFontOrDeath(String method, float size) { @@ -1290,11 +1306,13 @@ public class PGraphicsFX2D extends PGraphics { textFontInfo = fontCache.get(textFont.getName(), textFont.getSize()); } + @Override protected boolean textModeCheck(int mode) { return mode == MODEL; } + @Override public void textSize(float size) { if (size <= 0) { @@ -1311,6 +1329,7 @@ public class PGraphicsFX2D extends PGraphics { textFontImpl(textFont, size); } + @Override public void textFont(PFont which) { if (which != null) { @@ -1320,6 +1339,7 @@ public class PGraphicsFX2D extends PGraphics { } } + @Override public void textFont(PFont which, float size) { if (which != null) { @@ -1337,9 +1357,10 @@ public class PGraphicsFX2D extends PGraphics { } } + /** - * Sets the font and size without doing any checks. - * Check the validity of args before calling. + * Sets the font and the size. Check the validity of args and + * print possible errors to the user before calling this. * * @param which font to set, not null * @param size size to set, greater than zero @@ -1348,9 +1369,31 @@ public class PGraphicsFX2D extends PGraphics { textFont = which; textSize = size; - textFontInfo = fontCache.get(which.getName(), size); + String fontName = which.getName(); + + textFontInfo = fontCache.get(fontName, size); + if (textFontInfo == null) { + Font font; + String filename = fontCache.nameToFilename.get(fontName); + if (filename != null) { + font = Font.loadFont(parent.createInput(filename), size); + } else { + font = new Font(fontName, size); + } + + // Loading from file is guaranteed to succeed, font was already + // successfully loaded in createFont(). + // Loading system font may return fallback font if the font + // does not exist; this can be detected by comparing font names. + // Please note that some font names can differ in FX vs. AWT. + boolean isFallbackFont = filename == null && + !fontName.equalsIgnoreCase(font.getName()); + textFontInfo = fontCache.createFontInfo(font, isFallbackFont); + fontCache.put(fontName, size, textFontInfo); + } + context.setFont(textFontInfo.font); - measuringText.setFont(textFontInfo.font); + fontCache.measuringText.setFont(textFontInfo.font); if (textFontInfo.isFallbackFont) { textLeading = (textFont.ascent() + textFont.descent()) * 1.275f; } else { @@ -1399,6 +1442,8 @@ public class PGraphicsFX2D extends PGraphics { private static final int CACHE_SIZE = 512; + protected Map nameToFilename = new HashMap<>(); + private final LinkedHashMap cache = new LinkedHashMap(16, 0.75f, true) { @Override @@ -1413,27 +1458,28 @@ public class PGraphicsFX2D extends PGraphics { private FontInfo get(String name, float size) { retrievingKey.name = name; retrievingKey.size = size; - FontInfo fontInfo = cache.get(retrievingKey); - if (fontInfo == null) { - fontInfo = new FontInfo(); - fontInfo.font = new Font(name, size); - fontInfo.isFallbackFont = !name.equalsIgnoreCase(fontInfo.font.getName()); - { // measure ascent and descent - measuringText.setFont(fontInfo.font); - measuringText.setText(" "); - float lineHeight = (float) measuringText.getLayoutBounds().getHeight(); - fontInfo.ascent = (float) measuringText.getBaselineOffset(); - fontInfo.descent = lineHeight - fontInfo.ascent; - } + return cache.get(retrievingKey); + } - { // create new key and add the info to the cache - Key key = new Key(); - key.name = name; - key.size = size; - cache.put(key, fontInfo); - } + private void put(String name, float size, FontInfo fontInfo) { + Key key = new Key(); + key.name = name; + key.size = size; + cache.put(key, fontInfo); + } + + private FontInfo createFontInfo(Font font, boolean isFallbackFont) { + FontInfo result = new FontInfo(); + result.isFallbackFont = isFallbackFont; + result.font = font; + { // measure ascent and descent + measuringText.setFont(result.font); + measuringText.setText(" "); + float lineHeight = (float) measuringText.getLayoutBounds().getHeight(); + result.ascent = (float) measuringText.getBaselineOffset(); + result.descent = lineHeight - result.ascent; } - return fontInfo; + return result; } private static final class Key { @@ -1545,8 +1591,8 @@ public class PGraphicsFX2D extends PGraphics { return super.textWidthImpl(buffer, start, stop); } - measuringText.setText(new String(buffer, start, stop - start)); - return (float) measuringText.getLayoutBounds().getWidth(); + fontCache.measuringText.setText(new String(buffer, start, stop - start)); + return (float) fontCache.measuringText.getLayoutBounds().getWidth(); }