1 | /* | |
2 | * Copyright 2005 by Paulo Soares. | |
3 | * | |
4 | * The contents of this file are subject to the Mozilla Public License Version 1.1 | |
5 | * (the "License"); you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
7 | * | |
8 | * Software distributed under the License is distributed on an "AS IS" basis, | |
9 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
10 | * for the specific language governing rights and limitations under the License. | |
11 | * | |
12 | * The Original Code is 'iText, a free JAVA-PDF library'. | |
13 | * | |
14 | * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by | |
15 | * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. | |
16 | * All Rights Reserved. | |
17 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer | |
18 | * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. | |
19 | * | |
20 | * Contributor(s): all the names of the contributors are added in the source code | |
21 | * where applicable. | |
22 | * | |
23 | * Alternatively, the contents of this file may be used under the terms of the | |
24 | * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the | |
25 | * provisions of LGPL are applicable instead of those above. If you wish to | |
26 | * allow use of your version of this file only under the terms of the LGPL | |
27 | * License and not to allow others to use your version of this file under | |
28 | * the MPL, indicate your decision by deleting the provisions above and | |
29 | * replace them with the notice and other provisions required by the LGPL. | |
30 | * If you do not delete the provisions above, a recipient may use your version | |
31 | * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. | |
32 | * | |
33 | * This library is free software; you can redistribute it and/or modify it | |
34 | * under the terms of the MPL as stated above or under the terms of the GNU | |
35 | * Library General Public License as published by the Free Software Foundation; | |
36 | * either version 2 of the License, or any later version. | |
37 | * | |
38 | * This library is distributed in the hope that it will be useful, but WITHOUT | |
39 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |
40 | * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more | |
41 | * details. | |
42 | * | |
43 | * If you didn't download this code from the following link, you should check if | |
44 | * you aren't using an obsolete version: | |
45 | * http://www.lowagie.com/iText/ | |
46 | */ | |
47 | ||
48 | package com.lowagie.text.pdf; | |
49 | ||
50 | import java.util.HashMap; | |
51 | import com.lowagie.text.error_messages.MessageLocalization; | |
52 | ||
53 | import com.lowagie.text.DocumentException; | |
54 | ||
55 | /** | |
56 | * A class to support Type3 fonts. | |
57 | */ | |
58 | public class Type3Font extends BaseFont { | |
59 | | |
60 | private boolean[] usedSlot; | |
61 | private IntHashtable widths3 = new IntHashtable(); | |
62 | private HashMap char2glyph = new HashMap(); | |
63 | private PdfWriter writer; | |
64 | private float llx = Float.NaN, lly, urx, ury; | |
65 | private PageResources pageResources = new PageResources(); | |
66 | private boolean colorized; | |
67 | | |
68 | /** | |
69 | * Creates a Type3 font. | |
70 | * @param writer the writer | |
71 | * @param chars an array of chars corresponding to the glyphs used (not used, present for compatibility only) | |
72 | * @param colorized if <CODE>true</CODE> the font may specify color, if <CODE>false</CODE> no color commands are allowed | |
73 | * and only images as masks can be used | |
74 | */ | |
75 | public Type3Font(PdfWriter writer, char[] chars, boolean colorized) { | |
76 | this(writer, colorized); | |
77 | } | |
78 | | |
79 | /** | |
80 | * Creates a Type3 font. This implementation assumes that the /FontMatrix is | |
81 | * [0.001 0 0 0.001 0 0] or a 1000-unit glyph coordinate system. | |
82 | * <p> | |
83 | * An example: | |
84 | * <p> | |
85 | * <pre> | |
86 | * Document document = new Document(PageSize.A4); | |
87 | * PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("type3.pdf")); | |
88 | * document.open(); | |
89 | * Type3Font t3 = new Type3Font(writer, false); | |
90 | * PdfContentByte g = t3.defineGlyph('a', 1000, 0, 0, 750, 750); | |
91 | * g.rectangle(0, 0, 750, 750); | |
92 | * g.fill(); | |
93 | * g = t3.defineGlyph('b', 1000, 0, 0, 750, 750); | |
94 | * g.moveTo(0, 0); | |
95 | * g.lineTo(375, 750); | |
96 | * g.lineTo(750, 0); | |
97 | * g.fill(); | |
98 | * Font f = new Font(t3, 12); | |
99 | * document.add(new Paragraph("ababab", f)); | |
100 | * document.close(); | |
101 | * </pre> | |
102 | * @param writer the writer | |
103 | * @param colorized if <CODE>true</CODE> the font may specify color, if <CODE>false</CODE> no color commands are allowed | |
104 | * and only images as masks can be used | |
105 | */ | |
106 | public Type3Font(PdfWriter writer, boolean colorized) { | |
107 | this.writer = writer; | |
108 | this.colorized = colorized; | |
109 | fontType = FONT_TYPE_T3; | |
110 | usedSlot = new boolean[256]; | |
111 | } | |
112 | | |
113 | /** | |
114 | * Defines a glyph. If the character was already defined it will return the same content | |
115 | * @param c the character to match this glyph. | |
116 | * @param wx the advance this character will have | |
117 | * @param llx the X lower left corner of the glyph bounding box. If the <CODE>colorize</CODE> option is | |
118 | * <CODE>true</CODE> the value is ignored | |
119 | * @param lly the Y lower left corner of the glyph bounding box. If the <CODE>colorize</CODE> option is | |
120 | * <CODE>true</CODE> the value is ignored | |
121 | * @param urx the X upper right corner of the glyph bounding box. If the <CODE>colorize</CODE> option is | |
122 | * <CODE>true</CODE> the value is ignored | |
123 | * @param ury the Y upper right corner of the glyph bounding box. If the <CODE>colorize</CODE> option is | |
124 | * <CODE>true</CODE> the value is ignored | |
125 | * @return a content where the glyph can be defined | |
126 | */ | |
127 | public PdfContentByte defineGlyph(char c, float wx, float llx, float lly, float urx, float ury) { | |
128 |
3
1. defineGlyph : changed conditional boundary → NO_COVERAGE 2. defineGlyph : negated conditional → NO_COVERAGE 3. defineGlyph : negated conditional → NO_COVERAGE |
if (c == 0 || c > 255) |
129 | throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.char.1.doesn.t.belong.in.this.type3.font", (int)c)); | |
130 | usedSlot[c] = true; | |
131 | Integer ck = (int) c; | |
132 | Type3Glyph glyph = (Type3Glyph)char2glyph.get(ck); | |
133 |
1
1. defineGlyph : negated conditional → NO_COVERAGE |
if (glyph != null) |
134 |
1
1. defineGlyph : mutated return of Object value for com/lowagie/text/pdf/Type3Font::defineGlyph to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return glyph; |
135 | widths3.put(c, (int)wx); | |
136 |
1
1. defineGlyph : negated conditional → NO_COVERAGE |
if (!colorized) { |
137 |
1
1. defineGlyph : negated conditional → NO_COVERAGE |
if (Float.isNaN(this.llx)) { |
138 | this.llx = llx; | |
139 | this.lly = lly; | |
140 | this.urx = urx; | |
141 | this.ury = ury; | |
142 | } | |
143 | else { | |
144 | this.llx = Math.min(this.llx, llx); | |
145 | this.lly = Math.min(this.lly, lly); | |
146 | this.urx = Math.max(this.urx, urx); | |
147 | this.ury = Math.max(this.ury, ury); | |
148 | } | |
149 | } | |
150 | glyph = new Type3Glyph(writer, pageResources, wx, llx, lly, urx, ury, colorized); | |
151 | char2glyph.put(ck, glyph); | |
152 |
1
1. defineGlyph : mutated return of Object value for com/lowagie/text/pdf/Type3Font::defineGlyph to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return glyph; |
153 | } | |
154 | | |
155 | public String[][] getFamilyFontName() { | |
156 | return getFullFontName(); | |
157 | } | |
158 | | |
159 | public float getFontDescriptor(int key, float fontSize) { | |
160 | return 0; | |
161 | } | |
162 | | |
163 | public String[][] getFullFontName() { | |
164 |
1
1. getFullFontName : mutated return of Object value for com/lowagie/text/pdf/Type3Font::getFullFontName to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return new String[][]{{"", "", "", ""}}; |
165 | } | |
166 | | |
167 | /** | |
168 | * @since 2.0.8 | |
169 | */ | |
170 | public String[][] getAllNameEntries() { | |
171 |
1
1. getAllNameEntries : mutated return of Object value for com/lowagie/text/pdf/Type3Font::getAllNameEntries to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return new String[][]{{"4", "", "", "", ""}}; |
172 | } | |
173 | | |
174 | public int getKerning(int char1, int char2) { | |
175 | return 0; | |
176 | } | |
177 | | |
178 | public String getPostscriptFontName() { | |
179 | return ""; | |
180 | } | |
181 | | |
182 | protected int[] getRawCharBBox(int c, String name) { | |
183 | return null; | |
184 | } | |
185 | | |
186 | int getRawWidth(int c, String name) { | |
187 | return 0; | |
188 | } | |
189 | | |
190 | public boolean hasKernPairs() { | |
191 | return false; | |
192 | } | |
193 | | |
194 | public boolean setKerning(int char1, int char2, int kern) { | |
195 | return false; | |
196 | } | |
197 | | |
198 | public void setPostscriptFontName(String name) { | |
199 | } | |
200 | | |
201 | void writeFont(PdfWriter writer, PdfIndirectReference ref, Object[] params) throws com.lowagie.text.DocumentException, java.io.IOException { | |
202 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if (this.writer != writer) |
203 | throw new IllegalArgumentException(MessageLocalization.getComposedMessage("type3.font.used.with.the.wrong.pdfwriter")); | |
204 | | |
205 | // Get first & lastchar ... | |
206 | int firstChar = 0; | |
207 |
4
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : Changed increment from 1 to -1 → NO_COVERAGE 3. writeFont : negated conditional → NO_COVERAGE 4. writeFont : negated conditional → NO_COVERAGE |
while( firstChar < usedSlot.length && !usedSlot[firstChar] ) firstChar++; |
208 | | |
209 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if ( firstChar == usedSlot.length ) { |
210 | throw new DocumentException(MessageLocalization.getComposedMessage("no.glyphs.defined.for.type3.font")); | |
211 | } | |
212 |
1
1. writeFont : Replaced integer subtraction with addition → NO_COVERAGE |
int lastChar = usedSlot.length - 1; |
213 |
4
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : Changed increment from -1 to 1 → NO_COVERAGE 3. writeFont : negated conditional → NO_COVERAGE 4. writeFont : negated conditional → NO_COVERAGE |
while( lastChar >= firstChar && !usedSlot[lastChar] ) lastChar--; |
214 | | |
215 |
2
1. writeFont : Replaced integer subtraction with addition → NO_COVERAGE 2. writeFont : Replaced integer addition with subtraction → NO_COVERAGE |
int[] widths = new int[lastChar - firstChar + 1]; |
216 |
2
1. writeFont : Replaced integer subtraction with addition → NO_COVERAGE 2. writeFont : Replaced integer addition with subtraction → NO_COVERAGE |
int[] invOrd = new int[lastChar - firstChar + 1]; |
217 | | |
218 | int invOrdIndx = 0, w = 0; | |
219 |
4
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : Changed increment from 1 to -1 → NO_COVERAGE 3. writeFont : Changed increment from 1 to -1 → NO_COVERAGE 4. writeFont : negated conditional → NO_COVERAGE |
for( int u = firstChar; u<=lastChar; u++, w++ ) { |
220 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if ( usedSlot[u] ) { |
221 |
1
1. writeFont : Changed increment from 1 to -1 → NO_COVERAGE |
invOrd[invOrdIndx++] = u; |
222 | widths[w] = widths3.get(u); | |
223 | } | |
224 | } | |
225 | PdfArray diffs = new PdfArray(); | |
226 | PdfDictionary charprocs = new PdfDictionary(); | |
227 | int last = -1; | |
228 |
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 (int k = 0; k < invOrdIndx; ++k) { |
229 | int c = invOrd[k]; | |
230 |
2
1. writeFont : changed conditional boundary → NO_COVERAGE 2. writeFont : negated conditional → NO_COVERAGE |
if (c > last) { |
231 | last = c; | |
232 | diffs.add(new PdfNumber(last)); | |
233 | } | |
234 |
1
1. writeFont : Changed increment from 1 to -1 → NO_COVERAGE |
++last; |
235 | int c2 = invOrd[k]; | |
236 | String s = GlyphList.unicodeToName(c2); | |
237 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if (s == null) |
238 | s = "a" + c2; | |
239 | PdfName n = new PdfName(s); | |
240 | diffs.add(n); | |
241 | Type3Glyph glyph = (Type3Glyph)char2glyph.get(c2); | |
242 | PdfStream stream = new PdfStream(glyph.toPdf(null)); | |
243 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfStream::flateCompress → NO_COVERAGE |
stream.flateCompress(compressionLevel); |
244 | PdfIndirectReference refp = writer.addToBody(stream).getIndirectReference(); | |
245 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
charprocs.put(n, refp); |
246 | } | |
247 | PdfDictionary font = new PdfDictionary(PdfName.FONT); | |
248 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.SUBTYPE, PdfName.TYPE3); |
249 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if (colorized) |
250 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.FONTBBOX, new PdfRectangle(0, 0, 0, 0)); |
251 | else | |
252 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.FONTBBOX, new PdfRectangle(llx, lly, urx, ury)); |
253 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.FONTMATRIX, new PdfArray(new float[]{0.001f, 0, 0, 0.001f, 0, 0})); |
254 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.CHARPROCS, writer.addToBody(charprocs).getIndirectReference()); |
255 | PdfDictionary encoding = new PdfDictionary(); | |
256 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
encoding.put(PdfName.DIFFERENCES, diffs); |
257 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.ENCODING, writer.addToBody(encoding).getIndirectReference()); |
258 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.FIRSTCHAR, new PdfNumber(firstChar)); |
259 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.LASTCHAR, new PdfNumber(lastChar)); |
260 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.WIDTHS, writer.addToBody(new PdfArray(widths)).getIndirectReference()); |
261 |
1
1. writeFont : negated conditional → NO_COVERAGE |
if (pageResources.hasResources()) |
262 |
1
1. writeFont : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
font.put(PdfName.RESOURCES, writer.addToBody(pageResources.getResources()).getIndirectReference()); |
263 | writer.addToBody(font, ref); | |
264 | } | |
265 | | |
266 | /** | |
267 | * Always returns null, because you can't get the FontStream of a Type3 font. | |
268 | * @return null | |
269 | * @since 2.1.3 | |
270 | */ | |
271 | public PdfStream getFullFontStream() { | |
272 | return null; | |
273 | } | |
274 | | |
275 | | |
276 | byte[] convertToBytes(String text) { | |
277 | char[] cc = text.toCharArray(); | |
278 | byte[] b = new byte[cc.length]; | |
279 | int p = 0; | |
280 | for (char c : cc) { | |
281 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (charExists(c)) |
282 |
1
1. convertToBytes : Changed increment from 1 to -1 → NO_COVERAGE |
b[p++] = (byte) c; |
283 | } | |
284 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (b.length == p) |
285 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/Type3Font::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return b; |
286 | byte[] b2 = new byte[p]; | |
287 |
1
1. convertToBytes : removed call to java/lang/System::arraycopy → NO_COVERAGE |
System.arraycopy(b, 0, b2, 0, p); |
288 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/Type3Font::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return b2; |
289 | } | |
290 | | |
291 | byte[] convertToBytes(int char1) { | |
292 |
1
1. convertToBytes : negated conditional → NO_COVERAGE |
if (charExists(char1)) |
293 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/Type3Font::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return new byte[]{(byte)char1}; |
294 |
1
1. convertToBytes : mutated return of Object value for com/lowagie/text/pdf/Type3Font::convertToBytes to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
else return new byte[0]; |
295 | } | |
296 | | |
297 | public int getWidth(int char1) { | |
298 |
1
1. getWidth : negated conditional → NO_COVERAGE |
if (!widths3.containsKey(char1)) |
299 | throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.char.1.is.not.defined.in.a.type3.font", char1)); | |
300 |
1
1. getWidth : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return widths3.get(char1); |
301 | } | |
302 | | |
303 | public int getWidth(String text) { | |
304 | char[] c = text.toCharArray(); | |
305 | int total = 0; | |
306 |
1
1. getWidth : Replaced integer addition with subtraction → NO_COVERAGE |
for (char c1 : c) total += getWidth(c1); |
307 |
1
1. getWidth : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return total; |
308 | } | |
309 | | |
310 | public int[] getCharBBox(int c) { | |
311 | return null; | |
312 | } | |
313 | | |
314 | public boolean charExists(int c) { | |
315 |
4
1. charExists : changed conditional boundary → NO_COVERAGE 2. charExists : changed conditional boundary → NO_COVERAGE 3. charExists : negated conditional → NO_COVERAGE 4. charExists : negated conditional → NO_COVERAGE |
if (c > 0 && c < 256) { |
316 |
1
1. charExists : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return usedSlot[c]; |
317 | } else { | |
318 |
1
1. charExists : replaced return of integer sized value with (x == 0 ? 1 : 0) → NO_COVERAGE |
return false; |
319 | } | |
320 | } | |
321 | | |
322 | public boolean setCharAdvance(int c, int advance) { | |
323 | return false; | |
324 | } | |
325 | | |
326 | } | |
Mutations | ||
128 |
1.1 2.2 3.3 |
|
133 |
1.1 |
|
134 |
1.1 |
|
136 |
1.1 |
|
137 |
1.1 |
|
152 |
1.1 |
|
164 |
1.1 |
|
171 |
1.1 |
|
202 |
1.1 |
|
207 |
1.1 2.2 3.3 4.4 |
|
209 |
1.1 |
|
212 |
1.1 |
|
213 |
1.1 2.2 3.3 4.4 |
|
215 |
1.1 2.2 |
|
216 |
1.1 2.2 |
|
219 |
1.1 2.2 3.3 4.4 |
|
220 |
1.1 |
|
221 |
1.1 |
|
228 |
1.1 2.2 3.3 |
|
230 |
1.1 2.2 |
|
234 |
1.1 |
|
237 |
1.1 |
|
243 |
1.1 |
|
245 |
1.1 |
|
248 |
1.1 |
|
249 |
1.1 |
|
250 |
1.1 |
|
252 |
1.1 |
|
253 |
1.1 |
|
254 |
1.1 |
|
256 |
1.1 |
|
257 |
1.1 |
|
258 |
1.1 |
|
259 |
1.1 |
|
260 |
1.1 |
|
261 |
1.1 |
|
262 |
1.1 |
|
281 |
1.1 |
|
282 |
1.1 |
|
284 |
1.1 |
|
285 |
1.1 |
|
287 |
1.1 |
|
288 |
1.1 |
|
292 |
1.1 |
|
293 |
1.1 |
|
294 |
1.1 |
|
298 |
1.1 |
|
300 |
1.1 |
|
306 |
1.1 |
|
307 |
1.1 |
|
315 |
1.1 2.2 3.3 4.4 |
|
316 |
1.1 |
|
318 |
1.1 |