KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fonts > TTFSubSetFile


1 /*
2  * $Id: TTFSubSetFile.java,v 1.5.2.5 2003/02/25 13:13:21 jeremias Exp $
3  * ============================================================================
4  * The Apache Software License, Version 1.1
5  * ============================================================================
6  *
7  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "FOP" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  * ============================================================================
45  *
46  * This software consists of voluntary contributions made by many individuals
47  * on behalf of the Apache Software Foundation and was originally created by
48  * James Tauber <jtauber@jtauber.com>. For more information on the Apache
49  * Software Foundation, please see <http://www.apache.org/>.
50  */

51 package org.apache.fop.fonts;
52
53 import org.apache.fop.messaging.MessageHandler;
54
55 import java.io.IOException JavaDoc;
56 import java.util.Iterator JavaDoc;
57 import java.util.Map JavaDoc;
58 import java.util.List JavaDoc;
59
60 /**
61  * Reads a TrueType file and generates a subset
62  * That can be used to embed a TrueType CID font
63  * TrueType tables needed for embedded CID fonts are:
64  * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm"
65  * The TrueType spec can be found at the Microsoft
66  * Typography site: http://www.microsoft.com/truetype/
67  */

68 public class TTFSubSetFile extends TTFFile {
69     byte[] output = null;
70     int realSize = 0;
71     int currentPos = 0;
72
73     /*
74      * Offsets in name table to be filled out by table.
75      * The offsets are to the checkSum field
76      */

77     int cvtDirOffset = 0;
78     int fpgmDirOffset = 0;
79     int glyfDirOffset = 0;
80     int headDirOffset = 0;
81     int hheaDirOffset = 0;
82     int hmtxDirOffset = 0;
83     int locaDirOffset = 0;
84     int maxpDirOffset = 0;
85     int prepDirOffset = 0;
86
87     int checkSumAdjustmentOffset = 0;
88     int locaOffset = 0;
89
90     /**
91      * Initalize the output array
92      */

93     private void init(int size) {
94         output = new byte[size];
95         realSize = 0;
96         currentPos = 0;
97
98         // createDirectory()
99
}
100
101     /**
102      * Create the directory table
103      */

104     private void createDirectory() {
105         int numTables = 9;
106         // Create the TrueType header
107
writeByte((byte)0);
108         writeByte((byte)1);
109         writeByte((byte)0);
110         writeByte((byte)0);
111         realSize += 4;
112
113         writeUShort(numTables);
114         realSize += 2;
115
116         // Create searchRange, entrySelector and rangeShift
117
int maxPow = maxPow2(numTables);
118         int searchRange = maxPow * 16;
119         writeUShort(searchRange);
120         realSize += 2;
121
122         writeUShort(maxPow);
123         realSize += 2;
124
125         writeUShort((numTables * 16) - searchRange);
126         realSize += 2;
127
128         // Create space for the table entries
129
writeString("cvt ");
130         cvtDirOffset = currentPos;
131         currentPos += 12;
132         realSize += 16;
133
134         if (hasFpgm()) {
135             writeString("fpgm");
136             fpgmDirOffset = currentPos;
137             currentPos += 12;
138             realSize += 16;
139         }
140
141         writeString("glyf");
142         glyfDirOffset = currentPos;
143         currentPos += 12;
144         realSize += 16;
145
146         writeString("head");
147         headDirOffset = currentPos;
148         currentPos += 12;
149         realSize += 16;
150
151         writeString("hhea");
152         hheaDirOffset = currentPos;
153         currentPos += 12;
154         realSize += 16;
155
156         writeString("hmtx");
157         hmtxDirOffset = currentPos;
158         currentPos += 12;
159         realSize += 16;
160
161         writeString("loca");
162         locaDirOffset = currentPos;
163         currentPos += 12;
164         realSize += 16;
165
166         writeString("maxp");
167         maxpDirOffset = currentPos;
168         currentPos += 12;
169         realSize += 16;
170
171         writeString("prep");
172         prepDirOffset = currentPos;
173         currentPos += 12;
174         realSize += 16;
175     }
176
177
178     /**
179      * Copy the cvt table as is from original font to subset font
180      */

181     private void createCvt(FontFileReader in) throws IOException JavaDoc {
182         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
183         if (entry != null) {
184             pad4();
185             seek_tab(in, "cvt ", 0);
186             System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
187                              0, output, currentPos, (int)entry.length);
188
189             int checksum = getCheckSum(currentPos, (int)entry.length);
190             writeULong(cvtDirOffset, checksum);
191             writeULong(cvtDirOffset + 4, currentPos);
192             writeULong(cvtDirOffset + 8, (int)entry.length);
193             currentPos += (int)entry.length;
194             realSize += (int)entry.length;
195         } else {
196             throw new IOException JavaDoc("Can't find cvt table");
197         }
198     }
199
200
201     private boolean hasFpgm() {
202         return (dirTabs.get("fpgm") != null);
203     }
204
205     /**
206      * Copy the fpgm table as is from original font to subset font
207      */

208     private void createFpgm(FontFileReader in) throws IOException JavaDoc {
209         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
210         if (entry != null) {
211             pad4();
212             seek_tab(in, "fpgm", 0);
213             System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
214                              0, output, currentPos, (int)entry.length);
215             int checksum = getCheckSum(currentPos, (int)entry.length);
216             writeULong(fpgmDirOffset, checksum);
217             writeULong(fpgmDirOffset + 4, currentPos);
218             writeULong(fpgmDirOffset + 8, (int)entry.length);
219             currentPos += (int)entry.length;
220             realSize += (int)entry.length;
221         } else {
222             //fpgm table is optional
223
//throw new IOException("Can't find fpgm table");
224
}
225     }
226
227
228
229     /**
230      * Create an empty loca table without updating checksum
231      */

232     private void createLoca(int size) throws IOException JavaDoc {
233         pad4();
234         locaOffset = currentPos;
235         writeULong(locaDirOffset + 4, currentPos);
236         writeULong(locaDirOffset + 8, size * 4 + 4);
237         currentPos += size * 4 + 4;
238         realSize += size * 4 + 4;
239     }
240
241
242     /**
243      * Copy the maxp table as is from original font to subset font
244      * and set num glyphs to size
245      */

246     private void createMaxp(FontFileReader in, int size) throws IOException JavaDoc {
247         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
248         if (entry != null) {
249             pad4();
250             seek_tab(in, "maxp", 0);
251             System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
252                              0, output, currentPos, (int)entry.length);
253             writeUShort(currentPos + 4, size);
254
255             int checksum = getCheckSum(currentPos, (int)entry.length);
256             writeULong(maxpDirOffset, checksum);
257             writeULong(maxpDirOffset + 4, currentPos);
258             writeULong(maxpDirOffset + 8, (int)entry.length);
259             currentPos += (int)entry.length;
260             realSize += (int)entry.length;
261         } else {
262             throw new IOException JavaDoc("Can't find maxp table");
263         }
264     }
265
266
267     /**
268      * Copy the prep table as is from original font to subset font
269      */

270     private void createPrep(FontFileReader in) throws IOException JavaDoc {
271         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
272         if (entry != null) {
273             pad4();
274             seek_tab(in, "prep", 0);
275             System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
276                              0, output, currentPos, (int)entry.length);
277
278             int checksum = getCheckSum(currentPos, (int)entry.length);
279             writeULong(prepDirOffset, checksum);
280             writeULong(prepDirOffset + 4, currentPos);
281             writeULong(prepDirOffset + 8, (int)entry.length);
282             currentPos += (int)entry.length;
283             realSize += (int)entry.length;
284         } else {
285             throw new IOException JavaDoc("Can't find prep table");
286         }
287     }
288
289
290     /**
291      * Copy the hhea table as is from original font to subset font
292      * and fill in size of hmtx table
293      */

294     private void createHhea(FontFileReader in, int size) throws IOException JavaDoc {
295         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
296         if (entry != null) {
297             pad4();
298             seek_tab(in, "hhea", 0);
299             System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
300                              0, output, currentPos, (int)entry.length);
301             writeUShort((int)entry.length + currentPos - 2, size);
302
303             int checksum = getCheckSum(currentPos, (int)entry.length);
304             writeULong(hheaDirOffset, checksum);
305             writeULong(hheaDirOffset + 4, currentPos);
306             writeULong(hheaDirOffset + 8, (int)entry.length);
307             currentPos += (int)entry.length;
308             realSize += (int)entry.length;
309         } else {
310             throw new IOException JavaDoc("Can't find hhea table");
311         }
312     }
313
314
315     /**
316      * Copy the head table as is from original font to subset font
317      * and set indexToLocaFormat to long and set
318      * checkSumAdjustment to 0, store offset to checkSumAdjustment
319      * in checkSumAdjustmentOffset
320      */

321     private void createHead(FontFileReader in) throws IOException JavaDoc {
322         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
323         if (entry != null) {
324             pad4();
325             seek_tab(in, "head", 0);
326             System.arraycopy(in.getBytes((int)entry.offset, (int)entry.length),
327                              0, output, currentPos, (int)entry.length);
328
329             checkSumAdjustmentOffset = currentPos + 8;
330             output[currentPos + 8] = 0; // Set checkSumAdjustment to 0
331
output[currentPos + 9] = 0;
332             output[currentPos + 10] = 0;
333             output[currentPos + 11] = 0;
334             output[currentPos + 50] = 0; // long locaformat
335
output[currentPos + 51] = 1; // long locaformat
336

337             int checksum = getCheckSum(currentPos, (int)entry.length);
338             writeULong(headDirOffset, checksum);
339             writeULong(headDirOffset + 4, currentPos);
340             writeULong(headDirOffset + 8, (int)entry.length);
341
342             currentPos += (int)entry.length;
343             realSize += (int)entry.length;
344         } else {
345             throw new IOException JavaDoc("Can't find head table");
346         }
347     }
348
349
350     /**
351      * Create the glyf table and fill in loca table
352      */

353     private void createGlyf(FontFileReader in,
354                             Map JavaDoc glyphs) throws IOException JavaDoc {
355         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
356         int size = 0;
357         int start = 0;
358         int endOffset = 0; // Store this as the last loca
359
if (entry != null) {
360             pad4();
361             start = currentPos;
362
363             /* Loca table must be in order by glyph index, so build
364              * an array first and then write the glyph info and
365              * location offset.
366              */

367             int[] origIndexes = new int[glyphs.size()];
368
369             for (Iterator JavaDoc e = glyphs.keySet().iterator(); e.hasNext(); ) {
370                 Integer JavaDoc origIndex = (Integer JavaDoc)e.next();
371                 Integer JavaDoc subsetIndex = (Integer JavaDoc)glyphs.get(origIndex);
372                 origIndexes[subsetIndex.intValue()] = origIndex.intValue();
373             }
374
375             for (int i=0;i<origIndexes.length;i++) {
376                 int glyphLength = 0;
377                 int nextOffset = 0;
378                 int origGlyphIndex = origIndexes[i];
379                 if (origGlyphIndex >= (mtx_tab.length - 1)) {
380                     nextOffset = (int)lastLoca;
381                 }
382                 else {
383                     nextOffset =
384                         (int)mtx_tab[origGlyphIndex + 1].offset;
385                 }
386                 glyphLength = nextOffset
387                               - (int)mtx_tab[origGlyphIndex].offset;
388
389                 // Copy glyph
390
System.arraycopy(in.getBytes((int)entry.offset +
391                                        (int)mtx_tab[origGlyphIndex].offset,
392                                        glyphLength),
393                                  0, output, currentPos, glyphLength);
394
395
396                 // Update loca table
397
writeULong(locaOffset + i * 4, currentPos - start);
398                 if ((currentPos - start + glyphLength) > endOffset) {
399                     endOffset = (currentPos - start + glyphLength);
400                 }
401
402                 currentPos += glyphLength;
403                 realSize += glyphLength;
404
405             }
406
407             size = currentPos - start;
408
409             int checksum = getCheckSum(start, size);
410             writeULong(glyfDirOffset, checksum);
411             writeULong(glyfDirOffset + 4, start);
412             writeULong(glyfDirOffset + 8, size);
413             currentPos += 12;
414             realSize += 12;
415
416             // Update loca checksum and last loca index
417
writeULong(locaOffset + glyphs.size() * 4, endOffset);
418
419             checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4);
420             writeULong(locaDirOffset, checksum);
421         } else {
422             throw new IOException JavaDoc("Can't find glyf table");
423         }
424     }
425
426
427     /**
428      * Create the hmtx table by copying metrics from original
429      * font to subset font. The glyphs Map contains an
430      * Integer key and Integer value that maps the original
431      * metric (key) to the subset metric (value)
432      */

433     private void createHmtx(FontFileReader in,
434                             Map JavaDoc glyphs) throws IOException JavaDoc {
435         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
436
437         int longHorMetricSize = glyphs.size() * 2;
438         int leftSideBearingSize = glyphs.size() * 2;
439         int hmtxSize = longHorMetricSize + leftSideBearingSize;
440
441         if (entry != null) {
442             pad4();
443             int offset = (int)entry.offset;
444             for (Iterator JavaDoc e = glyphs.keySet().iterator(); e.hasNext(); ) {
445                 Integer JavaDoc origIndex = (Integer JavaDoc)e.next();
446                 Integer JavaDoc subsetIndex = (Integer JavaDoc)glyphs.get(origIndex);
447
448                 writeUShort(currentPos + subsetIndex.intValue() * 4,
449                             mtx_tab[origIndex.intValue()].wx);
450                 writeUShort(currentPos + subsetIndex.intValue() * 4 + 2,
451                             mtx_tab[origIndex.intValue()].lsb);
452             }
453
454             int checksum = getCheckSum(currentPos, hmtxSize);
455             writeULong(hmtxDirOffset, checksum);
456             writeULong(hmtxDirOffset + 4, currentPos);
457             writeULong(hmtxDirOffset + 8, hmtxSize);
458             currentPos += hmtxSize;
459             realSize += hmtxSize;
460         } else {
461             throw new IOException JavaDoc("Can't find hmtx table");
462         }
463     }
464
465     /**
466      * Returns a List containing the glyph itself plus all glyphs
467      * that this composite glyph uses
468      */

469     private List JavaDoc getIncludedGlyphs(FontFileReader in, int glyphOffset,
470                                      Integer JavaDoc glyphIdx) throws IOException JavaDoc {
471         List JavaDoc ret = new java.util.ArrayList JavaDoc();
472         ret.add(glyphIdx);
473         int offset = glyphOffset + (int)mtx_tab[glyphIdx.intValue()].offset
474                      + 10;
475         Integer JavaDoc compositeIdx = null;
476         int flags = 0;
477         boolean moreComposites = true;
478         while (moreComposites) {
479             flags = in.readTTFUShort(offset);
480             compositeIdx = new Integer JavaDoc(in.readTTFUShort(offset + 2));
481             ret.add(compositeIdx);
482
483             offset += 4;
484             if ((flags & 1) > 0) {
485                 // ARG_1_AND_ARG_2_ARE_WORDS
486
offset += 4;
487             } else {
488                 offset += 2;
489             }
490
491             if ((flags & 8) > 0) {
492                 offset += 2; // WE_HAVE_A_SCALE
493
}
494             else if ((flags & 64) > 0) {
495                 offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
496
}
497             else if ((flags & 128) > 0) {
498                 offset += 8; // WE_HAVE_A_TWO_BY_TWO
499
}
500             if ((flags & 32) > 0) {
501                 moreComposites = true;
502             }
503             else {
504                 moreComposites = false;
505             }
506         }
507
508         return ret;
509     }
510
511
512     /**
513      * Rewrite all compositepointers in glyphindex glyphIdx
514      *
515      */

516     private void remapComposite(FontFileReader in, Map JavaDoc glyphs,
517                                 int glyphOffset,
518                                 Integer JavaDoc glyphIdx) throws IOException JavaDoc {
519         int offset = glyphOffset + (int)mtx_tab[glyphIdx.intValue()].offset
520                      + 10;
521
522         Integer JavaDoc compositeIdx = null;
523         int flags = 0;
524         boolean moreComposites = true;
525
526         while (moreComposites) {
527             flags = in.readTTFUShort(offset);
528             compositeIdx = new Integer JavaDoc(in.readTTFUShort(offset + 2));
529             Integer JavaDoc newIdx = (Integer JavaDoc)glyphs.get(compositeIdx);
530             if (newIdx == null) {
531                 // This errormessage would look much better
532
// if the fontname was printed to
533
MessageHandler.error("An embedded font "
534                                      + "contains bad glyph data. "
535                                      + "Characters might not display "
536                                      + "correctly.");
537                 moreComposites = false;
538                 continue;
539             }
540
541             in.writeTTFUShort(offset + 2, newIdx.intValue());
542
543             offset += 4;
544
545             if ((flags & 1) > 0) {
546                 // ARG_1_AND_ARG_2_ARE_WORDS
547
offset += 4;
548             } else {
549                 offset += 2;
550             }
551
552             if ((flags & 8) > 0) {
553                 offset += 2; // WE_HAVE_A_SCALE
554
} else if ((flags & 64) > 0) {
555                 offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
556
} else if ((flags & 128) > 0) {
557                 offset += 8; // WE_HAVE_A_TWO_BY_TWO
558
}
559
560             if ((flags & 32) > 0) {
561                 moreComposites = true;
562             }
563             else {
564                 moreComposites = false;
565             }
566         }
567     }
568
569
570     /**
571      * Scan all the original glyphs for composite glyphs and add those glyphs
572      * to the glyphmapping also rewrite the composite glyph pointers to the new
573      * mapping
574      */

575     private void scanGlyphs(FontFileReader in,
576                             Map JavaDoc glyphs) throws IOException JavaDoc {
577         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
578         Map JavaDoc newComposites = null;
579         Map JavaDoc allComposites = new java.util.HashMap JavaDoc();
580
581         int newIndex = glyphs.size();
582
583         if (entry != null) {
584             while (newComposites == null || newComposites.size() > 0) {
585                 // Inefficient to iterate through all glyphs
586
newComposites = new java.util.HashMap JavaDoc();
587
588                 for (Iterator JavaDoc e = glyphs.keySet().iterator(); e.hasNext(); ) {
589                     Integer JavaDoc origIndex = (Integer JavaDoc)e.next();
590
591                     if (in.readTTFShort(entry.offset
592                                         + mtx_tab[origIndex.intValue()].offset) < 0) {
593                         // origIndex is a composite glyph
594
allComposites.put(origIndex, glyphs.get(origIndex));
595                         List JavaDoc composites =
596                             getIncludedGlyphs(in, (int)entry.offset,
597                                               origIndex);
598
599                         // Iterate through all composites pointed to
600
// by this composite and check if they exists
601
// in the glyphs map, add them if not.
602
for (int i = 0; i < composites.size(); i++ ) {
603                             Integer JavaDoc cIdx = (Integer JavaDoc)composites.get(i);
604                             if (glyphs.get(cIdx) == null
605                                 && newComposites.get(cIdx) == null) {
606                                 newComposites.put(cIdx,
607                                                   new Integer JavaDoc(newIndex));
608                                 newIndex++;
609                             }
610                         }
611                     }
612                 }
613
614                 // Add composites to glyphs
615
for (Iterator JavaDoc m = newComposites.keySet().iterator(); m.hasNext(); ) {
616                     Integer JavaDoc im = (Integer JavaDoc)m.next();
617                     glyphs.put(im, newComposites.get(im));
618                 }
619             }
620
621             // Iterate through all composites to remap their composite index
622

623             for (Iterator JavaDoc ce = allComposites.keySet().iterator(); ce.hasNext(); ) {
624                 remapComposite(in, glyphs, (int)entry.offset,
625                                (Integer JavaDoc)ce.next());
626             }
627
628         } else {
629             throw new IOException JavaDoc("Can't find glyph table");
630         }
631     }
632
633
634
635     /**
636      * glyphs has old index as (Integer) key and new index
637      * as (Integer) value
638      */

639
640     public byte[] readFont(FontFileReader in, String JavaDoc name,
641                            Map JavaDoc glyphs) throws IOException JavaDoc {
642
643         /*
644          * Check if TrueType collection, and that the name
645          * exists in the collection
646          */

647         if (!checkTTC(in, name, false)) {
648             throw new IOException JavaDoc("Failed to read font");
649         }
650
651         output = new byte[in.getFileSize()];
652
653         readDirTabs(in);
654         readFontHeader(in);
655         getNumGlyphs(in);
656         readHorizontalHeader(in);
657         readHorizontalMetrics(in);
658         readIndexToLocation(in);
659
660         scanGlyphs(in, glyphs);
661
662         createDirectory(); // Create the TrueType header and directory
663

664         createHead(in);
665         createHhea(in, glyphs.size()); // Create the hhea table
666
createHmtx(in, glyphs); // Create hmtx table
667
createMaxp(in, glyphs.size()); // copy the maxp table
668

669         try {
670             createCvt(in); // copy the cvt table
671
} catch (IOException JavaDoc ex) {
672             // Cvt is optional (only required for OpenType (MS) fonts)
673
MessageHandler.errorln("TrueType warning: " + ex.getMessage());
674         }
675
676         try {
677             createFpgm(in); // copy fpgm table
678
} catch (IOException JavaDoc ex) {
679             // Fpgm is optional (only required for OpenType (MS) fonts)
680
MessageHandler.errorln("TrueType warning: " + ex.getMessage());
681         }
682
683         try {
684             createPrep(in); // copy prep table
685
} catch (IOException JavaDoc ex) {
686             // Prep is optional (only required for OpenType (MS) fonts)
687
MessageHandler.errorln("TrueType warning: " + ex.getMessage());
688         }
689
690         try {
691             createLoca(glyphs.size()); // create empty loca table
692
} catch (IOException JavaDoc ex) {
693             // Loca is optional (only required for OpenType (MS) fonts)
694
MessageHandler.errorln("TrueType warning: " + ex.getMessage());
695         }
696
697         try {
698             createGlyf(in, glyphs);
699         } catch (IOException JavaDoc ex) {
700             // Glyf is optional (only required for OpenType (MS) fonts)
701
MessageHandler.errorln("TrueType warning: " + ex.getMessage());
702         }
703
704         pad4();
705         createCheckSumAdjustment();
706
707         byte[] ret = new byte[realSize];
708         System.arraycopy(output, 0, ret, 0, realSize);
709
710         return ret;
711     }
712
713     /**
714      * writes a ISO-8859-1 string at the currentPosition
715      * updates currentPosition but not realSize
716      * @return number of bytes written
717      */

718     private int writeString(String JavaDoc str) {
719         int length = 0;
720         try {
721             byte[] buf = str.getBytes("ISO-8859-1");
722             System.arraycopy(buf, 0, output, currentPos, buf.length);
723             length = buf.length;
724             currentPos += length;
725         } catch (Exception JavaDoc e) {
726             // This should never happen!
727
}
728
729         return length;
730     }
731
732     /**
733      * Appends a byte to the output array,
734      * updates currentPost but not realSize
735      */

736     private void writeByte(byte b) {
737         output[currentPos++] = b;
738     }
739
740     /**
741      * Appends a USHORT to the output array,
742      * updates currentPost but not realSize
743      */

744     private void writeUShort(int s) {
745         byte b1 = (byte)((s >> 8) & 0xff);
746         byte b2 = (byte)(s & 0xff);
747         writeByte(b1);
748         writeByte(b2);
749     }
750
751     /**
752      * Appends a USHORT to the output array,
753      * at the given position without changing currentPos
754      */

755     private void writeUShort(int pos, int s) {
756         byte b1 = (byte)((s >> 8) & 0xff);
757         byte b2 = (byte)(s & 0xff);
758         output[pos] = b1;
759         output[pos + 1] = b2;
760     }
761
762     /**
763      * Appends a ULONG to the output array,
764      * updates currentPos but not realSize
765      */

766     private void writeULong(int s) {
767         byte b1 = (byte)((s >> 24) & 0xff);
768         byte b2 = (byte)((s >> 16) & 0xff);
769         byte b3 = (byte)((s >> 8) & 0xff);
770         byte b4 = (byte)(s & 0xff);
771         writeByte(b1);
772         writeByte(b2);
773         writeByte(b3);
774         writeByte(b4);
775     }
776
777     /**
778      * Appends a ULONG to the output array,
779      * at the given position without changing currentPos
780      */

781     private void writeULong(int pos, int s) {
782         byte b1 = (byte)((s >> 24) & 0xff);
783         byte b2 = (byte)((s >> 16) & 0xff);
784         byte b3 = (byte)((s >> 8) & 0xff);
785         byte b4 = (byte)(s & 0xff);
786         output[pos] = b1;
787         output[pos + 1] = b2;
788         output[pos + 2] = b3;
789         output[pos + 3] = b4;
790     }
791
792     /**
793      * Read a signed short value at given position
794      */

795     private short readShort(int pos) {
796         int ret = readUShort(pos);
797         return (short)ret;
798     }
799
800     /**
801      * Read a unsigned short value at given position
802      */

803     private int readUShort(int pos) {
804         int ret = (int)output[pos];
805         if (ret < 0) {
806             ret += 256;
807         }
808         ret = ret << 8;
809         if ((int)output[pos + 1] < 0) {
810             ret |= (int)output[pos + 1] + 256;
811         } else
812             ret |= (int)output[pos + 1];
813
814         return ret;
815     }
816
817     /**
818      * Create a padding in the fontfile to align
819      * on a 4-byte boundary
820      */

821     private void pad4() {
822         int padSize = currentPos % 4;
823         for (int i = 0; i < padSize; i++) {
824             output[currentPos++] = 0;
825             realSize++;
826         }
827     }
828
829     /**
830      * Returns the maximum power of 2 <= max
831      */

832     private int maxPow2(int max) {
833         int i = 0;
834         while (Math.pow(2, (double)i) < max)
835             i++;
836
837         return (i - 1);
838     }
839
840     private int log2(int num) {
841         return (int)(Math.log((double)num) / Math.log(2));
842     }
843
844
845     private int getCheckSum(int start, int size) {
846         return (int)getLongCheckSum(start, size);
847     }
848
849     private long getLongCheckSum(int start, int size) {
850         // All the tables here are aligned on four byte boundaries
851
// Add remainder to size if it's not a multiple of 4
852
int remainder = size % 4;
853         if (remainder != 0) {
854             size += remainder;
855         }
856
857         long sum = 0;
858
859         for (int i = 0; i < size; i += 4) {
860             int l = (int)(output[start + i] << 24);
861             l += (int)(output[start + i + 1] << 16);
862             l += (int)(output[start + i + 2] << 16);
863             l += (int)(output[start + i + 3] << 16);
864             sum += l;
865             if (sum > 0xffffffff) {
866                 sum = sum - 0xffffffff;
867             }
868         }
869
870         return sum;
871     }
872
873     private void createCheckSumAdjustment() {
874         long sum = getLongCheckSum(0, realSize);
875         int checksum = (int)(0xb1b0afba - sum);
876         writeULong(checkSumAdjustmentOffset, checksum);
877     }
878
879 }
880
881
882
883
Popular Tags