001/* 002 * $Id: CFFFontSubset.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.io.IOException; 047import java.util.ArrayList; 048import java.util.HashMap; 049import java.util.HashSet; 050import java.util.Iterator; 051import java.util.LinkedList; 052 053/** 054 * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts. 055 * The Charstring is subsetted for both types. For CID fonts only the FDArray which are used are embedded. 056 * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2 057 * formatting although only tested on Type2 Format. 058 * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted. 059 * A font which was not of CID type is transformed into CID as a part of the subset process. 060 * The CID synthetic creation was written by Sivan Toledo (sivan@math.tau.ac.il) 061 * @author Oren Manor (manorore@post.tau.ac.il) and Ygal Blum (blumygal@post.tau.ac.il) 062 */ 063public class CFFFontSubset extends CFFFont { 064 065 /** 066 * The Strings in this array represent Type1/Type2 operator names 067 */ 068 static final String SubrsFunctions[] = { 069 "RESERVED_0","hstem","RESERVED_2","vstem","vmoveto","rlineto","hlineto","vlineto", 070 "rrcurveto","RESERVED_9","callsubr","return","escape","RESERVED_13", 071 "endchar","RESERVED_15","RESERVED_16","RESERVED_17","hstemhm","hintmask", 072 "cntrmask","rmoveto","hmoveto","vstemhm","rcurveline","rlinecurve","vvcurveto", 073 "hhcurveto","shortint","callgsubr","vhcurveto","hvcurveto" 074 }; 075 /** 076 * The Strings in this array represent Type1/Type2 escape operator names 077 */ 078 static final String SubrsEscapeFuncs[] = { 079 "RESERVED_0","RESERVED_1","RESERVED_2","and","or","not","RESERVED_6", 080 "RESERVED_7","RESERVED_8","abs","add","sub","div","RESERVED_13","neg", 081 "eq","RESERVED_16","RESERVED_17","drop","RESERVED_19","put","get","ifelse", 082 "random","mul","RESERVED_25","sqrt","dup","exch","index","roll","RESERVED_31", 083 "RESERVED_32","RESERVED_33","hflex","flex","hflex1","flex1","RESERVED_REST" 084 }; 085 086 /** 087 * Operator codes for unused CharStrings and unused local and global Subrs 088 */ 089 static final byte ENDCHAR_OP = 14; 090 static final byte RETURN_OP = 11; 091 092 /** 093 * A HashMap containing the glyphs used in the text after being converted 094 * to glyph number by the CMap 095 */ 096 HashMap<Integer, int[]> GlyphsUsed; 097 /** 098 * The GlyphsUsed keys as an ArrayList 099 */ 100 ArrayList<Integer> glyphsInList; 101 /** 102 * A HashSet for keeping the FDArrays being used by the font 103 */ 104 HashSet<Integer> FDArrayUsed = new HashSet<Integer>(); 105 /** 106 * A HashMaps array for keeping the subroutines used in each FontDict 107 */ 108 HashMap<Integer, int[]>[] hSubrsUsed; 109 /** 110 * The SubroutinesUsed HashMaps as ArrayLists 111 */ 112 ArrayList<Integer>[] lSubrsUsed; 113 /** 114 * A HashMap for keeping the Global subroutines used in the font 115 */ 116 HashMap<Integer, int[]> hGSubrsUsed = new HashMap<Integer, int[]>(); 117 /** 118 * The Global SubroutinesUsed HashMaps as ArrayLists 119 */ 120 ArrayList<Integer> lGSubrsUsed = new ArrayList<Integer>(); 121 /** 122 * A HashMap for keeping the subroutines used in a non-cid font 123 */ 124 HashMap<Integer, int[]> hSubrsUsedNonCID = new HashMap<Integer, int[]>(); 125 /** 126 * The SubroutinesUsed HashMap as ArrayList 127 */ 128 ArrayList<Integer> lSubrsUsedNonCID = new ArrayList<Integer>(); 129 /** 130 * An array of the new Indexes for the local Subr. One index for each FontDict 131 */ 132 byte[][] NewLSubrsIndex; 133 /** 134 * The new subroutines index for a non-cid font 135 */ 136 byte[] NewSubrsIndexNonCID; 137 /** 138 * The new global subroutines index of the font 139 */ 140 byte[] NewGSubrsIndex; 141 /** 142 * The new CharString of the font 143 */ 144 byte[] NewCharStringsIndex; 145 146 /** 147 * The bias for the global subroutines 148 */ 149 int GBias = 0; 150 151 /** 152 * The linked list for generating the new font stream 153 */ 154 LinkedList<Item> OutputList; 155 156 /** 157 * Number of arguments to the stem operators in a subroutine calculated recursively 158 */ 159 int NumOfHints=0; 160 161 162 /** 163 * C'tor for CFFFontSubset 164 * @param rf - The font file 165 * @param GlyphsUsed - a HashMap that contains the glyph used in the subset 166 */ 167 public CFFFontSubset(RandomAccessFileOrArray rf,HashMap<Integer, int[]> GlyphsUsed){ 168 // Use CFFFont c'tor in order to parse the font file. 169 super(rf); 170 this.GlyphsUsed = GlyphsUsed; 171 //Put the glyphs into a list 172 glyphsInList = new ArrayList<Integer>(GlyphsUsed.keySet()); 173 174 175 for (int i=0;i<fonts.length;++i) 176 { 177 // Read the number of glyphs in the font 178 seek(fonts[i].charstringsOffset); 179 fonts[i].nglyphs = getCard16(); 180 181 // Jump to the count field of the String Index 182 seek(stringIndexOffset); 183 fonts[i].nstrings = getCard16()+standardStrings.length; 184 185 // For each font save the offset array of the charstring 186 fonts[i].charstringsOffsets = getIndex(fonts[i].charstringsOffset); 187 188 // Process the FDSelect if exist 189 if (fonts[i].fdselectOffset>=0) 190 { 191 // Process the FDSelect 192 readFDSelect(i); 193 // Build the FDArrayUsed hashmap 194 BuildFDArrayUsed(i); 195 } 196 if (fonts[i].isCID) 197 // Build the FD Array used Hash Map 198 ReadFDArray(i); 199 // compute the charset length 200 fonts[i].CharsetLength = CountCharset(fonts[i].charsetOffset,fonts[i].nglyphs); 201 } 202 } 203 204 /** 205 * Calculates the length of the charset according to its format 206 * @param Offset The Charset Offset 207 * @param NumofGlyphs Number of glyphs in the font 208 * @return the length of the Charset 209 */ 210 int CountCharset(int Offset,int NumofGlyphs){ 211 int format; 212 int Length=0; 213 seek(Offset); 214 // Read the format 215 format = getCard8(); 216 // Calc according to format 217 switch (format){ 218 case 0: 219 Length = 1+2*NumofGlyphs; 220 break; 221 case 1: 222 Length = 1+3*CountRange(NumofGlyphs,1); 223 break; 224 case 2: 225 Length = 1+4*CountRange(NumofGlyphs,2); 226 break; 227 default: 228 break; 229 } 230 return Length; 231 } 232 233 /** 234 * Function calculates the number of ranges in the Charset 235 * @param NumofGlyphs The number of glyphs in the font 236 * @param Type The format of the Charset 237 * @return The number of ranges in the Charset data structure 238 */ 239 int CountRange(int NumofGlyphs,int Type){ 240 int num=0; 241 char Sid; 242 int i=1,nLeft; 243 while (i<NumofGlyphs){ 244 num++; 245 Sid = getCard16(); 246 if (Type==1) 247 nLeft = getCard8(); 248 else 249 nLeft = getCard16(); 250 i += nLeft+1; 251 } 252 return num; 253 } 254 255 256 /** 257 * Read the FDSelect of the font and compute the array and its length 258 * @param Font The index of the font being processed 259 */ 260 protected void readFDSelect(int Font) 261 { 262 // Restore the number of glyphs 263 int NumOfGlyphs = fonts[Font].nglyphs; 264 int[] FDSelect = new int[NumOfGlyphs]; 265 // Go to the beginning of the FDSelect 266 seek(fonts[Font].fdselectOffset); 267 // Read the FDSelect's format 268 fonts[Font].FDSelectFormat = getCard8(); 269 270 switch(fonts[Font].FDSelectFormat){ 271 // Format==0 means each glyph has an entry that indicated 272 // its FD. 273 case 0: 274 for (int i=0;i<NumOfGlyphs;i++) 275 { 276 FDSelect[i] = getCard8(); 277 } 278 // The FDSelect's Length is one for each glyph + the format 279 // for later use 280 fonts[Font].FDSelectLength = fonts[Font].nglyphs+1; 281 break; 282 case 3: 283 // Format==3 means the ranges version 284 // The number of ranges 285 int nRanges = getCard16(); 286 int l=0; 287 // Read the first in the first range 288 int first = getCard16(); 289 for (int i=0;i<nRanges;i++) 290 { 291 // Read the FD index 292 int fd = getCard8(); 293 // Read the first of the next range 294 int last = getCard16(); 295 // Calc the steps and write to the array 296 int steps = last-first; 297 for (int k=0;k<steps;k++) 298 { 299 FDSelect[l] = fd; 300 l++; 301 } 302 // The last from this iteration is the first of the next 303 first = last; 304 } 305 // Store the length for later use 306 fonts[Font].FDSelectLength = 1+2+nRanges*3+2; 307 break; 308 default: 309 break; 310 } 311 // Save the FDSelect of the font 312 fonts[Font].FDSelect = FDSelect; 313 } 314 315 /** 316 * Function reads the FDSelect and builds the FDArrayUsed HashMap According to the glyphs used 317 * @param Font the Number of font being processed 318 */ 319 protected void BuildFDArrayUsed(int Font) 320 { 321 int[] FDSelect = fonts[Font].FDSelect; 322 // For each glyph used 323 for (int i=0;i<glyphsInList.size();i++) 324 { 325 // Pop the glyphs index 326 int glyph = glyphsInList.get(i).intValue(); 327 // Pop the glyph's FD 328 int FD = FDSelect[glyph]; 329 // Put the FD index into the FDArrayUsed HashMap 330 FDArrayUsed.add(Integer.valueOf(FD)); 331 } 332 } 333 334 /** 335 * Read the FDArray count, offsize and Offset array 336 * @param Font 337 */ 338 protected void ReadFDArray(int Font) 339 { 340 seek(fonts[Font].fdarrayOffset); 341 fonts[Font].FDArrayCount = getCard16(); 342 fonts[Font].FDArrayOffsize = getCard8(); 343 // Since we will change values inside the FDArray objects 344 // We increase its offsize to prevent errors 345 if (fonts[Font].FDArrayOffsize < 4) 346 fonts[Font].FDArrayOffsize++; 347 fonts[Font].FDArrayOffsets = getIndex(fonts[Font].fdarrayOffset); 348 } 349 350 351 /** 352 * The Process function extracts one font out of the CFF file and returns a 353 * subset version of the original. 354 * @param fontName - The name of the font to be taken out of the CFF 355 * @return The new font stream 356 * @throws IOException 357 */ 358 public byte[] Process(String fontName)throws IOException{ 359 try 360 { 361 // Verify that the file is open 362 buf.reOpen(); 363 // Find the Font that we will be dealing with 364 int j; 365 for (j=0; j<fonts.length; j++) 366 if (fontName.equals(fonts[j].name)) break; 367 if (j==fonts.length) return null; 368 369 // Calc the bias for the global subrs 370 if (gsubrIndexOffset >= 0) 371 GBias = CalcBias(gsubrIndexOffset,j); 372 373 // Prepare the new CharStrings Index 374 BuildNewCharString(j); 375 // Prepare the new Global and Local Subrs Indices 376 BuildNewLGSubrs(j); 377 // Build the new file 378 byte[] Ret = BuildNewFile(j); 379 return Ret; 380 } 381 finally { 382 try { 383 buf.close(); 384 } 385 catch (Exception e) { 386 // empty on purpose 387 } 388 } 389 } 390 391 /** 392 * Function calcs bias according to the CharString type and the count 393 * of the subrs 394 * @param Offset The offset to the relevant subrs index 395 * @param Font the font 396 * @return The calculated Bias 397 */ 398 protected int CalcBias(int Offset,int Font) 399 { 400 seek(Offset); 401 int nSubrs = getCard16(); 402 // If type==1 -> bias=0 403 if (fonts[Font].CharstringType == 1) 404 return 0; 405 // else calc according to the count 406 else if (nSubrs < 1240) 407 return 107; 408 else if (nSubrs < 33900) 409 return 1131; 410 else 411 return 32768; 412 } 413 414 /** 415 *Function uses BuildNewIndex to create the new index of the subset charstrings 416 * @param FontIndex the font 417 * @throws IOException 418 */ 419 protected void BuildNewCharString(int FontIndex) throws IOException 420 { 421 NewCharStringsIndex = BuildNewIndex(fonts[FontIndex].charstringsOffsets,GlyphsUsed,ENDCHAR_OP); 422 } 423 424 /** 425 * Function builds the new local & global subsrs indices. IF CID then All of 426 * the FD Array lsubrs will be subsetted. 427 * @param Font the font 428 * @throws IOException 429 */ 430 @SuppressWarnings("unchecked") 431 protected void BuildNewLGSubrs(int Font)throws IOException 432 { 433 // If the font is CID then the lsubrs are divided into FontDicts. 434 // for each FD array the lsubrs will be subsetted. 435 if(fonts[Font].isCID) 436 { 437 // Init the hashmap-array and the arraylist-array to hold the subrs used 438 // in each private dict. 439 hSubrsUsed = new HashMap[fonts[Font].fdprivateOffsets.length]; 440 lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.length]; 441 // A [][] which will store the byte array for each new FD Array lsubs index 442 NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.length][]; 443 // An array to hold the offset for each Lsubr index 444 fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.length]; 445 // A [][] which will store the offset array for each lsubr index 446 fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.length][]; 447 448 // Put the FDarrayUsed into a list 449 ArrayList<Integer> FDInList = new ArrayList<Integer>(FDArrayUsed); 450 // For each FD array which is used subset the lsubr 451 for (int j=0;j<FDInList.size();j++) 452 { 453 // The FDArray index, Hash Map, Array List to work on 454 int FD = FDInList.get(j).intValue(); 455 hSubrsUsed[FD] = new HashMap<Integer, int[]>(); 456 lSubrsUsed[FD] = new ArrayList<Integer>(); 457 //Reads the private dicts looking for the subr operator and 458 // store both the offset for the index and its offset array 459 BuildFDSubrsOffsets(Font,FD); 460 // Verify that FDPrivate has a LSubrs index 461 if(fonts[Font].PrivateSubrsOffset[FD]>=0) 462 { 463 //Scans the Charstring data storing the used Local and Global subroutines 464 // by the glyphs. Scans the Subrs recursively. 465 BuildSubrUsed(Font,FD,fonts[Font].PrivateSubrsOffset[FD],fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],lSubrsUsed[FD]); 466 // Builds the New Local Subrs index 467 NewLSubrsIndex[FD] = BuildNewIndex(fonts[Font].PrivateSubrsOffsetsArray[FD],hSubrsUsed[FD],RETURN_OP); 468 } 469 } 470 } 471 // If the font is not CID && the Private Subr exists then subset: 472 else if (fonts[Font].privateSubrs>=0) 473 { 474 // Build the subrs offsets; 475 fonts[Font].SubrsOffsets = getIndex(fonts[Font].privateSubrs); 476 //Scans the Charstring data storing the used Local and Global subroutines 477 // by the glyphs. Scans the Subrs recursively. 478 BuildSubrUsed(Font,-1,fonts[Font].privateSubrs,fonts[Font].SubrsOffsets,hSubrsUsedNonCID,lSubrsUsedNonCID); 479 } 480 // For all fonts subset the Global Subroutines 481 // Scan the Global Subr Hashmap recursively on the Gsubrs 482 BuildGSubrsUsed(Font); 483 if (fonts[Font].privateSubrs>=0) 484 // Builds the New Local Subrs index 485 NewSubrsIndexNonCID = BuildNewIndex(fonts[Font].SubrsOffsets,hSubrsUsedNonCID,RETURN_OP); 486 //Builds the New Global Subrs index 487 NewGSubrsIndex = BuildNewIndex(gsubrOffsets,hGSubrsUsed,RETURN_OP); 488 } 489 490 /** 491 * The function finds for the FD array processed the local subr offset and its 492 * offset array. 493 * @param Font the font 494 * @param FD The FDARRAY processed 495 */ 496 protected void BuildFDSubrsOffsets(int Font,int FD) 497 { 498 // Initiate to -1 to indicate lsubr operator present 499 fonts[Font].PrivateSubrsOffset[FD] = -1; 500 // Goto beginning of objects 501 seek(fonts[Font].fdprivateOffsets[FD]); 502 // While in the same object: 503 while (getPosition() < fonts[Font].fdprivateOffsets[FD]+fonts[Font].fdprivateLengths[FD]) 504 { 505 getDictItem(); 506 // If the dictItem is the "Subrs" then find and store offset, 507 if (key=="Subrs") 508 fonts[Font].PrivateSubrsOffset[FD] = ((Integer)args[0]).intValue()+fonts[Font].fdprivateOffsets[FD]; 509 } 510 //Read the lsubr index if the lsubr was found 511 if (fonts[Font].PrivateSubrsOffset[FD] >= 0) 512 fonts[Font].PrivateSubrsOffsetsArray[FD] = getIndex(fonts[Font].PrivateSubrsOffset[FD]); 513 } 514 515 /** 516 * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap. 517 * The HashMap (of the lsubr only) is then scanned recursively for Lsubr & Gsubrs 518 * calls. 519 * @param Font the font 520 * @param FD FD array processed. 0 indicates function was called by non CID font 521 * @param SubrOffset the offset to the subr index to calc the bias 522 * @param SubrsOffsets the offset array of the subr index 523 * @param hSubr HashMap of the subrs used 524 * @param lSubr ArrayList of the subrs used 525 */ 526 protected void BuildSubrUsed(int Font,int FD,int SubrOffset,int[] SubrsOffsets,HashMap<Integer, int[]> hSubr,ArrayList<Integer> lSubr) 527 { 528 529 // Calc the Bias for the subr index 530 int LBias = CalcBias(SubrOffset,Font); 531 532 // For each glyph used find its GID, start & end pos 533 for (int i=0;i<glyphsInList.size();i++) 534 { 535 int glyph = glyphsInList.get(i).intValue(); 536 int Start = fonts[Font].charstringsOffsets[glyph]; 537 int End = fonts[Font].charstringsOffsets[glyph+1]; 538 539 // IF CID: 540 if (FD >= 0) 541 { 542 EmptyStack(); 543 NumOfHints=0; 544 // Using FDSELECT find the FD Array the glyph belongs to. 545 int GlyphFD = fonts[Font].FDSelect[glyph]; 546 // If the Glyph is part of the FD being processed 547 if (GlyphFD == FD) 548 // Find the Subrs called by the glyph and insert to hash: 549 ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); 550 } 551 else 552 // If the font is not CID 553 //Find the Subrs called by the glyph and insert to hash: 554 ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); 555 } 556 // For all Lsubrs used, check recursively for Lsubr & Gsubr used 557 for (int i=0;i<lSubr.size();i++) 558 { 559 // Pop the subr value from the hash 560 int Subr = lSubr.get(i).intValue(); 561 // Ensure the Lsubr call is valid 562 if (Subr < SubrsOffsets.length-1 && Subr>=0) 563 { 564 // Read and process the subr 565 int Start = SubrsOffsets[Subr]; 566 int End = SubrsOffsets[Subr+1]; 567 ReadASubr(Start,End,GBias,LBias,hSubr,lSubr,SubrsOffsets); 568 } 569 } 570 } 571 572 /** 573 * Function scans the Glsubr used ArrayList to find recursive calls 574 * to Gsubrs and adds to Hashmap & ArrayList 575 * @param Font the font 576 */ 577 protected void BuildGSubrsUsed(int Font) 578 { 579 int LBias = 0; 580 int SizeOfNonCIDSubrsUsed = 0; 581 if (fonts[Font].privateSubrs>=0) 582 { 583 LBias = CalcBias(fonts[Font].privateSubrs,Font); 584 SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size(); 585 } 586 587 // For each global subr used 588 for (int i=0;i<lGSubrsUsed.size();i++) 589 { 590 //Pop the value + check valid 591 int Subr = lGSubrsUsed.get(i).intValue(); 592 if (Subr < gsubrOffsets.length-1 && Subr>=0) 593 { 594 // Read the subr and process 595 int Start = gsubrOffsets[Subr]; 596 int End = gsubrOffsets[Subr+1]; 597 598 if (fonts[Font].isCID) 599 ReadASubr(Start,End,GBias,0,hGSubrsUsed,lGSubrsUsed,null); 600 else 601 { 602 ReadASubr(Start,End,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); 603 if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.size()) 604 { 605 for (int j=SizeOfNonCIDSubrsUsed;j<lSubrsUsedNonCID.size();j++) 606 { 607 //Pop the value + check valid 608 int LSubr = lSubrsUsedNonCID.get(j).intValue(); 609 if (LSubr < fonts[Font].SubrsOffsets.length-1 && LSubr>=0) 610 { 611 // Read the subr and process 612 int LStart = fonts[Font].SubrsOffsets[LSubr]; 613 int LEnd = fonts[Font].SubrsOffsets[LSubr+1]; 614 ReadASubr(LStart,LEnd,GBias,LBias,hSubrsUsedNonCID,lSubrsUsedNonCID,fonts[Font].SubrsOffsets); 615 } 616 } 617 SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size(); 618 } 619 } 620 } 621 } 622 } 623 624 /** 625 * The function reads a subrs (glyph info) between begin and end. 626 * Adds calls to a Lsubr to the hSubr and lSubrs. 627 * Adds calls to a Gsubr to the hGSubr and lGSubrs. 628 * @param begin the start point of the subr 629 * @param end the end point of the subr 630 * @param GBias the bias of the Global Subrs 631 * @param LBias the bias of the Local Subrs 632 * @param hSubr the HashMap for the lSubrs 633 * @param lSubr the ArrayList for the lSubrs 634 */ 635 protected void ReadASubr(int begin,int end,int GBias,int LBias,HashMap<Integer, int[]> hSubr,ArrayList<Integer> lSubr,int[] LSubrsOffsets) 636 { 637 // Clear the stack for the subrs 638 EmptyStack(); 639 NumOfHints = 0; 640 // Goto beginning of the subr 641 seek(begin); 642 while (getPosition() < end) 643 { 644 // Read the next command 645 ReadCommand(); 646 int pos = getPosition(); 647 Object TopElement=null; 648 if (arg_count > 0) 649 TopElement = args[arg_count-1]; 650 int NumOfArgs = arg_count; 651 // Check the modification needed on the Argument Stack according to key; 652 HandelStack(); 653 // a call to a Lsubr 654 if (key=="callsubr") 655 { 656 // Verify that arguments are passed 657 if (NumOfArgs > 0) 658 { 659 // Calc the index of the Subrs 660 int Subr = ((Integer)TopElement).intValue() + LBias; 661 // If the subr isn't in the HashMap -> Put in 662 if (!hSubr.containsKey(Integer.valueOf (Subr))) 663 { 664 hSubr.put(Integer.valueOf(Subr),null); 665 lSubr.add(Integer.valueOf(Subr)); 666 } 667 CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); 668 seek(pos); 669 } 670 } 671 // a call to a Gsubr 672 else if (key=="callgsubr") 673 { 674 // Verify that arguments are passed 675 if (NumOfArgs > 0) 676 { 677 // Calc the index of the Subrs 678 int Subr = ((Integer)TopElement).intValue() + GBias; 679 // If the subr isn't in the HashMap -> Put in 680 if (!hGSubrsUsed.containsKey(Integer.valueOf (Subr))) 681 { 682 hGSubrsUsed.put(Integer.valueOf(Subr),null); 683 lGSubrsUsed.add(Integer.valueOf(Subr)); 684 } 685 CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); 686 seek(pos); 687 } 688 } 689 // A call to "stem" 690 else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") 691 // Increment the NumOfHints by the number couples of of arguments 692 NumOfHints += NumOfArgs/2; 693 // A call to "mask" 694 else if (key == "hintmask" || key == "cntrmask") 695 { 696 // Compute the size of the mask 697 int SizeOfMask = NumOfHints/8; 698 if (NumOfHints%8 != 0 || SizeOfMask == 0) 699 SizeOfMask++; 700 // Continue the pointer in SizeOfMask steps 701 for (int i=0;i<SizeOfMask;i++) 702 getCard8(); 703 } 704 } 705 } 706 707 /** 708 * Function Checks how the current operator effects the run time stack after being run 709 * An operator may increase or decrease the stack size 710 */ 711 protected void HandelStack() 712 { 713 // Find out what the operator does to the stack 714 int StackHandel = StackOpp(); 715 if (StackHandel < 2) 716 { 717 // The operators that enlarge the stack by one 718 if (StackHandel==1) 719 PushStack(); 720 // The operators that pop the stack 721 else 722 { 723 // Abs value for the for loop 724 StackHandel *= -1; 725 for (int i=0;i<StackHandel;i++) 726 PopStack(); 727 } 728 729 } 730 // All other flush the stack 731 else 732 EmptyStack(); 733 } 734 735 /** 736 * Function checks the key and return the change to the stack after the operator 737 * @return The change in the stack. 2-> flush the stack 738 */ 739 protected int StackOpp() 740 { 741 if (key == "ifelse") 742 return -3; 743 if (key == "roll" || key == "put") 744 return -2; 745 if (key == "callsubr" || key == "callgsubr" || key == "add" || key == "sub" || 746 key == "div" || key == "mul" || key == "drop" || key == "and" || 747 key == "or" || key == "eq") 748 return -1; 749 if (key == "abs" || key == "neg" || key == "sqrt" || key == "exch" || 750 key == "index" || key == "get" || key == "not" || key == "return") 751 return 0; 752 if (key == "random" || key == "dup") 753 return 1; 754 return 2; 755 } 756 757 /** 758 * Empty the Type2 Stack 759 * 760 */ 761 protected void EmptyStack() 762 { 763 // Null the arguments 764 for (int i=0; i<arg_count; i++) args[i]=null; 765 arg_count = 0; 766 } 767 768 /** 769 * Pop one element from the stack 770 * 771 */ 772 protected void PopStack() 773 { 774 if (arg_count>0) 775 { 776 args[arg_count-1]=null; 777 arg_count--; 778 } 779 } 780 781 /** 782 * Add an item to the stack 783 * 784 */ 785 protected void PushStack() 786 { 787 arg_count++; 788 } 789 790 /** 791 * The function reads the next command after the file pointer is set 792 */ 793 protected void ReadCommand() 794 { 795 key = null; 796 boolean gotKey = false; 797 // Until a key is found 798 while (!gotKey) { 799 // Read the first Char 800 char b0 = getCard8(); 801 // decode according to the type1/type2 format 802 if (b0 == 28) // the two next bytes represent a short int; 803 { 804 int first = getCard8(); 805 int second = getCard8(); 806 args[arg_count] = Integer.valueOf(first<<8 | second); 807 arg_count++; 808 continue; 809 } 810 if (b0 >= 32 && b0 <= 246) // The byte read is the byte; 811 { 812 args[arg_count] = Integer.valueOf(b0 - 139); 813 arg_count++; 814 continue; 815 } 816 if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constitute a short int 817 { 818 int w = getCard8(); 819 args[arg_count] = Integer.valueOf((b0-247)*256 + w + 108); 820 arg_count++; 821 continue; 822 } 823 if (b0 >= 251 && b0 <= 254)// Same as above except negative 824 { 825 int w = getCard8(); 826 args[arg_count] = Integer.valueOf(-(b0-251)*256 - w - 108); 827 arg_count++; 828 continue; 829 } 830 if (b0 == 255)// The next for bytes represent a double. 831 { 832 int first = getCard8(); 833 int second = getCard8(); 834 int third = getCard8(); 835 int fourth = getCard8(); 836 args[arg_count] = Integer.valueOf(first<<24 | second<<16 | third<<8 | fourth); 837 arg_count++; 838 continue; 839 } 840 if (b0<=31 && b0 != 28) // An operator was found.. Set Key. 841 { 842 gotKey=true; 843 // 12 is an escape command therefore the next byte is a part 844 // of this command 845 if (b0 == 12) 846 { 847 int b1 = getCard8(); 848 if (b1>SubrsEscapeFuncs.length-1) 849 b1 = SubrsEscapeFuncs.length-1; 850 key = SubrsEscapeFuncs[b1]; 851 } 852 else 853 key = SubrsFunctions[b0]; 854 continue; 855 } 856 } 857 } 858 859 /** 860 * The function reads the subroutine and returns the number of the hint in it. 861 * If a call to another subroutine is found the function calls recursively. 862 * @param begin the start point of the subr 863 * @param end the end point of the subr 864 * @param LBias the bias of the Local Subrs 865 * @param GBias the bias of the Global Subrs 866 * @param LSubrsOffsets The Offsets array of the subroutines 867 * @return The number of hints in the subroutine read. 868 */ 869 protected int CalcHints(int begin,int end,int LBias,int GBias,int[] LSubrsOffsets) 870 { 871 // Goto beginning of the subr 872 seek(begin); 873 while (getPosition() < end) 874 { 875 // Read the next command 876 ReadCommand(); 877 int pos = getPosition(); 878 Object TopElement = null; 879 if (arg_count>0) 880 TopElement = args[arg_count-1]; 881 int NumOfArgs = arg_count; 882 //Check the modification needed on the Argument Stack according to key; 883 HandelStack(); 884 // a call to a Lsubr 885 if (key=="callsubr") 886 { 887 if (NumOfArgs>0) 888 { 889 int Subr = ((Integer)TopElement).intValue() + LBias; 890 CalcHints(LSubrsOffsets[Subr],LSubrsOffsets[Subr+1],LBias,GBias,LSubrsOffsets); 891 seek(pos); 892 } 893 } 894 // a call to a Gsubr 895 else if (key=="callgsubr") 896 { 897 if (NumOfArgs>0) 898 { 899 int Subr = ((Integer)TopElement).intValue() + GBias; 900 CalcHints(gsubrOffsets[Subr],gsubrOffsets[Subr+1],LBias,GBias,LSubrsOffsets); 901 seek(pos); 902 } 903 } 904 // A call to "stem" 905 else if (key == "hstem" || key == "vstem" || key == "hstemhm" || key == "vstemhm") 906 // Increment the NumOfHints by the number couples of of arguments 907 NumOfHints += NumOfArgs/2; 908 // A call to "mask" 909 else if (key == "hintmask" || key == "cntrmask") 910 { 911 // Compute the size of the mask 912 int SizeOfMask = NumOfHints/8; 913 if (NumOfHints%8 != 0 || SizeOfMask == 0) 914 SizeOfMask++; 915 // Continue the pointer in SizeOfMask steps 916 for (int i=0;i<SizeOfMask;i++) 917 getCard8(); 918 } 919 } 920 return NumOfHints; 921 } 922 923 924 /** 925 * Function builds the new offset array, object array and assembles the index. 926 * used for creating the glyph and subrs subsetted index 927 * @param Offsets the offset array of the original index 928 * @param Used the hashmap of the used objects 929 * @param OperatorForUnusedEntries the operator inserted into the data stream for unused entries 930 * @return the new index subset version 931 * @throws IOException 932 */ 933 protected byte[] BuildNewIndex(int[] Offsets,HashMap<Integer, int[]> Used,byte OperatorForUnusedEntries) throws IOException 934 { 935 int unusedCount = 0; 936 int Offset=0; 937 int[] NewOffsets = new int[Offsets.length]; 938 // Build the Offsets Array for the Subset 939 for (int i=0;i<Offsets.length;++i) 940 { 941 NewOffsets[i] = Offset; 942 // If the object in the offset is also present in the used 943 // HashMap then increment the offset var by its size 944 if (Used.containsKey(Integer.valueOf(i))) { 945 Offset += Offsets[i+1] - Offsets[i]; 946 } else { 947 // Else the same offset is kept in i+1. 948 unusedCount++; 949 } 950 } 951 // Offset var determines the size of the object array 952 byte[] NewObjects = new byte[Offset+unusedCount]; 953 // Build the new Object array 954 int unusedOffset = 0; 955 for (int i=0;i<Offsets.length-1;++i) 956 { 957 int start = NewOffsets[i]; 958 int end = NewOffsets[i+1]; 959 NewOffsets[i] = start+unusedOffset; 960 // If start != End then the Object is used 961 // So, we will copy the object data from the font file 962 if (start != end) 963 { 964 // All offsets are Global Offsets relative to the beginning of the font file. 965 // Jump the file pointer to the start address to read from. 966 buf.seek(Offsets[i]); 967 // Read from the buffer and write into the array at start. 968 buf.readFully(NewObjects, start+unusedOffset, end-start); 969 } else { 970 NewObjects[start+unusedOffset] = OperatorForUnusedEntries; 971 unusedOffset++; 972 } 973 } 974 NewOffsets[Offsets.length-1] += unusedOffset; 975 // Use AssembleIndex to build the index from the offset & object arrays 976 return AssembleIndex(NewOffsets,NewObjects); 977 } 978 979 /** 980 * Function creates the new index, inserting the count,offsetsize,offset array 981 * and object array. 982 * @param NewOffsets the subsetted offset array 983 * @param NewObjects the subsetted object array 984 * @return the new index created 985 */ 986 protected byte[] AssembleIndex(int[] NewOffsets,byte[] NewObjects) 987 { 988 // Calc the index' count field 989 char Count = (char)(NewOffsets.length-1); 990 // Calc the size of the object array 991 int Size = NewOffsets[NewOffsets.length-1]; 992 // Calc the Offsize 993 byte Offsize; 994 if (Size <= 0xff) Offsize = 1; 995 else if (Size <= 0xffff) Offsize = 2; 996 else if (Size <= 0xffffff) Offsize = 3; 997 else Offsize = 4; 998 // The byte array for the new index. The size is calc by 999 // Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array 1000 byte[] NewIndex = new byte[2+1+Offsize*(Count+1)+NewObjects.length]; 1001 // The counter for writing 1002 int Place = 0; 1003 // Write the count field 1004 NewIndex[Place++] = (byte) (Count >>> 8 & 0xff); 1005 NewIndex[Place++] = (byte) (Count >>> 0 & 0xff); 1006 // Write the offsize field 1007 NewIndex[Place++] = Offsize; 1008 // Write the offset array according to the offsize 1009 for (int newOffset : NewOffsets) { 1010 // The value to be written 1011 int Num = newOffset-NewOffsets[0]+1; 1012 // Write in bytes according to the offsize 1013 switch (Offsize) { 1014 case 4: 1015 NewIndex[Place++] = (byte) (Num >>> 24 & 0xff); 1016 case 3: 1017 NewIndex[Place++] = (byte) (Num >>> 16 & 0xff); 1018 case 2: 1019 NewIndex[Place++] = (byte) (Num >>> 8 & 0xff); 1020 case 1: 1021 NewIndex[Place++] = (byte) (Num >>> 0 & 0xff); 1022 } 1023 } 1024 // Write the new object array one by one 1025 for (byte newObject : NewObjects) { 1026 NewIndex[Place++] = newObject; 1027 } 1028 // Return the new index 1029 return NewIndex; 1030 } 1031 1032 /** 1033 * The function builds the new output stream according to the subset process 1034 * @param Font the font 1035 * @return the subsetted font stream 1036 */ 1037 protected byte[] BuildNewFile(int Font) 1038 { 1039 // Prepare linked list for new font components 1040 OutputList = new LinkedList<Item>(); 1041 1042 // copy the header of the font 1043 CopyHeader(); 1044 1045 // create a name index 1046 BuildIndexHeader(1,1,1); 1047 OutputList.addLast(new UInt8Item((char)( 1+fonts[Font].name.length() ))); 1048 OutputList.addLast(new StringItem(fonts[Font].name)); 1049 1050 // create the topdict Index 1051 BuildIndexHeader(1,2,1); 1052 OffsetItem topdictIndex1Ref = new IndexOffsetItem(2); 1053 OutputList.addLast(topdictIndex1Ref); 1054 IndexBaseItem topdictBase = new IndexBaseItem(); 1055 OutputList.addLast(topdictBase); 1056 1057 // Initialize the Dict Items for later use 1058 OffsetItem charsetRef = new DictOffsetItem(); 1059 OffsetItem charstringsRef = new DictOffsetItem(); 1060 OffsetItem fdarrayRef = new DictOffsetItem(); 1061 OffsetItem fdselectRef = new DictOffsetItem(); 1062 OffsetItem privateRef = new DictOffsetItem(); 1063 1064 // If the font is not CID create the following keys 1065 if ( !fonts[Font].isCID ) { 1066 // create a ROS key 1067 OutputList.addLast(new DictNumberItem(fonts[Font].nstrings)); 1068 OutputList.addLast(new DictNumberItem(fonts[Font].nstrings+1)); 1069 OutputList.addLast(new DictNumberItem(0)); 1070 OutputList.addLast(new UInt8Item((char)12)); 1071 OutputList.addLast(new UInt8Item((char)30)); 1072 // create a CIDCount key 1073 OutputList.addLast(new DictNumberItem(fonts[Font].nglyphs)); 1074 OutputList.addLast(new UInt8Item((char)12)); 1075 OutputList.addLast(new UInt8Item((char)34)); 1076 // Sivan's comments 1077 // What about UIDBase (12,35)? Don't know what is it. 1078 // I don't think we need FontName; the font I looked at didn't have it. 1079 } 1080 // Go to the TopDict of the font being processed 1081 seek(topdictOffsets[Font]); 1082 // Run until the end of the TopDict 1083 while (getPosition() < topdictOffsets[Font+1]) { 1084 int p1 = getPosition(); 1085 getDictItem(); 1086 int p2 = getPosition(); 1087 // The encoding key is disregarded since CID has no encoding 1088 if (key=="Encoding" 1089 // These keys will be added manually by the process. 1090 || key=="Private" 1091 || key=="FDSelect" 1092 || key=="FDArray" 1093 || key=="charset" 1094 || key=="CharStrings" 1095 ) { 1096 }else { 1097 //OtherWise copy key "as is" to the output list 1098 OutputList.add(new RangeItem(buf,p1,p2-p1)); 1099 } 1100 } 1101 // Create the FDArray, FDSelect, Charset and CharStrings Keys 1102 CreateKeys(fdarrayRef,fdselectRef,charsetRef,charstringsRef); 1103 1104 // Mark the end of the top dict area 1105 OutputList.addLast(new IndexMarkerItem(topdictIndex1Ref,topdictBase)); 1106 1107 // Copy the string index 1108 1109 if (fonts[Font].isCID) 1110 OutputList.addLast(getEntireIndexRange(stringIndexOffset)); 1111 // If the font is not CID we need to append new strings. 1112 // We need 3 more strings: Registry, Ordering, and a FontName for one FD. 1113 // The total length is at most "Adobe"+"Identity"+63 = 76 1114 else 1115 CreateNewStringIndex(Font); 1116 1117 // copy the new subsetted global subroutine index 1118 OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewGSubrsIndex),0,NewGSubrsIndex.length)); 1119 1120 // deal with fdarray, fdselect, and the font descriptors 1121 // If the font is CID: 1122 if (fonts[Font].isCID) { 1123 // copy the FDArray, FDSelect, charset 1124 1125 // Copy FDSelect 1126 // Mark the beginning 1127 OutputList.addLast(new MarkerItem(fdselectRef)); 1128 // If an FDSelect exists copy it 1129 if (fonts[Font].fdselectOffset>=0) 1130 OutputList.addLast(new RangeItem(buf,fonts[Font].fdselectOffset,fonts[Font].FDSelectLength)); 1131 // Else create a new one 1132 else 1133 CreateFDSelect(fdselectRef,fonts[Font].nglyphs); 1134 1135 // Copy the Charset 1136 // Mark the beginning and copy entirely 1137 OutputList.addLast(new MarkerItem(charsetRef)); 1138 OutputList.addLast(new RangeItem(buf,fonts[Font].charsetOffset,fonts[Font].CharsetLength)); 1139 1140 // Copy the FDArray 1141 // If an FDArray exists 1142 if (fonts[Font].fdarrayOffset>=0) 1143 { 1144 // Mark the beginning 1145 OutputList.addLast(new MarkerItem(fdarrayRef)); 1146 // Build a new FDArray with its private dicts and their LSubrs 1147 Reconstruct(Font); 1148 } 1149 else 1150 // Else create a new one 1151 CreateFDArray(fdarrayRef,privateRef,Font); 1152 1153 } 1154 // If the font is not CID 1155 else 1156 { 1157 // create FDSelect 1158 CreateFDSelect(fdselectRef,fonts[Font].nglyphs); 1159 // recreate a new charset 1160 CreateCharset(charsetRef,fonts[Font].nglyphs); 1161 // create a font dict index (fdarray) 1162 CreateFDArray(fdarrayRef,privateRef,Font); 1163 } 1164 1165 // if a private dict exists insert its subsetted version 1166 if (fonts[Font].privateOffset>=0) 1167 { 1168 // Mark the beginning of the private dict 1169 IndexBaseItem PrivateBase = new IndexBaseItem(); 1170 OutputList.addLast(PrivateBase); 1171 OutputList.addLast(new MarkerItem(privateRef)); 1172 1173 OffsetItem Subr = new DictOffsetItem(); 1174 // Build and copy the new private dict 1175 CreateNonCIDPrivate(Font,Subr); 1176 // Copy the new LSubrs index 1177 CreateNonCIDSubrs(Font,PrivateBase,Subr); 1178 } 1179 1180 // copy the charstring index 1181 OutputList.addLast(new MarkerItem(charstringsRef)); 1182 1183 // Add the subsetted charstring 1184 OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewCharStringsIndex),0,NewCharStringsIndex.length)); 1185 1186 // now create the new CFF font 1187 int[] currentOffset = new int[1]; 1188 currentOffset[0] = 0; 1189 // Count and save the offset for each item 1190 Iterator<Item> listIter = OutputList.iterator(); 1191 while ( listIter.hasNext() ) { 1192 Item item = listIter.next(); 1193 item.increment(currentOffset); 1194 } 1195 // Compute the Xref for each of the offset items 1196 listIter = OutputList.iterator(); 1197 while ( listIter.hasNext() ) { 1198 Item item = listIter.next(); 1199 item.xref(); 1200 } 1201 1202 int size = currentOffset[0]; 1203 byte[] b = new byte[size]; 1204 1205 // Emit all the items into the new byte array 1206 listIter = OutputList.iterator(); 1207 while ( listIter.hasNext() ) { 1208 Item item = listIter.next(); 1209 item.emit(b); 1210 } 1211 // Return the new stream 1212 return b; 1213 } 1214 1215 /** 1216 * Function Copies the header from the original fileto the output list 1217 */ 1218 protected void CopyHeader() 1219 { 1220 seek(0); 1221 int major = getCard8(); 1222 int minor = getCard8(); 1223 int hdrSize = getCard8(); 1224 int offSize = getCard8(); 1225 nextIndexOffset = hdrSize; 1226 OutputList.addLast(new RangeItem(buf,0,hdrSize)); 1227 } 1228 1229 /** 1230 * Function Build the header of an index 1231 * @param Count the count field of the index 1232 * @param Offsize the offsize field of the index 1233 * @param First the first offset of the index 1234 */ 1235 protected void BuildIndexHeader(int Count,int Offsize,int First) 1236 { 1237 // Add the count field 1238 OutputList.addLast(new UInt16Item((char)Count)); // count 1239 // Add the offsize field 1240 OutputList.addLast(new UInt8Item((char)Offsize)); // offSize 1241 // Add the first offset according to the offsize 1242 switch(Offsize){ 1243 case 1: 1244 OutputList.addLast(new UInt8Item((char)First)); // first offset 1245 break; 1246 case 2: 1247 OutputList.addLast(new UInt16Item((char)First)); // first offset 1248 break; 1249 case 3: 1250 OutputList.addLast(new UInt24Item((char)First)); // first offset 1251 break; 1252 case 4: 1253 OutputList.addLast(new UInt32Item((char)First)); // first offset 1254 break; 1255 default: 1256 break; 1257 } 1258 } 1259 1260 /** 1261 * Function adds the keys into the TopDict 1262 * @param fdarrayRef OffsetItem for the FDArray 1263 * @param fdselectRef OffsetItem for the FDSelect 1264 * @param charsetRef OffsetItem for the CharSet 1265 * @param charstringsRef OffsetItem for the CharString 1266 */ 1267 protected void CreateKeys(OffsetItem fdarrayRef,OffsetItem fdselectRef,OffsetItem charsetRef,OffsetItem charstringsRef) 1268 { 1269 // create an FDArray key 1270 OutputList.addLast(fdarrayRef); 1271 OutputList.addLast(new UInt8Item((char)12)); 1272 OutputList.addLast(new UInt8Item((char)36)); 1273 // create an FDSelect key 1274 OutputList.addLast(fdselectRef); 1275 OutputList.addLast(new UInt8Item((char)12)); 1276 OutputList.addLast(new UInt8Item((char)37)); 1277 // create an charset key 1278 OutputList.addLast(charsetRef); 1279 OutputList.addLast(new UInt8Item((char)15)); 1280 // create a CharStrings key 1281 OutputList.addLast(charstringsRef); 1282 OutputList.addLast(new UInt8Item((char)17)); 1283 } 1284 1285 /** 1286 * Function takes the original string item and adds the new strings 1287 * to accommodate the CID rules 1288 * @param Font the font 1289 */ 1290 protected void CreateNewStringIndex(int Font) 1291 { 1292 String fdFontName = fonts[Font].name+"-OneRange"; 1293 if (fdFontName.length() > 127) 1294 fdFontName = fdFontName.substring(0,127); 1295 String extraStrings = "Adobe"+"Identity"+fdFontName; 1296 1297 int origStringsLen = stringOffsets[stringOffsets.length-1] 1298 - stringOffsets[0]; 1299 int stringsBaseOffset = stringOffsets[0]-1; 1300 1301 byte stringsIndexOffSize; 1302 if (origStringsLen+extraStrings.length() <= 0xff) stringsIndexOffSize = 1; 1303 else if (origStringsLen+extraStrings.length() <= 0xffff) stringsIndexOffSize = 2; 1304 else if (origStringsLen+extraStrings.length() <= 0xffffff) stringsIndexOffSize = 3; 1305 else stringsIndexOffSize = 4; 1306 1307 OutputList.addLast(new UInt16Item((char)(stringOffsets.length-1+3))); // count 1308 OutputList.addLast(new UInt8Item((char)stringsIndexOffSize)); // offSize 1309 for (int stringOffset : stringOffsets) 1310 OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize, 1311 stringOffset-stringsBaseOffset)); 1312 int currentStringsOffset = stringOffsets[stringOffsets.length-1] 1313 - stringsBaseOffset; 1314 //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 1315 currentStringsOffset += "Adobe".length(); 1316 OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 1317 currentStringsOffset += "Identity".length(); 1318 OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 1319 currentStringsOffset += fdFontName.length(); 1320 OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset)); 1321 1322 OutputList.addLast(new RangeItem(buf,stringOffsets[0],origStringsLen)); 1323 OutputList.addLast(new StringItem(extraStrings)); 1324 } 1325 1326 /** 1327 * Function creates new FDSelect for non-CID fonts. 1328 * The FDSelect built uses a single range for all glyphs 1329 * @param fdselectRef OffsetItem for the FDSelect 1330 * @param nglyphs the number of glyphs in the font 1331 */ 1332 protected void CreateFDSelect(OffsetItem fdselectRef,int nglyphs) 1333 { 1334 OutputList.addLast(new MarkerItem(fdselectRef)); 1335 OutputList.addLast(new UInt8Item((char)3)); // format identifier 1336 OutputList.addLast(new UInt16Item((char)1)); // nRanges 1337 1338 OutputList.addLast(new UInt16Item((char)0)); // Range[0].firstGlyph 1339 OutputList.addLast(new UInt8Item((char)0)); // Range[0].fd 1340 1341 OutputList.addLast(new UInt16Item((char)nglyphs)); // sentinel 1342 } 1343 1344 /** 1345 * Function creates new CharSet for non-CID fonts. 1346 * The CharSet built uses a single range for all glyphs 1347 * @param charsetRef OffsetItem for the CharSet 1348 * @param nglyphs the number of glyphs in the font 1349 */ 1350 protected void CreateCharset(OffsetItem charsetRef,int nglyphs) 1351 { 1352 OutputList.addLast(new MarkerItem(charsetRef)); 1353 OutputList.addLast(new UInt8Item((char)2)); // format identifier 1354 OutputList.addLast(new UInt16Item((char)1)); // first glyph in range (ignore .notdef) 1355 OutputList.addLast(new UInt16Item((char)(nglyphs-1))); // nLeft 1356 } 1357 1358 /** 1359 * Function creates new FDArray for non-CID fonts. 1360 * The FDArray built has only the "Private" operator that points to the font's 1361 * original private dict 1362 * @param fdarrayRef OffsetItem for the FDArray 1363 * @param privateRef OffsetItem for the Private Dict 1364 * @param Font the font 1365 */ 1366 protected void CreateFDArray(OffsetItem fdarrayRef,OffsetItem privateRef,int Font) 1367 { 1368 OutputList.addLast(new MarkerItem(fdarrayRef)); 1369 // Build the header (count=offsize=first=1) 1370 BuildIndexHeader(1,1,1); 1371 1372 // Mark 1373 OffsetItem privateIndex1Ref = new IndexOffsetItem(1); 1374 OutputList.addLast(privateIndex1Ref); 1375 IndexBaseItem privateBase = new IndexBaseItem(); 1376 // Insert the private operands and operator 1377 OutputList.addLast(privateBase); 1378 // Calc the new size of the private after subsetting 1379 // Origianl size 1380 int NewSize = fonts[Font].privateLength; 1381 // Calc the original size of the Subr offset in the private 1382 int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].privateOffset,fonts[Font].privateLength); 1383 // Increase the ptivate's size 1384 if (OrgSubrsOffsetSize != 0) 1385 NewSize += 5-OrgSubrsOffsetSize; 1386 OutputList.addLast(new DictNumberItem(NewSize)); 1387 OutputList.addLast(privateRef); 1388 OutputList.addLast(new UInt8Item((char)18)); // Private 1389 1390 OutputList.addLast(new IndexMarkerItem(privateIndex1Ref,privateBase)); 1391 } 1392 1393 /** 1394 * Function reconstructs the FDArray, PrivateDict and LSubr for CID fonts 1395 * @param Font the font 1396 */ 1397 void Reconstruct(int Font) 1398 { 1399 // Init for later use 1400 OffsetItem[] fdPrivate = new DictOffsetItem[fonts[Font].FDArrayOffsets.length-1]; 1401 IndexBaseItem[] fdPrivateBase = new IndexBaseItem[fonts[Font].fdprivateOffsets.length]; 1402 OffsetItem[] fdSubrs = new DictOffsetItem[fonts[Font].fdprivateOffsets.length]; 1403 // Reconstruct each type 1404 ReconstructFDArray(Font,fdPrivate); 1405 ReconstructPrivateDict(Font,fdPrivate,fdPrivateBase,fdSubrs); 1406 ReconstructPrivateSubrs(Font,fdPrivateBase,fdSubrs); 1407 } 1408 1409 /** 1410 * Function subsets the FDArray and builds the new one with new offsets 1411 * @param Font The font 1412 * @param fdPrivate OffsetItem Array (one for each FDArray) 1413 */ 1414 void ReconstructFDArray(int Font,OffsetItem[] fdPrivate) 1415 { 1416 // Build the header of the index 1417 BuildIndexHeader(fonts[Font].FDArrayCount,fonts[Font].FDArrayOffsize,1); 1418 1419 // For each offset create an Offset Item 1420 OffsetItem[] fdOffsets = new IndexOffsetItem[fonts[Font].FDArrayOffsets.length-1]; 1421 for (int i=0;i<fonts[Font].FDArrayOffsets.length-1;i++) 1422 { 1423 fdOffsets[i] = new IndexOffsetItem(fonts[Font].FDArrayOffsize); 1424 OutputList.addLast(fdOffsets[i]); 1425 } 1426 1427 // Declare beginning of the object array 1428 IndexBaseItem fdArrayBase = new IndexBaseItem(); 1429 OutputList.addLast(fdArrayBase); 1430 1431 // For each object check if that FD is used. 1432 // if is used build a new one by changing the private object 1433 // Else do nothing 1434 // At the end of each object mark its ending (Even if wasn't written) 1435 for (int k=0; k<fonts[Font].FDArrayOffsets.length-1; k++) { 1436// if (FDArrayUsed.contains(Integer.valueOf(k))) 1437// { 1438 // Goto beginning of objects 1439 seek(fonts[Font].FDArrayOffsets[k]); 1440 while (getPosition() < fonts[Font].FDArrayOffsets[k+1]) 1441 { 1442 int p1 = getPosition(); 1443 getDictItem(); 1444 int p2 = getPosition(); 1445 // If the dictItem is the "Private" then compute and copy length, 1446 // use marker for offset and write operator number 1447 if (key=="Private") { 1448 // Save the original length of the private dict 1449 int NewSize = ((Integer)args[0]).intValue(); 1450 // Save the size of the offset to the subrs in that private 1451 int OrgSubrsOffsetSize = CalcSubrOffsetSize(fonts[Font].fdprivateOffsets[k],fonts[Font].fdprivateLengths[k]); 1452 // Increase the private's length accordingly 1453 if (OrgSubrsOffsetSize != 0) 1454 NewSize += 5-OrgSubrsOffsetSize; 1455 // Insert the new size, OffsetItem and operator key number 1456 OutputList.addLast(new DictNumberItem(NewSize)); 1457 fdPrivate[k] = new DictOffsetItem(); 1458 OutputList.addLast(fdPrivate[k]); 1459 OutputList.addLast(new UInt8Item((char)18)); // Private 1460 // Go back to place 1461 seek(p2); 1462 } 1463 // Else copy the entire range 1464 else // other than private 1465 OutputList.addLast(new RangeItem(buf,p1,p2-p1)); 1466 } 1467// } 1468 // Mark the ending of the object (even if wasn't written) 1469 OutputList.addLast(new IndexMarkerItem(fdOffsets[k],fdArrayBase)); 1470 } 1471 } 1472 /** 1473 * Function Adds the new private dicts (only for the FDs used) to the list 1474 * @param Font the font 1475 * @param fdPrivate OffsetItem array one element for each private 1476 * @param fdPrivateBase IndexBaseItem array one element for each private 1477 * @param fdSubrs OffsetItem array one element for each private 1478 */ 1479 void ReconstructPrivateDict(int Font,OffsetItem[] fdPrivate,IndexBaseItem[] fdPrivateBase, 1480 OffsetItem[] fdSubrs) 1481 { 1482 1483 // For each fdarray private dict check if that FD is used. 1484 // if is used build a new one by changing the subrs offset 1485 // Else do nothing 1486 for (int i=0;i<fonts[Font].fdprivateOffsets.length;i++) 1487 { 1488// if (FDArrayUsed.contains(Integer.valueOf(i))) 1489// { 1490 // Mark beginning 1491 OutputList.addLast(new MarkerItem(fdPrivate[i])); 1492 fdPrivateBase[i] = new IndexBaseItem(); 1493 OutputList.addLast(fdPrivateBase[i]); 1494 // Goto beginning of objects 1495 seek(fonts[Font].fdprivateOffsets[i]); 1496 while (getPosition() < fonts[Font].fdprivateOffsets[i]+fonts[Font].fdprivateLengths[i]) 1497 { 1498 int p1 = getPosition(); 1499 getDictItem(); 1500 int p2 = getPosition(); 1501 // If the dictItem is the "Subrs" then, 1502 // use marker for offset and write operator number 1503 if (key=="Subrs") { 1504 fdSubrs[i] = new DictOffsetItem(); 1505 OutputList.addLast(fdSubrs[i]); 1506 OutputList.addLast(new UInt8Item((char)19)); // Subrs 1507 } 1508 // Else copy the entire range 1509 else 1510 OutputList.addLast(new RangeItem(buf,p1,p2-p1)); 1511 } 1512// } 1513 } 1514 } 1515 1516 /** 1517 * Function Adds the new LSubrs dicts (only for the FDs used) to the list 1518 * @param Font The index of the font 1519 * @param fdPrivateBase The IndexBaseItem array for the linked list 1520 * @param fdSubrs OffsetItem array for the linked list 1521 */ 1522 1523 void ReconstructPrivateSubrs(int Font,IndexBaseItem[] fdPrivateBase, 1524 OffsetItem[] fdSubrs) 1525 { 1526 // For each private dict 1527 for (int i=0;i<fonts[Font].fdprivateLengths.length;i++) 1528 { 1529 // If that private dict's Subrs are used insert the new LSubrs 1530 // computed earlier 1531 if (fdSubrs[i]!= null && fonts[Font].PrivateSubrsOffset[i] >= 0) 1532 { 1533 OutputList.addLast(new SubrMarkerItem(fdSubrs[i],fdPrivateBase[i])); 1534 OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewLSubrsIndex[i]),0,NewLSubrsIndex[i].length)); 1535 } 1536 } 1537 } 1538 1539 /** 1540 * Calculates how many byte it took to write the offset for the subrs in a specific 1541 * private dict. 1542 * @param Offset The Offset for the private dict 1543 * @param Size The size of the private dict 1544 * @return The size of the offset of the subrs in the private dict 1545 */ 1546 int CalcSubrOffsetSize(int Offset,int Size) 1547 { 1548 // Set the size to 0 1549 int OffsetSize = 0; 1550 // Go to the beginning of the private dict 1551 seek(Offset); 1552 // Go until the end of the private dict 1553 while (getPosition() < Offset+Size) 1554 { 1555 int p1 = getPosition(); 1556 getDictItem(); 1557 int p2 = getPosition(); 1558 // When reached to the subrs offset 1559 if (key=="Subrs") { 1560 // The Offsize (minus the subrs key) 1561 OffsetSize = p2-p1-1; 1562 } 1563 // All other keys are ignored 1564 } 1565 // return the size 1566 return OffsetSize; 1567 } 1568 1569 /** 1570 * Function computes the size of an index 1571 * @param indexOffset The offset for the computed index 1572 * @return The size of the index 1573 */ 1574 protected int countEntireIndexRange(int indexOffset) 1575 { 1576 // Go to the beginning of the index 1577 seek(indexOffset); 1578 // Read the count field 1579 int count = getCard16(); 1580 // If count==0 -> size=2 1581 if (count==0) 1582 return 2; 1583 else 1584 { 1585 // Read the offsize field 1586 int indexOffSize = getCard8(); 1587 // Go to the last element of the offset array 1588 seek(indexOffset+2+1+count*indexOffSize); 1589 // The size of the object array is the value of the last element-1 1590 int size = getOffset(indexOffSize)-1; 1591 // Return the size of the entire index 1592 return 2+1+(count+1)*indexOffSize+size; 1593 } 1594 } 1595 1596 /** 1597 * The function creates a private dict for a font that was not CID 1598 * All the keys are copied as is except for the subrs key 1599 * @param Font the font 1600 * @param Subr The OffsetItem for the subrs of the private 1601 */ 1602 void CreateNonCIDPrivate(int Font,OffsetItem Subr) 1603 { 1604 // Go to the beginning of the private dict and read until the end 1605 seek(fonts[Font].privateOffset); 1606 while (getPosition() < fonts[Font].privateOffset+fonts[Font].privateLength) 1607 { 1608 int p1 = getPosition(); 1609 getDictItem(); 1610 int p2 = getPosition(); 1611 // If the dictItem is the "Subrs" then, 1612 // use marker for offset and write operator number 1613 if (key=="Subrs") { 1614 OutputList.addLast(Subr); 1615 OutputList.addLast(new UInt8Item((char)19)); // Subrs 1616 } 1617 // Else copy the entire range 1618 else 1619 OutputList.addLast(new RangeItem(buf,p1,p2-p1)); 1620 } 1621 } 1622 1623 /** 1624 * the function marks the beginning of the subrs index and adds the subsetted subrs 1625 * index to the output list. 1626 * @param Font the font 1627 * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs 1628 * @param Subrs OffsetItem for the subrs 1629 */ 1630 void CreateNonCIDSubrs(int Font,IndexBaseItem PrivateBase,OffsetItem Subrs) 1631 { 1632 // Mark the beginning of the Subrs index 1633 OutputList.addLast(new SubrMarkerItem(Subrs,PrivateBase)); 1634 // Put the subsetted new subrs index 1635 if (NewSubrsIndexNonCID != null) { 1636 OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(NewSubrsIndexNonCID),0,NewSubrsIndexNonCID.length)); 1637 } 1638 } 1639}