1 /*
2 * $Id: FontDetails.java 3427 2008-05-24 18:32:31Z xlv $
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.io.UnsupportedEncodingException;
53 import java.util.HashMap;
54
55 import com.lowagie.text.ExceptionConverter;
56 import com.lowagie.text.Utilities;
57 /** Each font in the document will have an instance of this class
58 * where the characters used will be represented.
59 *
60 * @author Paulo Soares (psoares@consiste.pt)
61 */
62 class FontDetails {
63
64 /** The indirect reference to this font
65 */
66 PdfIndirectReference indirectReference;
67 /** The font name that appears in the document body stream
68 */
69 PdfName fontName;
70 /** The font
71 */
72 BaseFont baseFont;
73 /** The font if its an instance of <CODE>TrueTypeFontUnicode</CODE>
74 */
75 TrueTypeFontUnicode ttu;
76
77 CJKFont cjkFont;
78 /** The array used with single byte encodings
79 */
80 byte shortTag[];
81 /** The map used with double byte encodings. The key is Integer(glyph) and the
82 * value is int[]{glyph, width, Unicode code}
83 */
84 HashMap longTag;
85
86 IntHashtable cjkTag;
87 /** The font type
88 */
89 int fontType;
90 /** <CODE>true</CODE> if the font is symbolic
91 */
92 boolean symbolic;
93 /** Indicates if all the glyphs and widths for that particular
94 * encoding should be included in the document.
95 */
96 protected boolean subset = true;
97 /** Each font used in a document has an instance of this class.
98 * This class stores the characters used in the document and other
99 * specifics unique to the current working document.
100 * @param fontName the font name
101 * @param indirectReference the indirect reference to the font
102 * @param baseFont the <CODE>BaseFont</CODE>
103 */
104 FontDetails(PdfName fontName, PdfIndirectReference indirectReference, BaseFont baseFont) {
105 this.fontName = fontName;
106 this.indirectReference = indirectReference;
107 this.baseFont = baseFont;
108 fontType = baseFont.getFontType();
109 switch (fontType) {
110 case BaseFont.FONT_TYPE_T1:
111 case BaseFont.FONT_TYPE_TT:
112 shortTag = new byte[256];
113 break;
114 case BaseFont.FONT_TYPE_CJK:
115 cjkTag = new IntHashtable();
116 cjkFont = (CJKFont)baseFont;
117 break;
118 case BaseFont.FONT_TYPE_TTUNI:
119 longTag = new HashMap();
120 ttu = (TrueTypeFontUnicode)baseFont;
121 symbolic = baseFont.isFontSpecific();
122 break;
123 }
124 }
125
126 /** Gets the indirect reference to this font.
127 * @return the indirect reference to this font
128 */
129 PdfIndirectReference getIndirectReference() {
130 return indirectReference;
131 }
132
133 /** Gets the font name as it appears in the document body.
134 * @return the font name
135 */
136 PdfName getFontName() {
137 return fontName;
138 }
139
140 /** Gets the <CODE>BaseFont</CODE> of this font.
141 * @return the <CODE>BaseFont</CODE> of this font
142 */
143 BaseFont getBaseFont() {
144 return baseFont;
145 }
146
147 /** Converts the text into bytes to be placed in the document.
148 * The conversion is done according to the font and the encoding and the characters
149 * used are stored.
150 * @param text the text to convert
151 * @return the conversion
152 */
153 byte[] convertToBytes(String text) {
154 byte b[] = null;
155 switch (fontType) {
156 case BaseFont.FONT_TYPE_T3:
157 return baseFont.convertToBytes(text);
158 case BaseFont.FONT_TYPE_T1:
159 case BaseFont.FONT_TYPE_TT: {
160 b = baseFont.convertToBytes(text);
161 int len = b.length;
162 for (int k = 0; k < len; ++k)
163 shortTag[b[k] & 0xff] = 1;
164 break;
165 }
166 case BaseFont.FONT_TYPE_CJK: {
167 int len = text.length();
168 for (int k = 0; k < len; ++k)
169 cjkTag.put(cjkFont.getCidCode(text.charAt(k)), 0);
170 b = baseFont.convertToBytes(text);
171 break;
172 }
173 case BaseFont.FONT_TYPE_DOCUMENT: {
174 b = baseFont.convertToBytes(text);
175 break;
176 }
177 case BaseFont.FONT_TYPE_TTUNI: {
178 try {
179 int len = text.length();
180 int metrics[] = null;
181 char glyph[] = new char[len];
182 int i = 0;
183 if (symbolic) {
184 b = PdfEncodings.convertToBytes(text, "symboltt");
185 len = b.length;
186 for (int k = 0; k < len; ++k) {
187 metrics = ttu.getMetricsTT(b[k] & 0xff);
188 if (metrics == null)
189 continue;
190 longTag.put(new Integer(metrics[0]), new int[]{metrics[0], metrics[1], ttu.getUnicodeDifferences(b[k] & 0xff)});
191 glyph[i++] = (char)metrics[0];
192 }
193 }
194 else {
195 for (int k = 0; k < len; ++k) {
196 int val;
197 if (Utilities.isSurrogatePair(text, k)) {
198 val = Utilities.convertToUtf32(text, k);
199 k++;
200 }
201 else {
202 val = text.charAt(k);
203 }
204 metrics = ttu.getMetricsTT(val);
205 if (metrics == null)
206 continue;
207 int m0 = metrics[0];
208 Integer gl = new Integer(m0);
209 if (!longTag.containsKey(gl))
210 longTag.put(gl, new int[]{m0, metrics[1], val});
211 glyph[i++] = (char)m0;
212 }
213 }
214 String s = new String(glyph, 0, i);
215 b = s.getBytes(CJKFont.CJK_ENCODING);
216 }
217 catch (UnsupportedEncodingException e) {
218 throw new ExceptionConverter(e);
219 }
220 break;
221 }
222 }
223 return b;
224 }
225
226 /** Writes the font definition to the document.
227 * @param writer the <CODE>PdfWriter</CODE> of this document
228 */
229 void writeFont(PdfWriter writer) {
230 try {
231 switch (fontType) {
232 case BaseFont.FONT_TYPE_T3:
233 baseFont.writeFont(writer, indirectReference, null);
234 break;
235 case BaseFont.FONT_TYPE_T1:
236 case BaseFont.FONT_TYPE_TT: {
237 int firstChar;
238 int lastChar;
239 for (firstChar = 0; firstChar < 256; ++firstChar) {
240 if (shortTag[firstChar] != 0)
241 break;
242 }
243 for (lastChar = 255; lastChar >= firstChar; --lastChar) {
244 if (shortTag[lastChar] != 0)
245 break;
246 }
247 if (firstChar > 255) {
248 firstChar = 255;
249 lastChar = 255;
250 }
251 baseFont.writeFont(writer, indirectReference, new Object[]{new Integer(firstChar), new Integer(lastChar), shortTag, Boolean.valueOf(subset)});
252 break;
253 }
254 case BaseFont.FONT_TYPE_CJK:
255 baseFont.writeFont(writer, indirectReference, new Object[]{cjkTag});
256 break;
257 case BaseFont.FONT_TYPE_TTUNI:
258 baseFont.writeFont(writer, indirectReference, new Object[]{longTag, Boolean.valueOf(subset)});
259 break;
260 }
261 }
262 catch(Exception e) {
263 throw new ExceptionConverter(e);
264 }
265 }
266
267 /** Indicates if all the glyphs and widths for that particular
268 * encoding should be included in the document.
269 * @return <CODE>false</CODE> to include all the glyphs and widths.
270 */
271 public boolean isSubset() {
272 return subset;
273 }
274
275 /** Indicates if all the glyphs and widths for that particular
276 * encoding should be included in the document. Set to <CODE>false</CODE>
277 * to include all.
278 * @param subset new value of property subset
279 */
280 public void setSubset(boolean subset) {
281 this.subset = subset;
282 }
283 }