KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: TTFSubSetFile.java 426576 2006-07-28 15:44:37Z jeremias $ */
19  
20 package org.apache.fop.fonts.truetype;
21
22 import java.io.IOException JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.List JavaDoc;
26
27
28 /**
29  * Reads a TrueType file and generates a subset
30  * that can be used to embed a TrueType CID font.
31  * TrueType tables needed for embedded CID fonts are:
32  * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm".
33  * The TrueType spec can be found at the Microsoft
34  * Typography site: http://www.microsoft.com/truetype/
35  */

36 public class TTFSubSetFile extends TTFFile {
37
38     private byte[] output = null;
39     private int realSize = 0;
40     private int currentPos = 0;
41
42     /*
43      * Offsets in name table to be filled out by table.
44      * The offsets are to the checkSum field
45      */

46     private int cvtDirOffset = 0;
47     private int fpgmDirOffset = 0;
48     private int glyfDirOffset = 0;
49     private int headDirOffset = 0;
50     private int hheaDirOffset = 0;
51     private int hmtxDirOffset = 0;
52     private int locaDirOffset = 0;
53     private int maxpDirOffset = 0;
54     private int prepDirOffset = 0;
55
56     private int checkSumAdjustmentOffset = 0;
57     private int locaOffset = 0;
58
59     /**
60      * Initalize the output array
61      */

62     private void init(int size) {
63         output = new byte[size];
64         realSize = 0;
65         currentPos = 0;
66
67         // createDirectory()
68
}
69
70     /**
71      * Create the directory table
72      */

73     private void createDirectory() {
74         int numTables = 9;
75         // Create the TrueType header
76
writeByte((byte)0);
77         writeByte((byte)1);
78         writeByte((byte)0);
79         writeByte((byte)0);
80         realSize += 4;
81
82         writeUShort(numTables);
83         realSize += 2;
84
85         // Create searchRange, entrySelector and rangeShift
86
int maxPow = maxPow2(numTables);
87         int searchRange = maxPow * 16;
88         writeUShort(searchRange);
89         realSize += 2;
90
91         writeUShort(maxPow);
92         realSize += 2;
93
94         writeUShort((numTables * 16) - searchRange);
95         realSize += 2;
96
97         // Create space for the table entries
98
writeString("cvt ");
99         cvtDirOffset = currentPos;
100         currentPos += 12;
101         realSize += 16;
102
103         if (hasFpgm()) {
104             writeString("fpgm");
105             fpgmDirOffset = currentPos;
106             currentPos += 12;
107             realSize += 16;
108         }
109
110         writeString("glyf");
111         glyfDirOffset = currentPos;
112         currentPos += 12;
113         realSize += 16;
114
115         writeString("head");
116         headDirOffset = currentPos;
117         currentPos += 12;
118         realSize += 16;
119
120         writeString("hhea");
121         hheaDirOffset = currentPos;
122         currentPos += 12;
123         realSize += 16;
124
125         writeString("hmtx");
126         hmtxDirOffset = currentPos;
127         currentPos += 12;
128         realSize += 16;
129
130         writeString("loca");
131         locaDirOffset = currentPos;
132         currentPos += 12;
133         realSize += 16;
134
135         writeString("maxp");
136         maxpDirOffset = currentPos;
137         currentPos += 12;
138         realSize += 16;
139
140         writeString("prep");
141         prepDirOffset = currentPos;
142         currentPos += 12;
143         realSize += 16;
144     }
145
146
147     /**
148      * Copy the cvt table as is from original font to subset font
149      */

150     private void createCvt(FontFileReader in) throws IOException JavaDoc {
151         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
152         if (entry != null) {
153             pad4();
154             seekTab(in, "cvt ", 0);
155             System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
156                              0, output, currentPos, (int)entry.getLength());
157
158             int checksum = getCheckSum(currentPos, (int)entry.getLength());
159             writeULong(cvtDirOffset, checksum);
160             writeULong(cvtDirOffset + 4, currentPos);
161             writeULong(cvtDirOffset + 8, (int)entry.getLength());
162             currentPos += (int)entry.getLength();
163             realSize += (int)entry.getLength();
164         } else {
165             throw new IOException JavaDoc("Can't find cvt table");
166         }
167     }
168
169
170     private boolean hasFpgm() {
171         return (dirTabs.get("fpgm") != null);
172     }
173
174
175     /**
176      * Copy the fpgm table as is from original font to subset font
177      */

178     private void createFpgm(FontFileReader in) throws IOException JavaDoc {
179         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
180         if (entry != null) {
181             pad4();
182             seekTab(in, "fpgm", 0);
183             System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
184                              0, output, currentPos, (int)entry.getLength());
185             int checksum = getCheckSum(currentPos, (int)entry.getLength());
186             writeULong(fpgmDirOffset, checksum);
187             writeULong(fpgmDirOffset + 4, currentPos);
188             writeULong(fpgmDirOffset + 8, (int)entry.getLength());
189             currentPos += (int)entry.getLength();
190             realSize += (int)entry.getLength();
191         } else {
192             //fpgm table is optional
193
//throw new IOException("Can't find fpgm table");
194
}
195     }
196
197
198
199     /**
200      * Create an empty loca table without updating checksum
201      */

202     private void createLoca(int size) throws IOException JavaDoc {
203         pad4();
204         locaOffset = currentPos;
205         writeULong(locaDirOffset + 4, currentPos);
206         writeULong(locaDirOffset + 8, size * 4 + 4);
207         currentPos += size * 4 + 4;
208         realSize += size * 4 + 4;
209     }
210
211
212     /**
213      * Copy the maxp table as is from original font to subset font
214      * and set num glyphs to size
215      */

216     private void createMaxp(FontFileReader in, int size) throws IOException JavaDoc {
217         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
218         if (entry != null) {
219             pad4();
220             seekTab(in, "maxp", 0);
221             System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
222                              0, output, currentPos, (int)entry.getLength());
223             writeUShort(currentPos + 4, size);
224
225             int checksum = getCheckSum(currentPos, (int)entry.getLength());
226             writeULong(maxpDirOffset, checksum);
227             writeULong(maxpDirOffset + 4, currentPos);
228             writeULong(maxpDirOffset + 8, (int)entry.getLength());
229             currentPos += (int)entry.getLength();
230             realSize += (int)entry.getLength();
231         } else {
232             throw new IOException JavaDoc("Can't find maxp table");
233         }
234     }
235
236
237     /**
238      * Copy the prep table as is from original font to subset font
239      */

240     private void createPrep(FontFileReader in) throws IOException JavaDoc {
241         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
242         if (entry != null) {
243             pad4();
244             seekTab(in, "prep", 0);
245             System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
246                              0, output, currentPos, (int)entry.getLength());
247
248             int checksum = getCheckSum(currentPos, (int)entry.getLength());
249             writeULong(prepDirOffset, checksum);
250             writeULong(prepDirOffset + 4, currentPos);
251             writeULong(prepDirOffset + 8, (int)entry.getLength());
252             currentPos += (int)entry.getLength();
253             realSize += (int)entry.getLength();
254         } else {
255             throw new IOException JavaDoc("Can't find prep table");
256         }
257     }
258
259
260     /**
261      * Copy the hhea table as is from original font to subset font
262      * and fill in size of hmtx table
263      */

264     private void createHhea(FontFileReader in, int size) throws IOException JavaDoc {
265         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
266         if (entry != null) {
267             pad4();
268             seekTab(in, "hhea", 0);
269             System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
270                              0, output, currentPos, (int)entry.getLength());
271             writeUShort((int)entry.getLength() + currentPos - 2, size);
272
273             int checksum = getCheckSum(currentPos, (int)entry.getLength());
274             writeULong(hheaDirOffset, checksum);
275             writeULong(hheaDirOffset + 4, currentPos);
276             writeULong(hheaDirOffset + 8, (int)entry.getLength());
277             currentPos += (int)entry.getLength();
278             realSize += (int)entry.getLength();
279         } else {
280             throw new IOException JavaDoc("Can't find hhea table");
281         }
282     }
283
284
285     /**
286      * Copy the head table as is from original font to subset font
287      * and set indexToLocaFormat to long and set
288      * checkSumAdjustment to 0, store offset to checkSumAdjustment
289      * in checkSumAdjustmentOffset
290      */

291     private void createHead(FontFileReader in) throws IOException JavaDoc {
292         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
293         if (entry != null) {
294             pad4();
295             seekTab(in, "head", 0);
296             System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
297                              0, output, currentPos, (int)entry.getLength());
298
299             checkSumAdjustmentOffset = currentPos + 8;
300             output[currentPos + 8] = 0; // Set checkSumAdjustment to 0
301
output[currentPos + 9] = 0;
302             output[currentPos + 10] = 0;
303             output[currentPos + 11] = 0;
304             output[currentPos + 50] = 0; // long locaformat
305
output[currentPos + 51] = 1; // long locaformat
306

307             int checksum = getCheckSum(currentPos, (int)entry.getLength());
308             writeULong(headDirOffset, checksum);
309             writeULong(headDirOffset + 4, currentPos);
310             writeULong(headDirOffset + 8, (int)entry.getLength());
311
312             currentPos += (int)entry.getLength();
313             realSize += (int)entry.getLength();
314         } else {
315             throw new IOException JavaDoc("Can't find head table");
316         }
317     }
318
319
320     /**
321      * Create the glyf table and fill in loca table
322      */

323     private void createGlyf(FontFileReader in,
324                             Map JavaDoc glyphs) throws IOException JavaDoc {
325         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
326         int size = 0;
327         int start = 0;
328         int endOffset = 0; // Store this as the last loca
329
if (entry != null) {
330             pad4();
331             start = currentPos;
332
333             /* Loca table must be in order by glyph index, so build
334              * an array first and then write the glyph info and
335              * location offset.
336              */

337             int[] origIndexes = new int[glyphs.size()];
338
339             Iterator JavaDoc e = glyphs.keySet().iterator();
340             while (e.hasNext()) {
341                 Integer JavaDoc origIndex = (Integer JavaDoc)e.next();
342                 Integer JavaDoc subsetIndex = (Integer JavaDoc)glyphs.get(origIndex);
343                 origIndexes[subsetIndex.intValue()] = origIndex.intValue();
344             }
345
346             for (int i = 0; i < origIndexes.length; i++) {
347                 int glyphLength = 0;
348                 int nextOffset = 0;
349                 int origGlyphIndex = origIndexes[i];
350                 if (origGlyphIndex >= (mtxTab.length - 1)) {
351                     nextOffset = (int)lastLoca;
352                 } else {
353                     nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset();
354                 }
355                 glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset();
356
357                 // Copy glyph
358
System.arraycopy(
359                     in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(),
360                         glyphLength), 0,
361                     output, currentPos,
362                     glyphLength);
363
364
365                 // Update loca table
366
writeULong(locaOffset + i * 4, currentPos - start);
367                 if ((currentPos - start + glyphLength) > endOffset) {
368                     endOffset = (currentPos - start + glyphLength);
369                 }
370
371                 currentPos += glyphLength;
372                 realSize += glyphLength;
373
374             }
375
376             size = currentPos - start;
377
378             int checksum = getCheckSum(start, size);
379             writeULong(glyfDirOffset, checksum);
380             writeULong(glyfDirOffset + 4, start);
381             writeULong(glyfDirOffset + 8, size);
382             currentPos += 12;
383             realSize += 12;
384
385             // Update loca checksum and last loca index
386
writeULong(locaOffset + glyphs.size() * 4, endOffset);
387
388             checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4);
389             writeULong(locaDirOffset, checksum);
390         } else {
391             throw new IOException JavaDoc("Can't find glyf table");
392         }
393     }
394
395
396     /**
397      * Create the hmtx table by copying metrics from original
398      * font to subset font. The glyphs Map contains an
399      * Integer key and Integer value that maps the original
400      * metric (key) to the subset metric (value)
401      */

402     private void createHmtx(FontFileReader in,
403                             Map JavaDoc glyphs) throws IOException JavaDoc {
404         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
405
406         int longHorMetricSize = glyphs.size() * 2;
407         int leftSideBearingSize = glyphs.size() * 2;
408         int hmtxSize = longHorMetricSize + leftSideBearingSize;
409
410         if (entry != null) {
411             pad4();
412             //int offset = (int)entry.offset;
413
Iterator JavaDoc e = glyphs.keySet().iterator();
414             while (e.hasNext()) {
415                 Integer JavaDoc origIndex = (Integer JavaDoc)e.next();
416                 Integer JavaDoc subsetIndex = (Integer JavaDoc)glyphs.get(origIndex);
417
418                 writeUShort(currentPos + subsetIndex.intValue() * 4,
419                             mtxTab[origIndex.intValue()].getWx());
420                 writeUShort(currentPos + subsetIndex.intValue() * 4 + 2,
421                             mtxTab[origIndex.intValue()].getLsb());
422             }
423
424             int checksum = getCheckSum(currentPos, hmtxSize);
425             writeULong(hmtxDirOffset, checksum);
426             writeULong(hmtxDirOffset + 4, currentPos);
427             writeULong(hmtxDirOffset + 8, hmtxSize);
428             currentPos += hmtxSize;
429             realSize += hmtxSize;
430         } else {
431             throw new IOException JavaDoc("Can't find hmtx table");
432         }
433     }
434
435     /**
436      * Returns a List containing the glyph itself plus all glyphs
437      * that this composite glyph uses
438      */

439     private List JavaDoc getIncludedGlyphs(FontFileReader in, int glyphOffset,
440                                      Integer JavaDoc glyphIdx) throws IOException JavaDoc {
441         List JavaDoc ret = new java.util.ArrayList JavaDoc();
442         ret.add(glyphIdx);
443         int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10;
444         Integer JavaDoc compositeIdx = null;
445         int flags = 0;
446         boolean moreComposites = true;
447         while (moreComposites) {
448             flags = in.readTTFUShort(offset);
449             compositeIdx = new Integer JavaDoc(in.readTTFUShort(offset + 2));
450             ret.add(compositeIdx);
451
452             offset += 4;
453             if ((flags & 1) > 0) {
454                 // ARG_1_AND_ARG_2_ARE_WORDS
455
offset += 4;
456             } else {
457                 offset += 2;
458             }
459
460             if ((flags & 8) > 0) {
461                 offset += 2; // WE_HAVE_A_SCALE
462
} else if ((flags & 64) > 0) {
463                 offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
464
} else if ((flags & 128) > 0) {
465                 offset += 8; // WE_HAVE_A_TWO_BY_TWO
466
}
467
468             if ((flags & 32) > 0) {
469                 moreComposites = true;
470             } else {
471                 moreComposites = false;
472             }
473         }
474
475         return ret;
476     }
477
478
479     /**
480      * Rewrite all compositepointers in glyphindex glyphIdx
481      *
482      */

483     private void remapComposite(FontFileReader in, Map JavaDoc glyphs,
484                                 int glyphOffset,
485                                 Integer JavaDoc glyphIdx) throws IOException JavaDoc {
486         int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset()
487                      + 10;
488
489         Integer JavaDoc compositeIdx = null;
490         int flags = 0;
491         boolean moreComposites = true;
492
493         while (moreComposites) {
494             flags = in.readTTFUShort(offset);
495             compositeIdx = new Integer JavaDoc(in.readTTFUShort(offset + 2));
496             Integer JavaDoc newIdx = (Integer JavaDoc)glyphs.get(compositeIdx);
497             if (newIdx == null) {
498                 // This errormessage would look much better
499
// if the fontname was printed to
500
//log.error("An embedded font "
501
// + "contains bad glyph data. "
502
// + "Characters might not display "
503
// + "correctly.");
504
moreComposites = false;
505                 continue;
506             }
507
508             in.writeTTFUShort(offset + 2, newIdx.intValue());
509
510             offset += 4;
511
512             if ((flags & 1) > 0) {
513                 // ARG_1_AND_ARG_2_ARE_WORDS
514
offset += 4;
515             } else {
516                 offset += 2;
517             }
518
519             if ((flags & 8) > 0) {
520                 offset += 2; // WE_HAVE_A_SCALE
521
} else if ((flags & 64) > 0) {
522                 offset += 4; // WE_HAVE_AN_X_AND_Y_SCALE
523
} else if ((flags & 128) > 0) {
524                 offset += 8; // WE_HAVE_A_TWO_BY_TWO
525
}
526
527             if ((flags & 32) > 0) {
528                 moreComposites = true;
529             } else {
530                 moreComposites = false;
531             }
532         }
533     }
534
535
536     /**
537      * Scan all the original glyphs for composite glyphs and add those glyphs
538      * to the glyphmapping also rewrite the composite glyph pointers to the new
539      * mapping
540      */

541     private void scanGlyphs(FontFileReader in,
542                             Map JavaDoc glyphs) throws IOException JavaDoc {
543         TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
544         Map JavaDoc newComposites = null;
545         Map JavaDoc allComposites = new java.util.HashMap JavaDoc();
546
547         int newIndex = glyphs.size();
548
549         if (entry != null) {
550             while (newComposites == null || newComposites.size() > 0) {
551                 // Inefficient to iterate through all glyphs
552
newComposites = new java.util.HashMap JavaDoc();
553
554                 Iterator JavaDoc e = glyphs.keySet().iterator();
555                 while (e.hasNext()) {
556                     Integer JavaDoc origIndex = (Integer JavaDoc)e.next();
557
558                     if (in.readTTFShort(entry.getOffset()
559                                         + mtxTab[origIndex.intValue()].getOffset()) < 0) {
560                         // origIndex is a composite glyph
561
allComposites.put(origIndex, glyphs.get(origIndex));
562                         List JavaDoc composites =
563                             getIncludedGlyphs(in, (int)entry.getOffset(),
564                                               origIndex);
565
566                         // Iterate through all composites pointed to
567
// by this composite and check if they exists
568
// in the glyphs map, add them if not.
569
Iterator JavaDoc cps = composites.iterator();
570                         while (cps.hasNext()) {
571                             Integer JavaDoc cIdx = (Integer JavaDoc)cps.next();
572                             if (glyphs.get(cIdx) == null
573                                     && newComposites.get(cIdx) == null) {
574                                 newComposites.put(cIdx,
575                                                   new Integer JavaDoc(newIndex));
576                                 newIndex++;
577                             }
578                         }
579                     }
580                 }
581
582                 // Add composites to glyphs
583
Iterator JavaDoc m = newComposites.keySet().iterator();
584                 while (m.hasNext()) {
585                     Integer JavaDoc im = (Integer JavaDoc)m.next();
586                     glyphs.put(im, newComposites.get(im));
587                 }
588             }
589
590             // Iterate through all composites to remap their composite index
591
Iterator JavaDoc ce = allComposites.keySet().iterator();
592             while (ce.hasNext()) {
593                 remapComposite(in, glyphs, (int)entry.getOffset(),
594                                (Integer JavaDoc)ce.next());
595             }
596
597         } else {
598             throw new IOException JavaDoc("Can't find glyf table");
599         }
600     }
601
602
603
604     /**
605      * Returns a subset of the original font.
606      *
607      * @param in FontFileReader to read from
608      * @param name Name to be checked for in the font file
609      * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and
610      * new index as (Integer) value)
611      * @return A subset of the original font
612      * @throws IOException in case of an I/O problem
613      */

614     public byte[] readFont(FontFileReader in, String JavaDoc name,
615                            Map JavaDoc glyphs) throws IOException JavaDoc {
616
617         //Check if TrueType collection, and that the name exists in the collection
618
if (!checkTTC(in, name)) {
619             throw new IOException JavaDoc("Failed to read font");
620         }
621
622         output = new byte[in.getFileSize()];
623
624         readDirTabs(in);
625         readFontHeader(in);
626         getNumGlyphs(in);
627         readHorizontalHeader(in);
628         readHorizontalMetrics(in);
629         readIndexToLocation(in);
630
631         scanGlyphs(in, glyphs);
632
633         createDirectory(); // Create the TrueType header and directory
634

635         createHead(in);
636         createHhea(in, glyphs.size()); // Create the hhea table
637
createHmtx(in, glyphs); // Create hmtx table
638
createMaxp(in, glyphs.size()); // copy the maxp table
639

640         try {
641             createCvt(in); // copy the cvt table
642
} catch (IOException JavaDoc ex) {
643             // Cvt is optional (only required for OpenType (MS) fonts)
644
//log.error("TrueType warning: " + ex.getMessage());
645
}
646
647         try {
648             createFpgm(in); // copy fpgm table
649
} catch (IOException JavaDoc ex) {
650             // Fpgm is optional (only required for OpenType (MS) fonts)
651
//log.error("TrueType warning: " + ex.getMessage());
652
}
653
654         try {
655             createPrep(in); // copy prep table
656
} catch (IOException JavaDoc ex) {
657             // Prep is optional (only required for OpenType (MS) fonts)
658
//log.error("TrueType warning: " + ex.getMessage());
659
}
660
661         try {
662             createLoca(glyphs.size()); // create empty loca table
663
} catch (IOException JavaDoc ex) {
664             // Loca is optional (only required for OpenType (MS) fonts)
665
//log.error("TrueType warning: " + ex.getMessage());
666
}
667
668         try {
669             createGlyf(in, glyphs);
670         } catch (IOException JavaDoc ex) {
671             // Glyf is optional (only required for OpenType (MS) fonts)
672
//log.error("TrueType warning: " + ex.getMessage());
673
}
674
675         pad4();
676         createCheckSumAdjustment();
677
678         byte[] ret = new byte[realSize];
679         System.arraycopy(output, 0, ret, 0, realSize);
680
681         return ret;
682     }
683
684     /**
685      * writes a ISO-8859-1 string at the currentPosition
686      * updates currentPosition but not realSize
687      * @return number of bytes written
688      */

689     private int writeString(String JavaDoc str) {
690         int length = 0;
691         try {
692             byte[] buf = str.getBytes("ISO-8859-1");
693             System.arraycopy(buf, 0, output, currentPos, buf.length);
694             length = buf.length;
695             currentPos += length;
696         } catch (java.io.UnsupportedEncodingException JavaDoc e) {
697             // This should never happen!
698
}
699
700         return length;
701     }
702
703     /**
704      * Appends a byte to the output array,
705      * updates currentPost but not realSize
706      */

707     private void writeByte(byte b) {
708         output[currentPos++] = b;
709     }
710
711     /**
712      * Appends a USHORT to the output array,
713      * updates currentPost but not realSize
714      */

715     private void writeUShort(int s) {
716         byte b1 = (byte)((s >> 8) & 0xff);
717         byte b2 = (byte)(s & 0xff);
718         writeByte(b1);
719         writeByte(b2);
720     }
721
722     /**
723      * Appends a USHORT to the output array,
724      * at the given position without changing currentPos
725      */

726     private void writeUShort(int pos, int s) {
727         byte b1 = (byte)((s >> 8) & 0xff);
728         byte b2 = (byte)(s & 0xff);
729         output[pos] = b1;
730         output[pos + 1] = b2;
731     }
732
733     /**
734      * Appends a ULONG to the output array,
735      * updates currentPos but not realSize
736      */

737     private void writeULong(int s) {
738         byte b1 = (byte)((s >> 24) & 0xff);
739         byte b2 = (byte)((s >> 16) & 0xff);
740         byte b3 = (byte)((s >> 8) & 0xff);
741         byte b4 = (byte)(s & 0xff);
742         writeByte(b1);
743         writeByte(b2);
744         writeByte(b3);
745         writeByte(b4);
746     }
747
748     /**
749      * Appends a ULONG to the output array,
750      * at the given position without changing currentPos
751      */

752     private void writeULong(int pos, int s) {
753         byte b1 = (byte)((s >> 24) & 0xff);
754         byte b2 = (byte)((s >> 16) & 0xff);
755         byte b3 = (byte)((s >> 8) & 0xff);
756         byte b4 = (byte)(s & 0xff);
757         output[pos] = b1;
758         output[pos + 1] = b2;
759         output[pos + 2] = b3;
760         output[pos + 3] = b4;
761     }
762
763     /**
764      * Read a signed short value at given position
765      */

766     private short readShort(int pos) {
767         int ret = readUShort(pos);
768         return (short)ret;
769     }
770
771     /**
772      * Read a unsigned short value at given position
773      */

774     private int readUShort(int pos) {
775         int ret = (int)output[pos];
776         if (ret < 0) {
777             ret += 256;
778         }
779         ret = ret << 8;
780         if ((int)output[pos + 1] < 0) {
781             ret |= (int)output[pos + 1] + 256;
782         } else {
783             ret |= (int)output[pos + 1];
784         }
785
786         return ret;
787     }
788
789     /**
790      * Create a padding in the fontfile to align
791      * on a 4-byte boundary
792      */

793     private void pad4() {
794         int padSize = currentPos % 4;
795         for (int i = 0; i < padSize; i++) {
796             output[currentPos++] = 0;
797             realSize++;
798         }
799     }
800
801     /**
802      * Returns the maximum power of 2 <= max
803      */

804     private int maxPow2(int max) {
805         int i = 0;
806         while (Math.pow(2, (double)i) < max) {
807             i++;
808         }
809
810         return (i - 1);
811     }
812
813     private int log2(int num) {
814         return (int)(Math.log((double)num) / Math.log(2));
815     }
816
817
818     private int getCheckSum(int start, int size) {
819         return (int)getLongCheckSum(start, size);
820     }
821
822     private long getLongCheckSum(int start, int size) {
823         // All the tables here are aligned on four byte boundaries
824
// Add remainder to size if it's not a multiple of 4
825
int remainder = size % 4;
826         if (remainder != 0) {
827             size += remainder;
828         }
829
830         long sum = 0;
831
832         for (int i = 0; i < size; i += 4) {
833             int l = (int)(output[start + i] << 24);
834             l += (int)(output[start + i + 1] << 16);
835             l += (int)(output[start + i + 2] << 16);
836             l += (int)(output[start + i + 3] << 16);
837             sum += l;
838             if (sum > 0xffffffff) {
839                 sum = sum - 0xffffffff;
840             }
841         }
842
843         return sum;
844     }
845
846     private void createCheckSumAdjustment() {
847         long sum = getLongCheckSum(0, realSize);
848         int checksum = (int)(0xb1b0afba - sum);
849         writeULong(checkSumAdjustmentOffset, checksum);
850     }
851
852 }
853
854
855
856
Popular Tags