1 | /* | |
2 | * $Id: FontDetails.java 4024 2009-07-12 00:33:57Z 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.awt.font.GlyphVector; | |
53 | import java.io.UnsupportedEncodingException; | |
54 | import java.util.HashMap; | |
55 | ||
56 | ||
57 | import com.lowagie.text.Utilities; | |
58 | import com.lowagie.text.ExceptionConverter; | |
59 | ||
60 | /** | |
61 | * Each font in the document will have an instance of this class | |
62 | * where the characters used will be represented. | |
63 | * | |
64 | * @author Paulo Soares (psoares@consiste.pt) | |
65 | */ | |
66 | class FontDetails { | |
67 | | |
68 | /** | |
69 | * The indirect reference to this font | |
70 | */ | |
71 | PdfIndirectReference indirectReference; | |
72 | /** | |
73 | * The font name that appears in the document body stream | |
74 | */ | |
75 | PdfName fontName; | |
76 | /** | |
77 | * The font | |
78 | */ | |
79 | BaseFont baseFont; | |
80 | /** | |
81 | * The font if it's an instance of <CODE>TrueTypeFontUnicode</CODE> | |
82 | */ | |
83 | TrueTypeFontUnicode ttu; | |
84 | /** | |
85 | * The font if it's an instance of <CODE>CJKFont</CODE> | |
86 | */ | |
87 | CJKFont cjkFont; | |
88 | /** | |
89 | * The array used with single byte encodings | |
90 | */ | |
91 | byte[] shortTag; | |
92 | /** | |
93 | * The map used with double byte encodings. The key is Integer(glyph) and | |
94 | * the value is int[]{glyph, width, Unicode code} | |
95 | */ | |
96 | HashMap longTag; | |
97 | /** | |
98 | * IntHashtable with CIDs of CJK glyphs that are used in the text. | |
99 | */ | |
100 | IntHashtable cjkTag; | |
101 | /** | |
102 | * The font type | |
103 | */ | |
104 | int fontType; | |
105 | /** | |
106 | * <CODE>true</CODE> if the font is symbolic | |
107 | */ | |
108 | boolean symbolic; | |
109 | /** | |
110 | * Indicates if only a subset of the glyphs and widths for that particular | |
111 | * encoding should be included in the document. | |
112 | */ | |
113 | protected boolean subset = true; | |
114 | | |
115 | /** | |
116 | * Each font used in a document has an instance of this class. | |
117 | * This class stores the characters used in the document and other | |
118 | * specifics unique to the current working document. | |
119 | * @param fontName the font name | |
120 | * @param indirectReference the indirect reference to the font | |
121 | * @param baseFont the <CODE>BaseFont</CODE> | |
122 | */ | |
123 | FontDetails(PdfName fontName, PdfIndirectReference indirectReference, BaseFont baseFont) { | |
124 | this.fontName = fontName; | |
125 | this.indirectReference = indirectReference; | |
126 | this.baseFont = baseFont; | |
127 | fontType = baseFont.getFontType(); | |
128 | switch (fontType) { | |
129 | case BaseFont.FONT_TYPE_T1: | |
130 | case BaseFont.FONT_TYPE_TT: | |
131 | shortTag = new byte[256]; | |
132 | break; | |
133 | case BaseFont.FONT_TYPE_CJK: | |
134 | cjkTag = new IntHashtable(); | |
135 | cjkFont = (CJKFont)baseFont; | |
136 | break; | |
137 | case BaseFont.FONT_TYPE_TTUNI: | |
138 | longTag = new HashMap(); | |
139 | ttu = (TrueTypeFontUnicode)baseFont; | |
140 | symbolic = baseFont.isFontSpecific(); | |
141 | break; | |
142 | } | |
143 | } | |
144 | | |
145 | /** | |
146 | * Gets the indirect reference to this font. | |
147 | * @return the indirect reference to this font | |
148 | */ | |
149 | PdfIndirectReference getIndirectReference() { | |
150 | return indirectReference; | |
151 | } | |
152 | | |
153 | /** | |
154 | * Gets the font name as it appears in the document body. | |
155 | * @return the font name | |
156 | */ | |
157 | PdfName getFontName() { | |
158 | return fontName; | |
159 | } | |
160 | | |
161 | /** | |
162 | * Gets the <CODE>BaseFont</CODE> of this font. | |
163 | * @return the <CODE>BaseFont</CODE> of this font | |
164 | */ | |
165 | BaseFont getBaseFont() { | |
166 | return baseFont; | |
167 | } | |
168 | | |
169 | /** | |
170 | * Converts the text into bytes to be placed in the document. | |
171 | * The conversion is done according to the font and the encoding and the characters | |
172 | * used are stored. | |
173 | * @param text the text to convert | |
174 | * @return the conversion | |
175 | */ | |
176 | byte[] convertToBytes(String text) { | |
177 | byte[] b = null; | |
178 | switch (fontType) { | |
179 | case BaseFont.FONT_TYPE_T3: | |
180 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/FontDetails::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return baseFont.convertToBytes(text); |
181 | case BaseFont.FONT_TYPE_T1: | |
182 | case BaseFont.FONT_TYPE_TT: { | |
183 | b = baseFont.convertToBytes(text); | |
184 | int len = b.length; | |
185 |
1
1. convertToBytes : Replaced bitwise AND with OR → NO_COVERAGE |
for (byte b1 : b) shortTag[b1 & 0xff] = 1; |
186 | break; | |
187 | } | |
188 | case BaseFont.FONT_TYPE_CJK: { | |
189 | int len = text.length(); | |
190 |
3
1. convertToBytes : changed conditional boundary → NO_COVERAGE 2. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE 3. convertToBytes : negated conditional → NO_COVERAGE |
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 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (symbolic) { |
206 | b = PdfEncodings.convertToBytes(text, "symboltt"); | |
207 | len = b.length; | |
208 |
3
1. convertToBytes : changed conditional boundary → NO_COVERAGE 2. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE 3. convertToBytes : negated conditional → NO_COVERAGE |
for (int k = 0; k < len; ++k) { |
209 |
1
1. convertToBytes : Replaced bitwise AND with OR → NO_COVERAGE |
metrics = ttu.getMetricsTT(b[k] & 0xff); |
210 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (metrics == null) |
211 | continue; | |
212 |
1
1. convertToBytes : Replaced bitwise AND with OR → NO_COVERAGE |
longTag.put(metrics[0], new int[]{metrics[0], metrics[1], ttu.getUnicodeDifferences(b[k] & 0xff)}); |
213 | glyph[i++] = (char)metrics[0]; | |
214 | } | |
215 | } | |
216 | else { | |
217 |
3
1. convertToBytes : changed conditional boundary → NO_COVERAGE 2. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE 3. convertToBytes : negated conditional → NO_COVERAGE |
for (int k = 0; k < len; ++k) { |
218 | int val; | |
219 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (Utilities.isSurrogatePair(text, k)) { |
220 | val = Utilities.convertToUtf32(text, k); | |
221 |
1
1. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE |
k++; |
222 | } | |
223 | else { | |
224 | val = text.charAt(k); | |
225 | } | |
226 | metrics = ttu.getMetricsTT(val); | |
227 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (metrics == null) |
228 | continue; | |
229 | int m0 = metrics[0]; | |
230 | Integer gl = m0; | |
231 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
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 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/FontDetails::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return b; |
246 | } | |
247 | | |
248 | byte[] convertToBytes(GlyphVector glyphVector) { | |
249 |
2
1. convertToBytes : negated conditional → NO_COVERAGE 2. convertToBytes : negated conditional → NO_COVERAGE |
if (fontType != BaseFont.FONT_TYPE_TTUNI || symbolic) { |
250 | throw new UnsupportedOperationException("Only supported for True Type Unicode fonts"); | |
251 | } | |
252 | ||
253 | char[] glyphs = new char[glyphVector.getNumGlyphs()]; | |
254 | int glyphCount = 0; | |
255 |
3
1. convertToBytes : changed conditional boundary → NO_COVERAGE 2. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE 3. convertToBytes : negated conditional → NO_COVERAGE |
for (int i = 0; i < glyphs.length; i++) { |
256 | int code = glyphVector.getGlyphCode(i); | |
257 |
2
1. convertToBytes : negated conditional → NO_COVERAGE 2. convertToBytes : negated conditional → NO_COVERAGE |
if (code == 0xFFFE || code == 0xFFFF) {// considered non-glyphs by |
258 | // AWT | |
259 | continue; | |
260 | } | |
261 | ||
262 |
1
1. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE |
glyphs[glyphCount++] = (char) code;// FIXME supplementary plane? |
263 | ||
264 | Integer codeKey = code; | |
265 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (!longTag.containsKey(codeKey)) { |
266 | int glyphWidth = ttu.getGlyphWidth(code); | |
267 | Integer charCode = ttu.getCharacterCode(code); | |
268 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
int[] metrics = charCode != null ? new int[] { code, glyphWidth, charCode} : new int[] { |
269 | code, glyphWidth }; | |
270 | longTag.put(codeKey, metrics); | |
271 | } | |
272 | } | |
273 | ||
274 | String s = new String(glyphs, 0, glyphCount); | |
275 | try { | |
276 | byte[] b = s.getBytes(CJKFont.CJK_ENCODING); | |
277 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/FontDetails::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return b; |
278 | } catch (UnsupportedEncodingException e) { | |
279 | throw new ExceptionConverter(e); | |
280 | } | |
281 | } | |
282 | | |
283 | | |
284 | /** | |
285 | * Writes the font definition to the document. | |
286 | * @param writer the <CODE>PdfWriter</CODE> of this document | |
287 | */ | |
288 | void writeFont(PdfWriter writer) { | |
289 | try { | |
290 | switch (fontType) { | |
291 | case BaseFont.FONT_TYPE_T3: | |
292 |
1
1. writeFont : removed call to com/lowagie/text/pdf/BaseFont::writeFont → NO_COVERAGE |
baseFont.writeFont(writer, indirectReference, null); |
293 | break; | |
294 | case BaseFont.FONT_TYPE_T1: | |
295 | case BaseFont.FONT_TYPE_TT: { | |
296 | int firstChar; | |
297 | int lastChar; | |
298 |
3
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : Changed increment from 1 to -1 → NO_COVERAGE 3. writeFont : negated conditional → NO_COVERAGE |
for (firstChar = 0; firstChar < 256; ++firstChar) { |
299 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if (shortTag[firstChar] != 0) |
300 | break; | |
301 | } | |
302 |
3
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : Changed increment from -1 to 1 → NO_COVERAGE 3. writeFont : negated conditional → NO_COVERAGE |
for (lastChar = 255; lastChar >= firstChar; --lastChar) { |
303 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if (shortTag[lastChar] != 0) |
304 | break; | |
305 | } | |
306 |
2
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : negated conditional → NO_COVERAGE |
if (firstChar > 255) { |
307 | firstChar = 255; | |
308 | lastChar = 255; | |
309 | } | |
310 |
1
1. writeFont : removed call to com/lowagie/text/pdf/BaseFont::writeFont → NO_COVERAGE |
baseFont.writeFont(writer, indirectReference, new Object[]{firstChar, lastChar, shortTag, subset}); |
311 | break; | |
312 | } | |
313 | case BaseFont.FONT_TYPE_CJK: | |
314 |
1
1. writeFont : removed call to com/lowagie/text/pdf/BaseFont::writeFont → NO_COVERAGE |
baseFont.writeFont(writer, indirectReference, new Object[]{cjkTag}); |
315 | break; | |
316 | case BaseFont.FONT_TYPE_TTUNI: | |
317 |
1
1. writeFont : removed call to com/lowagie/text/pdf/BaseFont::writeFont → NO_COVERAGE |
baseFont.writeFont(writer, indirectReference, new Object[]{longTag, subset}); |
318 | break; | |
319 | } | |
320 | } | |
321 | catch(Exception e) { | |
322 | throw new ExceptionConverter(e); | |
323 | } | |
324 | } | |
325 | | |
326 | /** | |
327 | * Indicates if all the glyphs and widths for that particular | |
328 | * encoding should be included in the document. | |
329 | * @return <CODE>false</CODE> to include all the glyphs and widths. | |
330 | */ | |
331 | public boolean isSubset() { | |
332 | return subset; | |
333 | } | |
334 | | |
335 | /** | |
336 | * Indicates if all the glyphs and widths for that particular | |
337 | * encoding should be included in the document. Set to <CODE>false</CODE> | |
338 | * to include all. | |
339 | * @param subset new value of property subset | |
340 | */ | |
341 | public void setSubset(boolean subset) { | |
342 | this.subset = subset; | |
343 | } | |
344 | } | |
Mutations | ||
180 |
1.1 |
|
185 |
1.1 |
|
190 |
1.1 2.2 3.3 |
|
205 |
1.1 |
|
208 |
1.1 2.2 3.3 |
|
209 |
1.1 |
|
210 |
1.1 |
|
212 |
1.1 |
|
217 |
1.1 2.2 3.3 |
|
219 |
1.1 |
|
221 |
1.1 |
|
227 |
1.1 |
|
231 |
1.1 |
|
245 |
1.1 |
|
249 |
1.1 2.2 |
|
255 |
1.1 2.2 3.3 |
|
257 |
1.1 2.2 |
|
262 |
1.1 |
|
265 |
1.1 |
|
268 |
1.1 |
|
277 |
1.1 |
|
292 |
1.1 |
|
298 |
1.1 2.2 3.3 |
|
299 |
1.1 |
|
302 |
1.1 2.2 3.3 |
|
303 |
1.1 |
|
306 |
1.1 2.2 |
|
310 |
1.1 |
|
314 |
1.1 |
|
317 |
1.1 |