1 /*
2  * $Id: FontDetails.java 3869 2009-04-17 18:03:45Z blowagie $
3  *
4  * Copyright 2001, 2002 by Paulo Soares.
5  *
6  * The contents of this file are subject to the Mozilla Public License Version 1.1
7  * (the "License"); you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the License.
13  *
14  * The Original Code is 'iText, a free JAVA-PDF library'.
15  *
16  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18  * All Rights Reserved.
19  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
21  *
22  * Contributor(s): all the names of the contributors are added in the source code
23  * where applicable.
24  *
25  * Alternatively, the contents of this file may be used under the terms of the
26  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27  * provisions of LGPL are applicable instead of those above.  If you wish to
28  * allow use of your version of this file only under the terms of the LGPL
29  * License and not to allow others to use your version of this file under
30  * the MPL, indicate your decision by deleting the provisions above and
31  * replace them with the notice and other provisions required by the LGPL.
32  * If you do not delete the provisions above, a recipient may use your version
33  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
34  *
35  * This library is free software; you can redistribute it and/or modify it
36  * under the terms of the MPL as stated above or under the terms of the GNU
37  * Library General Public License as published by the Free Software Foundation;
38  * either version 2 of the License, or any later version.
39  *
40  * This library is distributed in the hope that it will be useful, but WITHOUT
41  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
43  * details.
44  *
45  * If you didn't download this code from the following link, you should check if
46  * you aren't using an obsolete version:
47  * http://www.lowagie.com/iText/
48  */

49
50 package com.lowagie.text.pdf;
51
52 import java.awt.font.GlyphVector;
53 import java.io.UnsupportedEncodingException;
54 import java.util.HashMap;
55
56 import com.lowagie.text.ExceptionConverter;
57 import com.lowagie.text.Utilities;
58
59 /**
60  * Each font in the document will have an instance of this class
61  * where the characters used will be represented.
62  *
63  * @author  Paulo Soares (psoares@consiste.pt)
64  */

65 class FontDetails {
66     
67     /**
68      * The indirect reference to this font
69      */
    
70     PdfIndirectReference indirectReference;
71     /**
72      * The font name that appears in the document body stream
73      */
    
74     PdfName fontName;
75     /**
76      * The font
77      */
    
78     BaseFont baseFont;
79     /**
80      * The font if it's an instance of <CODE>TrueTypeFontUnicode</CODE>
81      */
    
82     TrueTypeFontUnicode ttu;
83     /**
84      * The font if it's an instance of <CODE>CJKFont</CODE>
85      */

86     CJKFont cjkFont;
87     /**
88      * The array used with single byte encodings
89      */
    
90     byte shortTag[];
91     /**
92      * The map used with double byte encodings. The key is Integer(glyph) and
93      * the value is int[]{glyph, width, Unicode code}
94      */
    
95     HashMap longTag;
96     /**
97      * IntHashtable with CIDs of CJK glyphs that are used in the text.
98      */

99     IntHashtable cjkTag;
100     /**
101      * The font type
102      */
    
103     int fontType;
104     /**
105      * <CODE>true</CODE> if the font is symbolic
106      */
    
107     boolean symbolic;
108     /**
109      * Indicates if only a subset of the glyphs and widths for that particular
110      * encoding should be included in the document.
111      */

112     protected boolean subset = true;
113     
114     /**
115      * Each font used in a document has an instance of this class.
116      * This class stores the characters used in the document and other
117      * specifics unique to the current working document.
118      * @param fontName the font name
119      * @param indirectReference the indirect reference to the font
120      * @param baseFont the <CODE>BaseFont</CODE>
121      */

122     FontDetails(PdfName fontName, PdfIndirectReference indirectReference, BaseFont baseFont) {
123         this.fontName = fontName;
124         this.indirectReference = indirectReference;
125         this.baseFont = baseFont;
126         fontType = baseFont.getFontType();
127         switch (fontType) {
128             case BaseFont.FONT_TYPE_T1:
129             case BaseFont.FONT_TYPE_TT:
130                 shortTag = new byte[256];
131                 break;
132             case BaseFont.FONT_TYPE_CJK:
133                 cjkTag = new IntHashtable();
134                 cjkFont = (CJKFont)baseFont;
135                 break;
136             case BaseFont.FONT_TYPE_TTUNI:
137                 longTag = new HashMap();
138                 ttu = (TrueTypeFontUnicode)baseFont;
139                 symbolic = baseFont.isFontSpecific();
140                 break;
141         }
142     }
143     
144     /**
145      * Gets the indirect reference to this font.
146      * @return the indirect reference to this font
147      */
    
148     PdfIndirectReference getIndirectReference() {
149         return indirectReference;
150     }
151     
152     /**
153      * Gets the font name as it appears in the document body.
154      * @return the font name
155      */
    
156     PdfName getFontName() {
157         return fontName;
158     }
159     
160     /**
161      * Gets the <CODE>BaseFont</CODE> of this font.
162      * @return the <CODE>BaseFont</CODE> of this font
163      */
    
164     BaseFont getBaseFont() {
165         return baseFont;
166     }
167     
168     /**
169      * Converts the text into bytes to be placed in the document.
170      * The conversion is done according to the font and the encoding and the characters
171      * used are stored.
172      * @param text the text to convert
173      * @return the conversion
174      */
    
175     byte[] convertToBytes(String text) {
176         byte b[] = null;
177         switch (fontType) {
178             case BaseFont.FONT_TYPE_T3:
179                 return baseFont.convertToBytes(text);
180             case BaseFont.FONT_TYPE_T1:
181             case BaseFont.FONT_TYPE_TT: {
182                 b = baseFont.convertToBytes(text);
183                 int len = b.length;
184                 for (int k = 0; k < len; ++k)
185                     shortTag[b[k] & 0xff] = 1;
186                 break;
187             }
188             case BaseFont.FONT_TYPE_CJK: {
189                 int len = text.length();
190                 for (int k = 0; k < len; ++k)
191                     cjkTag.put(cjkFont.getCidCode(text.charAt(k)), 0);
192                 b = baseFont.convertToBytes(text);
193                 break;
194             }
195             case BaseFont.FONT_TYPE_DOCUMENT: {
196                 b = baseFont.convertToBytes(text);
197                 break;
198             }
199             case BaseFont.FONT_TYPE_TTUNI: {
200                 try {
201                     int len = text.length();
202                     int metrics[] = null;
203                     char glyph[] = new char[len];
204                     int i = 0;
205                     if (symbolic) {
206                         b = PdfEncodings.convertToBytes(text, "symboltt");
207                         len = b.length;
208                         for (int k = 0; k < len; ++k) {
209                             metrics = ttu.getMetricsTT(b[k] & 0xff);
210                             if (metrics == null)
211                                 continue;
212                             longTag.put(new Integer(metrics[0]), new int[]{metrics[0], metrics[1], ttu.getUnicodeDifferences(b[k] & 0xff)});
213                             glyph[i++] = (char)metrics[0];
214                         }
215                     }
216                     else {
217                         for (int k = 0; k < len; ++k) {
218                             int val;
219                             if (Utilities.isSurrogatePair(text, k)) {
220                                 val = Utilities.convertToUtf32(text, k);
221                                 k++;
222                             }
223                             else {
224                                 val = text.charAt(k);
225                             }
226                             metrics = ttu.getMetricsTT(val);
227                             if (metrics == null)
228                                 continue;
229                             int m0 = metrics[0];
230                             Integer gl = new Integer(m0);
231                             if (!longTag.containsKey(gl))
232                                 longTag.put(gl, new int[]{m0, metrics[1], val});
233                             glyph[i++] = (char)m0;
234                         }
235                     }
236                     String s = new String(glyph, 0, i);
237                     b = s.getBytes(CJKFont.CJK_ENCODING);
238                 }
239                 catch (UnsupportedEncodingException e) {
240                     throw new ExceptionConverter(e);
241                 }
242                 break;
243             }
244         }
245         return b;
246     }
247     
248     /**
249      * Writes the font definition to the document.
250      * @param writer the <CODE>PdfWriter</CODE> of this document
251      */
    
252     void writeFont(PdfWriter writer) {
253         try {
254             switch (fontType) {
255                 case BaseFont.FONT_TYPE_T3:
256                     baseFont.writeFont(writer, indirectReference, null);
257                     break;
258                 case BaseFont.FONT_TYPE_T1:
259                 case BaseFont.FONT_TYPE_TT: {
260                     int firstChar;
261                     int lastChar;
262                     for (firstChar = 0; firstChar < 256; ++firstChar) {
263                         if (shortTag[firstChar] != 0)
264                             break;
265                     }
266                     for (lastChar = 255; lastChar >= firstChar; --lastChar) {
267                         if (shortTag[lastChar] != 0)
268                             break;
269                     }
270                     if (firstChar > 255) {
271                         firstChar = 255;
272                         lastChar = 255;
273                     }
274                     baseFont.writeFont(writer, indirectReference, new Object[]{new Integer(firstChar), new Integer(lastChar), shortTag, Boolean.valueOf(subset)});
275                     break;
276                 }
277                 case BaseFont.FONT_TYPE_CJK:
278                     baseFont.writeFont(writer, indirectReference, new Object[]{cjkTag});
279                     break;
280                 case BaseFont.FONT_TYPE_TTUNI:
281                     baseFont.writeFont(writer, indirectReference, new Object[]{longTag, Boolean.valueOf(subset)});
282                     break;
283             }
284         }
285         catch(Exception e) {
286             throw new ExceptionConverter(e);
287         }
288     }
289     
290     /**
291      * Indicates if all the glyphs and widths for that particular
292      * encoding should be included in the document.
293      * @return <CODE>false</CODE> to include all the glyphs and widths.
294      */

295     public boolean isSubset() {
296         return subset;
297     }
298     
299     /**
300      * Indicates if all the glyphs and widths for that particular
301      * encoding should be included in the document. Set to <CODE>false</CODE>
302      * to include all.
303      * @param subset new value of property subset
304      */

305     public void setSubset(boolean subset) {
306         this.subset = subset;
307     }
308 }
309