0001: /*
0002: * $Id: CFFFontSubset.java 2671 2007-04-03 16:08:04Z psoares33 $
0003: * $Name$
0004: *
0005: * Copyright 2004 Oren Manor and Ygal Blum
0006: *
0007: * The contents of this file are subject to the Mozilla Public License Version 1.1
0008: * (the "License"); you may not use this file except in compliance with the License.
0009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the License.
0014: *
0015: * The Original Code is 'iText, a free JAVA-PDF library'.
0016: *
0017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0018: * the Initial Developer are Copyright (C) 1999-2005 by Bruno Lowagie.
0019: * All Rights Reserved.
0020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0021: * are Copyright (C) 2000-2005 by Paulo Soares. All Rights Reserved.
0022: *
0023: * Contributor(s): all the names of the contributors are added in the source code
0024: * where applicable.
0025: *
0026: * Alternatively, the contents of this file may be used under the terms of the
0027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0028: * provisions of LGPL are applicable instead of those above. If you wish to
0029: * allow use of your version of this file only under the terms of the LGPL
0030: * License and not to allow others to use your version of this file under
0031: * the MPL, indicate your decision by deleting the provisions above and
0032: * replace them with the notice and other provisions required by the LGPL.
0033: * If you do not delete the provisions above, a recipient may use your version
0034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0035: *
0036: * This library is free software; you can redistribute it and/or modify it
0037: * under the terms of the MPL as stated above or under the terms of the GNU
0038: * Library General Public License as published by the Free Software Foundation;
0039: * either version 2 of the License, or any later version.
0040: *
0041: * This library is distributed in the hope that it will be useful, but WITHOUT
0042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0044: * details.
0045: *
0046: * If you didn't download this code from the following link, you should check if
0047: * you aren't using an obsolete version:
0048: * http://www.lowagie.com/iText/
0049: */
0050: package com.lowagie.text.pdf;
0051:
0052: import java.io.IOException;
0053: import java.util.ArrayList;
0054: import java.util.HashMap;
0055: import java.util.Iterator;
0056: import java.util.LinkedList;
0057:
0058: /**
0059: * This Class subsets a CFF Type Font. The subset is preformed for CID fonts and NON CID fonts.
0060: * The Charstring is subseted for both types. For CID fonts only the FDArray which are used are embedded.
0061: * The Lsubroutines of the FDArrays used are subsetted as well. The Subroutine subset supports both Type1 and Type2
0062: * formatting altough only tested on Type2 Format.
0063: * For Non CID the Lsubroutines are subsetted. On both types the Gsubroutines is subsetted.
0064: * A font which was not of CID type is transformed into CID as a part of the subset process.
0065: * The CID synthetic creation was written by Sivan Toledo (sivan@math.tau.ac.il)
0066: * @author Oren Manor (manorore@post.tau.ac.il) and Ygal Blum (blumygal@post.tau.ac.il)
0067: */
0068: public class CFFFontSubset extends CFFFont {
0069:
0070: /**
0071: * The Strings in this array represent Type1/Type2 operator names
0072: */
0073: static final String SubrsFunctions[] = { "RESERVED_0", "hstem",
0074: "RESERVED_2", "vstem", "vmoveto", "rlineto", "hlineto",
0075: "vlineto", "rrcurveto", "RESERVED_9", "callsubr", "return",
0076: "escape", "RESERVED_13", "endchar", "RESERVED_15",
0077: "RESERVED_16", "RESERVED_17", "hstemhm", "hintmask",
0078: "cntrmask", "rmoveto", "hmoveto", "vstemhm", "rcurveline",
0079: "rlinecurve", "vvcurveto", "hhcurveto", "shortint",
0080: "callgsubr", "vhcurveto", "hvcurveto" };
0081: /**
0082: * The Strings in this array represent Type1/Type2 escape operator names
0083: */
0084: static final String SubrsEscapeFuncs[] = { "RESERVED_0",
0085: "RESERVED_1", "RESERVED_2", "and", "or", "not",
0086: "RESERVED_6", "RESERVED_7", "RESERVED_8", "abs", "add",
0087: "sub", "div", "RESERVED_13", "neg", "eq", "RESERVED_16",
0088: "RESERVED_17", "drop", "RESERVED_19", "put", "get",
0089: "ifelse", "random", "mul", "RESERVED_25", "sqrt", "dup",
0090: "exch", "index", "roll", "RESERVED_31", "RESERVED_32",
0091: "RESERVED_33", "hflex", "flex", "hflex1", "flex1",
0092: "RESERVED_REST" };
0093:
0094: /**
0095: * A HashMap containing the glyphs used in the text after being converted
0096: * to glyph number by the CMap
0097: */
0098: HashMap GlyphsUsed;
0099: /**
0100: * The GlyphsUsed keys as an ArrayList
0101: */
0102: ArrayList glyphsInList;
0103: /**
0104: * A HashMap for keeping the FDArrays being used by the font
0105: */
0106: HashMap FDArrayUsed = new HashMap();
0107: /**
0108: * A HashMaps array for keeping the subroutines used in each FontDict
0109: */
0110: HashMap[] hSubrsUsed;
0111: /**
0112: * The SubroutinesUsed HashMaps as ArrayLists
0113: */
0114: ArrayList[] lSubrsUsed;
0115: /**
0116: * A HashMap for keeping the Global subroutines used in the font
0117: */
0118: HashMap hGSubrsUsed = new HashMap();
0119: /**
0120: * The Global SubroutinesUsed HashMaps as ArrayLists
0121: */
0122: ArrayList lGSubrsUsed = new ArrayList();
0123: /**
0124: * A HashMap for keeping the subroutines used in a non-cid font
0125: */
0126: HashMap hSubrsUsedNonCID = new HashMap();
0127: /**
0128: * The SubroutinesUsed HashMap as ArrayList
0129: */
0130: ArrayList lSubrsUsedNonCID = new ArrayList();
0131: /**
0132: * An array of the new Indexs for the local Subr. One index for each FontDict
0133: */
0134: byte[][] NewLSubrsIndex;
0135: /**
0136: * The new subroutines index for a non-cid font
0137: */
0138: byte[] NewSubrsIndexNonCID;
0139: /**
0140: * The new global subroutines index of the font
0141: */
0142: byte[] NewGSubrsIndex;
0143: /**
0144: * The new CharString of the font
0145: */
0146: byte[] NewCharStringsIndex;
0147:
0148: /**
0149: * The bias for the global subroutines
0150: */
0151: int GBias = 0;
0152:
0153: /**
0154: * The linked list for generating the new font stream
0155: */
0156: LinkedList OutputList;
0157:
0158: /**
0159: * Number of arguments to the stem operators in a subroutine calculated recursivly
0160: */
0161: int NumOfHints = 0;
0162:
0163: /**
0164: * C'tor for CFFFontSubset
0165: * @param rf - The font file
0166: * @param GlyphsUsed - a HashMap that contains the glyph used in the subset
0167: */
0168: public CFFFontSubset(RandomAccessFileOrArray rf, HashMap GlyphsUsed) {
0169: // Use CFFFont c'tor in order to parse the font file.
0170: super (rf);
0171: this .GlyphsUsed = GlyphsUsed;
0172: //Put the glyphs into a list
0173: glyphsInList = new ArrayList(GlyphsUsed.keySet());
0174:
0175: for (int i = 0; i < fonts.length; ++i) {
0176: // Read the number of glyphs in the font
0177: seek(fonts[i].charstringsOffset);
0178: fonts[i].nglyphs = getCard16();
0179:
0180: // Jump to the count field of the String Index
0181: seek(stringIndexOffset);
0182: fonts[i].nstrings = getCard16() + standardStrings.length;
0183:
0184: // For each font save the offset array of the charstring
0185: fonts[i].charstringsOffsets = getIndex(fonts[i].charstringsOffset);
0186:
0187: // Proces the FDSelect if exist
0188: if (fonts[i].fdselectOffset >= 0) {
0189: // Proces the FDSelect
0190: readFDSelect(i);
0191: // Build the FDArrayUsed hashmap
0192: BuildFDArrayUsed(i);
0193: }
0194: if (fonts[i].isCID)
0195: // Build the FD Array used Hash Map
0196: ReadFDArray(i);
0197: // compute the charset length
0198: fonts[i].CharsetLength = CountCharset(
0199: fonts[i].charsetOffset, fonts[i].nglyphs);
0200: }
0201: }
0202:
0203: /**
0204: * Calculates the length of the charset according to its format
0205: * @param Offset The Charset Offset
0206: * @param NumofGlyphs Number of glyphs in the font
0207: * @return the length of the Charset
0208: */
0209: int CountCharset(int Offset, int NumofGlyphs) {
0210: int format;
0211: int Length = 0;
0212: seek(Offset);
0213: // Read the format
0214: format = getCard8();
0215: // Calc according to format
0216: switch (format) {
0217: case 0:
0218: Length = 1 + 2 * NumofGlyphs;
0219: break;
0220: case 1:
0221: Length = 1 + 3 * CountRange(NumofGlyphs, 1);
0222: break;
0223: case 2:
0224: Length = 1 + 4 * CountRange(NumofGlyphs, 2);
0225: break;
0226: default:
0227: break;
0228: }
0229: return Length;
0230: }
0231:
0232: /**
0233: * Function calculates the number of ranges in the Charset
0234: * @param NumofGlyphs The number of glyphs in the font
0235: * @param Type The format of the Charset
0236: * @return The number of ranges in the Charset data structure
0237: */
0238: int CountRange(int NumofGlyphs, int Type) {
0239: int num = 0;
0240: char Sid;
0241: int i = 1, nLeft;
0242: while (i < NumofGlyphs) {
0243: num++;
0244: Sid = getCard16();
0245: if (Type == 1)
0246: nLeft = getCard8();
0247: else
0248: nLeft = getCard16();
0249: i += nLeft + 1;
0250: }
0251: return num;
0252: }
0253:
0254: /**
0255: * Read the FDSelect of the font and compute the array and its length
0256: * @param Font The index of the font being processed
0257: */
0258: protected void readFDSelect(int Font) {
0259: // Restore the number of glyphs
0260: int NumOfGlyphs = fonts[Font].nglyphs;
0261: int[] FDSelect = new int[NumOfGlyphs];
0262: // Go to the beginning of the FDSelect
0263: seek(fonts[Font].fdselectOffset);
0264: // Read the FDSelect's format
0265: fonts[Font].FDSelectFormat = getCard8();
0266:
0267: switch (fonts[Font].FDSelectFormat) {
0268: // Format==0 means each glyph has an entry that indicated
0269: // its FD.
0270: case 0:
0271: for (int i = 0; i < NumOfGlyphs; i++) {
0272: FDSelect[i] = getCard8();
0273: }
0274: // The FDSelect's Length is one for each glyph + the format
0275: // for later use
0276: fonts[Font].FDSelectLength = fonts[Font].nglyphs + 1;
0277: break;
0278: case 3:
0279: // Format==3 means the ranges version
0280: // The number of ranges
0281: int nRanges = getCard16();
0282: int l = 0;
0283: // Read the first in the first range
0284: int first = getCard16();
0285: for (int i = 0; i < nRanges; i++) {
0286: // Read the FD index
0287: int fd = getCard8();
0288: // Read the first of the next range
0289: int last = getCard16();
0290: // Calc the steps and write to the array
0291: int steps = last - first;
0292: for (int k = 0; k < steps; k++) {
0293: FDSelect[l] = fd;
0294: l++;
0295: }
0296: // The last from this iteration is the first of the next
0297: first = last;
0298: }
0299: // Store the length for later use
0300: fonts[Font].FDSelectLength = 1 + 2 + nRanges * 3 + 2;
0301: break;
0302: default:
0303: break;
0304: }
0305: // Save the FDSelect of the font
0306: fonts[Font].FDSelect = FDSelect;
0307: }
0308:
0309: /**
0310: * Function reads the FDSelect and builds the FDArrayUsed HashMap According to the glyphs used
0311: * @param Font the Number of font being processed
0312: */
0313: protected void BuildFDArrayUsed(int Font) {
0314: int[] FDSelect = fonts[Font].FDSelect;
0315: // For each glyph used
0316: for (int i = 0; i < glyphsInList.size(); i++) {
0317: // Pop the glyphs index
0318: int glyph = ((Integer) glyphsInList.get(i)).intValue();
0319: // Pop the glyph's FD
0320: int FD = FDSelect[glyph];
0321: // Put the FD index into the FDArrayUsed HashMap
0322: FDArrayUsed.put(new Integer(FD), null);
0323: }
0324: }
0325:
0326: /**
0327: * Read the FDArray count, offsize and Offset array
0328: * @param Font
0329: */
0330: protected void ReadFDArray(int Font) {
0331: seek(fonts[Font].fdarrayOffset);
0332: fonts[Font].FDArrayCount = getCard16();
0333: fonts[Font].FDArrayOffsize = getCard8();
0334: // Since we will change values inside the FDArray objects
0335: // We increase its offsize to prevent errors
0336: if (fonts[Font].FDArrayOffsize < 4)
0337: fonts[Font].FDArrayOffsize++;
0338: fonts[Font].FDArrayOffsets = getIndex(fonts[Font].fdarrayOffset);
0339: }
0340:
0341: /**
0342: * The Process function extracts one font out of the CFF file and returns a
0343: * subset version of the original.
0344: * @param fontName - The name of the font to be taken out of the CFF
0345: * @return The new font stream
0346: * @throws IOException
0347: */
0348: public byte[] Process(String fontName) throws IOException {
0349: try {
0350: // Verify that the file is open
0351: buf.reOpen();
0352: // Find the Font that we will be dealing with
0353: int j;
0354: for (j = 0; j < fonts.length; j++)
0355: if (fontName.equals(fonts[j].name))
0356: break;
0357: if (j == fonts.length)
0358: return null;
0359:
0360: // Calc the bias for the global subrs
0361: if (gsubrIndexOffset >= 0)
0362: GBias = CalcBias(gsubrIndexOffset, j);
0363:
0364: // Prepare the new CharStrings Index
0365: BuildNewCharString(j);
0366: // Prepare the new Global and Local Subrs Indices
0367: BuildNewLGSubrs(j);
0368: // Build the new file
0369: byte[] Ret = BuildNewFile(j);
0370: return Ret;
0371: } finally {
0372: try {
0373: buf.close();
0374: } catch (Exception e) {
0375: // empty on purpose
0376: }
0377: }
0378: }
0379:
0380: /**
0381: * Function calcs bias according to the CharString type and the count
0382: * of the subrs
0383: * @param Offset The offset to the relevent subrs index
0384: * @param Font the font
0385: * @return The calculated Bias
0386: */
0387: protected int CalcBias(int Offset, int Font) {
0388: seek(Offset);
0389: int nSubrs = getCard16();
0390: // If type==1 -> bias=0
0391: if (fonts[Font].CharstringType == 1)
0392: return 0;
0393: // else calc according to the count
0394: else if (nSubrs < 1240)
0395: return 107;
0396: else if (nSubrs < 33900)
0397: return 1131;
0398: else
0399: return 32768;
0400: }
0401:
0402: /**
0403: *Function uses BuildNewIndex to create the new index of the subset charstrings
0404: * @param FontIndex the font
0405: * @throws IOException
0406: */
0407: protected void BuildNewCharString(int FontIndex) throws IOException {
0408: NewCharStringsIndex = BuildNewIndex(
0409: fonts[FontIndex].charstringsOffsets, GlyphsUsed);
0410: }
0411:
0412: /**
0413: * Function builds the new local & global subsrs indices. IF CID then All of
0414: * the FD Array lsubrs will be subsetted.
0415: * @param Font the font
0416: * @throws IOException
0417: */
0418: protected void BuildNewLGSubrs(int Font) throws IOException {
0419: // If the font is CID then the lsubrs are divided into FontDicts.
0420: // for each FD array the lsubrs will be subsetted.
0421: if (fonts[Font].isCID) {
0422: // Init the hasmap-array and the arraylist-array to hold the subrs used
0423: // in each private dict.
0424: hSubrsUsed = new HashMap[fonts[Font].fdprivateOffsets.length];
0425: lSubrsUsed = new ArrayList[fonts[Font].fdprivateOffsets.length];
0426: // A [][] which will store the byte array for each new FD Array lsubs index
0427: NewLSubrsIndex = new byte[fonts[Font].fdprivateOffsets.length][];
0428: // An array to hold the offset for each Lsubr index
0429: fonts[Font].PrivateSubrsOffset = new int[fonts[Font].fdprivateOffsets.length];
0430: // A [][] which will store the offset array for each lsubr index
0431: fonts[Font].PrivateSubrsOffsetsArray = new int[fonts[Font].fdprivateOffsets.length][];
0432:
0433: // Put the FDarrayUsed into a list
0434: ArrayList FDInList = new ArrayList(FDArrayUsed.keySet());
0435: // For each FD array which is used subset the lsubr
0436: for (int j = 0; j < FDInList.size(); j++) {
0437: // The FDArray index, Hash Map, Arrat List to work on
0438: int FD = ((Integer) FDInList.get(j)).intValue();
0439: hSubrsUsed[FD] = new HashMap();
0440: lSubrsUsed[FD] = new ArrayList();
0441: //Reads the private dicts looking for the subr operator and
0442: // store both the offest for the index and its offset array
0443: BuildFDSubrsOffsets(Font, FD);
0444: // Verify that FDPrivate has a LSubrs index
0445: if (fonts[Font].PrivateSubrsOffset[FD] >= 0) {
0446: //Scans the Charsting data storing the used Local and Global subroutines
0447: // by the glyphs. Scans the Subrs recursivley.
0448: BuildSubrUsed(Font, FD,
0449: fonts[Font].PrivateSubrsOffset[FD],
0450: fonts[Font].PrivateSubrsOffsetsArray[FD],
0451: hSubrsUsed[FD], lSubrsUsed[FD]);
0452: // Builds the New Local Subrs index
0453: NewLSubrsIndex[FD] = BuildNewIndex(
0454: fonts[Font].PrivateSubrsOffsetsArray[FD],
0455: hSubrsUsed[FD]);
0456: }
0457: }
0458: }
0459: // If the font is not CID && the Private Subr exists then subset:
0460: else if (fonts[Font].privateSubrs >= 0) {
0461: // Build the subrs offsets;
0462: fonts[Font].SubrsOffsets = getIndex(fonts[Font].privateSubrs);
0463: //Scans the Charsting data storing the used Local and Global subroutines
0464: // by the glyphs. Scans the Subrs recursivley.
0465: BuildSubrUsed(Font, -1, fonts[Font].privateSubrs,
0466: fonts[Font].SubrsOffsets, hSubrsUsedNonCID,
0467: lSubrsUsedNonCID);
0468: }
0469: // For all fonts susbset the Global Subroutines
0470: // Scan the Global Subr Hashmap recursivly on the Gsubrs
0471: BuildGSubrsUsed(Font);
0472: if (fonts[Font].privateSubrs >= 0)
0473: // Builds the New Local Subrs index
0474: NewSubrsIndexNonCID = BuildNewIndex(
0475: fonts[Font].SubrsOffsets, hSubrsUsedNonCID);
0476: //Builds the New Global Subrs index
0477: NewGSubrsIndex = BuildNewIndex(gsubrOffsets, hGSubrsUsed);
0478: }
0479:
0480: /**
0481: * The function finds for the FD array processed the local subr offset and its
0482: * offset array.
0483: * @param Font the font
0484: * @param FD The FDARRAY processed
0485: */
0486: protected void BuildFDSubrsOffsets(int Font, int FD) {
0487: // Initiate to -1 to indicate lsubr operator present
0488: fonts[Font].PrivateSubrsOffset[FD] = -1;
0489: // Goto begining of objects
0490: seek(fonts[Font].fdprivateOffsets[FD]);
0491: // While in the same object:
0492: while (getPosition() < fonts[Font].fdprivateOffsets[FD]
0493: + fonts[Font].fdprivateLengths[FD]) {
0494: getDictItem();
0495: // If the dictItem is the "Subrs" then find and store offset,
0496: if (key == "Subrs")
0497: fonts[Font].PrivateSubrsOffset[FD] = ((Integer) args[0])
0498: .intValue()
0499: + fonts[Font].fdprivateOffsets[FD];
0500: }
0501: //Read the lsub index if the lsubr was found
0502: if (fonts[Font].PrivateSubrsOffset[FD] >= 0)
0503: fonts[Font].PrivateSubrsOffsetsArray[FD] = getIndex(fonts[Font].PrivateSubrsOffset[FD]);
0504: }
0505:
0506: /**
0507: * Function uses ReadAsubr on the glyph used to build the LSubr & Gsubr HashMap.
0508: * The HashMap (of the lsub only) is then scaned recursivly for Lsubr & Gsubrs
0509: * calls.
0510: * @param Font the font
0511: * @param FD FD array processed. 0 indicates function was called by non CID font
0512: * @param SubrOffset the offset to the subr index to calc the bias
0513: * @param SubrsOffsets the offset array of the subr index
0514: * @param hSubr HashMap of the subrs used
0515: * @param lSubr ArrayList of the subrs used
0516: */
0517: protected void BuildSubrUsed(int Font, int FD, int SubrOffset,
0518: int[] SubrsOffsets, HashMap hSubr, ArrayList lSubr) {
0519:
0520: // Calc the Bias for the subr index
0521: int LBias = CalcBias(SubrOffset, Font);
0522:
0523: // For each glyph used find its GID, start & end pos
0524: for (int i = 0; i < glyphsInList.size(); i++) {
0525: int glyph = ((Integer) glyphsInList.get(i)).intValue();
0526: int Start = fonts[Font].charstringsOffsets[glyph];
0527: int End = fonts[Font].charstringsOffsets[glyph + 1];
0528:
0529: // IF CID:
0530: if (FD >= 0) {
0531: EmptyStack();
0532: NumOfHints = 0;
0533: // Using FDSELECT find the FD Array the glyph belongs to.
0534: int GlyphFD = fonts[Font].FDSelect[glyph];
0535: // If the Glyph is part of the FD being processed
0536: if (GlyphFD == FD)
0537: // Find the Subrs called by the glyph and insert to hash:
0538: ReadASubr(Start, End, GBias, LBias, hSubr, lSubr,
0539: SubrsOffsets);
0540: } else
0541: // If the font is not CID
0542: //Find the Subrs called by the glyph and insert to hash:
0543: ReadASubr(Start, End, GBias, LBias, hSubr, lSubr,
0544: SubrsOffsets);
0545: }
0546: // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used
0547: for (int i = 0; i < lSubr.size(); i++) {
0548: // Pop the subr value from the hash
0549: int Subr = ((Integer) lSubr.get(i)).intValue();
0550: // Ensure the Lsubr call is valid
0551: if (Subr < SubrsOffsets.length - 1 && Subr >= 0) {
0552: // Read and process the subr
0553: int Start = SubrsOffsets[Subr];
0554: int End = SubrsOffsets[Subr + 1];
0555: ReadASubr(Start, End, GBias, LBias, hSubr, lSubr,
0556: SubrsOffsets);
0557: }
0558: }
0559: }
0560:
0561: /**
0562: * Function scans the Glsubr used ArrayList to find recursive calls
0563: * to Gsubrs and adds to Hashmap & ArrayList
0564: * @param Font the font
0565: */
0566: protected void BuildGSubrsUsed(int Font) {
0567: int LBias = 0;
0568: int SizeOfNonCIDSubrsUsed = 0;
0569: if (fonts[Font].privateSubrs >= 0) {
0570: LBias = CalcBias(fonts[Font].privateSubrs, Font);
0571: SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
0572: }
0573:
0574: // For each global subr used
0575: for (int i = 0; i < lGSubrsUsed.size(); i++) {
0576: //Pop the value + check valid
0577: int Subr = ((Integer) lGSubrsUsed.get(i)).intValue();
0578: if (Subr < gsubrOffsets.length - 1 && Subr >= 0) {
0579: // Read the subr and process
0580: int Start = gsubrOffsets[Subr];
0581: int End = gsubrOffsets[Subr + 1];
0582:
0583: if (fonts[Font].isCID)
0584: ReadASubr(Start, End, GBias, 0, hGSubrsUsed,
0585: lGSubrsUsed, null);
0586: else {
0587: ReadASubr(Start, End, GBias, LBias,
0588: hSubrsUsedNonCID, lSubrsUsedNonCID,
0589: fonts[Font].SubrsOffsets);
0590: if (SizeOfNonCIDSubrsUsed < lSubrsUsedNonCID.size()) {
0591: for (int j = SizeOfNonCIDSubrsUsed; j < lSubrsUsedNonCID
0592: .size(); j++) {
0593: //Pop the value + check valid
0594: int LSubr = ((Integer) lSubrsUsedNonCID
0595: .get(j)).intValue();
0596: if (LSubr < fonts[Font].SubrsOffsets.length - 1
0597: && LSubr >= 0) {
0598: // Read the subr and process
0599: int LStart = fonts[Font].SubrsOffsets[LSubr];
0600: int LEnd = fonts[Font].SubrsOffsets[LSubr + 1];
0601: ReadASubr(LStart, LEnd, GBias, LBias,
0602: hSubrsUsedNonCID,
0603: lSubrsUsedNonCID,
0604: fonts[Font].SubrsOffsets);
0605: }
0606: }
0607: SizeOfNonCIDSubrsUsed = lSubrsUsedNonCID.size();
0608: }
0609: }
0610: }
0611: }
0612: }
0613:
0614: /**
0615: * The function reads a subrs (glyph info) between begin and end.
0616: * Adds calls to a Lsubr to the hSubr and lSubrs.
0617: * Adds calls to a Gsubr to the hGSubr and lGSubrs.
0618: * @param begin the start point of the subr
0619: * @param end the end point of the subr
0620: * @param GBias the bias of the Global Subrs
0621: * @param LBias the bias of the Local Subrs
0622: * @param hSubr the HashMap for the lSubrs
0623: * @param lSubr the ArrayList for the lSubrs
0624: */
0625: protected void ReadASubr(int begin, int end, int GBias, int LBias,
0626: HashMap hSubr, ArrayList lSubr, int[] LSubrsOffsets) {
0627: // Clear the stack for the subrs
0628: EmptyStack();
0629: NumOfHints = 0;
0630: // Goto begining of the subr
0631: seek(begin);
0632: while (getPosition() < end) {
0633: // Read the next command
0634: ReadCommand();
0635: int pos = getPosition();
0636: Object TopElement = null;
0637: if (arg_count > 0)
0638: TopElement = args[arg_count - 1];
0639: int NumOfArgs = arg_count;
0640: // Check the modification needed on the Argument Stack according to key;
0641: HandelStack();
0642: // a call to a Lsubr
0643: if (key == "callsubr") {
0644: // Verify that arguments are passed
0645: if (NumOfArgs > 0) {
0646: // Calc the index of the Subrs
0647: int Subr = ((Integer) TopElement).intValue()
0648: + LBias;
0649: // If the subr isn't in the HashMap -> Put in
0650: if (!hSubr.containsKey(new Integer(Subr))) {
0651: hSubr.put(new Integer(Subr), null);
0652: lSubr.add(new Integer(Subr));
0653: }
0654: CalcHints(LSubrsOffsets[Subr],
0655: LSubrsOffsets[Subr + 1], LBias, GBias,
0656: LSubrsOffsets);
0657: seek(pos);
0658: }
0659: }
0660: // a call to a Gsubr
0661: else if (key == "callgsubr") {
0662: // Verify that arguments are passed
0663: if (NumOfArgs > 0) {
0664: // Calc the index of the Subrs
0665: int Subr = ((Integer) TopElement).intValue()
0666: + GBias;
0667: // If the subr isn't in the HashMap -> Put in
0668: if (!hGSubrsUsed.containsKey(new Integer(Subr))) {
0669: hGSubrsUsed.put(new Integer(Subr), null);
0670: lGSubrsUsed.add(new Integer(Subr));
0671: }
0672: CalcHints(gsubrOffsets[Subr],
0673: gsubrOffsets[Subr + 1], LBias, GBias,
0674: LSubrsOffsets);
0675: seek(pos);
0676: }
0677: }
0678: // A call to "stem"
0679: else if (key == "hstem" || key == "vstem"
0680: || key == "hstemhm" || key == "vstemhm")
0681: // Increment the NumOfHints by the number couples of of arguments
0682: NumOfHints += NumOfArgs / 2;
0683: // A call to "mask"
0684: else if (key == "hintmask" || key == "cntrmask") {
0685: // Compute the size of the mask
0686: int SizeOfMask = NumOfHints / 8;
0687: if (NumOfHints % 8 != 0 || SizeOfMask == 0)
0688: SizeOfMask++;
0689: // Continue the pointer in SizeOfMask steps
0690: for (int i = 0; i < SizeOfMask; i++)
0691: getCard8();
0692: }
0693: }
0694: }
0695:
0696: /**
0697: * Function Checks how the current operator effects the run time stack after being run
0698: * An operator may increase or decrease the stack size
0699: */
0700: protected void HandelStack() {
0701: // Findout what the operator does to the stack
0702: int StackHandel = StackOpp();
0703: if (StackHandel < 2) {
0704: // The operators that enlarge the stack by one
0705: if (StackHandel == 1)
0706: PushStack();
0707: // The operators that pop the stack
0708: else {
0709: // Abs value for the for loop
0710: StackHandel *= -1;
0711: for (int i = 0; i < StackHandel; i++)
0712: PopStack();
0713: }
0714:
0715: }
0716: // All other flush the stack
0717: else
0718: EmptyStack();
0719: }
0720:
0721: /**
0722: * Function checks the key and return the change to the stack after the operator
0723: * @return The change in the stack. 2-> flush the stack
0724: */
0725: protected int StackOpp() {
0726: if (key == "ifelse")
0727: return -3;
0728: if (key == "roll" || key == "put")
0729: return -2;
0730: if (key == "callsubr" || key == "callgsubr" || key == "add"
0731: || key == "sub" || key == "div" || key == "mul"
0732: || key == "drop" || key == "and" || key == "or"
0733: || key == "eq")
0734: return -1;
0735: if (key == "abs" || key == "neg" || key == "sqrt"
0736: || key == "exch" || key == "index" || key == "get"
0737: || key == "not" || key == "return")
0738: return 0;
0739: if (key == "random" || key == "dup")
0740: return 1;
0741: return 2;
0742: }
0743:
0744: /**
0745: * Empty the Type2 Stack
0746: *
0747: */
0748: protected void EmptyStack() {
0749: // Null the arguments
0750: for (int i = 0; i < arg_count; i++)
0751: args[i] = null;
0752: arg_count = 0;
0753: }
0754:
0755: /**
0756: * Pop one element from the stack
0757: *
0758: */
0759: protected void PopStack() {
0760: if (arg_count > 0) {
0761: args[arg_count - 1] = null;
0762: arg_count--;
0763: }
0764: }
0765:
0766: /**
0767: * Add an item to the stack
0768: *
0769: */
0770: protected void PushStack() {
0771: arg_count++;
0772: }
0773:
0774: /**
0775: * The function reads the next command after the file pointer is set
0776: */
0777: protected void ReadCommand() {
0778: key = null;
0779: boolean gotKey = false;
0780: // Until a key is found
0781: while (!gotKey) {
0782: // Read the first Char
0783: char b0 = getCard8();
0784: // decode according to the type1/type2 format
0785: if (b0 == 28) // the two next bytes represent a short int;
0786: {
0787: int first = getCard8();
0788: int second = getCard8();
0789: args[arg_count] = new Integer(first << 8 | second);
0790: arg_count++;
0791: continue;
0792: }
0793: if (b0 >= 32 && b0 <= 246) // The byte read is the byte;
0794: {
0795: args[arg_count] = new Integer(b0 - 139);
0796: arg_count++;
0797: continue;
0798: }
0799: if (b0 >= 247 && b0 <= 250) // The byte read and the next byte constetute a short int
0800: {
0801: int w = getCard8();
0802: args[arg_count] = new Integer((b0 - 247) * 256 + w
0803: + 108);
0804: arg_count++;
0805: continue;
0806: }
0807: if (b0 >= 251 && b0 <= 254)// Same as above except negative
0808: {
0809: int w = getCard8();
0810: args[arg_count] = new Integer(-(b0 - 251) * 256 - w
0811: - 108);
0812: arg_count++;
0813: continue;
0814: }
0815: if (b0 == 255)// The next for bytes represent a double.
0816: {
0817: int first = getCard8();
0818: int second = getCard8();
0819: int third = getCard8();
0820: int fourth = getCard8();
0821: args[arg_count] = new Integer(first << 24
0822: | second << 16 | third << 8 | fourth);
0823: arg_count++;
0824: continue;
0825: }
0826: if (b0 <= 31 && b0 != 28) // An operator was found.. Set Key.
0827: {
0828: gotKey = true;
0829: // 12 is an escape command therefor the next byte is a part
0830: // of this command
0831: if (b0 == 12) {
0832: int b1 = getCard8();
0833: if (b1 > SubrsEscapeFuncs.length - 1)
0834: b1 = SubrsEscapeFuncs.length - 1;
0835: key = SubrsEscapeFuncs[b1];
0836: } else
0837: key = SubrsFunctions[b0];
0838: continue;
0839: }
0840: }
0841: }
0842:
0843: /**
0844: * The function reads the subroutine and returns the number of the hint in it.
0845: * If a call to another subroutine is found the function calls recursively.
0846: * @param begin the start point of the subr
0847: * @param end the end point of the subr
0848: * @param LBias the bias of the Local Subrs
0849: * @param GBias the bias of the Global Subrs
0850: * @param LSubrsOffsets The Offsets array of the subroutines
0851: * @return The number of hints in the subroutine read.
0852: */
0853: protected int CalcHints(int begin, int end, int LBias, int GBias,
0854: int[] LSubrsOffsets) {
0855: // Goto begining of the subr
0856: seek(begin);
0857: while (getPosition() < end) {
0858: // Read the next command
0859: ReadCommand();
0860: int pos = getPosition();
0861: Object TopElement = null;
0862: if (arg_count > 0)
0863: TopElement = args[arg_count - 1];
0864: int NumOfArgs = arg_count;
0865: //Check the modification needed on the Argument Stack according to key;
0866: HandelStack();
0867: // a call to a Lsubr
0868: if (key == "callsubr") {
0869: if (NumOfArgs > 0) {
0870: int Subr = ((Integer) TopElement).intValue()
0871: + LBias;
0872: CalcHints(LSubrsOffsets[Subr],
0873: LSubrsOffsets[Subr + 1], LBias, GBias,
0874: LSubrsOffsets);
0875: seek(pos);
0876: }
0877: }
0878: // a call to a Gsubr
0879: else if (key == "callgsubr") {
0880: if (NumOfArgs > 0) {
0881: int Subr = ((Integer) TopElement).intValue()
0882: + GBias;
0883: CalcHints(gsubrOffsets[Subr],
0884: gsubrOffsets[Subr + 1], LBias, GBias,
0885: LSubrsOffsets);
0886: seek(pos);
0887: }
0888: }
0889: // A call to "stem"
0890: else if (key == "hstem" || key == "vstem"
0891: || key == "hstemhm" || key == "vstemhm")
0892: // Increment the NumOfHints by the number couples of of arguments
0893: NumOfHints += NumOfArgs / 2;
0894: // A call to "mask"
0895: else if (key == "hintmask" || key == "cntrmask") {
0896: // Compute the size of the mask
0897: int SizeOfMask = NumOfHints / 8;
0898: if (NumOfHints % 8 != 0 || SizeOfMask == 0)
0899: SizeOfMask++;
0900: // Continue the pointer in SizeOfMask steps
0901: for (int i = 0; i < SizeOfMask; i++)
0902: getCard8();
0903: }
0904: }
0905: return NumOfHints;
0906: }
0907:
0908: /**
0909: * Function builds the new offset array, object array and assembles the index.
0910: * used for creating the glyph and subrs subsetted index
0911: * @param Offsets the offset array of the original index
0912: * @param Used the hashmap of the used objects
0913: * @return the new index subset version
0914: * @throws IOException
0915: */
0916: protected byte[] BuildNewIndex(int[] Offsets, HashMap Used)
0917: throws IOException {
0918: int Offset = 0;
0919: int[] NewOffsets = new int[Offsets.length];
0920: // Build the Offsets Array for the Subset
0921: for (int i = 0; i < Offsets.length; ++i) {
0922: NewOffsets[i] = Offset;
0923: // If the object in the offset is also present in the used
0924: // HashMap then increment the offset var by its size
0925: if (Used.containsKey(new Integer(i)))
0926: Offset += Offsets[i + 1] - Offsets[i];
0927: // Else the same offset is kept in i+1.
0928: }
0929: // Offset var determines the size of the object array
0930: byte[] NewObjects = new byte[Offset];
0931: // Build the new Object array
0932: for (int i = 0; i < Offsets.length - 1; ++i) {
0933: int start = NewOffsets[i];
0934: int end = NewOffsets[i + 1];
0935: // If start != End then the Object is used
0936: // So, we will copy the object data from the font file
0937: if (start != end) {
0938: // All offsets are Global Offsets relative to the begining of the font file.
0939: // Jump the file pointer to the start address to read from.
0940: buf.seek(Offsets[i]);
0941: // Read from the buffer and write into the array at start.
0942: buf.readFully(NewObjects, start, end - start);
0943: }
0944: }
0945: // Use AssembleIndex to build the index from the offset & object arrays
0946: return AssembleIndex(NewOffsets, NewObjects);
0947: }
0948:
0949: /**
0950: * Function creates the new index, inserting the count,offsetsize,offset array
0951: * and object array.
0952: * @param NewOffsets the subsetted offset array
0953: * @param NewObjects the subsetted object array
0954: * @return the new index created
0955: */
0956: protected byte[] AssembleIndex(int[] NewOffsets, byte[] NewObjects) {
0957: // Calc the index' count field
0958: char Count = (char) (NewOffsets.length - 1);
0959: // Calc the size of the object array
0960: int Size = NewOffsets[NewOffsets.length - 1];
0961: // Calc the Offsize
0962: byte Offsize;
0963: if (Size <= 0xff)
0964: Offsize = 1;
0965: else if (Size <= 0xffff)
0966: Offsize = 2;
0967: else if (Size <= 0xffffff)
0968: Offsize = 3;
0969: else
0970: Offsize = 4;
0971: // The byte array for the new index. The size is calc by
0972: // Count=2, Offsize=1, OffsetArray = Offsize*(Count+1), The object array
0973: byte[] NewIndex = new byte[2 + 1 + Offsize * (Count + 1)
0974: + NewObjects.length];
0975: // The counter for writing
0976: int Place = 0;
0977: // Write the count field
0978: NewIndex[Place++] = (byte) ((Count >>> 8) & 0xff);
0979: NewIndex[Place++] = (byte) ((Count >>> 0) & 0xff);
0980: // Write the offsize field
0981: NewIndex[Place++] = Offsize;
0982: // Write the offset array according to the offsize
0983: for (int i = 0; i < NewOffsets.length; i++) {
0984: // The value to be written
0985: int Num = NewOffsets[i] - NewOffsets[0] + 1;
0986: // Write in bytes according to the offsize
0987: switch (Offsize) {
0988: case 4:
0989: NewIndex[Place++] = (byte) ((Num >>> 24) & 0xff);
0990: case 3:
0991: NewIndex[Place++] = (byte) ((Num >>> 16) & 0xff);
0992: case 2:
0993: NewIndex[Place++] = (byte) ((Num >>> 8) & 0xff);
0994: case 1:
0995: NewIndex[Place++] = (byte) ((Num >>> 0) & 0xff);
0996: }
0997: }
0998: // Write the new object array one by one
0999: for (int i = 0; i < NewObjects.length; i++) {
1000: NewIndex[Place++] = NewObjects[i];
1001: }
1002: // Return the new index
1003: return NewIndex;
1004: }
1005:
1006: /**
1007: * The function builds the new output stream according to the subset process
1008: * @param Font the font
1009: * @return the subseted font stream
1010: */
1011: protected byte[] BuildNewFile(int Font) {
1012: // Prepare linked list for new font components
1013: OutputList = new LinkedList();
1014:
1015: // copy the header of the font
1016: CopyHeader();
1017:
1018: // create a name index
1019: BuildIndexHeader(1, 1, 1);
1020: OutputList.addLast(new UInt8Item((char) (1 + fonts[Font].name
1021: .length())));
1022: OutputList.addLast(new StringItem(fonts[Font].name));
1023:
1024: // create the topdict Index
1025: BuildIndexHeader(1, 2, 1);
1026: OffsetItem topdictIndex1Ref = new IndexOffsetItem(2);
1027: OutputList.addLast(topdictIndex1Ref);
1028: IndexBaseItem topdictBase = new IndexBaseItem();
1029: OutputList.addLast(topdictBase);
1030:
1031: // Initialise the Dict Items for later use
1032: OffsetItem charsetRef = new DictOffsetItem();
1033: OffsetItem charstringsRef = new DictOffsetItem();
1034: OffsetItem fdarrayRef = new DictOffsetItem();
1035: OffsetItem fdselectRef = new DictOffsetItem();
1036: OffsetItem privateRef = new DictOffsetItem();
1037:
1038: // If the font is not CID create the following keys
1039: if (!fonts[Font].isCID) {
1040: // create a ROS key
1041: OutputList
1042: .addLast(new DictNumberItem(fonts[Font].nstrings));
1043: OutputList.addLast(new DictNumberItem(
1044: fonts[Font].nstrings + 1));
1045: OutputList.addLast(new DictNumberItem(0));
1046: OutputList.addLast(new UInt8Item((char) 12));
1047: OutputList.addLast(new UInt8Item((char) 30));
1048: // create a CIDCount key
1049: OutputList.addLast(new DictNumberItem(fonts[Font].nglyphs));
1050: OutputList.addLast(new UInt8Item((char) 12));
1051: OutputList.addLast(new UInt8Item((char) 34));
1052: // Sivan's comments
1053: // What about UIDBase (12,35)? Don't know what is it.
1054: // I don't think we need FontName; the font I looked at didn't have it.
1055: }
1056: // Go to the TopDict of the font being processed
1057: seek(topdictOffsets[Font]);
1058: // Run untill the end of the TopDict
1059: while (getPosition() < topdictOffsets[Font + 1]) {
1060: int p1 = getPosition();
1061: getDictItem();
1062: int p2 = getPosition();
1063: // The encoding key is disregarded since CID has no encoding
1064: if (key == "Encoding"
1065: // These keys will be added manualy by the process.
1066: || key == "Private" || key == "FDSelect"
1067: || key == "FDArray" || key == "charset"
1068: || key == "CharStrings") {
1069: } else {
1070: //OtherWise copy key "as is" to the output list
1071: OutputList.add(new RangeItem(buf, p1, p2 - p1));
1072: }
1073: }
1074: // Create the FDArray, FDSelect, Charset and CharStrings Keys
1075: CreateKeys(fdarrayRef, fdselectRef, charsetRef, charstringsRef);
1076:
1077: // Mark the end of the top dict area
1078: OutputList.addLast(new IndexMarkerItem(topdictIndex1Ref,
1079: topdictBase));
1080:
1081: // Copy the string index
1082:
1083: if (fonts[Font].isCID)
1084: OutputList.addLast(getEntireIndexRange(stringIndexOffset));
1085: // If the font is not CID we need to append new strings.
1086: // We need 3 more strings: Registry, Ordering, and a FontName for one FD.
1087: // The total length is at most "Adobe"+"Identity"+63 = 76
1088: else
1089: CreateNewStringIndex(Font);
1090:
1091: // copy the new subsetted global subroutine index
1092: OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(
1093: NewGSubrsIndex), 0, NewGSubrsIndex.length));
1094:
1095: // deal with fdarray, fdselect, and the font descriptors
1096: // If the font is CID:
1097: if (fonts[Font].isCID) {
1098: // copy the FDArray, FDSelect, charset
1099:
1100: // Copy FDSelect
1101: // Mark the beginning
1102: OutputList.addLast(new MarkerItem(fdselectRef));
1103: // If an FDSelect exists copy it
1104: if (fonts[Font].fdselectOffset >= 0)
1105: OutputList.addLast(new RangeItem(buf,
1106: fonts[Font].fdselectOffset,
1107: fonts[Font].FDSelectLength));
1108: // Else create a new one
1109: else
1110: CreateFDSelect(fdselectRef, fonts[Font].nglyphs);
1111:
1112: // Copy the Charset
1113: // Mark the beginning and copy entirly
1114: OutputList.addLast(new MarkerItem(charsetRef));
1115: OutputList.addLast(new RangeItem(buf,
1116: fonts[Font].charsetOffset,
1117: fonts[Font].CharsetLength));
1118:
1119: // Copy the FDArray
1120: // If an FDArray exists
1121: if (fonts[Font].fdarrayOffset >= 0) {
1122: // Mark the beginning
1123: OutputList.addLast(new MarkerItem(fdarrayRef));
1124: // Build a new FDArray with its private dicts and their LSubrs
1125: Reconstruct(Font);
1126: } else
1127: // Else create a new one
1128: CreateFDArray(fdarrayRef, privateRef, Font);
1129:
1130: }
1131: // If the font is not CID
1132: else {
1133: // create FDSelect
1134: CreateFDSelect(fdselectRef, fonts[Font].nglyphs);
1135: // recreate a new charset
1136: CreateCharset(charsetRef, fonts[Font].nglyphs);
1137: // create a font dict index (fdarray)
1138: CreateFDArray(fdarrayRef, privateRef, Font);
1139: }
1140:
1141: // if a private dict exists insert its subsetted version
1142: if (fonts[Font].privateOffset >= 0) {
1143: // Mark the beginning of the private dict
1144: IndexBaseItem PrivateBase = new IndexBaseItem();
1145: OutputList.addLast(PrivateBase);
1146: OutputList.addLast(new MarkerItem(privateRef));
1147:
1148: OffsetItem Subr = new DictOffsetItem();
1149: // Build and copy the new private dict
1150: CreateNonCIDPrivate(Font, Subr);
1151: // Copy the new LSubrs index
1152: CreateNonCIDSubrs(Font, PrivateBase, Subr);
1153: }
1154:
1155: // copy the charstring index
1156: OutputList.addLast(new MarkerItem(charstringsRef));
1157:
1158: // Add the subsetted charstring
1159: OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(
1160: NewCharStringsIndex), 0, NewCharStringsIndex.length));
1161:
1162: // now create the new CFF font
1163: int[] currentOffset = new int[1];
1164: currentOffset[0] = 0;
1165: // Count and save the offset for each item
1166: Iterator listIter = OutputList.iterator();
1167: while (listIter.hasNext()) {
1168: Item item = (Item) listIter.next();
1169: item.increment(currentOffset);
1170: }
1171: // Compute the Xref for each of the offset items
1172: listIter = OutputList.iterator();
1173: while (listIter.hasNext()) {
1174: Item item = (Item) listIter.next();
1175: item.xref();
1176: }
1177:
1178: int size = currentOffset[0];
1179: byte[] b = new byte[size];
1180:
1181: // Emit all the items into the new byte array
1182: listIter = OutputList.iterator();
1183: while (listIter.hasNext()) {
1184: Item item = (Item) listIter.next();
1185: item.emit(b);
1186: }
1187: // Return the new stream
1188: return b;
1189: }
1190:
1191: /**
1192: * Function Copies the header from the original fileto the output list
1193: */
1194: protected void CopyHeader() {
1195: seek(0);
1196: int major = getCard8();
1197: int minor = getCard8();
1198: int hdrSize = getCard8();
1199: int offSize = getCard8();
1200: nextIndexOffset = hdrSize;
1201: OutputList.addLast(new RangeItem(buf, 0, hdrSize));
1202: }
1203:
1204: /**
1205: * Function Build the header of an index
1206: * @param Count the count field of the index
1207: * @param Offsize the offsize field of the index
1208: * @param First the first offset of the index
1209: */
1210: protected void BuildIndexHeader(int Count, int Offsize, int First) {
1211: // Add the count field
1212: OutputList.addLast(new UInt16Item((char) Count)); // count
1213: // Add the offsize field
1214: OutputList.addLast(new UInt8Item((char) Offsize)); // offSize
1215: // Add the first offset according to the offsize
1216: switch (Offsize) {
1217: case 1:
1218: OutputList.addLast(new UInt8Item((char) First)); // first offset
1219: break;
1220: case 2:
1221: OutputList.addLast(new UInt16Item((char) First)); // first offset
1222: break;
1223: case 3:
1224: OutputList.addLast(new UInt24Item((char) First)); // first offset
1225: break;
1226: case 4:
1227: OutputList.addLast(new UInt32Item((char) First)); // first offset
1228: break;
1229: default:
1230: break;
1231: }
1232: }
1233:
1234: /**
1235: * Function adds the keys into the TopDict
1236: * @param fdarrayRef OffsetItem for the FDArray
1237: * @param fdselectRef OffsetItem for the FDSelect
1238: * @param charsetRef OffsetItem for the CharSet
1239: * @param charstringsRef OffsetItem for the CharString
1240: */
1241: protected void CreateKeys(OffsetItem fdarrayRef,
1242: OffsetItem fdselectRef, OffsetItem charsetRef,
1243: OffsetItem charstringsRef) {
1244: // create an FDArray key
1245: OutputList.addLast(fdarrayRef);
1246: OutputList.addLast(new UInt8Item((char) 12));
1247: OutputList.addLast(new UInt8Item((char) 36));
1248: // create an FDSelect key
1249: OutputList.addLast(fdselectRef);
1250: OutputList.addLast(new UInt8Item((char) 12));
1251: OutputList.addLast(new UInt8Item((char) 37));
1252: // create an charset key
1253: OutputList.addLast(charsetRef);
1254: OutputList.addLast(new UInt8Item((char) 15));
1255: // create a CharStrings key
1256: OutputList.addLast(charstringsRef);
1257: OutputList.addLast(new UInt8Item((char) 17));
1258: }
1259:
1260: /**
1261: * Function takes the original string item and adds the new strings
1262: * to accomodate the CID rules
1263: * @param Font the font
1264: */
1265: protected void CreateNewStringIndex(int Font) {
1266: String fdFontName = fonts[Font].name + "-OneRange";
1267: if (fdFontName.length() > 127)
1268: fdFontName = fdFontName.substring(0, 127);
1269: String extraStrings = "Adobe" + "Identity" + fdFontName;
1270:
1271: int origStringsLen = stringOffsets[stringOffsets.length - 1]
1272: - stringOffsets[0];
1273: int stringsBaseOffset = stringOffsets[0] - 1;
1274:
1275: byte stringsIndexOffSize;
1276: if (origStringsLen + extraStrings.length() <= 0xff)
1277: stringsIndexOffSize = 1;
1278: else if (origStringsLen + extraStrings.length() <= 0xffff)
1279: stringsIndexOffSize = 2;
1280: else if (origStringsLen + extraStrings.length() <= 0xffffff)
1281: stringsIndexOffSize = 3;
1282: else
1283: stringsIndexOffSize = 4;
1284:
1285: OutputList.addLast(new UInt16Item(
1286: (char) ((stringOffsets.length - 1) + 3))); // count
1287: OutputList.addLast(new UInt8Item((char) stringsIndexOffSize)); // offSize
1288: for (int i = 0; i < stringOffsets.length; i++)
1289: OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
1290: stringOffsets[i] - stringsBaseOffset));
1291: int currentStringsOffset = stringOffsets[stringOffsets.length - 1]
1292: - stringsBaseOffset;
1293: //l.addLast(new IndexOffsetItem(stringsIndexOffSize,currentStringsOffset));
1294: currentStringsOffset += ("Adobe").length();
1295: OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
1296: currentStringsOffset));
1297: currentStringsOffset += ("Identity").length();
1298: OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
1299: currentStringsOffset));
1300: currentStringsOffset += fdFontName.length();
1301: OutputList.addLast(new IndexOffsetItem(stringsIndexOffSize,
1302: currentStringsOffset));
1303:
1304: OutputList.addLast(new RangeItem(buf, stringOffsets[0],
1305: origStringsLen));
1306: OutputList.addLast(new StringItem(extraStrings));
1307: }
1308:
1309: /**
1310: * Function creates new FDSelect for non-CID fonts.
1311: * The FDSelect built uses a single range for all glyphs
1312: * @param fdselectRef OffsetItem for the FDSelect
1313: * @param nglyphs the number of glyphs in the font
1314: */
1315: protected void CreateFDSelect(OffsetItem fdselectRef, int nglyphs) {
1316: OutputList.addLast(new MarkerItem(fdselectRef));
1317: OutputList.addLast(new UInt8Item((char) 3)); // format identifier
1318: OutputList.addLast(new UInt16Item((char) 1)); // nRanges
1319:
1320: OutputList.addLast(new UInt16Item((char) 0)); // Range[0].firstGlyph
1321: OutputList.addLast(new UInt8Item((char) 0)); // Range[0].fd
1322:
1323: OutputList.addLast(new UInt16Item((char) nglyphs)); // sentinel
1324: }
1325:
1326: /**
1327: * Function creates new CharSet for non-CID fonts.
1328: * The CharSet built uses a single range for all glyphs
1329: * @param charsetRef OffsetItem for the CharSet
1330: * @param nglyphs the number of glyphs in the font
1331: */
1332: protected void CreateCharset(OffsetItem charsetRef, int nglyphs) {
1333: OutputList.addLast(new MarkerItem(charsetRef));
1334: OutputList.addLast(new UInt8Item((char) 2)); // format identifier
1335: OutputList.addLast(new UInt16Item((char) 1)); // first glyph in range (ignore .notdef)
1336: OutputList.addLast(new UInt16Item((char) (nglyphs - 1))); // nLeft
1337: }
1338:
1339: /**
1340: * Function creates new FDArray for non-CID fonts.
1341: * The FDArray built has only the "Private" operator that points to the font's
1342: * original private dict
1343: * @param fdarrayRef OffsetItem for the FDArray
1344: * @param privateRef OffsetItem for the Private Dict
1345: * @param Font the font
1346: */
1347: protected void CreateFDArray(OffsetItem fdarrayRef,
1348: OffsetItem privateRef, int Font) {
1349: OutputList.addLast(new MarkerItem(fdarrayRef));
1350: // Build the header (count=offsize=first=1)
1351: BuildIndexHeader(1, 1, 1);
1352:
1353: // Mark
1354: OffsetItem privateIndex1Ref = new IndexOffsetItem(1);
1355: OutputList.addLast(privateIndex1Ref);
1356: IndexBaseItem privateBase = new IndexBaseItem();
1357: // Insert the private operands and operator
1358: OutputList.addLast(privateBase);
1359: // Calc the new size of the private after subsetting
1360: // Origianl size
1361: int NewSize = fonts[Font].privateLength;
1362: // Calc the original size of the Subr offset in the private
1363: int OrgSubrsOffsetSize = CalcSubrOffsetSize(
1364: fonts[Font].privateOffset, fonts[Font].privateLength);
1365: // Increase the ptivate's size
1366: if (OrgSubrsOffsetSize != 0)
1367: NewSize += 5 - OrgSubrsOffsetSize;
1368: OutputList.addLast(new DictNumberItem(NewSize));
1369: OutputList.addLast(privateRef);
1370: OutputList.addLast(new UInt8Item((char) 18)); // Private
1371:
1372: OutputList.addLast(new IndexMarkerItem(privateIndex1Ref,
1373: privateBase));
1374: }
1375:
1376: /**
1377: * Function reconstructs the FDArray, PrivateDict and LSubr for CID fonts
1378: * @param Font the font
1379: */
1380: void Reconstruct(int Font) {
1381: // Init for later use
1382: OffsetItem[] fdPrivate = new DictOffsetItem[fonts[Font].FDArrayOffsets.length - 1];
1383: IndexBaseItem[] fdPrivateBase = new IndexBaseItem[fonts[Font].fdprivateOffsets.length];
1384: OffsetItem[] fdSubrs = new DictOffsetItem[fonts[Font].fdprivateOffsets.length];
1385: // Reconstruct each type
1386: ReconstructFDArray(Font, fdPrivate);
1387: ReconstructPrivateDict(Font, fdPrivate, fdPrivateBase, fdSubrs);
1388: ReconstructPrivateSubrs(Font, fdPrivateBase, fdSubrs);
1389: }
1390:
1391: /**
1392: * Function subsets the FDArray and builds the new one with new offsets
1393: * @param Font The font
1394: * @param fdPrivate OffsetItem Array (one for each FDArray)
1395: */
1396: void ReconstructFDArray(int Font, OffsetItem[] fdPrivate) {
1397: // Build the header of the index
1398: BuildIndexHeader(fonts[Font].FDArrayCount,
1399: fonts[Font].FDArrayOffsize, 1);
1400:
1401: // For each offset create an Offset Item
1402: OffsetItem[] fdOffsets = new IndexOffsetItem[fonts[Font].FDArrayOffsets.length - 1];
1403: for (int i = 0; i < fonts[Font].FDArrayOffsets.length - 1; i++) {
1404: fdOffsets[i] = new IndexOffsetItem(
1405: fonts[Font].FDArrayOffsize);
1406: OutputList.addLast(fdOffsets[i]);
1407: }
1408:
1409: // Declare beginning of the object array
1410: IndexBaseItem fdArrayBase = new IndexBaseItem();
1411: OutputList.addLast(fdArrayBase);
1412:
1413: // For each object check if that FD is used.
1414: // if is used build a new one by changing the private object
1415: // Else do nothing
1416: // At the end of each object mark its ending (Even if wasn't written)
1417: for (int k = 0; k < fonts[Font].FDArrayOffsets.length - 1; k++) {
1418: if (FDArrayUsed.containsKey(new Integer(k))) {
1419: // Goto begining of objects
1420: seek(fonts[Font].FDArrayOffsets[k]);
1421: while (getPosition() < fonts[Font].FDArrayOffsets[k + 1]) {
1422: int p1 = getPosition();
1423: getDictItem();
1424: int p2 = getPosition();
1425: // If the dictItem is the "Private" then compute and copy length,
1426: // use marker for offset and write operator number
1427: if (key == "Private") {
1428: // Save the original length of the private dict
1429: int NewSize = ((Integer) args[0]).intValue();
1430: // Save the size of the offset to the subrs in that private
1431: int OrgSubrsOffsetSize = CalcSubrOffsetSize(
1432: fonts[Font].fdprivateOffsets[k],
1433: fonts[Font].fdprivateLengths[k]);
1434: // Increase the private's length accordingly
1435: if (OrgSubrsOffsetSize != 0)
1436: NewSize += 5 - OrgSubrsOffsetSize;
1437: // Insert the new size, OffsetItem and operator key number
1438: OutputList.addLast(new DictNumberItem(NewSize));
1439: fdPrivate[k] = new DictOffsetItem();
1440: OutputList.addLast(fdPrivate[k]);
1441: OutputList.addLast(new UInt8Item((char) 18)); // Private
1442: // Go back to place
1443: seek(p2);
1444: }
1445: // Else copy the entire range
1446: else
1447: // other than private
1448: OutputList.addLast(new RangeItem(buf, p1, p2
1449: - p1));
1450: }
1451: }
1452: // Mark the ending of the object (even if wasn't written)
1453: OutputList.addLast(new IndexMarkerItem(fdOffsets[k],
1454: fdArrayBase));
1455: }
1456: }
1457:
1458: /**
1459: * Function Adds the new private dicts (only for the FDs used) to the list
1460: * @param Font the font
1461: * @param fdPrivate OffsetItem array one element for each private
1462: * @param fdPrivateBase IndexBaseItem array one element for each private
1463: * @param fdSubrs OffsetItem array one element for each private
1464: */
1465: void ReconstructPrivateDict(int Font, OffsetItem[] fdPrivate,
1466: IndexBaseItem[] fdPrivateBase, OffsetItem[] fdSubrs) {
1467:
1468: // For each fdarray private dict check if that FD is used.
1469: // if is used build a new one by changing the subrs offset
1470: // Else do nothing
1471: for (int i = 0; i < fonts[Font].fdprivateOffsets.length; i++) {
1472: if (FDArrayUsed.containsKey(new Integer(i))) {
1473: // Mark beginning
1474: OutputList.addLast(new MarkerItem(fdPrivate[i]));
1475: fdPrivateBase[i] = new IndexBaseItem();
1476: OutputList.addLast(fdPrivateBase[i]);
1477: // Goto begining of objects
1478: seek(fonts[Font].fdprivateOffsets[i]);
1479: while (getPosition() < fonts[Font].fdprivateOffsets[i]
1480: + fonts[Font].fdprivateLengths[i]) {
1481: int p1 = getPosition();
1482: getDictItem();
1483: int p2 = getPosition();
1484: // If the dictItem is the "Subrs" then,
1485: // use marker for offset and write operator number
1486: if (key == "Subrs") {
1487: fdSubrs[i] = new DictOffsetItem();
1488: OutputList.addLast(fdSubrs[i]);
1489: OutputList.addLast(new UInt8Item((char) 19)); // Subrs
1490: }
1491: // Else copy the entire range
1492: else
1493: OutputList.addLast(new RangeItem(buf, p1, p2
1494: - p1));
1495: }
1496: }
1497: }
1498: }
1499:
1500: /**
1501: * Function Adds the new LSubrs dicts (only for the FDs used) to the list
1502: * @param Font The index of the font
1503: * @param fdPrivateBase The IndexBaseItem array for the linked list
1504: * @param fdSubrs OffsetItem array for the linked list
1505: */
1506:
1507: void ReconstructPrivateSubrs(int Font,
1508: IndexBaseItem[] fdPrivateBase, OffsetItem[] fdSubrs) {
1509: // For each private dict
1510: for (int i = 0; i < fonts[Font].fdprivateLengths.length; i++) {
1511: // If that private dict's Subrs are used insert the new LSubrs
1512: // computed earlier
1513: if (fdSubrs[i] != null
1514: && fonts[Font].PrivateSubrsOffset[i] >= 0) {
1515: OutputList.addLast(new SubrMarkerItem(fdSubrs[i],
1516: fdPrivateBase[i]));
1517: OutputList.addLast(new RangeItem(
1518: new RandomAccessFileOrArray(NewLSubrsIndex[i]),
1519: 0, NewLSubrsIndex[i].length));
1520: }
1521: }
1522: }
1523:
1524: /**
1525: * Calculates how many byte it took to write the offset for the subrs in a specific
1526: * private dict.
1527: * @param Offset The Offset for the private dict
1528: * @param Size The size of the private dict
1529: * @return The size of the offset of the subrs in the private dict
1530: */
1531: int CalcSubrOffsetSize(int Offset, int Size) {
1532: // Set the size to 0
1533: int OffsetSize = 0;
1534: // Go to the beginning of the private dict
1535: seek(Offset);
1536: // Go until the end of the private dict
1537: while (getPosition() < Offset + Size) {
1538: int p1 = getPosition();
1539: getDictItem();
1540: int p2 = getPosition();
1541: // When reached to the subrs offset
1542: if (key == "Subrs") {
1543: // The Offsize (minus the subrs key)
1544: OffsetSize = p2 - p1 - 1;
1545: }
1546: // All other keys are ignored
1547: }
1548: // return the size
1549: return OffsetSize;
1550: }
1551:
1552: /**
1553: * Function computes the size of an index
1554: * @param indexOffset The offset for the computed index
1555: * @return The size of the index
1556: */
1557: protected int countEntireIndexRange(int indexOffset) {
1558: // Go to the beginning of the index
1559: seek(indexOffset);
1560: // Read the count field
1561: int count = getCard16();
1562: // If count==0 -> size=2
1563: if (count == 0)
1564: return 2;
1565: else {
1566: // Read the offsize field
1567: int indexOffSize = getCard8();
1568: // Go to the last element of the offset array
1569: seek(indexOffset + 2 + 1 + count * indexOffSize);
1570: // The size of the object array is the value of the last element-1
1571: int size = getOffset(indexOffSize) - 1;
1572: // Return the size of the entire index
1573: return 2 + 1 + (count + 1) * indexOffSize + size;
1574: }
1575: }
1576:
1577: /**
1578: * The function creates a private dict for a font that was not CID
1579: * All the keys are copied as is except for the subrs key
1580: * @param Font the font
1581: * @param Subr The OffsetItem for the subrs of the private
1582: */
1583: void CreateNonCIDPrivate(int Font, OffsetItem Subr) {
1584: // Go to the beginning of the private dict and read untill the end
1585: seek(fonts[Font].privateOffset);
1586: while (getPosition() < fonts[Font].privateOffset
1587: + fonts[Font].privateLength) {
1588: int p1 = getPosition();
1589: getDictItem();
1590: int p2 = getPosition();
1591: // If the dictItem is the "Subrs" then,
1592: // use marker for offset and write operator number
1593: if (key == "Subrs") {
1594: OutputList.addLast(Subr);
1595: OutputList.addLast(new UInt8Item((char) 19)); // Subrs
1596: }
1597: // Else copy the entire range
1598: else
1599: OutputList.addLast(new RangeItem(buf, p1, p2 - p1));
1600: }
1601: }
1602:
1603: /**
1604: * the function marks the beginning of the subrs index and adds the subsetted subrs
1605: * index to the output list.
1606: * @param Font the font
1607: * @param PrivateBase IndexBaseItem for the private that's referencing to the subrs
1608: * @param Subrs OffsetItem for the subrs
1609: */
1610: void CreateNonCIDSubrs(int Font, IndexBaseItem PrivateBase,
1611: OffsetItem Subrs) {
1612: // Mark the beginning of the Subrs index
1613: OutputList.addLast(new SubrMarkerItem(Subrs, PrivateBase));
1614: // Put the subsetted new subrs index
1615: OutputList.addLast(new RangeItem(new RandomAccessFileOrArray(
1616: NewSubrsIndexNonCID), 0, NewSubrsIndexNonCID.length));
1617: }
1618: }
|