KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > CFFFontSubset


1 /*
2  * $Id: CFFFontSubset.java 2671 2007-04-03 16:08:04Z psoares33 $
3  * $Name$
4  *
5  * Copyright 2004 Oren Manor and Ygal Blum
6  *
7  * The contents of this file are subject to the Mozilla Public License Version 1.1
8  * (the "License"); you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the License.
14  *
15  * The Original Code is 'iText, a free JAVA-PDF library'.
16  *
17  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
18  * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie.
19  * All Rights Reserved.
20  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
21  * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved.
22  *
23  * Contributor(s): all the names of the contributors are added in the source code
24  * where applicable.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
28  * provisions of LGPL are applicable instead of those above. If you wish to
29  * allow use of your version of this file only under the terms of the LGPL
30  * License and not to allow others to use your version of this file under
31  * the MPL, indicate your decision by deleting the provisions above and
32  * replace them with the notice and other provisions required by the LGPL.
33  * If you do not delete the provisions above, a recipient may use your version
34  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Library General Public License as published by the Free Software Foundation;
39  * either version 2 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
44  * details.
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */

50 package com.lowagie.text.pdf;
51
52 import java.io.IOException JavaDoc;
53 import java.util.ArrayList JavaDoc;
54 import java.util.HashMap JavaDoc;
55 import java.util.Iterator JavaDoc;
56 import java.util.LinkedList JavaDoc;
57
58 /**
59  * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts.
60  * The Charstring is subseted for both types. For CID fonts only the FDArray which are used are embedded.
61  * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2
62  * formatting altough only tested on Type2 Format.
63  * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted.
64  * A font which was not of CID type is transformed into CID as a part of the subset process.
65  * The CID synthetic creation was written by Sivan Toledo (sivan@math.tau.ac.il)
66  * @author Oren Manor (manorore@post.tau.ac.il) and Ygal Blum (blumygal@post.tau.ac.il)
67  */

68 public class CFFFontSubset extends CFFFont {
69     
70     /**
71      * The Strings in this array represent Type1/Type2 operator names
72      */

73     static final String JavaDoc SubrsFunctions[] = {
74             "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto",
75             "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13",
76             "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask",
77             "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto",
78             "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto"
79             };
80     /**
81      * The Strings in this array represent Type1/Type2 escape operator names
82      */

83     static final String JavaDoc SubrsEscapeFuncs[] = {
84             "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6",
85             "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg",
86             "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse",
87             "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31",
88             "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST"
89     };
90     
91     /**
92      * A HashMap containing the glyphs used in the text after being converted
93      * to glyph number by the CMap
94      */

95     HashMap JavaDoc GlyphsUsed;
96     /**
97      * The GlyphsUsed keys as an ArrayList
98      */

99     ArrayList JavaDoc glyphsInList;
100     /**
101      * A HashMap for keeping the FDArrays being used by the font
102      */

103     HashMap JavaDoc FDArrayUsed = new HashMap JavaDoc();
104     /**
105      * A HashMaps array for keeping the subroutines used in each FontDict
106      */

107     HashMap JavaDoc[] hSubrsUsed;
108     /**
109      * The SubroutinesUsed HashMaps as ArrayLists
110      */

111     ArrayList JavaDoc[] lSubrsUsed;
112     /**
113      * A HashMap for keeping the Global subroutines used in the font
114      */

115     HashMap JavaDoc hGSubrsUsed = new HashMap JavaDoc();
116     /**
117      * The Global SubroutinesUsed HashMaps as ArrayLists
118      */

119     ArrayList JavaDoc lGSubrsUsed = new ArrayList JavaDoc();
120     /**
121      * A HashMap for keeping the subroutines used in a non-cid font
122      */

123     HashMap JavaDoc hSubrsUsedNonCID = new HashMap JavaDoc();
124     /**
125      * The SubroutinesUsed HashMap as ArrayList
126      */

127     ArrayList JavaDoc lSubrsUsedNonCID = new ArrayList JavaDoc();
128     /**
129      * An array of the new Indexs for the local Subr. One index for each FontDict
130      */

131     byte[][] NewLSubrsIndex;
132     /**
133      * The new subroutines index for a non-cid font
134      */

135     byte[] NewSubrsIndexNonCID;
136     /**
137      * The new global subroutines index of the font
138      */

139     byte[] NewGSubrsIndex;
140     /**
141      * The new CharString of the font
142      */

143     byte[] NewCharStringsIndex;
144     
145     /**
146      * The bias for the global subroutines
147      */

148     int GBias = 0;
149     
150     /**
151      * The linked list for generating the new font stream
152      */

153     LinkedList JavaDoc OutputList;
154     
155     /**
156      * Number of arguments to the stem operators in a subroutine calculated recursivly
157      */

158     int NumOfHints=0;
159
160     
161     /**
162      * C'tor for CFFFontSubset
163      * @param rf - The font file
164      * @param GlyphsUsed - a HashMap that contains the glyph used in the subset
165      */

166     public CFFFontSubset(RandomAccessFileOrArray rf,HashMap JavaDoc GlyphsUsed){
167         // Use CFFFont c'tor in order to parse the font file.
168
super(rf);
169         this.GlyphsUsed = GlyphsUsed;
170         //Put the glyphs into a list
171
glyphsInList = new ArrayList JavaDoc(GlyphsUsed.keySet());
172         
173         
174         for (int i=0;i<fonts.length;++i)
175         {
176             // Read the number of glyphs in the font
177
seek(fonts[i].charstringsOffset);
178             fonts[i].nglyphs = getCard16();
179             
180             // Jump to the count field of the String Index
181
seek(stringIndexOffset);
182             fonts[i].nstrings = getCard16()+standardStrings.length;
183             
184             // For each font save the offset array of the charstring
185
fonts[i].charstringsOffsets = getIndex(fonts[i].charstringsOffset);
186             
187             // Proces the FDSelect if exist
188
if (fonts[i].fdselectOffset>=0)
189             {
190                 // Proces the FDSelect
191
readFDSelect(i);
192                 // Build the FDArrayUsed hashmap
193
BuildFDArrayUsed(i);
194             }
195             if (fonts[i].isCID)
196                 // Build the FD Array used Hash Map
197
ReadFDArray(i);
198             // compute the charset length
199
fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs);
200         }
201     }
202
203     /**
204      * Calculates the length of the charset according to its format
205      * @param Offset The Charset Offset
206      * @param NumofGlyphs Number of glyphs in the font
207      * @return the length of the Charset
208      */

209     int CountCharset(int Offset,int NumofGlyphs){
210         int format;
211         int Length=0;
212         seek(Offset);
213         // Read the format
214
format = getCard8();
215         // Calc according to format
216
switch (format){
217             case 0:
218                 Length = 1+2*NumofGlyphs;
219                 break;
220             case 1:
221                 Length = 1+3*CountRange(NumofGlyphs,1);
222                 break;
223             case 2:
224                 Length = 1+4*CountRange(NumofGlyphs,2);
225                 break;
226             default:
227                 break;
228         }
229         return Length;
230     }
231     
232     /**
233      * Function calculates the number of ranges in the Charset
234      * @param NumofGlyphs The number of glyphs in the font
235      * @param Type The format of the Charset
236      * @return The number of ranges in the Charset data structure
237      */

238     int CountRange(int NumofGlyphs,int Type){
239         int num=0;
240         char Sid;
241         int i=1,nLeft;
242         while (i<NumofGlyphs){
243             num++;
244             Sid = getCard16();
245             if (Type==1)
246                 nLeft = getCard8();
247             else
248                 nLeft = getCard16();
249             i += nLeft+1;
250         }
251         return num;
252     }
253
254
255     /**
256      * Read the FDSelect of the font and compute the array and its length
257      * @param Font The index of the font being processed
258      */

259     protected void readFDSelect(int Font)
260     {
261         // Restore the number of glyphs
262
int NumOfGlyphs = fonts[Font].nglyphs;
263         int[] FDSelect = new int[NumOfGlyphs];
264         // Go to the beginning of the FDSelect
265
seek(fonts[Font].fdselectOffset);
266         // Read the FDSelect's format
267
fonts[Font].FDSelectFormat = getCard8();
268         
269         switch(fonts[Font].FDSelectFormat){
270             // Format==0 means each glyph has an entry that indicated
271
// its FD.
272
case 0:
273                 for (int i=0;i<NumOfGlyphs;i++)
274                 {
275                     FDSelect[i] = getCard8();
276                 }
277                 // The FDSelect's Length is one for each glyph + the format
278
// for later use
279
fonts[Font].FDSelectLength = fonts[Font].nglyphs+1;
280                 break;
281             case 3:
282                 // Format==3 means the ranges version
283
// The number of ranges
284
int nRanges = getCard16();
285                 int l=0;
286                 // Read the first in the first range
287
int first = getCard16();
288                 for (int i=0;i<nRanges;i++)
289                 {
290                     // Read the FD index
291
int fd = getCard8();
292                     // Read the first of the next range
293
int last = getCard16();
294                     // Calc the steps and write to the array
295
int steps = last-first;
296                     for (int k=0;k<steps;k++)
297                     {
298                         FDSelect[l] = fd;
299                         l++;
300                     }
301                     // The last from this iteration is the first of the next
302
first = last;
303                 }
304                 // Store the length for later use
305
fonts[Font].FDSelectLength = 1+2+nRanges*3+2;
306                 break;
307             default:
308                 break;
309         }
310         // Save the FDSelect of the font
311
fonts[Font].FDSelect = FDSelect;
312     }
313     
314     /**
315      * Function reads the FDSelect and builds the FDArrayUsed HashMap According to the glyphs used
316      * @param Font the Number of font being processed
317      */

318     protected void BuildFDArrayUsed(int Font)
319     {
320         int[] FDSelect = fonts[Font].FDSelect;
321         // For each glyph used
322
for (int i=0;i<glyphsInList.size();i++)
323         {
324             // Pop the glyphs index
325
int glyph = ((Integer JavaDoc)glyphsInList.get(i)).intValue();
326             // Pop the glyph's FD
327
int FD = FDSelect[glyph];
328             // Put the FD index into the FDArrayUsed HashMap
329
FDArrayUsed.put(new Integer JavaDoc(FD),null);
330         }
331     }
332
333     /**
334      * Read the FDArray count, offsize and Offset array
335      * @param Font
336      */

337     protected void ReadFDArray(int Font)
338     {
339         seek(fonts[Font].fdarrayOffset);
340         fonts[Font].FDArrayCount = getCard16();
341         fonts[Font].FDArrayOffsize = getCard8();
342         // Since we will change values inside the FDArray objects
343
// We increase its offsize to prevent errors
344
if (fonts[Font].FDArrayOffsize < 4)
345             fonts[Font].FDArrayOffsize++;
346         fonts[Font].FDArrayOffsets = getIndex(fonts[Font].fdarrayOffset);
347     }
348
349     
350     /**
351      * The Process function extracts one font out of the CFF file and returns a
352      * subset version of the original.
353      * @param fontName - The name of the font to be taken out of the CFF
354      * @return The new font stream
355      * @throws IOException
356      */

357     public byte[] Process(String JavaDoc fontName)throws IOException JavaDoc{
358         try
359         {
360             // Verify that the file is open
361
buf.reOpen();
362             // Find the Font that we will be dealing with
363
int j;
364             for (j=0; j<fonts.length; j++)
365                 if (fontName.equals(fonts[j].name)) break;
366             if (j==fonts.length) return null;
367             
368             // Calc the bias for the global subrs
369
if (gsubrIndexOffset >= 0)
370                 GBias = CalcBias(gsubrIndexOffset,j);
371
372             // Prepare the new CharStrings Index
373
BuildNewCharString(j);
374              // Prepare the new Global and Local Subrs Indices
375
BuildNewLGSubrs(j);
376             // Build the new file
377
byte[] Ret = BuildNewFile(j);
378             return Ret;
379         }
380         finally {
381             try {
382                 buf.close();
383             }
384             catch (Exception JavaDoc e) {
385                 // empty on purpose
386
}
387         }
388     }
389
390     /**
391      * Function calcs bias according to the CharString type and the count
392      * of the subrs
393      * @param Offset The offset to the relevent subrs index
394      * @param Font the font
395      * @return The calculated Bias
396      */

397     protected int CalcBias(int Offset,int Font)
398     {
399         seek(Offset);
400         int nSubrs = getCard16();
401         // If type==1 -> bias=0
402
if (fonts[Font].CharstringType == 1)
403             return 0;
404         // else calc according to the count
405
else if (nSubrs < 1240)
406             return 107;
407         else if (nSubrs < 33900)
408             return 1131;
409         else
410             return 32768;
411     }
412
413     /**
414      *Function uses BuildNewIndex to create the new index of the subset charstrings
415      * @param FontIndex the font
416      * @throws IOException
417      */

418     protected void BuildNewCharString(int FontIndex) throws IOException JavaDoc
419     {
420         NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed);
421     }
422     
423     /**
424      * Function builds the new local & global subsrs indices. IF CID then All of
425      * the FD Array lsubrs will be subsetted.
426      * @param Font the font
427      * @throws IOException
428      */

429     protected void BuildNewLGSubrs(int Font)throws IOException JavaDoc
430     {
431         // If the font is CID then the lsubrs are divided into FontDicts.
432
// for each FD array the lsubrs will be subsetted.
433
if(fonts[Font].isCID)
434         {
435             // Init the hasmap-array and the arraylist-array to hold the subrs used
436
// in each private dict.
437
hSubrsUsed = new HashMap JavaDoc[fonts[Font].fdprivateOffsets.length];
438             lSubrsUsed = new ArrayList JavaDoc[fonts[Font].fdprivateOffsets.length];
439             // A [][] which will store the byte array for each new FD Array lsubs index
440
NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.length][];
441             // An array to hold the offset for each Lsubr index
442
fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.length];
443             // A [][] which will store the offset array for each lsubr index
444
fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.length][];
445             
446             // Put the FDarrayUsed into a list
447
ArrayList JavaDoc FDInList = new ArrayList JavaDoc(FDArrayUsed.keySet());
448             // For each FD array which is used subset the lsubr
449
for (int j=0;j<FDInList.size();j++)
450             {
451                 // The FDArray index, Hash Map, Arrat List to work on
452
int FD = ((Integer JavaDoc)FDInList.get(j)).intValue();
453                 hSubrsUsed[FD] = new HashMap JavaDoc();
454                 lSubrsUsed[FD] = new ArrayList JavaDoc();
455                 //Reads the private dicts looking for the subr operator and
456
// store both the offest for the index and its offset array
457
BuildFDSubrsOffsets(Font,FD);
458                 // Verify that FDPrivate has a LSubrs index
459
if(fonts[Font].PrivateSubrsOffset[FD]>=0)
460                 {
461                     //Scans the Charsting data storing the used Local and Global subroutines
462
// by the glyphs. Scans the Subrs recursivley.
463
BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]);
464                     // Builds the New Local Subrs index
465
NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD]);
466                 }
467             }
468         }
469         // If the font is not CID && the Private Subr exists then subset:
470
else if (fonts[Font].privateSubrs>=0)
471         {
472             // Build the subrs offsets;
473
fonts[Font].SubrsOffsets = getIndex(fonts[Font].privateSubrs);
474             //Scans the Charsting data storing the used Local and Global subroutines
475
// by the glyphs. Scans the Subrs recursivley.
476
BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID);
477         }
478         // For all fonts susbset the Global Subroutines
479
// Scan the Global Subr Hashmap recursivly on the Gsubrs
480
BuildGSubrsUsed(Font);
481         if (fonts[Font].privateSubrs>=0)
482             // Builds the New Local Subrs index
483
NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID);
484         //Builds the New Global Subrs index
485
NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed);
486     }
487
488     /**
489      * The function finds for the FD array processed the local subr offset and its
490      * offset array.
491      * @param Font the font
492      * @param FD The FDARRAY processed
493      */

494     protected void BuildFDSubrsOffsets(int Font,int FD)
495     {
496         // Initiate to -1 to indicate lsubr operator present
497
fonts[Font].PrivateSubrsOffset[FD] = -1;
498         // Goto begining of objects
499
seek(fonts[Font].fdprivateOffsets[FD]);
500         // While in the same object:
501
while (getPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD])
502         {
503             getDictItem();
504             // If the dictItem is the "Subrs" then find and store offset,
505
if (key=="Subrs")
506                 fonts[Font].PrivateSubrsOffset[FD] = ((Integer JavaDoc)args[0]).intValue()+fonts[Font].fdprivateOffsets[FD];
507         }
508         //Read the lsub index if the lsubr was found
509
if (fonts[Font].PrivateSubrsOffset[FD] >= 0)
510             fonts[Font].PrivateSubrsOffsetsArray[FD] = getIndex(fonts[Font].PrivateSubrsOffset[FD]);
511     }
512
513     /**
514      * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap.
515      * The HashMap (of the lsub only) is then scaned recursivly for Lsubr & Gsubrs
516      * calls.
517      * @param Font the font
518      * @param FD FD array processed. 0 indicates function was called by non CID font
519      * @param SubrOffset the offset to the subr index to calc the bias
520      * @param SubrsOffsets the offset array of the subr index
521      * @param hSubr HashMap of the subrs used
522      * @param lSubr ArrayList of the subrs used
523      */

524     protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,HashMap JavaDoc hSubr,ArrayList JavaDoc lSubr)
525     {
526
527         // Calc the Bias for the subr index
528
int LBias = CalcBias(SubrOffset,Font);
529         
530         // For each glyph used find its GID, start & end pos
531
for (int i=0;i<glyphsInList.size();i++)
532         {
533             int glyph = ((Integer JavaDoc)glyphsInList.get(i)).intValue();
534             int Start = fonts[Font].charstringsOffsets[glyph];
535             int End = fonts[Font].charstringsOffsets[glyph+1];
536             
537             // IF CID:
538
if (FD >= 0)
539             {
540                 EmptyStack();
541                 NumOfHints=0;
542                 // Using FDSELECT find the FD Array the glyph belongs to.
543
int GlyphFD = fonts[Font].FDSelect[glyph];
544                 // If the Glyph is part of the FD being processed
545
if (GlyphFD == FD)
546                     // Find the Subrs called by the glyph and insert to hash:
547
ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
548             }
549             else
550                 // If the font is not CID
551
//Find the Subrs called by the glyph and insert to hash:
552
ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
553         }
554         // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used
555
for (int i=0;i<lSubr.size();i++)
556         {
557             // Pop the subr value from the hash
558
int Subr = ((Integer JavaDoc)lSubr.get(i)).intValue();
559             // Ensure the Lsubr call is valid
560
if (Subr < SubrsOffsets.length-1 && Subr>=0)
561             {
562                 // Read and process the subr
563
int Start = SubrsOffsets[Subr];
564                 int End = SubrsOffsets[Subr+1];
565                 ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets);
566             }
567         }
568     }
569     
570     /**
571      * Function scans the Glsubr used ArrayList to find recursive calls
572      * to Gsubrs and adds to Hashmap & ArrayList
573      * @param Font the font
574      */

575     protected void BuildGSubrsUsed(int Font)
576     {
577         int LBias = 0;
578         int SizeOfNonCIDSubrsUsed = 0;
579         if (fonts[Font].privateSubrs>=0)
580         {
581             LBias = CalcBias(fonts[Font].privateSubrs,Font);
582             SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
583         }
584         
585         // For each global subr used
586
for (int i=0;i<lGSubrsUsed.size();i++)
587         {
588             //Pop the value + check valid
589
int Subr = ((Integer JavaDoc)lGSubrsUsed.get(i)).intValue();
590             if (Subr < gsubrOffsets.length-1 && Subr>=0)
591             {
592                 // Read the subr and process
593
int Start = gsubrOffsets[Subr];
594                 int End = gsubrOffsets[Subr+1];
595                 
596                 if (fonts[Font].isCID)
597                     ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null);
598                 else
599                 {
600                     ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets);
601                     if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.size())
602                     {
603                         for (int j=SizeOfNonCIDSubrsUsed;j<lSubrsUsedNonCID.size();j++)
604                         {
605                             //Pop the value + check valid
606
int LSubr = ((Integer JavaDoc)lSubrsUsedNonCID.get(j)).intValue();
607                             if (LSubr < fonts[Font].SubrsOffsets.length-1 && LSubr>=0)
608                             {
609                                 // Read the subr and process
610
int LStart = fonts[Font].SubrsOffsets[LSubr];
611                                 int LEnd = fonts[Font].SubrsOffsets[LSubr+1];
612                                 ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets);
613                             }
614                         }
615                         SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
616                     }
617                 }
618             }
619         }
620     }
621
622     /**
623      * The function reads a subrs (glyph info) between begin and end.
624      * Adds calls to a Lsubr to the hSubr and lSubrs.
625      * Adds calls to a Gsubr to the hGSubr and lGSubrs.
626      * @param begin the start point of the subr
627      * @param end the end point of the subr
628      * @param GBias the bias of the Global Subrs
629      * @param LBias the bias of the Local Subrs
630      * @param hSubr the HashMap for the lSubrs
631      * @param lSubr the ArrayList for the lSubrs
632      */

633     protected void ReadASubr(int begin,int end,int GBias,int LBias,HashMap JavaDoc hSubr,ArrayList JavaDoc lSubr,int[] LSubrsOffsets)
634     {
635         // Clear the stack for the subrs
636
EmptyStack();
637         NumOfHints = 0;
638         // Goto begining of the subr
639
seek(begin);
640         while (getPosition() < end)
641         {
642             // Read the next command
643
ReadCommand();
644             int pos = getPosition();
645             Object JavaDoc TopElement=null;
646             if (arg_count > 0)
647                 TopElement = args[arg_count-1];
648             int NumOfArgs = arg_count;
649             // Check the modification needed on the Argument Stack according to key;
650
HandelStack();
651             // a call to a Lsubr
652
if (key=="callsubr")
653             {
654                 // Verify that arguments are passed
655
if (NumOfArgs > 0)
656                 {
657                     // Calc the index of the Subrs
658
int Subr = ((Integer JavaDoc)TopElement).intValue() + LBias;
659                     // If the subr isn't in the HashMap -> Put in
660
if (!hSubr.containsKey(new Integer JavaDoc (Subr)))
661                     {
662                         hSubr.put(new Integer JavaDoc(Subr),null);
663                         lSubr.add(new Integer JavaDoc(Subr));
664                     }
665                     CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
666                     seek(pos);
667                 }
668             }
669             // a call to a Gsubr
670
else if (key=="callgsubr")
671             {
672                 // Verify that arguments are passed
673
if (NumOfArgs > 0)
674                 {
675                     // Calc the index of the Subrs
676
int Subr = ((Integer JavaDoc)TopElement).intValue() + GBias;
677                     // If the subr isn't in the HashMap -> Put in
678
if (!hGSubrsUsed.containsKey(new Integer JavaDoc (Subr)))
679                     {
680                         hGSubrsUsed.put(new Integer JavaDoc(Subr),null);
681                         lGSubrsUsed.add(new Integer JavaDoc(Subr));
682                     }
683                     CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
684                     seek(pos);
685                 }
686             }
687             // A call to "stem"
688
else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm")
689                 // Increment the NumOfHints by the number couples of of arguments
690
NumOfHints += NumOfArgs/2;
691             // A call to "mask"
692
else if (key == "hintmask" || key == "cntrmask")
693             {
694                 // Compute the size of the mask
695
int SizeOfMask = NumOfHints/8;
696                 if (NumOfHints%8 != 0 || SizeOfMask == 0)
697                     SizeOfMask++;
698                 // Continue the pointer in SizeOfMask steps
699
for (int i=0;i<SizeOfMask;i++)
700                     getCard8();
701             }
702         }
703     }
704
705     /**
706      * Function Checks how the current operator effects the run time stack after being run
707      * An operator may increase or decrease the stack size
708      */

709     protected void HandelStack()
710     {
711         // Findout what the operator does to the stack
712
int StackHandel = StackOpp();
713         if (StackHandel < 2)
714         {
715             // The operators that enlarge the stack by one
716
if (StackHandel==1)
717                 PushStack();
718             // The operators that pop the stack
719
else
720             {
721                 // Abs value for the for loop
722
StackHandel *= -1;
723                 for (int i=0;i<StackHandel;i++)
724                     PopStack();
725             }
726             
727         }
728         // All other flush the stack
729
else
730             EmptyStack();
731     }
732     
733     /**
734      * Function checks the key and return the change to the stack after the operator
735      * @return The change in the stack. 2-> flush the stack
736      */

737     protected int StackOpp()
738     {
739         if (key == "ifelse")
740             return -3;
741         if (key == "roll" || key == "put")
742             return -2;
743         if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" ||
744             key == "div" || key == "mul" || key == "drop" || key == "and" ||
745             key == "or" || key == "eq")
746             return -1;
747         if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" ||
748             key == "index" || key == "get" || key == "not" || key == "return")
749             return 0;
750         if (key == "random" || key == "dup")
751             return 1;
752         return 2;
753     }
754     
755     /**
756      * Empty the Type2 Stack
757      *
758      */

759     protected void EmptyStack()
760     {
761         // Null the arguments
762
for (int i=0; i<arg_count; i++) args[i]=null;
763         arg_count = 0;
764     }
765     
766     /**
767      * Pop one element from the stack
768      *
769      */

770     protected void PopStack()
771     {
772         if (arg_count>0)
773         {
774             args[arg_count-1]=null;
775             arg_count--;
776         }
777     }
778     
779     /**
780      * Add an item to the stack
781      *
782      */

783     protected void PushStack()
784     {
785         arg_count++;
786     }
787     
788     /**
789      * The function reads the next command after the file pointer is set
790      */

791     protected void ReadCommand()
792     {
793         key = null;
794         boolean gotKey = false;
795         // Until a key is found
796
while (!gotKey) {
797             // Read the first Char
798
char b0 = getCard8();
799             // decode according to the type1/type2 format
800
if (b0 == 28) // the two next bytes represent a short int;
801
{
802                 int first = getCard8();
803                 int second = getCard8();
804                 args[arg_count] = new Integer JavaDoc(first<<8 | second);
805                 arg_count++;
806                 continue;
807             }
808             if (b0 >= 32 && b0 <= 246) // The byte read is the byte;
809
{
810                 args[arg_count] = new Integer JavaDoc(b0 - 139);
811                 arg_count++;
812                 continue;
813             }
814             if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constetute a short int
815
{
816                 int w = getCard8();
817                 args[arg_count] = new Integer JavaDoc((b0-247)*256 + w + 108);
818                 arg_count++;
819                 continue;
820             }
821             if (b0 >= 251 && b0 <= 254)// Same as above except negative
822
{
823                 int w = getCard8();
824                 args[arg_count] = new Integer JavaDoc(-(b0-251)*256 - w - 108);
825                 arg_count++;
826                 continue;
827             }
828             if (b0 == 255)// The next for bytes represent a double.
829
{
830                 int first = getCard8();
831                 int second = getCard8();
832                 int third = getCard8();
833                 int fourth = getCard8();
834                 args[arg_count] = new Integer JavaDoc(first<<24 | second<<16 | third<<8 | fourth);
835                 arg_count++;
836                 continue;
837             }
838             if (b0<=31 && b0 != 28) // An operator was found.. Set Key.
839
{
840                 gotKey=true;
841                 // 12 is an escape command therefor the next byte is a part
842
// of this command
843
if (b0 == 12)
844                 {
845                     int b1 = getCard8();
846                     if (b1>SubrsEscapeFuncs.length-1)
847                         b1 = SubrsEscapeFuncs.length-1;
848                     key = SubrsEscapeFuncs[b1];
849                 }
850                 else
851                     key = SubrsFunctions[b0];
852                 continue;
853             }
854         }
855     }
856     
857     /**
858      * The function reads the subroutine and returns the number of the hint in it.
859      * If a call to another subroutine is found the function calls recursively.
860      * @param begin the start point of the subr
861      * @param end the end point of the subr
862      * @param LBias the bias of the Local Subrs
863      * @param GBias the bias of the Global Subrs
864      * @param LSubrsOffsets The Offsets array of the subroutines
865      * @return The number of hints in the subroutine read.
866      */

867     protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets)
868     {
869         // Goto begining of the subr
870
seek(begin);
871         while (getPosition() < end)
872         {
873             // Read the next command
874
ReadCommand();
875             int pos = getPosition();
876             Object JavaDoc TopElement = null;
877             if (arg_count>0)
878                 TopElement = args[arg_count-1];
879             int NumOfArgs = arg_count;
880             //Check the modification needed on the Argument Stack according to key;
881
HandelStack();
882             // a call to a Lsubr
883
if (key=="callsubr")
884             {
885                 if (NumOfArgs>0)
886                 {
887                     int Subr = ((Integer JavaDoc)TopElement).intValue() + LBias;
888                     CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
889                     seek(pos);
890                 }
891             }
892             // a call to a Gsubr
893
else if (key=="callgsubr")
894             {
895                 if (NumOfArgs>0)
896                 {
897                     int Subr = ((Integer JavaDoc)TopElement).intValue() + GBias;
898                     CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets);
899                     seek(pos);
900                 }
901             }
902             // A call to "stem"
903
else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm")
904                 // Increment the NumOfHints by the number couples of of arguments
905
NumOfHints += NumOfArgs/2;
906             // A call to "mask"
907
else if (key == "hintmask" || key == "cntrmask")
908             {
909                 // Compute the size of the mask
910
int SizeOfMask = NumOfHints/8;
911                 if (NumOfHints%8 != 0 || SizeOfMask == 0)
912                     SizeOfMask++;
913                 // Continue the pointer in SizeOfMask steps
914
for (int i=0;i<SizeOfMask;i++)
915                     getCard8();
916             }
917         }
918         return NumOfHints;
919     }
920
921
922     /**
923      * Function builds the new offset array, object array and assembles the index.
924      * used for creating the glyph and subrs subsetted index
925      * @param Offsets the offset array of the original index
926      * @param Used the hashmap of the used objects
927      * @return the new index subset version
928      * @throws IOException
929      */

930     protected byte[] BuildNewIndex(int[] Offsets,HashMap JavaDoc Used) throws IOException JavaDoc
931     {
932         int Offset=0;
933         int[] NewOffsets = new int[Offsets.length];
934         // Build the Offsets Array for the Subset
935
for (int i=0;i<Offsets.length;++i)
936         {
937             NewOffsets[i] = Offset;
938             // If the object in the offset is also present in the used
939
// HashMap then increment the offset var by its size
940
if (Used.containsKey(new Integer JavaDoc(i)))
941                 Offset += Offsets[i+1] - Offsets[i];
942                 // Else the same offset is kept in i+1.
943
}
944         // Offset var determines the size of the object array
945
byte[] NewObjects = new byte[Offset];
946         // Build the new Object array
947
for (int i=0;i<Offsets.length-1;++i)
948         {
949             int start = NewOffsets[i];
950             int end = NewOffsets[i+1];
951             // If start != End then the Object is used
952
// So, we will copy the object data from the font file
953
if (start != end)
954             {
955                 // All offsets are Global Offsets relative to the begining of the font file.
956
// Jump the file pointer to the start address to read from.
957
buf.seek(Offsets[i]);
958                 // Read from the buffer and write into the array at start.
959
buf.readFully(NewObjects, start, end-start);
960             }
961         }
962         // Use AssembleIndex to build the index from the offset & object arrays
963
return AssembleIndex(NewOffsets,NewObjects);
964     }
965
966     /**
967      * Function creates the new index, inserting the count,offsetsize,offset array
968      * and object array.
969      * @param NewOffsets the subsetted offset array
970      * @param NewObjects the subsetted object array
971      * @return the new index created
972      */

973     protected byte[] AssembleIndex(int[] NewOffsets,byte[] NewObjects)
974     {
975         // Calc the index' count field
976
char Count = (char)(NewOffsets.length-1);
977         // Calc the size of the object array
978
int Size = NewOffsets[NewOffsets.length-1];
979         // Calc the Offsize
980
byte Offsize;
981         if (Size <= 0xff) Offsize = 1;
982         else if (Size <= 0xffff) Offsize = 2;
983         else if (Size <= 0xffffff) Offsize = 3;
984         else Offsize = 4;
985         // The byte array for the new index. The size is calc by
986
// Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array
987
byte[] NewIndex = new byte[2+1+Offsize*(Count+1)+NewObjects.length];
988         // The counter for writing
989
int Place = 0;
990         // Write the count field
991
NewIndex[Place++] = (byte) ((Count >>> 8) & 0xff);
992         NewIndex[Place++] = (byte) ((Count >>> 0) & 0xff);
993         // Write the offsize field
994
NewIndex[Place++] = Offsize;
995         // Write the offset array according to the offsize
996
for (int i=0;i<NewOffsets.length;i++)
997         {
998             // The value to be written
999
int Num = NewOffsets[i]-NewOffsets[0]+1;
1000            // Write in bytes according to the offsize
1001
switch (Offsize) {
1002                case 4:
1003                    NewIndex[Place++] = (byte) ((Num >>> 24) & 0xff);
1004                case 3:
1005                    NewIndex[Place++] = (byte) ((Num >>> 16) & 0xff);
1006                case 2:
1007                    NewIndex[Place++] = (byte) ((Num >>> 8) & 0xff);
1008                case 1:
1009                    NewIndex[Place++] = (byte) ((Num >>> 0) & 0xff);
1010            }
1011        }
1012        // Write the new object array one by one
1013
for (int i=0;i<NewObjects.length;i++)
1014        {
1015            NewIndex[Place++] = NewObjects[i];
1016        }
1017        // Return the new index
1018
return NewIndex;
1019    }
1020    
1021    /**
1022     * The function builds the new output stream according to the subset process
1023     * @param Font the font
1024     * @return the subseted font stream
1025     */

1026    protected byte[] BuildNewFile(int Font)
1027    {
1028        // Prepare linked list for new font components
1029
OutputList = new LinkedList JavaDoc();
1030
1031        // copy the header of the font
1032
CopyHeader();
1033                
1034        // create a name index
1035
BuildIndexHeader(1,1,1);
1036        OutputList.addLast(new UInt8Item((char)( 1+fonts[Font].name.length() )));
1037        OutputList.addLast(new StringItem(fonts[Font].name));
1038        
1039        // create the topdict Index
1040
BuildIndexHeader(1,2,1);
1041        OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
1042        OutputList.addLast(topdictIndex1Ref);
1043        IndexBaseItem topdictBase = new IndexBaseItem();
1044        OutputList.addLast(topdictBase);
1045                
1046        // Initialise the Dict Items for later use
1047
OffsetItem charsetRef = new DictOffsetItem();
1048        OffsetItem charstringsRef = new DictOffsetItem();
1049        OffsetItem fdarrayRef = new DictOffsetItem();
1050        OffsetItem fdselectRef = new DictOffsetItem();
1051        OffsetItem privateRef = new DictOffsetItem();
1052        
1053        // If the font is not CID create the following keys
1054
if ( !fonts[Font].isCID ) {
1055            // create a ROS key
1056
OutputList.addLast(new DictNumberItem(fonts[Font].nstrings));
1057            OutputList.addLast(new DictNumberItem(fonts[Font].nstrings+1));
1058            OutputList.addLast(new DictNumberItem(0));
1059            OutputList.addLast(new UInt8Item((char)12));
1060            OutputList.addLast(new UInt8Item((char)30));
1061            // create a CIDCount key
1062
OutputList.addLast(new DictNumberItem(fonts[Font].nglyphs));
1063            OutputList.addLast(new UInt8Item((char)12));
1064            OutputList.addLast(new UInt8Item((char)34));
1065            // Sivan's comments
1066
// What about UIDBase (12,35)? Don't know what is it.
1067
// I don't think we need FontName; the font I looked at didn't have it.
1068
}
1069        // Go to the TopDict of the font being processed
1070
seek(topdictOffsets[Font]);
1071        // Run untill the end of the TopDict
1072
while (getPosition() < topdictOffsets[Font+1]) {
1073            int p1 = getPosition();
1074            getDictItem();
1075            int p2 = getPosition();
1076            // The encoding key is disregarded since CID has no encoding
1077
if (key=="Encoding"
1078            // These keys will be added manualy by the process.
1079
|| key=="Private"
1080            || key=="FDSelect"
1081            || key=="FDArray"
1082            || key=="charset"
1083            || key=="CharStrings"
1084            ) {
1085            }else {
1086            //OtherWise copy key "as is" to the output list
1087
OutputList.add(new RangeItem(buf,p1,p2-p1));
1088            }
1089        }
1090        // Create the FDArray, FDSelect, Charset and CharStrings Keys
1091
CreateKeys(fdarrayRef,fdselectRef,charsetRef,charstringsRef);
1092        
1093        // Mark the end of the top dict area
1094
OutputList.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase));
1095        
1096        // Copy the string index
1097

1098        if (fonts[Font].isCID)
1099            OutputList.addLast(getEntireIndexRange(stringIndexOffset));
1100        // If the font is not CID we need to append new strings.
1101
// We need 3 more strings: Registry, Ordering, and a FontName for one FD.
1102
// The total length is at most "Adobe"+"Identity"+63 = 76
1103
else
1104            CreateNewStringIndex(Font);
1105        
1106        // copy the new subsetted global subroutine index
1107
OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewGSubrsIndex),0,NewGSubrsIndex.length));
1108        
1109        // deal with fdarray, fdselect, and the font descriptors
1110
// If the font is CID:
1111
if (fonts[Font].isCID) {
1112            // copy the FDArray, FDSelect, charset
1113

1114            // Copy FDSelect
1115
// Mark the beginning
1116
OutputList.addLast(new MarkerItem(fdselectRef));
1117            // If an FDSelect exists copy it
1118
if (fonts[Font].fdselectOffset>=0)
1119                OutputList.addLast(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength));
1120            // Else create a new one
1121
else
1122                CreateFDSelect(fdselectRef,fonts[Font].nglyphs);
1123                           
1124            // Copy the Charset
1125
// Mark the beginning and copy entirly
1126
OutputList.addLast(new MarkerItem(charsetRef));
1127            OutputList.addLast(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength));
1128            
1129            // Copy the FDArray
1130
// If an FDArray exists
1131
if (fonts[Font].fdarrayOffset>=0)
1132            {
1133                // Mark the beginning
1134
OutputList.addLast(new MarkerItem(fdarrayRef));
1135                // Build a new FDArray with its private dicts and their LSubrs
1136
Reconstruct(Font);
1137            }
1138            else
1139                // Else create a new one
1140
CreateFDArray(fdarrayRef,privateRef,Font);
1141           
1142        }
1143        // If the font is not CID
1144
else
1145        {
1146            // create FDSelect
1147
CreateFDSelect(fdselectRef,fonts[Font].nglyphs);
1148            // recreate a new charset
1149
CreateCharset(charsetRef,fonts[Font].nglyphs);
1150            // create a font dict index (fdarray)
1151
CreateFDArray(fdarrayRef,privateRef,Font);
1152        }
1153        
1154        // if a private dict exists insert its subsetted version
1155
if (fonts[Font].privateOffset>=0)
1156        {
1157            // Mark the beginning of the private dict
1158
IndexBaseItem PrivateBase = new IndexBaseItem();
1159            OutputList.addLast(PrivateBase);
1160            OutputList.addLast(new MarkerItem(privateRef));
1161
1162            OffsetItem Subr = new DictOffsetItem();
1163            // Build and copy the new private dict
1164
CreateNonCIDPrivate(Font,Subr);
1165            // Copy the new LSubrs index
1166
CreateNonCIDSubrs(Font,PrivateBase,Subr);
1167        }
1168        
1169        // copy the charstring index
1170
OutputList.addLast(new MarkerItem(charstringsRef));
1171
1172        // Add the subsetted charstring
1173
OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.length));
1174        
1175        // now create the new CFF font
1176
int[] currentOffset = new int[1];
1177        currentOffset[0] = 0;
1178        // Count and save the offset for each item
1179
Iterator JavaDoc listIter = OutputList.iterator();
1180        while ( listIter.hasNext() ) {
1181            Item item = (Item) listIter.next();
1182            item.increment(currentOffset);
1183        }
1184        // Compute the Xref for each of the offset items
1185
listIter = OutputList.iterator();
1186        while ( listIter.hasNext() ) {
1187            Item item = (Item) listIter.next();
1188            item.xref();
1189        }
1190        
1191        int size = currentOffset[0];
1192        byte[] b = new byte[size];
1193        
1194        // Emit all the items into the new byte array
1195
listIter = OutputList.iterator();
1196        while ( listIter.hasNext() ) {
1197            Item item = (Item) listIter.next();
1198            item.emit(b);
1199        }
1200        // Return the new stream
1201
return b;
1202    }
1203
1204    /**
1205     * Function Copies the header from the original fileto the output list
1206     */

1207    protected void CopyHeader()
1208    {
1209        seek(0);
1210        int major = getCard8();
1211        int minor = getCard8();
1212        int hdrSize = getCard8();
1213        int offSize = getCard8();
1214        nextIndexOffset = hdrSize;
1215        OutputList.addLast(new RangeItem(buf,0,hdrSize));
1216    }
1217
1218    /**
1219     * Function Build the header of an index
1220     * @param Count the count field of the index
1221     * @param Offsize the offsize field of the index
1222     * @param First the first offset of the index
1223     */

1224    protected void BuildIndexHeader(int Count,int Offsize,int First)
1225    {
1226        // Add the count field
1227
OutputList.addLast(new UInt16Item((char)Count)); // count
1228
// Add the offsize field
1229
OutputList.addLast(new UInt8Item((char)Offsize)); // offSize
1230
// Add the first offset according to the offsize
1231
switch(Offsize){
1232            case 1:
1233                OutputList.addLast(new UInt8Item((char)First)); // first offset
1234
break;
1235            case 2:
1236                OutputList.addLast(new UInt16Item((char)First)); // first offset
1237
break;
1238            case 3:
1239                OutputList.addLast(new UInt24Item((char)First)); // first offset
1240
break;
1241            case 4:
1242                OutputList.addLast(new UInt32Item((char)First)); // first offset
1243
break;
1244            default:
1245                break;
1246        }
1247    }
1248    
1249    /**
1250     * Function adds the keys into the TopDict
1251     * @param fdarrayRef OffsetItem for the FDArray
1252     * @param fdselectRef OffsetItem for the FDSelect
1253     * @param charsetRef OffsetItem for the CharSet
1254     * @param charstringsRef OffsetItem for the CharString
1255     */

1256    protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef)
1257    {
1258        // create an FDArray key
1259
OutputList.addLast(fdarrayRef);
1260        OutputList.addLast(new UInt8Item((char)12));
1261        OutputList.addLast(new UInt8Item((char)36));
1262        // create an FDSelect key
1263
OutputList.addLast(fdselectRef);
1264        OutputList.addLast(new UInt8Item((char)12));
1265        OutputList.addLast(new UInt8Item((char)37));
1266        // create an charset key
1267
OutputList.addLast(charsetRef);
1268        OutputList.addLast(new UInt8Item((char)15));
1269        // create a CharStrings key
1270
OutputList.addLast(charstringsRef);
1271        OutputList.addLast(new UInt8Item((char)17));
1272    }
1273    
1274    /**
1275     * Function takes the original string item and adds the new strings
1276     * to accomodate the CID rules
1277     * @param Font the font
1278     */

1279    protected void CreateNewStringIndex(int Font)
1280    {
1281        String JavaDoc fdFontName = fonts[Font].name+"-OneRange";
1282        if (fdFontName.length() > 127)
1283            fdFontName = fdFontName.substring(0,127);
1284        String JavaDoc extraStrings = "Adobe"+"Identity"+fdFontName;
1285        
1286        int origStringsLen = stringOffsets[stringOffsets.length-1]
1287        - stringOffsets[0];
1288        int stringsBaseOffset = stringOffsets[0]-1;
1289        
1290        byte stringsIndexOffSize;
1291        if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1;
1292        else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2;
1293        else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3;
1294        else stringsIndexOffSize = 4;
1295        
1296        OutputList.addLast(new UInt16Item((char)((stringOffsets.length-1)+3))); // count
1297
OutputList.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize
1298
for (int i=0; i<stringOffsets.length; i++)
1299            OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
1300            stringOffsets[i]-stringsBaseOffset));
1301        int currentStringsOffset = stringOffsets[stringOffsets.length-1]
1302        - stringsBaseOffset;
1303        //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1304
currentStringsOffset += ("Adobe").length();
1305        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1306        currentStringsOffset += ("Identity").length();
1307        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1308        currentStringsOffset += fdFontName.length();
1309        OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1310        
1311        OutputList.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen));
1312        OutputList.addLast(new StringItem(extraStrings));
1313    }
1314     
1315    /**
1316     * Function creates new FDSelect for non-CID fonts.
1317     * The FDSelect built uses a single range for all glyphs
1318     * @param fdselectRef OffsetItem for the FDSelect
1319     * @param nglyphs the number of glyphs in the font
1320     */

1321    protected void CreateFDSelect(OffsetItem fdselectRef,int nglyphs)
1322    {
1323        OutputList.addLast(new MarkerItem(fdselectRef));
1324        OutputList.addLast(new UInt8Item((char)3)); // format identifier
1325
OutputList.addLast(new UInt16Item((char)1)); // nRanges
1326

1327        OutputList.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph
1328
OutputList.addLast(new UInt8Item((char)0)); // Range[0].fd
1329

1330        OutputList.addLast(new UInt16Item((char)nglyphs)); // sentinel
1331
}
1332
1333    /**
1334     * Function creates new CharSet for non-CID fonts.
1335     * The CharSet built uses a single range for all glyphs
1336     * @param charsetRef OffsetItem for the CharSet
1337     * @param nglyphs the number of glyphs in the font
1338     */

1339    protected void CreateCharset(OffsetItem charsetRef,int nglyphs)
1340    {
1341        OutputList.addLast(new MarkerItem(charsetRef));
1342        OutputList.addLast(new UInt8Item((char)2)); // format identifier
1343
OutputList.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef)
1344
OutputList.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft
1345
}
1346    
1347    /**
1348     * Function creates new FDArray for non-CID fonts.
1349     * The FDArray built has only the "Private" operator that points to the font's
1350     * original private dict
1351     * @param fdarrayRef OffsetItem for the FDArray
1352     * @param privateRef OffsetItem for the Private Dict
1353     * @param Font the font
1354     */

1355    protected void CreateFDArray(OffsetItem fdarrayRef,OffsetItem privateRef,int Font)
1356    {
1357        OutputList.addLast(new MarkerItem(fdarrayRef));
1358        // Build the header (count=offsize=first=1)
1359
BuildIndexHeader(1,1,1);
1360        
1361        // Mark
1362
OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
1363        OutputList.addLast(privateIndex1Ref);
1364        IndexBaseItem privateBase = new IndexBaseItem();
1365        // Insert the private operands and operator
1366
OutputList.addLast(privateBase);
1367        // Calc the new size of the private after subsetting
1368
// Origianl size
1369
int NewSize = fonts[Font].privateLength;
1370        // Calc the original size of the Subr offset in the private
1371
int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].privateOffset,fonts[Font].privateLength);
1372        // Increase the ptivate's size
1373
if (OrgSubrsOffsetSize != 0)
1374            NewSize += 5-OrgSubrsOffsetSize;
1375        OutputList.addLast(new DictNumberItem(NewSize));
1376        OutputList.addLast(privateRef);
1377        OutputList.addLast(new UInt8Item((char)18)); // Private
1378

1379        OutputList.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase));
1380    }
1381    
1382    /**
1383     * Function reconstructs the FDArray, PrivateDict and LSubr for CID fonts
1384     * @param Font the font
1385     */

1386    void Reconstruct(int Font)
1387    {
1388        // Init for later use
1389
OffsetItem[] fdPrivate = new DictOffsetItem[fonts[Font].FDArrayOffsets.length-1];
1390        IndexBaseItem[] fdPrivateBase = new IndexBaseItem[fonts[Font].fdprivateOffsets.length];
1391        OffsetItem[] fdSubrs = new DictOffsetItem[fonts[Font].fdprivateOffsets.length];
1392        // Reconstruct each type
1393
ReconstructFDArray(Font,fdPrivate);
1394        ReconstructPrivateDict(Font,fdPrivate,fdPrivateBase,fdSubrs);
1395        ReconstructPrivateSubrs(Font,fdPrivateBase,fdSubrs);
1396    }
1397
1398    /**
1399     * Function subsets the FDArray and builds the new one with new offsets
1400     * @param Font The font
1401     * @param fdPrivate OffsetItem Array (one for each FDArray)
1402     */

1403    void ReconstructFDArray(int Font,OffsetItem[] fdPrivate)
1404    {
1405        // Build the header of the index
1406
BuildIndexHeader(fonts[Font].FDArrayCount,fonts[Font].FDArrayOffsize,1);
1407
1408        // For each offset create an Offset Item
1409
OffsetItem[] fdOffsets = new IndexOffsetItem[fonts[Font].FDArrayOffsets.length-1];
1410        for (int i=0;i<fonts[Font].FDArrayOffsets.length-1;i++)
1411        {
1412            fdOffsets[i] = new IndexOffsetItem(fonts[Font].FDArrayOffsize);
1413            OutputList.addLast(fdOffsets[i]);
1414        }
1415        
1416        // Declare beginning of the object array
1417
IndexBaseItem fdArrayBase = new IndexBaseItem();
1418        OutputList.addLast(fdArrayBase);
1419        
1420        // For each object check if that FD is used.
1421
// if is used build a new one by changing the private object
1422
// Else do nothing
1423
// At the end of each object mark its ending (Even if wasn't written)
1424
for (int k=0; k<fonts[Font].FDArrayOffsets.length-1; k++) {
1425            if (FDArrayUsed.containsKey(new Integer JavaDoc (k)))
1426            {
1427                // Goto begining of objects
1428
seek(fonts[Font].FDArrayOffsets[k]);
1429                while (getPosition() < fonts[Font].FDArrayOffsets[k+1])
1430                {
1431                    int p1 = getPosition();
1432                    getDictItem();
1433                    int p2 = getPosition();
1434                    // If the dictItem is the "Private" then compute and copy length,
1435
// use marker for offset and write operator number
1436
if (key=="Private") {
1437                        // Save the original length of the private dict
1438
int NewSize = ((Integer JavaDoc)args[0]).intValue();
1439                        // Save the size of the offset to the subrs in that private
1440
int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].fdprivateOffsets[k],fonts[Font].fdprivateLengths[k]);
1441                        // Increase the private's length accordingly
1442
if (OrgSubrsOffsetSize != 0)
1443                            NewSize += 5-OrgSubrsOffsetSize;
1444                        // Insert the new size, OffsetItem and operator key number
1445
OutputList.addLast(new DictNumberItem(NewSize));
1446                        fdPrivate[k] = new DictOffsetItem();
1447                        OutputList.addLast(fdPrivate[k]);
1448                        OutputList.addLast(new UInt8Item((char)18)); // Private
1449
// Go back to place
1450
seek(p2);
1451                    }
1452                    // Else copy the entire range
1453
else // other than private
1454
OutputList.addLast(new RangeItem(buf,p1,p2-p1));
1455                }
1456            }
1457            // Mark the ending of the object (even if wasn't written)
1458
OutputList.addLast(new IndexMarkerItem(fdOffsets[k],fdArrayBase));
1459        }
1460    }
1461    /**
1462     * Function Adds the new private dicts (only for the FDs used) to the list
1463     * @param Font the font
1464     * @param fdPrivate OffsetItem array one element for each private
1465     * @param fdPrivateBase IndexBaseItem array one element for each private
1466     * @param fdSubrs OffsetItem array one element for each private
1467     */

1468    void ReconstructPrivateDict(int Font,OffsetItem[] fdPrivate,IndexBaseItem[] fdPrivateBase,
1469            OffsetItem[] fdSubrs)
1470    {
1471        
1472        // For each fdarray private dict check if that FD is used.
1473
// if is used build a new one by changing the subrs offset
1474
// Else do nothing
1475
for (int i=0;i<fonts[Font].fdprivateOffsets.length;i++)
1476        {
1477            if (FDArrayUsed.containsKey(new Integer JavaDoc (i)))
1478            {
1479                // Mark beginning
1480
OutputList.addLast(new MarkerItem(fdPrivate[i]));
1481                fdPrivateBase[i] = new IndexBaseItem();
1482                OutputList.addLast(fdPrivateBase[i]);
1483                // Goto begining of objects
1484
seek(fonts[Font].fdprivateOffsets[i]);
1485                while (getPosition() < fonts[Font].fdprivateOffsets[i]+fonts[Font].fdprivateLengths[i])
1486                {
1487                    int p1 = getPosition();
1488                    getDictItem();
1489                    int p2 = getPosition();
1490                    // If the dictItem is the "Subrs" then,
1491
// use marker for offset and write operator number
1492
if (key=="Subrs") {
1493                        fdSubrs[i] = new DictOffsetItem();
1494                        OutputList.addLast(fdSubrs[i]);
1495                        OutputList.addLast(new UInt8Item((char)19)); // Subrs
1496
}
1497                    // Else copy the entire range
1498
else
1499                        OutputList.addLast(new RangeItem(buf,p1,p2-p1));
1500                }
1501            }
1502        }
1503    }
1504    
1505    /**
1506     * Function Adds the new LSubrs dicts (only for the FDs used) to the list
1507     * @param Font The index of the font
1508     * @param fdPrivateBase The IndexBaseItem array for the linked list
1509     * @param fdSubrs OffsetItem array for the linked list
1510     */

1511    
1512    void ReconstructPrivateSubrs(int Font,IndexBaseItem[] fdPrivateBase,
1513            OffsetItem[] fdSubrs)
1514    {
1515        // For each private dict
1516
for (int i=0;i<fonts[Font].fdprivateLengths.length;i++)
1517        {
1518            // If that private dict's Subrs are used insert the new LSubrs
1519
// computed earlier
1520
if (fdSubrs[i]!= null && fonts[Font].PrivateSubrsOffset[i] >= 0)
1521            {
1522                OutputList.addLast(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i]));
1523                OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].length));
1524            }
1525        }
1526    }
1527
1528    /**
1529     * Calculates how many byte it took to write the offset for the subrs in a specific
1530     * private dict.
1531     * @param Offset The Offset for the private dict
1532     * @param Size The size of the private dict
1533     * @return The size of the offset of the subrs in the private dict
1534     */

1535    int CalcSubrOffsetSize(int Offset,int Size)
1536    {
1537        // Set the size to 0
1538
int OffsetSize = 0;
1539        // Go to the beginning of the private dict
1540
seek(Offset);
1541        // Go until the end of the private dict
1542
while (getPosition() < Offset+Size)
1543        {
1544            int p1 = getPosition();
1545            getDictItem();
1546            int p2 = getPosition();
1547            // When reached to the subrs offset
1548
if (key=="Subrs") {
1549                // The Offsize (minus the subrs key)
1550
OffsetSize = p2-p1-1;
1551            }
1552            // All other keys are ignored
1553
}
1554        // return the size
1555
return OffsetSize;
1556    }
1557    
1558    /**
1559     * Function computes the size of an index
1560     * @param indexOffset The offset for the computed index
1561     * @return The size of the index
1562     */

1563    protected int countEntireIndexRange(int indexOffset)
1564    {
1565        // Go to the beginning of the index
1566
seek(indexOffset);
1567        // Read the count field
1568
int count = getCard16();
1569        // If count==0 -> size=2
1570
if (count==0)
1571            return 2;
1572        else
1573        {
1574            // Read the offsize field
1575
int indexOffSize = getCard8();
1576            // Go to the last element of the offset array
1577
seek(indexOffset+2+1+count*indexOffSize);
1578            // The size of the object array is the value of the last element-1
1579
int size = getOffset(indexOffSize)-1;
1580            // Return the size of the entire index
1581
return 2+1+(count+1)*indexOffSize+size;
1582        }
1583    }
1584    
1585    /**
1586     * The function creates a private dict for a font that was not CID
1587     * All the keys are copied as is except for the subrs key
1588     * @param Font the font
1589     * @param Subr The OffsetItem for the subrs of the private
1590     */

1591    void CreateNonCIDPrivate(int Font,OffsetItem Subr)
1592    {
1593        // Go to the beginning of the private dict and read untill the end
1594
seek(fonts[Font].privateOffset);
1595        while (getPosition() < fonts[Font].privateOffset+fonts[Font].privateLength)
1596        {
1597            int p1 = getPosition();
1598            getDictItem();
1599            int p2 = getPosition();
1600            // If the dictItem is the "Subrs" then,
1601
// use marker for offset and write operator number
1602
if (key=="Subrs") {
1603                OutputList.addLast(Subr);
1604                OutputList.addLast(new UInt8Item((char)19)); // Subrs
1605
}
1606            // Else copy the entire range
1607
else
1608                OutputList.addLast(new RangeItem(buf,p1,p2-p1));
1609        }
1610    }
1611    
1612    /**
1613     * the function marks the beginning of the subrs index and adds the subsetted subrs
1614     * index to the output list.
1615     * @param Font the font
1616     * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs
1617     * @param Subrs OffsetItem for the subrs
1618     */

1619    void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs)
1620    {
1621        // Mark the beginning of the Subrs index
1622
OutputList.addLast(new SubrMarkerItem(Subrs,PrivateBase));
1623        // Put the subsetted new subrs index
1624
OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.length));
1625    }
1626}
Popular Tags