Jeremias,

Here's a patch. It fixes the DejaVu Condensed problem as well as my
Nimbus problem, as well as other problems of the same sort that
surfaced during testing. It is somewhat less clean a solution than I
had hoped; however, I cannot currently think of anything substantially
better short of a full-fledged, configurable font fallback system.

Jeremias Maerki <[EMAIL PROTECTED]> wrote on Tue, 12 Feb 2008
09:46:35 +0100:

>> > - If the triplet exists already and the family name equals the full name
>> > then replace the triplet.

This does not quite cut it, as it does not properly resolve things in
cases where neither of the colliding family names equal the full
name.

Here's my new heuristic: The more similar the family name to the full
name, the higher the priority of the family-name triplet.

Here is a brief account of my changes:

- In FontInfoFinder.generateTripletsFromFont(), triplets are assigned
  a priority based on a crude approximation to the above heuristic.

- This priority is added to the FontTriplet.

- In FontInfo.java, the triplets Map now maps to an object that, in
  addition to the "font key", now contains a reference back to the
  triplet so that FontInfo.addFontProperties() can access its
  priority. (An alternative solution would be to store the priorities
  in a separate HashMap. This would require additional put()s and
  get()s, but would slightly shorten the code and would have the
  advantage that once addFontProperties() is done, all remains the
  same as before.)

- FontInfo.addFontProperties() now checks for triplet collisions and
  resolves them by simply comparing the priorities stored in the
  FontTriplets.

This solved *all* of my DejaVu Condensed and related problems. I made
some other minor changes along the way:

- To solve the Nimbus problem where bold and italic fonts replaced the
  correct, normal fonts (as well as related problems involving other
  URW Type-1 fonts), I added "medium" and "demi" to the
  BOLD_WORDS. (According to FontForge, my "medium" fonts are
  explicitly marked bold; in URW Gothic "demi" is used as a font
  weight, and the "Demi" font is heavier than "Book".)

- These words appear truncated in some of my font names; therefore, in
  FontInfoFinder.generateTripletsFromFont() searchName is now based on
  fullName instead of on fontName.

- I fixed a couple of unrelated comments along the way.

Justus

Index: src/java/org/apache/fop/render/PrintRenderer.java
===================================================================
--- src/java/org/apache/fop/render/PrintRenderer.java	(revision 628254)
+++ src/java/org/apache/fop/render/PrintRenderer.java	(working copy)
@@ -78,7 +78,7 @@
     }
 
     /**
-     * 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
      */
Index: src/java/org/apache/fop/fonts/FontUtil.java
===================================================================
--- src/java/org/apache/fop/fonts/FontUtil.java	(revision 628254)
+++ src/java/org/apache/fop/fonts/FontUtil.java	(working copy)
@@ -82,7 +82,7 @@
     /** 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 "bold" weight */
-    private static final String[] BOLD_WORDS = {"bold"};
+    private static final String[] BOLD_WORDS = {"bold", "medium", "demi"};
     /** font constituent names which identify a font as being of "bold" weight */
     private static final String[] EXTRA_BOLD_WORDS = {"extrabold", "black", 
         "heavy", "ultra", "super"};
Index: src/java/org/apache/fop/fonts/FontTriplet.java
===================================================================
--- src/java/org/apache/fop/fonts/FontTriplet.java	(revision 628254)
+++ src/java/org/apache/fop/fonts/FontTriplet.java	(working copy)
@@ -32,10 +32,11 @@
     private String name;
     private String style;
     private int weight;
+    private int priority;
     
     //This is only a cache
     private transient String key;
-    
+
     /**
      * Creates a new font triplet.
      * @param name font name
@@ -43,9 +44,21 @@
      * @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 association
+     */
+    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 @@
         return weight;
     }
 
+    /** @return the priority of this font association */
+    public int getPriority() {
+	return priority;
+    }
+
     private String getKey() {
         if (this.key == null) {
             //This caches the combined key
Index: src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java
===================================================================
--- src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java	(revision 628254)
+++ src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java	(working copy)
@@ -67,27 +67,28 @@
         // 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 fullName = stripQuotes(customFont.getFullName());
+        String searchName = fullName.toLowerCase();
+
         String style = guessStyle(customFont, searchName);
+	// Isn't weight information contained in the font file??:
         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));
+		int priority = fullName.startsWith(familyName)
+		    ? fullName.length() - familyName.length()
+		    : fullName.length();
+                triplets.add(new FontTriplet(familyName, style, weight, priority));
             }
         }
     }
Index: src/java/org/apache/fop/fonts/FontInfo.java
===================================================================
--- src/java/org/apache/fop/fonts/FontInfo.java	(revision 628254)
+++ src/java/org/apache/fop/fonts/FontInfo.java	(working copy)
@@ -50,7 +50,23 @@
     private Map usedFonts; //Map<String,FontMetrics> (String = font key)
     
     /** look up a font-triplet to find a font-name */
-    private Map triplets; //Map<FontTriplet,String> (String = font key)
+    private Map triplets; //Map<FontTriplet,TripletAndFontKey>
+
+    /** allows the retrieval of the entire FontTriplet (not only the
+	part serving as the hash code) and the internal font key it
+	maps to */
+    private class TripletAndFontKey {
+	private FontTriplet triplet;
+	private String fontKey;
+
+	public TripletAndFontKey(FontTriplet triplet, String fontKey) {
+	    this.triplet = triplet;
+	    this.fontKey = fontKey;
+	}
+
+	public FontTriplet getTriplet() { return triplet; }
+	public String getFontKey() { return fontKey; }
+    }
     
     /** look up a font-name to get a font (that implements FontMetrics at least) */
     private Map fonts; //Map<String,FontMetrics> (String = font key)
@@ -92,6 +108,25 @@
         addFontProperties(name, createFontKey(family, style, weight));
     }
 
+    /** Log warning about repeated font triplets.
+     * @param oldFont existing entry in this.triplets
+     * @param newTriplet new triplet (key part identical to that in oldFont)
+     * @param newKey new internal font name
+     * @param replacing true iff the new font will replace the old one
+     */
+    private void logDuplicateFont(TripletAndFontKey oldFont,
+				  FontTriplet newTriplet, String newKey,
+				  boolean replacing) {
+	if (log.isDebugEnabled()) {
+	    log.debug(newTriplet +
+		      (replacing ? ": Replacing " : ": Not replacing ") +
+		      ((FontMetrics)fonts.get(oldFont.getFontKey())).getFullName() + " (" +
+		      oldFont.getTriplet().getPriority() + ") by " +
+		      ((FontMetrics)fonts.get(newKey)).getFullName() +
+		      " (" + newTriplet.getPriority() + ")");
+	}
+    }
+
     /**
      * Adds a new font triplet.
      * @param name internal key
@@ -105,7 +140,17 @@
         if (log.isDebugEnabled()) {
             log.debug("Registering: " + triplet + " under " + name);
         }
-        this.triplets.put(triplet, name);
+	TripletAndFontKey oldTFK = (TripletAndFontKey)triplets.get(triplet);
+	if (oldTFK != null) {
+	    if (oldTFK.getTriplet().getPriority() < triplet.getPriority()) {
+		logDuplicateFont(oldTFK, triplet, name, false);
+		return;
+	    }
+	    else {
+		logDuplicateFont(oldTFK, triplet, name, true);
+	    }
+	}
+        this.triplets.put(triplet, new TripletAndFontKey(triplet, name));
     }
 
     /**
@@ -392,7 +437,8 @@
      * @return the associated internal key or null, if not found
      */
     public String getInternalFontKey(FontTriplet triplet) {
-        return (String)triplets.get(triplet);
+	TripletAndFontKey tak = (TripletAndFontKey)triplets.get(triplet);
+        return (tak == null) ? null : tak.getFontKey();
     }
     
     /**
Index: src/java/org/apache/fop/fonts/FontResolver.java
===================================================================
--- src/java/org/apache/fop/fonts/FontResolver.java	(revision 628254)
+++ src/java/org/apache/fop/fonts/FontResolver.java	(working copy)
@@ -28,7 +28,7 @@
 
     /**
      * 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.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to