View Javadoc

1   // Copyright 2001-2007 freehep
2   package org.freehep.graphicsio.font;
3   
4   import java.awt.Font;
5   import java.awt.font.TextAttribute;
6   import java.io.IOException;
7   import java.util.Collection;
8   import java.util.Hashtable;
9   import java.util.Map;
10  
11  import org.freehep.graphics2d.font.CharTable;
12  import org.freehep.graphics2d.font.FontUtilities;
13  import org.freehep.graphics2d.font.Lookup;
14  
15  /**
16   * A table to remember which fonts were used while writing a document.
17   * 
18   * @author Simon Fischer
19   * @version $Id: FontTable.java 10516 2007-02-06 21:11:19Z duns $
20   */
21  public abstract class FontTable {
22  
23      protected class Entry {
24          private Font font;
25  
26          private String ref;
27  
28          private CharTable encoding;
29  
30          private boolean written;
31  
32          private Entry(Font f, CharTable encoding) {
33              // get attributes of font for the stored default font
34              Map/*<TextAttribute,?>*/ attributes = FontUtilities.getAttributes(f);
35  
36              // set default font size
37              attributes.put(TextAttribute.SIZE, new Float(FontEmbedder.FONT_SIZE));
38  
39              // remove font transformations
40              attributes.remove(TextAttribute.TRANSFORM);
41              attributes.remove(TextAttribute.SUPERSCRIPT);
42  
43              this.font = new Font(attributes);
44  
45              this.ref = createFontReference(this.font);
46              this.encoding = encoding;
47              this.written = false;
48          }
49  
50          public Font getFont() {
51              return font;
52          }
53  
54          public String getReference() {
55              return ref;
56          }
57  
58          protected void setReference(String ref) {
59              this.ref = ref;
60          }
61  
62          public CharTable getEncoding() {
63              return encoding;
64          }
65  
66          public void setWritten(boolean written) {
67              this.written = written;
68          }
69  
70          public boolean isWritten() {
71              return written;
72          }
73  
74          public String toString() {
75              return ref + "=" + font;
76          }
77      }
78  
79      private Hashtable table;
80  
81      public FontTable() {
82          this.table = new Hashtable();
83      }
84  
85      /**
86       * Returns a default CharTable to be used for normal text (not Symbol or
87       * Dingbats).
88       */
89      public abstract CharTable getEncodingTable();
90  
91      /**
92       * Called whenever a specific font is used for the first time. Subclasses
93       * may use this method to include the font instantly. This method may change
94       * the value of the reference by calling <tt>e.setReference(String)</tt>
95       * e.g. if it wants to substitute the font by a standard font that can be
96       * addressed under a name different from the generated one.
97       */
98      protected abstract void firstRequest(Entry e, boolean embed, String embedAs)
99              throws IOException;
100 
101     /** Creates a unique reference to address this font. */
102     protected abstract String createFontReference(Font f);
103 
104     protected abstract Font substituteFont(Font font);
105 
106     /**
107      * Returns a name for this font that can be used in the document. A new name
108      * is generated if the font was not used yet. For different fontsizes the
109      * same name is returned.
110      */
111     public String fontReference(Font font, boolean embed, String embedAs) {
112         // look for stored font
113         font = substituteFont(font);
114         String key = getKey(font);
115         Entry e = (Entry) table.get(key);
116 
117         // create new one
118         if (e == null) {
119             e = new Entry(font, getEncodingTable(font));
120             try {
121                 firstRequest(e, embed, embedAs);
122             } catch (IOException exc) {
123                 exc.printStackTrace();
124             }
125             table.put(key, e);
126         }
127 
128         return e.ref;
129     }
130 
131     /**
132      * To embed all derivations of a font too (with underline,
133      * strikethrough etc.) the key consists all these attributes.
134      *
135      * @param font ist attributes are used
136      * @return something like Helvetica[BOLD:1][ITALIC:0][UNDERLINE:1]
137      */
138     private String getKey(Font font) {
139         Map/*<TextAttribute,?>*/ attributes = FontUtilities.getAttributes(font);
140 
141         StringBuffer result = new StringBuffer(font.getName());
142 
143         // bold
144         result.append("[WEIGHT:");
145         result.append(attributes.get(TextAttribute.WEIGHT));
146         result.append("]");
147 
148         // italic
149         result.append("[POSTURE:");
150         result.append(attributes.get(TextAttribute.POSTURE));
151         result.append("]");
152 
153         // underline is not handled as an font property
154         // result.append("[UNDERLINE:");
155         // result.append(attributes.get(TextAttribute.UNDERLINE));
156         // result.append("]");
157 
158         // strike through is not handled as an font property
159         // result.append("[STRIKETHROUGH:");
160         // result.append(attributes.get(TextAttribute.STRIKETHROUGH));
161         // result.append("]");
162 
163         // SUPERSCRIPT is apllied by font.getTransformation()
164         // leave this as a reminder!
165         // result.append("[");
166         // result.append(attributes.get(TextAttribute.SUPERSCRIPT));
167         // result.append("]");
168 
169         // width is not handled as an font property
170         // result.append("[WIDTH:");
171         // result.append(attributes.get(TextAttribute.WIDTH));
172         // result.append("]");
173 
174         return result.toString();
175     }
176 
177     /**
178      * creates a normalized attribute map, e.g.
179      * java.awt.Font[family=Dialog,name=dialog.bold,style=plain,size=20]
180      * becomes
181      * java.awt.Font[family=Dialog,name=Dialog,style=bold,size=20]
182      *
183      * @param attributes
184      */
185     public static void normalize(Map/*<TextAttribute,?>*/ attributes) {
186         // get name
187         String family = (String) attributes.get(TextAttribute.FAMILY);
188 
189         // Java font names could end with ".plain" ".bold"
190         // and ".italic". We have to convert this to an
191         // attribute first
192         if (family.toLowerCase().endsWith(".bold")) {
193             attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
194             // cut the ".bold"
195             int pos = family.toLowerCase().indexOf(".bold");
196             family = family.substring(0, pos);
197         } else if (family.toLowerCase().endsWith(".italic")) {
198             attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
199             // cut the ".italic"
200             int pos = family.toLowerCase().indexOf(".italic");
201             family = family.substring(0, pos);
202         } else if (family.toLowerCase().endsWith(".plain")) {
203             // cut the ".plain"
204             int pos = family.toLowerCase().indexOf(".plain");
205             family = family.substring(0, pos);
206         }
207 
208         // first character up
209         family = family.substring(0, 1).toUpperCase() + family.substring(1, family.length());
210         attributes.put(TextAttribute.FAMILY, family);
211     }
212 
213     /**
214      * Returns a Collection view of all fonts. The elements of the collection
215      * are <tt>Entrie</tt>s.
216      */
217     public Collection getEntries() {
218         return table.values();
219     }
220 
221     private CharTable getEncodingTable(Font font) {
222         String fontname = font.getName().toLowerCase();
223         if (fontname.indexOf("symbol") >= 0)
224             return Lookup.getInstance().getTable("Symbol");
225         if (fontname.indexOf("zapfdingbats") >= 0)
226             return Lookup.getInstance().getTable("Zapfdingbats");
227         return getEncodingTable();
228     }
229 
230 }