From ff6ac460f195633039ec5697519a1fa1228a038a Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 19 Feb 2008 13:08:39 +0000 Subject: [PATCH] Bugzilla #44451: The patch fixes two problems: - If distinct fonts declare the same font family name, the resulting font mapping is currently arbitrary; now, a name-similarity heuristic is used to prioritize the font mappings. - "Medium" and "demi" fonts are now recognized as "bold", solving several real-world problems (although this solution may be an oversimplification). Submitted by: Justus Piater Patch modified by jeremias: - Style fixes (tab chars) - Refined font weight identification: medium -> 500, semi/demi -> 600 git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@629093 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fonts/FontInfo.java | 42 +++++++++++++++++++ .../org/apache/fop/fonts/FontResolver.java | 2 +- .../org/apache/fop/fonts/FontTriplet.java | 20 ++++++++- src/java/org/apache/fop/fonts/FontUtil.java | 25 +++++++++-- .../fop/fonts/autodetect/FontInfoFinder.java | 25 ++++++----- .../org/apache/fop/render/PrintRenderer.java | 2 +- status.xml | 4 ++ 7 files changed, 104 insertions(+), 16 deletions(-) diff --git a/src/java/org/apache/fop/fonts/FontInfo.java b/src/java/org/apache/fop/fonts/FontInfo.java index af0fba579..ab11eb768 100644 --- a/src/java/org/apache/fop/fonts/FontInfo.java +++ b/src/java/org/apache/fop/fonts/FontInfo.java @@ -52,6 +52,10 @@ public class FontInfo { /** look up a font-triplet to find a font-name */ private Map triplets; //Map (String = font key) + /** look up a font-triplet to find its priority + * (only used inside addFontProperties()) */ + private Map tripletPriorities; //Map + /** look up a font-name to get a font (that implements FontMetrics at least) */ private Map fonts; //Map (String = font key) @@ -68,6 +72,7 @@ public class FontInfo { */ public FontInfo() { this.triplets = new java.util.HashMap(); + this.tripletPriorities = new java.util.HashMap(); this.fonts = new java.util.HashMap(); this.usedFonts = new java.util.HashMap(); } @@ -78,6 +83,8 @@ public class FontInfo { * @return True if valid */ public boolean isSetupValid() { + //We're only called when font setup is done: + tripletPriorities = null; // candidate for garbage collection return triplets.containsKey(Font.DEFAULT_FONT); } @@ -105,7 +112,42 @@ public class FontInfo { if (log.isDebugEnabled()) { log.debug("Registering: " + triplet + " under " + name); } + String oldName = (String)triplets.get(triplet); + int newPriority = triplet.getPriority(); + if (oldName != null) { + int oldPriority = ((Integer)tripletPriorities.get(triplet)).intValue(); + if (oldPriority < newPriority) { + logDuplicateFont(triplet, false, oldName, oldPriority, + name, newPriority); + return; + } else { + logDuplicateFont(triplet, true, oldName, oldPriority, + name, newPriority); + } + } this.triplets.put(triplet, name); + this.tripletPriorities.put(triplet, new Integer(newPriority)); + } + + /** Log warning about duplicate font triplets. + * @param triplet the duplicate font triplet + * @param replacing true iff the new font will replace the old one + * @param oldKey the old internal font name + * @param oldPriority the priority of the existing font mapping + * @param newKey the new internal font name + * @param newPriority the priority of the duplicate font mapping + */ + private void logDuplicateFont(FontTriplet triplet, boolean replacing, + String oldKey, int oldPriority, + String newKey, int newPriority) { + if (log.isDebugEnabled()) { + log.debug(triplet + + (replacing ? ": Replacing " : ": Not replacing ") + + ((FontMetrics)fonts.get(triplets.get(triplet))).getFullName() + + " (" + oldPriority + ") by " + + ((FontMetrics)fonts.get(newKey)).getFullName() + + " (" + newPriority + ")"); + } } /** diff --git a/src/java/org/apache/fop/fonts/FontResolver.java b/src/java/org/apache/fop/fonts/FontResolver.java index cd8e965fb..b054b054a 100644 --- a/src/java/org/apache/fop/fonts/FontResolver.java +++ b/src/java/org/apache/fop/fonts/FontResolver.java @@ -28,7 +28,7 @@ public interface FontResolver { /** * Called to resolve an URI to a Source instance. The base URI needed by the URIResolver's - * resolve() method is defined to be implicitely available in this case. If the URI cannot + * resolve() method is defined to be implicitly available in this case. If the URI cannot * be resolved, null is returned and it is assumed that the FontResolver implementation * already warned the user about the problem. * @param href An href attribute, which may be relative or absolute. diff --git a/src/java/org/apache/fop/fonts/FontTriplet.java b/src/java/org/apache/fop/fonts/FontTriplet.java index 66be36bc7..a7890ecbd 100644 --- a/src/java/org/apache/fop/fonts/FontTriplet.java +++ b/src/java/org/apache/fop/fonts/FontTriplet.java @@ -32,10 +32,11 @@ public class FontTriplet implements Comparable, Serializable { private String name; private String style; private int weight; + private int priority; // priority of this triplet/font mapping //This is only a cache private transient String key; - + /** * Creates a new font triplet. * @param name font name @@ -43,9 +44,21 @@ public class FontTriplet implements Comparable, Serializable { * @param weight font weight (100, 200, 300...800, 900) */ public FontTriplet(String name, String style, int weight) { + this(name, style, weight, 0); + } + + /** + * Creates a new font triplet. + * @param name font name + * @param style font style (normal, italic etc.) + * @param weight font weight (100, 200, 300...800, 900) + * @param priority priority of this triplet/font mapping + */ + public FontTriplet(String name, String style, int weight, int priority) { this.name = name; this.style = style; this.weight = weight; + this.priority = priority; } /** @return the font name */ @@ -63,6 +76,11 @@ public class FontTriplet implements Comparable, Serializable { return weight; } + /** @return the priority of this triplet/font mapping */ + public int getPriority() { + return priority; + } + private String getKey() { if (this.key == null) { //This caches the combined key diff --git a/src/java/org/apache/fop/fonts/FontUtil.java b/src/java/org/apache/fop/fonts/FontUtil.java index b9e891c9c..89ea132c0 100644 --- a/src/java/org/apache/fop/fonts/FontUtil.java +++ b/src/java/org/apache/fop/fonts/FontUtil.java @@ -77,14 +77,18 @@ public class FontUtil { } /** font constituent names which identify a font as being of "italic" style */ - private static final String[] ITALIC_WORDS = {"italic", "oblique"}; + private static final String[] ITALIC_WORDS = {"italic", "oblique", "inclined"}; /** font constituent names which identify a font as being of "light" weight */ private static final String[] LIGHT_WORDS = {"light"}; + /** font constituent names which identify a font as being of "medium" weight */ + private static final String[] MEDIUM_WORDS = {"medium"}; + /** font constituent names which identify a font as being of "demi/semi" weight */ + private static final String[] DEMI_WORDS = {"demi", "semi"}; /** font constituent names which identify a font as being of "bold" weight */ private static final String[] BOLD_WORDS = {"bold"}; - /** font constituent names which identify a font as being of "bold" weight */ - private static final String[] EXTRA_BOLD_WORDS = {"extrabold", "black", + /** font constituent names which identify a font as being of "extra bold" weight */ + private static final String[] EXTRA_BOLD_WORDS = {"extrabold", "extra bold", "black", "heavy", "ultra", "super"}; /** @@ -109,12 +113,27 @@ public class FontUtil { public static int guessWeight(String fontName) { // weight int weight = Font.WEIGHT_NORMAL; + for (int i = 0; i < BOLD_WORDS.length; i++) { if (fontName.indexOf(BOLD_WORDS[i]) != -1) { weight = Font.WEIGHT_BOLD; break; } } + for (int i = 0; i < MEDIUM_WORDS.length; i++) { + if (fontName.indexOf(MEDIUM_WORDS[i]) != -1) { + weight = Font.WEIGHT_NORMAL + 100; //500 + break; + } + } + //Search for "semi/demi" before "light", but after "bold" + //(normally semi/demi-bold is meant, but it can also be semi/demi-light) + for (int i = 0; i < DEMI_WORDS.length; i++) { + if (fontName.indexOf(DEMI_WORDS[i]) != -1) { + weight = Font.WEIGHT_BOLD - 100; //600 + break; + } + } for (int i = 0; i < EXTRA_BOLD_WORDS.length; i++) { if (fontName.indexOf(EXTRA_BOLD_WORDS[i]) != -1) { weight = Font.WEIGHT_EXTRA_BOLD; diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java index aaefc789b..1ec8a5528 100644 --- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java +++ b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java @@ -31,6 +31,7 @@ import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.fonts.CachedFontInfo; import org.apache.fop.fonts.CustomFont; import org.apache.fop.fonts.EmbedFontInfo; @@ -66,28 +67,32 @@ public class FontInfoFinder { // default style and weight triplet vales (fallback) String strippedName = stripQuotes(customFont.getStrippedFontName()); - String subName = customFont.getFontSubName(); - String searchName = strippedName.toLowerCase(); - if (subName != null) { - searchName += subName.toLowerCase(); - } - + //String subName = customFont.getFontSubName(); + String fullName = stripQuotes(customFont.getFullName()); + String searchName = fullName.toLowerCase(); + String style = guessStyle(customFont, searchName); int weight = FontUtil.guessWeight(searchName); //Full Name usually includes style/weight info so don't use these traits //If we still want to use these traits, we have to make FontInfo.fontLookup() smarter - String fullName = stripQuotes(customFont.getFullName()); - triplets.add(new FontTriplet(fullName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); + triplets.add(new FontTriplet(fullName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, 0)); if (!fullName.equals(strippedName)) { - triplets.add(new FontTriplet(strippedName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); + triplets.add(new FontTriplet(strippedName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL, 0)); } Set familyNames = customFont.getFamilyNames(); Iterator iter = familyNames.iterator(); while (iter.hasNext()) { String familyName = stripQuotes((String)iter.next()); if (!fullName.equals(familyName)) { - triplets.add(new FontTriplet(familyName, style, weight)); + /* Heuristic: + * The more similar the family name to the full font name, + * the higher the priority of its triplet. + * (Lower values indicate higher priorities.) */ + int priority = fullName.startsWith(familyName) + ? fullName.length() - familyName.length() + : fullName.length(); + triplets.add(new FontTriplet(familyName, style, weight, priority)); } } } diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index f725bd711..6f1bfeea6 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -78,7 +78,7 @@ public abstract class PrintRenderer extends AbstractRenderer { } /** - * Returns the internal font key fot a font triplet coming from the area tree + * Returns the internal font key for a font triplet coming from the area tree * @param area the area from which to retrieve the font triplet information * @return the internal font key (F1, F2 etc.) or null if not found */ diff --git a/status.xml b/status.xml index d6693d2cd..6236a7c56 100644 --- a/status.xml +++ b/status.xml @@ -28,6 +28,10 @@ + + Improved the font auto-detection so fonts accessed using the font-family name are + selected with higher accuracy. + Removed deprecated methods in the "apps" package that were left-overs from the API discussions. -- 2.39.5