Source Code Cross Referenced for Type1CFont.java in  » PDF » PDF-Renderer » com » sun » pdfview » font » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » PDF Renderer » com.sun.pdfview.font 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: Type1CFont.java,v 1.2 2007/12/20 18:33:32 rbair Exp $
0003:         *
0004:         * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
0005:         * Santa Clara, California 95054, U.S.A. All rights reserved.
0006:         *
0007:         * This library is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU Lesser General Public
0009:         * License as published by the Free Software Foundation; either
0010:         * version 2.1 of the License, or (at your option) any later version.
0011:         * 
0012:         * This library is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         * Lesser General Public License for more details.
0016:         * 
0017:         * You should have received a copy of the GNU Lesser General Public
0018:         * License along with this library; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0020:         */
0021:
0022:        package com.sun.pdfview.font;
0023:
0024:        import java.awt.geom.AffineTransform;
0025:        import java.awt.geom.GeneralPath;
0026:        import java.awt.geom.NoninvertibleTransformException;
0027:        import java.io.IOException;
0028:
0029:        import com.sun.pdfview.PDFObject;
0030:
0031:        /**
0032:         * A representation, with parser, of an Adobe Type 1C font.
0033:         * @author Mike Wessler
0034:         */
0035:        public class Type1CFont extends OutlineFont {
0036:            String chr2name[] = new String[256];
0037:
0038:            byte[] data;
0039:            int pos;
0040:            byte[] subrs;
0041:            float[] stack = new float[100];
0042:            int stackptr = 0;
0043:
0044:            String names[];
0045:            int glyphnames[];
0046:            int encoding[] = new int[256];
0047:
0048:            String fontname;
0049:            AffineTransform at = new AffineTransform(0.001f, 0, 0, 0.001f, 0, 0);
0050:
0051:            int num;
0052:            float fnum;
0053:            int type;
0054:            static int CMD = 0;
0055:            static int NUM = 1;
0056:            static int FLT = 2;
0057:
0058:            /**
0059:             * create a new Type1CFont based on a font data stream and a descriptor
0060:             * @param baseFont the postscript name of this font
0061:             * @param src a stream containing the font
0062:             * @param descriptor the descriptor for this font
0063:             */
0064:            public Type1CFont(String baseFont, PDFObject src,
0065:                    PDFFontDescriptor descriptor) throws IOException {
0066:                super (baseFont, src, descriptor);
0067:
0068:                PDFObject dataObj = descriptor.getFontFile3();
0069:                data = dataObj.getStream();
0070:                pos = 0;
0071:                parse();
0072:
0073:                // TODO: free up (set to null) unused structures (data, subrs, stack)
0074:            }
0075:
0076:            /**
0077:             * a debug method for printing the data
0078:             */
0079:            private void printData() {
0080:                char[] parts = new char[17];
0081:                int partsloc = 0;
0082:                for (int i = 0; i < data.length; i++) {
0083:                    int d = ((int) data[i]) & 0xff;
0084:                    if (d == 0) {
0085:                        parts[partsloc++] = '.';
0086:                    } else if (d < 32 || d >= 127) {
0087:                        parts[partsloc++] = '?';
0088:                    } else {
0089:                        parts[partsloc++] = (char) d;
0090:                    }
0091:                    if (d < 16) {
0092:                        System.out.print("0" + Integer.toHexString(d));
0093:                    } else {
0094:                        System.out.print(Integer.toHexString(d));
0095:                    }
0096:                    if ((i & 15) == 15) {
0097:                        System.out.println("      " + new String(parts));
0098:                        partsloc = 0;
0099:                    } else if ((i & 7) == 7) {
0100:                        System.out.print("  ");
0101:                        parts[partsloc++] = ' ';
0102:                    } else if ((i & 1) == 1) {
0103:                        System.out.print(" ");
0104:                    }
0105:                }
0106:                System.out.println();
0107:            }
0108:
0109:            /**
0110:             * read the next decoded value from the stream
0111:             * @param charstring ????
0112:             */
0113:            private int readNext(boolean charstring) {
0114:                num = (int) (data[pos++]) & 0xff;
0115:                if (num == 30 && !charstring) { // goofy floatingpoint rep
0116:                    readFNum();
0117:                    return type = FLT;
0118:                } else if (num == 28) {
0119:                    num = (((int) data[pos]) << 8)
0120:                            + (((int) data[pos + 1]) & 0xff);
0121:                    pos += 2;
0122:                    return type = NUM;
0123:                } else if (num == 29 && !charstring) {
0124:                    num = (((int) data[pos] & 0xff) << 24)
0125:                            | (((int) data[pos + 1] & 0xff) << 16)
0126:                            | (((int) data[pos + 2] & 0xff) << 8)
0127:                            | (((int) data[pos + 3] & 0xff));
0128:                    pos += 4;
0129:                    return type = NUM;
0130:                } else if (num == 12) { // two-byte command
0131:                    num = 1000 + ((int) (data[pos++]) & 0xff);
0132:                    return type = CMD;
0133:                } else if (num < 32) {
0134:                    return type = CMD;
0135:                } else if (num < 247) {
0136:                    num -= 139;
0137:                    return type = NUM;
0138:                } else if (num < 251) {
0139:                    num = (num - 247) * 256 + (((int) data[pos++]) & 0xff)
0140:                            + 108;
0141:                    return type = NUM;
0142:                } else if (num < 255) {
0143:                    num = -(num - 251) * 256 - (((int) data[pos++]) & 0xff)
0144:                            - 108;
0145:                    return type = NUM;
0146:                } else if (!charstring) { // dict shouldn't have a 255 code
0147:                    printData();
0148:                    throw new RuntimeException(
0149:                            "Got a 255 code while reading dict");
0150:                } else { // num was 255
0151:                    fnum = ((((int) data[pos] & 0xff) << 24)
0152:                            | (((int) data[pos + 1] & 0xff) << 16)
0153:                            | (((int) data[pos + 2] & 0xff) << 8) | (((int) data[pos + 3] & 0xff))) / 65536f;
0154:                    pos += 4;
0155:                    return type = FLT;
0156:                }
0157:            }
0158:
0159:            /**
0160:             * read the next funky floating point number from the input stream.
0161:             * value gets put into the fnum field.
0162:             */
0163:            public void readFNum() {
0164:                // work in nybbles: 0-9=0-9, a=. b=E, c=E-, d=rsvd e=neg f=end
0165:                float f = 0;
0166:                boolean neg = false;
0167:                int exp = 0;
0168:                int eval = 0;
0169:                float mul = 1;
0170:                byte work = data[pos++];
0171:                while (true) {
0172:                    if (work == (byte) 0xdd) {
0173:                        work = data[pos++];
0174:                    }
0175:                    int nyb = (work >> 4) & 0xf;
0176:                    work = (byte) ((work << 4) | 0xd);
0177:                    if (nyb < 10) {
0178:                        if (exp != 0) { // working on the exponent
0179:                            eval = eval * 10 + nyb;
0180:                        } else if (mul == 1) { // working on an int
0181:                            f = f * 10 + nyb;
0182:                        } else { // working on decimal part
0183:                            f += nyb * mul;
0184:                            mul /= 10f;
0185:                        }
0186:                    } else if (nyb == 0xa) { // decimal
0187:                        mul = 0.1f;
0188:                    } else if (nyb == 0xb) { // E+
0189:                        exp = 1;
0190:                    } else if (nyb == 0xc) { // E-
0191:                        exp = -1;
0192:                    } else if (nyb == 0xe) { // neg
0193:                        neg = true;
0194:                    } else {
0195:                        break;
0196:                    }
0197:                }
0198:                fnum = (neg ? -1 : 1) * f * (float) Math.pow(10, eval * exp);
0199:            }
0200:
0201:            /**
0202:             * read an integer from the input stream
0203:             * @param len the number of bytes in the integer
0204:             * @return the integer
0205:             */
0206:            private int readInt(int len) {
0207:                int n = 0;
0208:                for (int i = 0; i < len; i++) {
0209:                    n = (n << 8) | (((int) data[pos++]) & 0xff);
0210:                }
0211:                return n;
0212:            }
0213:
0214:            /**
0215:             * read the next byte from the stream
0216:             * @return the byte
0217:             */
0218:            private int readByte() {
0219:                return ((int) data[pos++]) & 0xff;
0220:            }
0221:
0222:            // DICT structure:
0223:            // operand operator operand operator ...
0224:
0225:            // INDEX structure:
0226:            // count(2) offsize [offset offset ... offset] data
0227:            // offset array has count+1 entries
0228:            // data starts at 3+(count+1)*offsize
0229:            // offset for data is offset+2+(count+1)*offsize
0230:
0231:            /**
0232:             * get the size of the dictionary located within the stream at
0233:             * some offset.
0234:             * @param loc the index of the start of the dictionary
0235:             * @return the size of the dictionary, in bytes.
0236:             */
0237:            public int getIndexSize(int loc) {
0238:                //	System.out.println("Getting size of index at "+loc);
0239:                int hold = pos;
0240:                pos = loc;
0241:                int count = readInt(2);
0242:                if (count == 0) {
0243:                    return 2;
0244:                }
0245:                int encsz = readByte();
0246:                // pos is now at the first offset.  last offset is at count*encsz
0247:                pos += count * encsz;
0248:                int end = readInt(encsz);
0249:                pos = hold;
0250:                return 2 + (count + 1) * encsz + end;
0251:            }
0252:
0253:            /**
0254:             * A range.  There's probably a version of this class floating around
0255:             * somewhere already in Java.
0256:             */
0257:            class Range {
0258:                private int start;
0259:                private int len;
0260:
0261:                public Range(int start, int len) {
0262:                    this .start = start;
0263:                    this .len = len;
0264:                }
0265:
0266:                public final int getStart() {
0267:                    return start;
0268:                }
0269:
0270:                public final int getLen() {
0271:                    return len;
0272:                }
0273:
0274:                public final int getEnd() {
0275:                    return start + len;
0276:                }
0277:            }
0278:
0279:            /**
0280:             * Get the range of a particular index in a dictionary.
0281:             * @param index the start of the dictionary.
0282:             * @param id the index of the entry in the dictionary
0283:             * @return a range describing the offsets of the start and end of
0284:             * the entry from the start of the file, not the dictionary
0285:             */
0286:            Range getIndexEntry(int index, int id) {
0287:                int hold = pos;
0288:                pos = index;
0289:                int count = readInt(2);
0290:                int encsz = readByte();
0291:                pos += encsz * id;
0292:                int from = readInt(encsz);
0293:                Range r = new Range(from + 2 + index + encsz * (count + 1),
0294:                        readInt(encsz) - from);
0295:                pos = hold;
0296:                return r;
0297:            }
0298:
0299:            // Top DICT: NAME    CODE   DEFAULT
0300:            // charstringtype    12 6    2
0301:            // fontmatrix        12 7    0.001 0 0 0.001
0302:            // charset           15      - (offset)  names of glyphs (ref to name idx)
0303:            // encoding          16      - (offset)  array of codes
0304:            // CharStrings       17      - (offset)
0305:            // Private           18      - (size, offset)
0306:
0307:            // glyph at position i in CharStrings has name charset[i]
0308:            // and code encoding[i]
0309:
0310:            int charstringtype = 2;
0311:            float temps[] = new float[32];
0312:            int charsetbase = 0;
0313:            int encodingbase = 0;
0314:            int charstringbase = 0;
0315:            int privatebase = 0;
0316:            int privatesize = 0;
0317:            int gsubrbase = 0;
0318:            int lsubrbase = 0;
0319:            int gsubrsoffset = 0;
0320:            int lsubrsoffset = 0;
0321:
0322:            int nglyphs = 1;
0323:
0324:            /**
0325:             * read a dictionary that exists within some range, parsing the entries
0326:             * within the dictionary.
0327:             */
0328:            private void readDict(Range r) {
0329:                //	System.out.println("reading dictionary from "+r.getStart()+" to "+r.getEnd());
0330:                pos = r.getStart();
0331:                while (pos < r.getEnd()) {
0332:                    int cmd = readCommand(false);
0333:                    if (cmd == 1006) { // charstringtype, default=2
0334:                        charstringtype = (int) stack[0];
0335:                    } else if (cmd == 1007) { // fontmatrix
0336:                        if (stackptr == 4) {
0337:                            at = new AffineTransform((float) stack[0],
0338:                                    (float) stack[1], (float) stack[2],
0339:                                    (float) stack[3], 0, 0);
0340:                        } else {
0341:                            at = new AffineTransform((float) stack[0],
0342:                                    (float) stack[1], (float) stack[2],
0343:                                    (float) stack[3], (float) stack[4],
0344:                                    (float) stack[5]);
0345:                        }
0346:                    } else if (cmd == 15) { // charset
0347:                        charsetbase = (int) stack[0];
0348:                    } else if (cmd == 16) { // encoding
0349:                        encodingbase = (int) stack[0];
0350:                    } else if (cmd == 17) { // charstrings
0351:                        charstringbase = (int) stack[0];
0352:                    } else if (cmd == 18) { // private
0353:                        privatesize = (int) stack[0];
0354:                        privatebase = (int) stack[1];
0355:                    } else if (cmd == 19) { // subrs (in Private dict)
0356:                        lsubrbase = (int) stack[0];
0357:                        lsubrsoffset = calcoffset(lsubrbase);
0358:                    }
0359:                    stackptr = 0;
0360:                }
0361:            }
0362:
0363:            /**
0364:             * read a complete command.  this may involve several numbers
0365:             * which go onto a stack before an actual command is read.
0366:             * @param charstring ????
0367:             * @return the command.  Some numbers may also be on the stack.
0368:             */
0369:            private int readCommand(boolean charstring) {
0370:                while (true) {
0371:                    int t = readNext(charstring);
0372:                    if (t == CMD) {
0373:                        /*
0374:                        System.out.print("CMD= "+num+", args=");
0375:                        for (int i=0; i<stackptr; i++) {
0376:                            System.out.print(" "+stack[i]);
0377:                        }
0378:                        System.out.println();
0379:                         */
0380:                        return num;
0381:                    } else {
0382:                        stack[stackptr++] = (t == NUM) ? (float) num
0383:                                : (float) fnum;
0384:                    }
0385:                }
0386:            }
0387:
0388:            /**
0389:             * parse information about the encoding of this file.
0390:             * @param base the start of the encoding data
0391:             */
0392:            private void readEncodingData(int base) {
0393:                if (base == 0) { // this is the StandardEncoding
0394:                    //	    System.out.println("**** STANDARD ENCODING!");
0395:                    System.arraycopy(FontSupport.standardEncoding, 0, encoding,
0396:                            0, FontSupport.standardEncoding.length);
0397:                } else if (base == 1) { // this is the expert encoding
0398:                    System.out.println("**** EXPERT ENCODING!");
0399:                    // TODO: copy ExpertEncoding
0400:                } else {
0401:                    pos = base;
0402:                    int encodingtype = readByte();
0403:                    if ((encodingtype & 127) == 0) {
0404:                        int ncodes = readByte();
0405:                        for (int i = 1; i < ncodes + 1; i++) {
0406:                            int idx = readByte() & 0xff;
0407:                            encoding[idx] = i;
0408:                        }
0409:                    } else if ((encodingtype & 127) == 1) {
0410:                        int nranges = readByte();
0411:                        int p = 1;
0412:                        for (int i = 0; i < nranges; i++) {
0413:                            int start = readByte();
0414:                            int more = readByte();
0415:                            for (int j = start; j < start + more + 1; j++) {
0416:                                encoding[j] = p++;
0417:                            }
0418:                        }
0419:                    } else {
0420:                        System.out
0421:                                .println("Bad encoding type: " + encodingtype);
0422:                    }
0423:                    // TODO: now check for supplemental encoding data
0424:                }
0425:            }
0426:
0427:            /**
0428:             * read the names of the glyphs.
0429:             * @param base the start of the glyph name table
0430:             */
0431:            private void readGlyphNames(int base) {
0432:                if (base == 0) {
0433:                    glyphnames = new int[229];
0434:                    for (int i = 0; i < glyphnames.length; i++) {
0435:                        glyphnames[i] = i;
0436:                    }
0437:                    return;
0438:                } else if (base == 1) {
0439:                    glyphnames = FontSupport.type1CExpertCharset;
0440:                    return;
0441:                } else if (base == 2) {
0442:                    glyphnames = FontSupport.type1CExpertSubCharset;
0443:                    return;
0444:                }
0445:                // nglyphs has already been set.
0446:                glyphnames = new int[nglyphs];
0447:                glyphnames[0] = 0;
0448:                pos = base;
0449:                int t = readByte();
0450:                if (t == 0) {
0451:                    for (int i = 1; i < nglyphs; i++) {
0452:                        glyphnames[i] = readInt(2);
0453:                    }
0454:                } else if (t == 1) {
0455:                    int n = 1;
0456:                    while (n < nglyphs) {
0457:                        int sid = readInt(2);
0458:                        int range = readByte() + 1;
0459:                        for (int i = 0; i < range; i++) {
0460:                            glyphnames[n++] = sid++;
0461:                        }
0462:                    }
0463:                } else if (t == 2) {
0464:                    int n = 1;
0465:                    while (n < nglyphs) {
0466:                        int sid = readInt(2);
0467:                        int range = readInt(2) + 1;
0468:                        for (int i = 0; i < range; i++) {
0469:                            glyphnames[n++] = sid++;
0470:                        }
0471:                    }
0472:                }
0473:            }
0474:
0475:            /**
0476:             * read a list of names
0477:             * @param base the start of the name table
0478:             */
0479:            private void readNames(int base) {
0480:                pos = base;
0481:                int nextra = readInt(2);
0482:                names = new String[nextra];
0483:                //	safenames= new String[nextra];
0484:                for (int i = 0; i < nextra; i++) {
0485:                    Range r = getIndexEntry(base, i);
0486:                    names[i] = new String(data, r.getStart(), r.getLen());
0487:                    //	    System.out.println("Read name: "+i+" from "+r.getStart()+" to "+r.getEnd()+": "+safe(names[i]));
0488:                }
0489:            }
0490:
0491:            /**
0492:             * parse the font data.
0493:             * @param encdif a dictionary describing the encoding.
0494:             */
0495:            private void parse() throws IOException {
0496:                int majorVersion = readByte();
0497:                int minorVersion = readByte();
0498:                int hdrsz = readByte();
0499:                int offsize = readByte();
0500:                // jump over rest of header: base of font names index
0501:                int fnames = hdrsz;
0502:                // offset in the file of the array of font dicts
0503:                int topdicts = fnames + getIndexSize(fnames);
0504:                // offset in the file of local names
0505:                int theNames = topdicts + getIndexSize(topdicts);
0506:                // offset in the file of the array of global subroutines
0507:                gsubrbase = theNames + getIndexSize(theNames);
0508:                gsubrsoffset = calcoffset(gsubrbase);
0509:                // read extra names
0510:                readNames(theNames);
0511:                // does this file have more than one font?
0512:                pos = topdicts;
0513:                if (readInt(2) != 1) {
0514:                    printData();
0515:                    throw new RuntimeException(
0516:                            "More than one font in this file!");
0517:                }
0518:                Range r = getIndexEntry(fnames, 0);
0519:                fontname = new String(data, r.getStart(), r.getLen());
0520:                // read first dict
0521:                //	System.out.println("TOPDICT[0]:");
0522:                readDict(getIndexEntry(topdicts, 0));
0523:                // read the private dictionary
0524:                //	System.out.println("PRIVATE DICT:");
0525:                readDict(new Range(privatebase, privatesize));
0526:                // calculate the number of glyphs
0527:                pos = charstringbase;
0528:                nglyphs = readInt(2);
0529:                // now get the glyph names
0530:                //	System.out.println("GLYPHNAMES:");
0531:                readGlyphNames(charsetbase);
0532:                // now figure out the encoding
0533:                //	System.out.println("ENCODING:");
0534:                readEncodingData(encodingbase);
0535:            }
0536:
0537:            /**
0538:             * get the index of a particular name.  The name table starts with
0539:             * the standard names in FontSupport.stdNames, and is appended by
0540:             * any names in the name table from this font's dictionary.
0541:             */
0542:            private int getNameIndex(String name) {
0543:                int val = FontSupport.findName(name, FontSupport.stdNames);
0544:                if (val == -1) {
0545:                    val = FontSupport.findName(name, names)
0546:                            + FontSupport.stdNames.length;
0547:                }
0548:                if (val == -1) {
0549:                    val = 0;
0550:                }
0551:                return val;
0552:            }
0553:
0554:            /**
0555:             * convert a string to one in which any non-printable bytes are
0556:             * replaced by "<###>" where ## is the value of the byte.
0557:             */
0558:            private String safe(String src) {
0559:                StringBuffer sb = new StringBuffer();
0560:                for (int i = 0; i < src.length(); i++) {
0561:                    char c = src.charAt(i);
0562:                    if (c >= 32 && c < 128) {
0563:                        sb.append(c);
0564:                    } else {
0565:                        sb.append("<" + (int) c + ">");
0566:                    }
0567:                }
0568:                return sb.toString();
0569:            }
0570:
0571:            /**
0572:             * Read the data for a glyph from the glyph table, and transform
0573:             * it based on the current transform.
0574:             *
0575:             * @param base the start of the glyph table
0576:             * @param offset the index of this glyph in the glyph table
0577:             */
0578:            private synchronized GeneralPath readGlyph(int base, int offset) {
0579:                FlPoint pt = new FlPoint();
0580:
0581:                // find this entry
0582:                Range r = getIndexEntry(base, offset);
0583:
0584:                // create a path
0585:                GeneralPath gp = new GeneralPath();
0586:
0587:                // rember the start position (for recursive calls due to seac)
0588:                int hold = pos;
0589:
0590:                // read the glyph itself
0591:                stackptr = 0;
0592:                parseGlyph(r, gp, pt);
0593:
0594:                // restore the start position
0595:                pos = hold;
0596:
0597:                gp.transform(at);
0598:
0599:                return gp;
0600:            }
0601:
0602:            /**
0603:             * calculate an offset code for a dictionary
0604:             * @param base the index of the start of the dictionary
0605:             */
0606:            public int calcoffset(int base) {
0607:                int len = getIndexSize(base);
0608:                if (len < 1240) {
0609:                    return -107;
0610:                } else if (len < 33900) {
0611:                    return -1131;
0612:                } else {
0613:                    return -32768;
0614:                }
0615:            }
0616:
0617:            /**
0618:             * get the name associated with an ID.
0619:             * @param id the index of the name
0620:             * @return the name from the FontSupport.stdNames table augmented
0621:             * by the local name table
0622:             */
0623:            public String getSID(int id) {
0624:                if (id < FontSupport.stdNames.length) {
0625:                    return FontSupport.stdNames[id];
0626:                } else {
0627:                    id -= FontSupport.stdNames.length;
0628:                    return names[id];
0629:                }
0630:            }
0631:
0632:            /**
0633:             * build an accented character out of two pre-defined glyphs.
0634:             * @param x the x offset of the accent
0635:             * @param y the y offset of the accent
0636:             * @param b the index of the base glyph
0637:             * @param a the index of the accent glyph
0638:             * @param gp the GeneralPath into which the combined glyph will be
0639:             * written.
0640:             */
0641:            private void buildAccentChar(float x, float y, char b, char a,
0642:                    GeneralPath gp) {
0643:                // get the outline of the accent
0644:                GeneralPath pathA = getOutline(a, getWidth(a, null));
0645:
0646:                // undo the effect of the transform applied in read 
0647:                AffineTransform xformA = AffineTransform.getTranslateInstance(
0648:                        x, y);
0649:                try {
0650:                    xformA.concatenate(at.createInverse());
0651:                } catch (NoninvertibleTransformException nte) {
0652:                    // oh well ...
0653:                }
0654:                pathA.transform(xformA);
0655:
0656:                GeneralPath pathB = getOutline(b, getWidth(b, null));
0657:
0658:                try {
0659:                    AffineTransform xformB = at.createInverse();
0660:                    pathB.transform(xformB);
0661:                } catch (NoninvertibleTransformException nte) {
0662:                    // ignore
0663:                }
0664:
0665:                gp.append(pathB, false);
0666:                gp.append(pathA, false);
0667:            }
0668:
0669:            /**
0670:             * parse a glyph defined in a particular range
0671:             * @param r the range of the glyph definition
0672:             * @param gp a GeneralPath in which to store the glyph outline
0673:             * @param pt a FlPoint representing the end of the current path
0674:             */
0675:            void parseGlyph(Range r, GeneralPath gp, FlPoint pt) {
0676:                pos = r.getStart();
0677:                int i;
0678:                float x1, y1, x2, y2, x3, y3, ybase;
0679:                int hold;
0680:                int stemhints = 0;
0681:                while (pos < r.getEnd()) {
0682:                    int cmd = readCommand(true);
0683:                    hold = 0;
0684:                    switch (cmd) {
0685:                    case 1: // hstem
0686:                    case 3: // vstem
0687:                        stackptr = 0;
0688:                        break;
0689:                    case 4: // vmoveto
0690:                        if (stackptr > 1) { // this is the first call, arg1 is width
0691:                            stack[0] = stack[1];
0692:                        }
0693:                        pt.y += stack[0];
0694:                        if (pt.open) {
0695:                            gp.closePath();
0696:                        }
0697:                        pt.open = false;
0698:                        gp.moveTo(pt.x, pt.y);
0699:                        stackptr = 0;
0700:                        break;
0701:                    case 5: // rlineto
0702:                        for (i = 0; i < stackptr;) {
0703:                            pt.x += stack[i++];
0704:                            pt.y += stack[i++];
0705:                            gp.lineTo(pt.x, pt.y);
0706:                        }
0707:                        pt.open = true;
0708:                        stackptr = 0;
0709:                        break;
0710:                    case 6: // hlineto
0711:                        for (i = 0; i < stackptr;) {
0712:                            if ((i & 1) == 0) {
0713:                                pt.x += stack[i++];
0714:                            } else {
0715:                                pt.y += stack[i++];
0716:                            }
0717:                            gp.lineTo(pt.x, pt.y);
0718:                        }
0719:                        pt.open = true;
0720:                        stackptr = 0;
0721:                        break;
0722:                    case 7: // vlineto
0723:                        for (i = 0; i < stackptr;) {
0724:                            if ((i & 1) == 0) {
0725:                                pt.y += stack[i++];
0726:                            } else {
0727:                                pt.x += stack[i++];
0728:                            }
0729:                            gp.lineTo(pt.x, pt.y);
0730:                        }
0731:                        pt.open = true;
0732:                        stackptr = 0;
0733:                        break;
0734:                    case 8: // rrcurveto
0735:                        for (i = 0; i < stackptr;) {
0736:                            x1 = pt.x + stack[i++];
0737:                            y1 = pt.y + stack[i++];
0738:                            x2 = x1 + stack[i++];
0739:                            y2 = y1 + stack[i++];
0740:                            pt.x = x2 + stack[i++];
0741:                            pt.y = y2 + stack[i++];
0742:                            gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
0743:                        }
0744:                        pt.open = true;
0745:                        stackptr = 0;
0746:                        break;
0747:                    case 10: // callsubr
0748:                        hold = pos;
0749:                        i = (int) stack[--stackptr] + lsubrsoffset;
0750:                        Range lsubr = getIndexEntry(lsubrbase, i);
0751:                        parseGlyph(lsubr, gp, pt);
0752:                        pos = hold;
0753:                        break;
0754:                    case 11: // return
0755:                        return;
0756:                    case 14: // endchar
0757:                        // width x y achar bchar endchar == x y achar bchar seac 
0758:                        if (stackptr == 5) {
0759:                            buildAccentChar(stack[1], stack[2],
0760:                                    (char) stack[3], (char) stack[4], gp);
0761:                        }
0762:                        if (pt.open) {
0763:                            gp.closePath();
0764:                        }
0765:                        pt.open = false;
0766:                        stackptr = 0;
0767:                        break;
0768:                    case 18: // hstemhm
0769:                        stemhints += stackptr / 2;
0770:                        stackptr = 0;
0771:                        break;
0772:                    case 19: // hintmask
0773:                    case 20: // cntrmask
0774:                        stemhints += stackptr / 2;
0775:                        pos += (stemhints - 1) / 8 + 1;
0776:                        stackptr = 0;
0777:                        break;
0778:                    case 21: // rmoveto
0779:                        if (stackptr > 2) {
0780:                            stack[0] = stack[1];
0781:                            stack[1] = stack[2];
0782:                        }
0783:                        pt.x += stack[0];
0784:                        pt.y += stack[1];
0785:                        if (pt.open) {
0786:                            gp.closePath();
0787:                        }
0788:                        gp.moveTo(pt.x, pt.y);
0789:                        pt.open = false;
0790:                        stackptr = 0;
0791:                        break;
0792:                    case 22: // hmoveto
0793:                        if (stackptr > 1) {
0794:                            stack[0] = stack[1];
0795:                        }
0796:                        pt.x += stack[0];
0797:                        if (pt.open) {
0798:                            gp.closePath();
0799:                        }
0800:                        gp.moveTo(pt.x, pt.y);
0801:                        pt.open = false;
0802:                        stackptr = 0;
0803:                        break;
0804:                    case 23: // vstemhm
0805:                        stemhints += stackptr / 2;
0806:                        stackptr = 0;
0807:                        break;
0808:                    case 24: // rcurveline
0809:                        for (i = 0; i < stackptr - 2;) {
0810:                            x1 = pt.x + stack[i++];
0811:                            y1 = pt.y + stack[i++];
0812:                            x2 = x1 + stack[i++];
0813:                            y2 = y1 + stack[i++];
0814:                            pt.x = x2 + stack[i++];
0815:                            pt.y = y2 + stack[i++];
0816:                            gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
0817:                        }
0818:                        pt.x += stack[i++];
0819:                        pt.y += stack[i++];
0820:                        gp.lineTo(pt.x, pt.y);
0821:                        pt.open = true;
0822:                        stackptr = 0;
0823:                        break;
0824:                    case 25: // rlinecurve
0825:                        for (i = 0; i < stackptr - 6;) {
0826:                            pt.x += stack[i++];
0827:                            pt.y += stack[i++];
0828:                            gp.lineTo(pt.x, pt.y);
0829:                        }
0830:                        x1 = pt.x + stack[i++];
0831:                        y1 = pt.y + stack[i++];
0832:                        x2 = x1 + stack[i++];
0833:                        y2 = y1 + stack[i++];
0834:                        pt.x = x2 + stack[i++];
0835:                        pt.y = y2 + stack[i++];
0836:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
0837:                        pt.open = true;
0838:                        stackptr = 0;
0839:                        break;
0840:                    case 26: // vvcurveto
0841:                        i = 0;
0842:                        if ((stackptr & 1) == 1) { // odd number of arguments
0843:                            pt.x += stack[i++];
0844:                        }
0845:                        while (i < stackptr) {
0846:                            x1 = pt.x;
0847:                            y1 = pt.y + stack[i++];
0848:                            x2 = x1 + stack[i++];
0849:                            y2 = y1 + stack[i++];
0850:                            pt.x = x2;
0851:                            pt.y = y2 + stack[i++];
0852:                            gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
0853:                        }
0854:                        pt.open = true;
0855:                        stackptr = 0;
0856:                        break;
0857:                    case 27: // hhcurveto
0858:                        i = 0;
0859:                        if ((stackptr & 1) == 1) { // odd number of arguments
0860:                            pt.y += stack[i++];
0861:                        }
0862:                        while (i < stackptr) {
0863:                            x1 = pt.x + stack[i++];
0864:                            y1 = pt.y;
0865:                            x2 = x1 + stack[i++];
0866:                            y2 = y1 + stack[i++];
0867:                            pt.x = x2 + stack[i++];
0868:                            pt.y = y2;
0869:                            gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
0870:                        }
0871:                        pt.open = true;
0872:                        stackptr = 0;
0873:                        break;
0874:                    case 29: // callgsubr
0875:                        hold = pos;
0876:                        i = (int) stack[--stackptr] + gsubrsoffset;
0877:                        Range gsubr = getIndexEntry(gsubrbase, i);
0878:                        parseGlyph(gsubr, gp, pt);
0879:                        pos = hold;
0880:                        break;
0881:                    case 30: // vhcurveto
0882:                        hold = 4;
0883:                    case 31: // hvcurveto
0884:                        for (i = 0; i < stackptr;) {
0885:                            boolean hv = (((i + hold) & 4) == 0);
0886:                            x1 = pt.x + (hv ? stack[i++] : 0);
0887:                            y1 = pt.y + (hv ? 0 : stack[i++]);
0888:                            x2 = x1 + stack[i++];
0889:                            y2 = y1 + stack[i++];
0890:                            pt.x = x2 + (hv ? 0 : stack[i++]);
0891:                            pt.y = y2 + (hv ? stack[i++] : 0);
0892:                            if (i == stackptr - 1) {
0893:                                if (hv) {
0894:                                    pt.x += stack[i++];
0895:                                } else {
0896:                                    pt.y += stack[i++];
0897:                                }
0898:                            }
0899:                            gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
0900:                        }
0901:                        pt.open = true;
0902:                        stackptr = 0;
0903:                        break;
0904:                    case 1000: // old dotsection command.  ignore.
0905:                        stackptr = 0;
0906:                        break;
0907:                    case 1003: // and
0908:                        x1 = stack[--stackptr];
0909:                        y1 = stack[--stackptr];
0910:                        stack[stackptr++] = ((x1 != 0) && (y1 != 0)) ? 1 : 0;
0911:                        break;
0912:                    case 1004: // or
0913:                        x1 = stack[--stackptr];
0914:                        y1 = stack[--stackptr];
0915:                        stack[stackptr++] = ((x1 != 0) || (y1 != 0)) ? 1 : 0;
0916:                        break;
0917:                    case 1005: // not
0918:                        x1 = stack[--stackptr];
0919:                        stack[stackptr++] = (x1 == 0) ? 1 : 0;
0920:                        break;
0921:                    case 1009: // abs
0922:                        stack[stackptr - 1] = Math.abs(stack[stackptr - 1]);
0923:                        break;
0924:                    case 1010: // add
0925:                        x1 = stack[--stackptr];
0926:                        y1 = stack[--stackptr];
0927:                        stack[stackptr++] = x1 + y1;
0928:                        break;
0929:                    case 1011: // sub
0930:                        x1 = stack[--stackptr];
0931:                        y1 = stack[--stackptr];
0932:                        stack[stackptr++] = y1 - x1;
0933:                        break;
0934:                    case 1012: // div
0935:                        x1 = stack[--stackptr];
0936:                        y1 = stack[--stackptr];
0937:                        stack[stackptr++] = y1 / x1;
0938:                        break;
0939:                    case 1014: // neg
0940:                        stack[stackptr - 1] = -stack[stackptr - 1];
0941:                        break;
0942:                    case 1015: // eq
0943:                        x1 = stack[--stackptr];
0944:                        y1 = stack[--stackptr];
0945:                        stack[stackptr++] = (x1 == y1) ? 1 : 0;
0946:                        break;
0947:                    case 1018: // drop
0948:                        stackptr--;
0949:                        break;
0950:                    case 1020: // put
0951:                        i = (int) stack[--stackptr];
0952:                        x1 = stack[--stackptr];
0953:                        temps[i] = x1;
0954:                        break;
0955:                    case 1021: // get
0956:                        i = (int) stack[--stackptr];
0957:                        stack[stackptr++] = temps[i];
0958:                        break;
0959:                    case 1022: // ifelse
0960:                        if (stack[stackptr - 2] > stack[stackptr - 1]) {
0961:                            stack[stackptr - 4] = stack[stackptr - 3];
0962:                        }
0963:                        stackptr -= 3;
0964:                        break;
0965:                    case 1023: // random
0966:                        stack[stackptr++] = (float) Math.random();
0967:                        break;
0968:                    case 1024: // mul
0969:                        x1 = stack[--stackptr];
0970:                        y1 = stack[--stackptr];
0971:                        stack[stackptr++] = y1 * x1;
0972:                        break;
0973:                    case 1026: // sqrt
0974:                        stack[stackptr - 1] = (float) Math
0975:                                .sqrt(stack[stackptr - 1]);
0976:                        break;
0977:                    case 1027: // dup
0978:                        x1 = stack[stackptr - 1];
0979:                        stack[stackptr++] = x1;
0980:                        break;
0981:                    case 1028: // exch
0982:                        x1 = stack[stackptr - 1];
0983:                        stack[stackptr - 1] = stack[stackptr - 2];
0984:                        stack[stackptr - 2] = x1;
0985:                        break;
0986:                    case 1029: // index
0987:                        i = (int) stack[stackptr - 1];
0988:                        if (i < 0)
0989:                            i = 0;
0990:                        stack[stackptr - 1] = stack[stackptr - 2 - i];
0991:                        break;
0992:                    case 1030: // roll
0993:                        i = (int) stack[--stackptr];
0994:                        int n = (int) stack[--stackptr];
0995:                        // roll n number by i (+ = upward)
0996:                        if (i > 0) {
0997:                            i = i % n;
0998:                        } else {
0999:                            i = n - (-i % n);
1000:                        }
1001:                        // x x x x i y y y -> y y y x x x x i (where i=3)
1002:                        if (i > 0) {
1003:                            float roll[] = new float[n];
1004:                            System.arraycopy(stack, stackptr - 1 - i, roll, 0,
1005:                                    i);
1006:                            System.arraycopy(stack, stackptr - 1 - n, roll, i,
1007:                                    n - i);
1008:                            System.arraycopy(roll, 0, stack, stackptr - 1 - n,
1009:                                    n);
1010:                        }
1011:                        break;
1012:                    case 1034: // hflex
1013:                        x1 = pt.x + stack[0];
1014:                        y1 = ybase = pt.y;
1015:                        x2 = x1 + stack[1];
1016:                        y2 = y1 + stack[2];
1017:                        pt.x = x2 + stack[3];
1018:                        pt.y = y2;
1019:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1020:                        x1 = pt.x + stack[4];
1021:                        y1 = pt.y;
1022:                        x2 = x1 + stack[5];
1023:                        y2 = ybase;
1024:                        pt.x = x2 + stack[6];
1025:                        pt.y = y2;
1026:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1027:                        pt.open = true;
1028:                        stackptr = 0;
1029:                        break;
1030:                    case 1035: // flex
1031:                        x1 = pt.x + stack[0];
1032:                        y1 = pt.y + stack[1];
1033:                        x2 = x1 + stack[2];
1034:                        y2 = y1 + stack[3];
1035:                        pt.x = x2 + stack[4];
1036:                        pt.y = y2 + stack[5];
1037:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1038:                        x1 = pt.x + stack[6];
1039:                        y1 = pt.y + stack[7];
1040:                        x2 = x1 + stack[8];
1041:                        y2 = y1 + stack[9];
1042:                        pt.x = x2 + stack[10];
1043:                        pt.y = y2 + stack[11];
1044:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1045:                        pt.open = true;
1046:                        stackptr = 0;
1047:                        break;
1048:                    case 1036: // hflex1
1049:                        ybase = pt.y;
1050:                        x1 = pt.x + stack[0];
1051:                        y1 = pt.y + stack[1];
1052:                        x2 = x1 + stack[2];
1053:                        y2 = y1 + stack[3];
1054:                        pt.x = x2 + stack[4];
1055:                        pt.y = y2;
1056:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1057:                        x1 = pt.x + stack[5];
1058:                        y1 = pt.y;
1059:                        x2 = x1 + stack[6];
1060:                        y2 = y1 + stack[7];
1061:                        pt.x = x2 + stack[8];
1062:                        pt.y = ybase;
1063:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1064:                        pt.open = true;
1065:                        stackptr = 0;
1066:                        break;
1067:                    case 1037: // flex1
1068:                        ybase = pt.y;
1069:                        float xbase = pt.x;
1070:                        x1 = pt.x + stack[0];
1071:                        y1 = pt.y + stack[1];
1072:                        x2 = x1 + stack[2];
1073:                        y2 = y1 + stack[3];
1074:                        pt.x = x2 + stack[4];
1075:                        pt.y = y2 + stack[5];
1076:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1077:                        x1 = pt.x + stack[6];
1078:                        y1 = pt.y + stack[7];
1079:                        x2 = x1 + stack[8];
1080:                        y2 = y1 + stack[9];
1081:                        if (Math.abs(x2 - xbase) > Math.abs(y2 - ybase)) {
1082:                            pt.x = x2 + stack[10];
1083:                            pt.y = ybase;
1084:                        } else {
1085:                            pt.x = xbase;
1086:                            pt.y = y2 + stack[10];
1087:                        }
1088:                        gp.curveTo(x1, y1, x2, y2, pt.x, pt.y);
1089:                        pt.open = true;
1090:                        stackptr = 0;
1091:                        break;
1092:                    default:
1093:                        System.out.println("ERROR! TYPE1C CHARSTRING CMD IS "
1094:                                + cmd);
1095:                        break;
1096:                    }
1097:                }
1098:            }
1099:
1100:            /**
1101:             * Get a glyph outline by name
1102:             *
1103:             * @param name the name of the desired glyph
1104:             * @return the glyph outline, or null if unavailable
1105:             */
1106:            protected GeneralPath getOutline(String name, float width) {
1107:                // first find the index of this name
1108:                int index = getNameIndex(name);
1109:
1110:                // now find the glyph with that name
1111:                for (int i = 0; i < glyphnames.length; i++) {
1112:                    if (glyphnames[i] == index) {
1113:                        return readGlyph(charstringbase, i);
1114:                    }
1115:                }
1116:
1117:                // not found -- return the unknown glyph
1118:                return readGlyph(charstringbase, 0);
1119:            }
1120:
1121:            /**
1122:             * Get a glyph outline by character code
1123:             *
1124:             * Note this method must always return an outline 
1125:             *
1126:             * @param src the character code of the desired glyph
1127:             * @return the glyph outline
1128:             */
1129:            protected GeneralPath getOutline(char src, float width) {
1130:                // ignore high bits
1131:                int index = (int) (src & 0xff);
1132:
1133:                // if we use a standard encoding, the mapping is from glyph to SID
1134:                // therefore we must find the glyph index in the name table
1135:                if (encodingbase == 0 || encodingbase == 1) {
1136:                    for (int i = 0; i < glyphnames.length; i++) {
1137:                        if (glyphnames[i] == encoding[index]) {
1138:                            return readGlyph(charstringbase, i);
1139:                        }
1140:                    }
1141:                } else {
1142:                    // for a custom encoding, the mapping is from glyph to GID, so
1143:                    // we can just map the glyph directly
1144:                    if (index > 0 && index < encoding.length) {
1145:                        return readGlyph(charstringbase, encoding[index]);
1146:                    }
1147:                }
1148:
1149:                // for some reason the glyph was not found, return the empty glyph
1150:                return readGlyph(charstringbase, 0);
1151:            }
1152:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.