From cd21a06638f361d74b58e751fe07c806ef89be0c Mon Sep 17 00:00:00 2001 From: Peter Bernard West Date: Sun, 23 May 2004 10:37:43 +0000 Subject: [PATCH] Fonts database for Java renderer git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/FOP_0-20-0_Alt-Design@197615 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/awt/Fonts.java | 514 ++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 src/java/org/apache/fop/render/awt/Fonts.java diff --git a/src/java/org/apache/fop/render/awt/Fonts.java b/src/java/org/apache/fop/render/awt/Fonts.java new file mode 100644 index 000000000..8951af796 --- /dev/null +++ b/src/java/org/apache/fop/render/awt/Fonts.java @@ -0,0 +1,514 @@ +/* + * + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Created on 23/05/2004 + * $Id$ + */ +package org.apache.fop.render.awt; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +/** + * Java font selection is based on family names. It seems that Java + * handles font mapping something like this:
+ * Given a set of physical fonts like, e.g., Arial, Java reports them as + *
+ * font face: Arial
+ *     logical:Arial
+ *     family:Arial
+ *     PSName:ArialMT
+ *     Style:
+ *         PLAIN
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * font face: Arial Cursiva
+ *     logical:Arial Cursiva
+ *     family:Arial
+ *     PSName:Arial-ItalicMT
+ *     Style:
+ *         PLAIN
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * font face: Arial Negreta
+ *     logical:Arial Negreta
+ *     family:Arial
+ *     PSName:Arial-BoldMT
+ *     Style:
+ *         PLAIN
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * font face: Arial Negreta cursiva
+ *     logical:Arial Negreta cursiva
+ *     family:Arial
+ *     PSName:Arial-BoldItalicMT
+ *     Style:
+ *         PLAIN
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * 
+ * There are other Arial forms, e.g. Arial Black and Arial Narrow, but + * they fall into different families, as indicated by the font name. + * java.awt.font.TextAttribute defines a number of TextAttribute + * constants, and querying a Font object via getAvailableAttributes() + * will provide an array of attributes available on the Font. + *

It seems there is a common set available on both Type1 and TrueType + * fonts in 1.4.2; viz FAMILY, WEIGHT, POSTURE, SIZE and TRANSFORM. + * Note that style is reported as PLAIN on all fonts, irrespective of + * the actual style according to the font name. + *

SIZE works as one might expect. WEIGHT is supported directly only + * for the weights provided in the set of family fonts. In the case of + * Arial, only REGULAR and BOLD. The same is true of POSTURE: REGULAR + * and OBLIQUE. There seems to be room here to experiment with + * virtual fonts. A virtual Arial font might be constructed from the + * Arial, Arial Narrow, Arial Black and Arial Black MT fonts. + * Another area where virtual fonts might be handy is for small caps. + * + *

In the case of the set of logical fonts defined for all Java + * implementations, the characteristics are reported like this: + *

+ * font face: serif.plain
+ *     logical:serif
+ *     family:serif
+ *     PSName:serif
+ *     PLAIN              
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * font face: serif.bold
+ *     logical:serif.bold
+ *     family:serif
+ *     PSName:serif.bold
+ *     PLAIN              
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * font face: serif.bolditalic
+ *     logical:serif.bolditalic
+ *     family:serif
+ *     PSName:serif.bolditalic
+ *     PLAIN              
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * font face: serif.italic
+ *     logical:serif.italic
+ *     family:serif
+ *     PSName:serif.italic
+ *     PLAIN              
+ *     FAMILY
+ *     WEIGHT
+ *     POSTURE
+ *     SIZE
+ *     TRANSFORM
+ * 
+ * Note that in this case, the logical name of the serif.plain font is + * serif. This correspondence only seems to occur with the logical + * fonts. + * + *

Three names are available for each Font object: + *

+ *
Font Face Name
+ *
Aka Font Name. Corresponds to a phsical font in the underlying + * system.
+ *
Family Name
+ *
the name of the font family that determines the typographic design + * across several faces.
+ *
Logical Name
+ *
The name that was used to construct the font. Each font has + * such a name, irrespective of whether it is a logical or + * physical font. The logical name only differs from the + * font face name in the case of logical fonts. E.g. + * the logical name of serif.plain is + * serif, which is also the name of the pre-defined + * logical font serif.
+ *
Postscript Name
+ *
The Postscript name of the font. Derivation and significance + * unknown.
+ *
+ * + * Initial font mapping is based on the names available to the font. + * + *

XSL-FO/CSS2 system fonts

+ * The CSS2 system fonts are: + * + * The situation on linux systems is that there are no system fonts as + * such. Individual GUI environments like Gnome, KDE, CDE and the like + * may define such fonts, but determining them will depend on the + * individual system's GUI environment. The closest parallel in Java is + * the set of logical fonts defined in every Java implementation, + * viz. + * + * The most obvious mapping from Java logical fonts to XSL-FO/CSS2 + * system fonts is + *
+ *
caption
SansSerif at size A
+ *
icon
SansSerif at size B
+ *
menu
SansSerif at size C
+ *
message-box
Dialog
+ *
small-caption
caption at size A/1.2
+ *
status-bar
SansSerif at size D
+ *
+ * where sizes A, B, C and D are UserAgent prerogatives determined in + * consultation with the underlying JVM font system. I.e., the fonts + * must support fractional metrics and dynamic sizing, which, in default + * Java implementations, they do, as far as I know. + * + *

XSL-FO/CSS2 Generic Font Families

+ * The generic families in the Recommendation are: + * + * The mapping of the CSS2 generics serif, + * sans-serif and monospace is a straightforward + * name translation. There is no such convenient correspondence between + * the Java font system and cursive and fantasy + * fonts. This mapping must be determined by the UserAgent by + * interrogating the JVM. + * + * @author pbw + * @version $Revision$ $Name$ + */ +public class Fonts { + +// public static final int +// NO_ATTR = 0 +// ,BACKGROUND = 1 +// ,BIDI_EMBEDDING = 2 +// ,CHAR_REPLACEMENT = 4 +// ,FAMILY = 8 +// ,FONT = 16 +// ,FOREGROUND = 32 +// ,INPUT_METHOD_HIGHLIGHT = 64 +// ,INPUT_METHOD_UNDERLINE = 128 +// ,JUSTIFICATION = 256 +// ,NUMERIC_SHAPING = 512 +// ,POSTURE = 1024 +// ,RUN_DIRECTION = 2048 +// ,SIZE = 4096 +// ,STRIKETHROUGH = 8192 +// ,SUPERSCRIPT = 16384 +// ,SWAP_COLORS = 32768 +// ,TRANSFORM = 65536 +// ,UNDERLINE = 131072 +// ,WEIGHT = 262144 +// ,WIDTH = 524288 +// ; + + //private HashMap fontAttributes = null; + + private HashMap fontFamilies = null; + private HashSet serif = new HashSet(); + private HashSet sansserif = new HashSet(); + private HashSet monospace = new HashSet(); + private HashSet cursive = new HashSet(); + private HashSet fantasy = new HashSet(); + private HashSet symbols = new HashSet(); + + /** + */ + private void setupFonts() { + // Set up the graphics environment + BufferedImage fontImage = + new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); + Graphics2D g2D = fontImage.createGraphics(); + FontRenderContext frcontext = g2D.getFontRenderContext(); + // Set up the fonts environment + // TODO Check whether this is needed to provide better mapping between + // requested fonts and those available on the system + GraphicsEnvironment gEnv = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + Font[] fonts = gEnv.getAllFonts(); + String[] families = gEnv.getAvailableFontFamilyNames(); + Locale locale = Locale.getDefault(); + fontFamilies = + new HashMap((int)(families.length + fonts.length * 4.5)); + //fontAttributes = new HashMap((int)(fonts.length / 0.7)); + // Enter all of the family names, keyed on themselves, and keyed on + // the lower-case version of the family name, if different. + // N.B. If there are two font family names which differ only in that + // one is the locale-specific lower-case version of the first, they + // will be recorded in availabelFonsts as two separate font families. + for (int i = 0; i < families.length; i++) { + if (fontFamilies.get(families[i]) == null) { + fontFamilies.put(families[i], families[i]); + } + } + for (int i = 0; i < families.length; i++) { + String lcase = families[i].toLowerCase(locale); + if (fontFamilies.get(lcase) == null) { + fontFamilies.put(lcase, families[i]); + } + } + String[] fontNames = new String[fonts.length]; + String[] psNames = new String[fonts.length]; + for (int i = 0; i < fonts.length; i++) { + Font f = fonts[i]; + String family = f.getFamily(); + String lcfamily = family.toLowerCase(locale); + String font = f.getFontName(); + String lcfont = font.toLowerCase(locale); + String psname = f.getPSName(); + String lcpsname = psname.toLowerCase(locale); + String logical = f.getName(); + String lclogical = logical.toLowerCase(locale); + // Map each of the font names to the family name + if (fontFamilies.get(font) == null) { + fontFamilies.put(font, family); + } + if (fontFamilies.get(psname) == null) { + fontFamilies.put(psname, family); + } + if (fontFamilies.get(logical) == null) { + fontFamilies.put(logical, family); + } + // Collect styles for possible intelligent font substitution + // TODO if this is not used, delete + checkMonospace(monospace, family, lcfamily); + checkSerif(serif, family, lcfamily); + checkSansSerif(sansserif, family, lcfamily); + checkCursive(cursive, family, lcfamily); + checkFantasy(fantasy, family, lcfamily); + checkSymbols(symbols, family, lcfamily); + // Add mappings for some of the CSS2 generic font families + setupCSSGenericMapping(fontFamilies); + // Add mappings for the CSS2 system fonts + setupCSSSystemFontMapping(fontFamilies); + } + } + + public void setupCSSGenericMapping(Map fontFamilies) { + // Add mappings for some of the CSS2 generic font families + // TODO set up mappings for "cursive" and "fantasy" + if (fontFamilies.get("serif") == null) { + fontFamilies.put("serif", "Serif"); + } + if (fontFamilies.get("sans-serif") == null) { + fontFamilies.put("sans-serif", "SansSerif"); + } + if (fontFamilies.get("monospace") == null) { + fontFamilies.put("monospace", "Monospaced"); + } + } + + public void setupCSSSystemFontMapping(Map fontFamilies) { + // TODO + } + + private void checkMonospace(Set monospace, String family, String lcfamily) { + int mono = lcfamily.lastIndexOf("mono"); + if (mono >= 0) { + if (lcfamily.indexOf("monotype") != mono) { + // Didn't find "Monotype" + monospace.add(family); + } + } + if (lcfamily.indexOf("courier") >= 0) { + monospace.add(family); + } + if (lcfamily.indexOf("console") >= 0) { + monospace.add(family); + } + if (lcfamily.indexOf("typewriter") >= 0) { + monospace.add(family); + } + } + + private void checkSerif(Set serif, String family, String lcfamily) { + int ser = lcfamily.indexOf("serif"); + if (ser >= 0) { + if (lcfamily.indexOf("sans") < 0) { + // Didn't find "sans serif" + serif.add(family); + } + } + if (lcfamily.indexOf("roman") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("times") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("bookman") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("utopia") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("palatino") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("palladio") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("bright") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("georgia") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("schoolbook") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("charter") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("antiqua") >= 0) { + serif.add(family); + } + if (lcfamily.indexOf("footlight") >= 0) { + serif.add(family); + } + } + + private void checkSansSerif(Set sansserif, String family, String lcfamily) { + if (lcfamily.indexOf("sans") >= 0) { + if (lcfamily.indexOf("comic") < 0) { + sansserif.add(family); + } + } + if (lcfamily.indexOf("helvetica") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("arial") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("avantgarde") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("gothic") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("tahoma") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("thonburi") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("trebuchet") >= 0) { + sansserif.add(family); + } + if (lcfamily.indexOf("verdana") >= 0) { + sansserif.add(family); + } + } + + private void checkCursive(Set cursive, String family, String lcfamily) { + if (lcfamily.indexOf("chancery") >= 0) { + cursive.add(family); + } + if (lcfamily.indexOf("brush") >= 0) { + cursive.add(family); + } + if (lcfamily.indexOf("script") >= 0) { + cursive.add(family); + } + if (lcfamily.indexOf("naskh") >= 0) { + cursive.add(family); + } + if (lcfamily.indexOf("shuwiefat") >= 0) { + cursive.add(family); + } + } + + private void checkFantasy(Set fantasy, String family, String lcfamily) { + if (lcfamily.indexOf("algerian") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("americantext") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("braggadocio") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("colonna") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("comic") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("desdemona") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("kino") >= 0) { + fantasy.add(family); + } + if (lcfamily.indexOf("playbill") >= 0) { + fantasy.add(family); + } + } + + private void checkSymbols(Set symbols, String family, String lcfamily) { + if (lcfamily.indexOf("symbol") >= 0) { + symbols.add(family); + } + if (lcfamily.indexOf("dingbats") >= 0) { + symbols.add(family); + } + if (lcfamily.indexOf("webdings") >= 0) { + symbols.add(family); + } + if (lcfamily.indexOf("wingdings") >= 0) { + symbols.add(family); + } + if (lcfamily.indexOf("sorts") >= 0) { + symbols.add(family); + } + } + +} -- 2.39.5