Source Code Cross Referenced for Type1Font.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) 


001:        /*
002:         * $Id: Type1Font.java,v 1.2 2007/12/20 18:33:31 rbair Exp $
003:         *
004:         * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005:         * Santa Clara, California 95054, U.S.A. All rights reserved.
006:         *
007:         * This library is free software; you can redistribute it and/or
008:         * modify it under the terms of the GNU Lesser General Public
009:         * License as published by the Free Software Foundation; either
010:         * version 2.1 of the License, or (at your option) any later version.
011:         * 
012:         * This library is distributed in the hope that it will be useful,
013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         * Lesser General Public License for more details.
016:         * 
017:         * You should have received a copy of the GNU Lesser General Public
018:         * License along with this library; if not, write to the Free Software
019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020:         */
021:
022:        package com.sun.pdfview.font;
023:
024:        import java.awt.geom.AffineTransform;
025:        import java.awt.geom.GeneralPath;
026:        import java.awt.geom.NoninvertibleTransformException;
027:        import java.awt.geom.Point2D;
028:        import java.io.IOException;
029:        import java.util.HashMap;
030:        import java.util.Map;
031:        import java.util.TreeMap;
032:
033:        import com.sun.pdfview.PDFFile;
034:        import com.sun.pdfview.PDFObject;
035:
036:        /**
037:         * A representation, with parser, of an Adobe Type 1 font.
038:         * @author Mike Wessler
039:         */
040:        public class Type1Font extends OutlineFont {
041:            String chr2name[];
042:            int password;
043:            byte[] subrs[];
044:
045:            int lenIV;
046:
047:            Map name2outline;
048:            Map name2width;
049:
050:            AffineTransform at;
051:
052:            /** the Type1 stack of command values */
053:            float stack[] = new float[100];
054:            /** the current position in the Type1 stack */
055:            int sloc = 0;
056:
057:            /** the stack of postscript commands (used by callothersubr) */
058:            float psStack[] = new float[3];
059:            /** the current position in the postscript stack */
060:            int psLoc = 0;
061:
062:            /**
063:             * create a new Type1Font based on a font data stream and an encoding.
064:             * @param baseName the postscript name of this font
065:             * @param src the Font object as a stream with a dictionary
066:             * @param descriptor the descriptor for this font
067:             */
068:            public Type1Font(String baseName, PDFObject src,
069:                    PDFFontDescriptor descriptor) throws IOException {
070:                super (baseName, src, descriptor);
071:
072:                if (descriptor != null && descriptor.getFontFile() != null) {
073:                    // parse that file, filling name2outline and chr2name
074:                    int start = descriptor.getFontFile().getDictRef("Length1")
075:                            .getIntValue();
076:                    int len = descriptor.getFontFile().getDictRef("Length2")
077:                            .getIntValue();
078:                    byte font[] = descriptor.getFontFile().getStream();
079:
080:                    parseFont(font, start, len);
081:                }
082:            }
083:
084:            /** Read a font from it's data, start position and length */
085:            protected void parseFont(byte[] font, int start, int len) {
086:                name2width = new HashMap();
087:
088:                byte data[] = null;
089:
090:                if (isASCII(font, start)) {
091:                    byte[] bData = readASCII(font, start, start + len);
092:                    data = decrypt(bData, 0, bData.length, 55665, 4);
093:                } else {
094:                    data = decrypt(font, start, start + len, 55665, 4);
095:                }
096:
097:                // encoding is in cleartext area
098:                chr2name = readEncoding(font);
099:                int lenIVLoc = findSlashName(data, "lenIV");
100:                PSParser psp = new PSParser(data, 0);
101:                if (lenIVLoc < 0) {
102:                    lenIV = 4;
103:                } else {
104:                    psp.setLoc(lenIVLoc + 6);
105:                    lenIV = Integer.parseInt(psp.readThing());
106:                }
107:                password = 4330;
108:                int matrixloc = findSlashName(font, "FontMatrix");
109:                if (matrixloc < 0) {
110:                    System.out.println("No FontMatrix!");
111:                    at = new AffineTransform(0.001f, 0, 0, 0.001f, 0, 0);
112:                } else {
113:                    PSParser psp2 = new PSParser(font, matrixloc + 11);
114:                    // read [num num num num num num]
115:                    float xf[] = psp2.readArray(6);
116:                    //	    System.out.println("FONT MATRIX: "+xf);
117:                    at = new AffineTransform(xf);
118:                }
119:
120:                subrs = readSubrs(data);
121:                name2outline = new TreeMap(readChars(data));
122:                // at this point, name2outline holds name -> byte[].
123:            }
124:
125:            /**
126:             * parse the encoding portion of the font definition
127:             * @param d the font definition stream
128:             * @return an array of the glyphs corresponding to each byte
129:             */
130:            private String[] readEncoding(byte[] d) {
131:                byte[][] ary = readArray(d, "Encoding", "def");
132:                String res[] = new String[256];
133:                for (int i = 0; i < ary.length; i++) {
134:                    if (ary[i] != null) {
135:                        if (ary[i][0] == '/') {
136:                            res[i] = new String(ary[i]).substring(1);
137:                        } else {
138:                            res[i] = new String(ary[i]);
139:                        }
140:                    } else {
141:                        res[i] = null;
142:                    }
143:                }
144:                return res;
145:            }
146:
147:            /**
148:             * read the subroutines out of the font definition
149:             * @param d the font definition stream
150:             * @return an array of the subroutines, each as a byte array.
151:             */
152:            private byte[][] readSubrs(byte[] d) {
153:                return readArray(d, "Subrs", "index");
154:            }
155:
156:            /**
157:             * read a named array out of the font definition.
158:             * <p>
159:             * this function attempts to parse an array out of a postscript
160:             * definition without doing any postscript.  It's actually looking
161:             * for things that look like "dup <i>id</i> <i>elt</i> put", and
162:             * placing the <i>elt</i> at the <i>i</i>th position in the array.
163:             * @param d the font definition stream
164:             * @param key the name of the array
165:             * @param end a string that appears at the end of the array
166:             * @return an array consisting of a byte array for each entry
167:             */
168:            private byte[][] readArray(byte[] d, String key, String end) {
169:                int i = findSlashName(d, key);
170:                if (i < 0) {
171:                    // not found.
172:                    return new byte[0][];
173:                }
174:                // now find things that look like "dup id elt put"
175:                // end at "def"
176:                PSParser psp = new PSParser(d, i);
177:                psp.readThing(); // read the key (i is the start of the key)
178:                double val;
179:                String type = psp.readThing();
180:                if (type.equals("StandardEncoding")) {
181:                    byte[] stdenc[] = new byte[FontSupport.standardEncoding.length][];
182:                    for (i = 0; i < stdenc.length; i++) {
183:                        stdenc[i] = FontSupport.getName(
184:                                FontSupport.standardEncoding[i]).getBytes();
185:                    }
186:                    return stdenc;
187:                }
188:                int len = Integer.parseInt(type);
189:                byte[] out[] = new byte[len][];
190:                byte[] line;
191:                while (true) {
192:                    String s = psp.readThing();
193:                    if (s.equals("dup")) {
194:                        int id = Integer.parseInt(psp.readThing());
195:                        String elt = psp.readThing();
196:                        line = elt.getBytes();
197:                        if (Character.isDigit(elt.charAt(0))) {
198:                            int hold = Integer.parseInt(elt);
199:                            String special = psp.readThing();
200:                            if (special.equals("-|") || special.equals("RD")) {
201:                                psp.setLoc(psp.getLoc() + 1);
202:                                line = psp.getNEncodedBytes(hold, password,
203:                                        lenIV);
204:                            }
205:                        }
206:                        out[id] = line;
207:                    } else if (s.equals(end)) {
208:                        break;
209:                    }
210:                }
211:                return out;
212:            }
213:
214:            /**
215:             * decrypt an array using the Adobe Type 1 Font decryption algorithm.
216:             * @param d the input array of bytes
217:             * @param start where in the array to start decoding
218:             * @param end where in the array to stop decoding
219:             * @param key the decryption key
220:             * @param skip how many bytes to skip initially
221:             * @return the decrypted bytes.  The length of this array will be
222:             * (start-end-skip) bytes long
223:             */
224:            private byte[] decrypt(byte[] d, int start, int end, int key,
225:                    int skip) {
226:                if (end - start - skip < 0) {
227:                    skip = 0;
228:                }
229:                byte[] o = new byte[end - start - skip];
230:                int r = key;
231:                int ipos;
232:                int c1 = 52845;
233:                int c2 = 22719;
234:                for (ipos = start; ipos < end; ipos++) {
235:                    int c = d[ipos] & 0xff;
236:                    int p = (c ^ (r >> 8)) & 0xff;
237:                    r = ((c + r) * c1 + c2) & 0xffff;
238:                    if (ipos - start - skip >= 0) {
239:                        o[ipos - start - skip] = (byte) p;
240:                    }
241:                }
242:                return o;
243:            }
244:
245:            /**
246:             * Read data formatted as ASCII strings as binary data
247:             *
248:             * @param data the data, formatted as ASCII strings
249:             * @param start where in the array to start decrypting
250:             * @param end where in the array to stop decrypting
251:             */
252:            private byte[] readASCII(byte[] data, int start, int end) {
253:                // each byte of output is derived from one character (two bytes) of
254:                // input
255:                byte[] o = new byte[(end - start) / 2];
256:
257:                int count = 0;
258:                int bit = 0;
259:
260:                for (int loc = start; loc < end; loc++) {
261:                    char c = (char) (data[loc] & 0xff);
262:                    byte b = (byte) 0;
263:
264:                    if (c >= '0' && c <= '9') {
265:                        b = (byte) (c - '0');
266:                    } else if (c >= 'a' && c <= 'f') {
267:                        b = (byte) (10 + (c - 'a'));
268:                    } else if (c >= 'A' && c <= 'F') {
269:                        b = (byte) (10 + (c - 'A'));
270:                    } else {
271:                        // linefeed or something.  Skip.
272:                        continue;
273:                    }
274:
275:                    // which half of the byte are we?
276:                    if ((bit++ % 2) == 0) {
277:                        o[count] = (byte) (b << 4);
278:                    } else {
279:                        o[count++] |= b;
280:                    }
281:                }
282:
283:                return o;
284:            }
285:
286:            /** 
287:             * Determine if data is in ASCII or binary format.  According to the spec,
288:             * if any of the first 4 bytes are not character codes ('0' - '9' or
289:             * 'A' - 'F' or 'a' - 'f'), then the data is binary.  Otherwise it is
290:             * ASCII
291:             */
292:            private boolean isASCII(byte[] data, int start) {
293:                // look at the first 4 bytes
294:                for (int i = start; i < start + 4; i++) {
295:                    // get the byte as a character
296:                    char c = (char) (data[i] & 0xff);
297:
298:                    if (c >= '0' && c <= '9') {
299:                        continue;
300:                    } else if (c >= 'a' && c <= 'f') {
301:                        continue;
302:                    } else if (c >= 'A' && c <= 'F') {
303:                        continue;
304:                    } else {
305:                        // out of range
306:                        return false;
307:                    }
308:                }
309:
310:                // all were in range, so it is ASCII
311:                return true;
312:            }
313:
314:            /**
315:             * PostScript reader (not a parser, as the name would seem to indicate).
316:             */
317:            class PSParser {
318:                byte[] data;
319:                int loc;
320:
321:                /**
322:                 * create a PostScript reader given some data and an initial offset
323:                 * into that data.
324:                 * @param data the bytes of the postscript information
325:                 * @param start an initial offset into the data
326:                 */
327:                public PSParser(byte[] data, int start) {
328:                    this .data = data;
329:                    this .loc = start;
330:                }
331:
332:                /**
333:                 * get the next postscript "word".  This is basically the next
334:                 * non-whitespace block between two whitespace delimiters.
335:                 * This means that something like " [2 4 53]" will produce
336:                 * three items, while " [2 4 56 ]" will produce four.
337:                 */
338:                public String readThing() {
339:                    // skip whitespace
340:                    while (PDFFile.isWhiteSpace(data[loc])) {
341:                        loc++;
342:                    }
343:                    // read thing
344:                    int start = loc;
345:                    while (!PDFFile.isWhiteSpace(data[loc])) {
346:                        loc++;
347:                    }
348:                    String s = new String(data, start, loc - start);
349:                    //	    System.out.println("Read: "+s);
350:                    return s;
351:                }
352:
353:                /**
354:                 * read a set of numbers from the input.  This method doesn't
355:                 * pay any attention to "[" or "]" delimiters, and reads any
356:                 * non-numeric items as the number 0.
357:                 * @param count the number of items to read
358:                 * @return an array of count floats
359:                 */
360:                public float[] readArray(int count) {
361:                    float[] ary = new float[count];
362:                    int idx = 0;
363:                    while (idx < count) {
364:                        String thing = readThing();
365:                        if (thing.charAt(0) == '[') {
366:                            thing = thing.substring(1);
367:                        }
368:                        if (thing.endsWith("]")) {
369:                            thing = thing.substring(0, thing.length() - 1);
370:                        }
371:                        ary[idx++] = Float.valueOf(thing).floatValue();
372:                    }
373:                    return ary;
374:                }
375:
376:                /**
377:                 * get the current location within the input stream
378:                 */
379:                public int getLoc() {
380:                    return loc;
381:                }
382:
383:                /**
384:                 * set the current location within the input stream
385:                 */
386:                public void setLoc(int loc) {
387:                    this .loc = loc;
388:                }
389:
390:                /**
391:                 * treat the next n bytes of the input stream as encoded
392:                 * information to be decrypted.
393:                 * @param n the number of bytes to decrypt
394:                 * @param key the decryption key
395:                 * @param skip the number of bytes to skip at the beginning of the
396:                 * decryption
397:                 * @return an array of decrypted bytes.  The length of the array
398:                 * will be n-skip.
399:                 */
400:                public byte[] getNEncodedBytes(int n, int key, int skip) {
401:                    byte[] result = decrypt(data, loc, loc + n, key, skip);
402:                    loc += n;
403:                    return result;
404:                }
405:            }
406:
407:            /**
408:             * get the index into the byte array of a slashed name, like "/name".
409:             * @param d the search array
410:             * @param name the name to look for, without the initial /
411:             * @return the index of the first occurance of /name in the array.
412:             */
413:            private int findSlashName(byte[] d, String name) {
414:                int i;
415:                for (i = 0; i < d.length; i++) {
416:                    if (d[i] == '/') {
417:                        // check for key
418:                        boolean found = true;
419:                        for (int j = 0; j < name.length(); j++) {
420:                            if (d[i + j + 1] != name.charAt(j)) {
421:                                found = false;
422:                                break;
423:                            }
424:                        }
425:                        if (found) {
426:                            return i;
427:                        }
428:                    }
429:                }
430:                return -1;
431:            }
432:
433:            /**
434:             * get the character definitions of the font.
435:             * @param d the font data
436:             * @return a HashMap that maps string glyph names to byte arrays of
437:             * decoded font data.
438:             */
439:            private HashMap readChars(byte[] d) {
440:                // skip thru data until we find "/"+key
441:                HashMap hm = new HashMap();
442:                int i = findSlashName(d, "CharStrings");
443:                if (i < 0) {
444:                    // not found
445:                    return hm;
446:                }
447:                PSParser psp = new PSParser(d, i);
448:                // read /name len -| [len bytes] |-
449:                // until "end"
450:                while (true) {
451:                    String s = psp.readThing();
452:                    char c = s.charAt(0);
453:                    if (c == '/') {
454:                        int len = Integer.parseInt(psp.readThing());
455:                        String go = psp.readThing(); // it's -| or RD
456:                        if (go.equals("-|") || go.equals("RD")) {
457:                            psp.setLoc(psp.getLoc() + 1);
458:                            byte[] line = psp.getNEncodedBytes(len, password,
459:                                    lenIV);
460:                            hm.put(s.substring(1), line);
461:                        }
462:                    } else if (s.equals("end")) {
463:                        break;
464:                    }
465:                }
466:                return hm;
467:            }
468:
469:            /**
470:             * pop the next item off the stack
471:             */
472:            private float pop() {
473:                float val = 0;
474:                if (sloc > 0) {
475:                    val = stack[--sloc];
476:                }
477:                return val;
478:            }
479:
480:            int callcount = 0;
481:
482:            /**
483:             * parse glyph data into a GeneralPath, and return the advance width.
484:             * The working point is passed in as a parameter in order to allow
485:             * recursion.
486:             * @param cs the decrypted glyph data
487:             * @param gp a GeneralPath into which the glyph shape will be stored
488:             * @param pt a FlPoint object that will be used to generate the path
489:             * @param wid a FlPoint into which the advance width will be placed.
490:             */
491:            private void parse(byte[] cs, GeneralPath gp, FlPoint pt,
492:                    FlPoint wid) {
493:                //	System.out.println("--- cmd length is "+cs.length);
494:                int loc = 0;
495:                float x1, x2, x3, y1, y2, y3;
496:                while (loc < cs.length) {
497:                    int v = ((int) cs[loc++]) & 0xff;
498:                    if (v == 255) {
499:                        stack[sloc++] = ((((int) cs[loc]) & 0xff) << 24)
500:                                + ((((int) cs[loc + 1]) & 0xff) << 16)
501:                                + ((((int) cs[loc + 2]) & 0xff) << 8)
502:                                + ((((int) cs[loc + 3]) & 0xff));
503:                        loc += 4;
504:                        //		System.out.println("Pushed long "+stack[sloc-1]);
505:                    } else if (v >= 251) {
506:                        stack[sloc++] = -((v - 251) << 8)
507:                                - (((int) cs[loc]) & 0xff) - 108;
508:                        loc++;
509:                        //		System.out.println("Pushed lo "+stack[sloc-1]);
510:                    } else if (v >= 247) {
511:                        stack[sloc++] = ((v - 247) << 8)
512:                                + (((int) cs[loc]) & 0xff) + 108;
513:                        loc++;
514:                        //		System.out.println("Pushed hi "+stack[sloc-1]);
515:                    } else if (v >= 32) {
516:                        stack[sloc++] = v - 139;
517:                        //		System.out.println("Pushed "+stack[sloc-1]);
518:                    } else {
519:                        //		System.out.println("CMD: "+v+" (stack is size "+sloc+")");
520:                        switch (v) {
521:                        case 0: // x
522:                            throw new RuntimeException("Bad command (" + v
523:                                    + ")");
524:                        case 1: // hstem
525:                            sloc = 0;
526:                            break;
527:                        case 2: // x
528:                            throw new RuntimeException("Bad command (" + v
529:                                    + ")");
530:                        case 3: // vstem
531:                            sloc = 0;
532:                            break;
533:                        case 4: // y vmoveto
534:                            pt.y += pop();
535:                            gp.moveTo(pt.x, pt.y);
536:                            sloc = 0;
537:                            break;
538:                        case 5: // x y rlineto
539:                            pt.y += pop();
540:                            pt.x += pop();
541:                            gp.lineTo(pt.x, pt.y);
542:                            sloc = 0;
543:                            break;
544:                        case 6: // x hlineto
545:                            pt.x += pop();
546:                            gp.lineTo(pt.x, pt.y);
547:                            sloc = 0;
548:                            break;
549:                        case 7: // y vlineto
550:                            pt.y += pop();
551:                            gp.lineTo(pt.x, pt.y);
552:                            sloc = 0;
553:                            break;
554:                        case 8: // x1 y1 x2 y2 x3 y3 rcurveto
555:                            y3 = pop();
556:                            x3 = pop();
557:                            y2 = pop();
558:                            x2 = pop();
559:                            y1 = pop();
560:                            x1 = pop();
561:                            gp.curveTo(pt.x + x1, pt.y + y1, pt.x + x1 + x2,
562:                                    pt.y + y1 + y2, pt.x + x1 + x2 + x3, pt.y
563:                                            + y1 + y2 + y3);
564:                            pt.x += x1 + x2 + x3;
565:                            pt.y += y1 + y2 + y3;
566:                            sloc = 0;
567:                            break;
568:                        case 9: // closepath
569:                            gp.closePath();
570:                            sloc = 0;
571:                            break;
572:                        case 10: // n callsubr
573:                            int n = (int) pop();
574:                            if (subrs[n] == null) {
575:                                System.out.println("No subroutine #" + n);
576:                            } else {
577:                                callcount++;
578:                                if (callcount > 10) {
579:                                    System.out.println("Call stack too large");
580:                                    //			    throw new RuntimeException("Call stack too large");
581:                                } else {
582:                                    parse(subrs[n], gp, pt, wid);
583:                                }
584:                                callcount--;
585:                            }
586:                            break;
587:                        case 11: // return
588:                            return;
589:                        case 12: // ext...
590:                            v = ((int) cs[loc++]) & 0xff;
591:                            if (v == 6) { // s x y a b seac
592:                                char b = (char) pop();
593:                                char a = (char) pop();
594:                                float y = pop();
595:                                float x = pop();
596:                                buildAccentChar(x, y, a, b, gp);
597:                                sloc = 0;
598:                            } else if (v == 7) { // x y w h sbw
599:                                wid.y = pop();
600:                                wid.x = pop();
601:                                pt.y = pop();
602:                                pt.x = pop();
603:                                sloc = 0;
604:                            } else if (v == 12) { // a b div -> a/b
605:                                float b = pop();
606:                                float a = pop();
607:                                stack[sloc++] = a / b;
608:                            } else if (v == 33) { // a b setcurrentpoint
609:                                pt.y = pop();
610:                                pt.x = pop();
611:                                gp.moveTo(pt.x, pt.y);
612:                                sloc = 0;
613:                            } else if (v == 0) { // dotsection
614:                                sloc = 0;
615:                            } else if (v == 1) { // vstem3
616:                                sloc = 0;
617:                            } else if (v == 2) { // hstem3
618:                                sloc = 0;
619:                            } else if (v == 16) { // n callothersubr
620:                                int cn = (int) pop();
621:                                int countargs = (int) pop();
622:
623:                                //    System.out.println("Called othersubr with index "+cn);
624:
625:                                switch (cn) {
626:                                case 0:
627:                                    // push args2 and args3 onto stack
628:                                    psStack[psLoc++] = pop();
629:                                    psStack[psLoc++] = pop();
630:                                    pop();
631:                                    break;
632:                                case 3:
633:                                    // push 3 onto the postscript stack
634:                                    psStack[psLoc++] = 3;
635:                                    break;
636:                                default:
637:                                    // push arguments onto the postscript stack
638:                                    for (int i = 0; i > countargs; i--) {
639:                                        psStack[psLoc++] = pop();
640:                                    }
641:                                    break;
642:                                }
643:                            } else if (v == 17) { // pop
644:                                // pop from the postscript stack onto the type1 stack
645:                                stack[sloc++] = psStack[psLoc - 1];
646:                                psLoc--;
647:                            } else {
648:                                throw new RuntimeException("Bad command (" + v
649:                                        + ")");
650:                            }
651:                            break;
652:                        case 13: // s w hsbw
653:                            wid.x = pop();
654:                            wid.y = 0;
655:                            pt.x = pop();
656:                            pt.y = 0;
657:                            //		    gp.moveTo(pt.x, pt.y);
658:                            sloc = 0;
659:                            break;
660:                        case 14: // endchar
661:                            //		    return;
662:                            break;
663:                        case 15: // x
664:                        case 16: // x
665:                        case 17: // x
666:                        case 18: // x
667:                        case 19: // x
668:                        case 20: // x
669:                            throw new RuntimeException("Bad command (" + v
670:                                    + ")");
671:                        case 21: // x y rmoveto
672:                            pt.y += pop();
673:                            pt.x += pop();
674:                            gp.moveTo(pt.x, pt.y);
675:                            sloc = 0;
676:                            break;
677:                        case 22: // x hmoveto
678:                            pt.x += pop();
679:                            gp.moveTo(pt.x, pt.y);
680:                            sloc = 0;
681:                            break;
682:                        case 23: // x
683:                        case 24: // x
684:                        case 25: // x
685:                        case 26: // x
686:                        case 27: // x
687:                        case 28: // x
688:                        case 29: // x
689:                            throw new RuntimeException("Bad command (" + v
690:                                    + ")");
691:                        case 30: // y1 x2 y2 x3 vhcurveto
692:                            x3 = pop();
693:                            y2 = pop();
694:                            x2 = pop();
695:                            y1 = pop();
696:                            x1 = y3 = 0;
697:                            gp.curveTo(pt.x, pt.y + y1, pt.x + x2, pt.y + y1
698:                                    + y2, pt.x + x2 + x3, pt.y + y1 + y2);
699:                            pt.x += x2 + x3;
700:                            pt.y += y1 + y2;
701:                            sloc = 0;
702:                            break;
703:                        case 31: // x1 x2 y2 y3 hvcurveto
704:                            y3 = pop();
705:                            y2 = pop();
706:                            x2 = pop();
707:                            x1 = pop();
708:                            y1 = x3 = 0;
709:                            gp.curveTo(pt.x + x1, pt.y, pt.x + x1 + x2, pt.y
710:                                    + y2, pt.x + x1 + x2, pt.y + y2 + y3);
711:                            pt.x += x1 + x2;
712:                            pt.y += y2 + y3;
713:                            sloc = 0;
714:                            break;
715:                        }
716:                    }
717:                }
718:            }
719:
720:            /**
721:             * build an accented character out of two pre-defined glyphs.
722:             * @param x the x offset of the accent
723:             * @param y the y offset of the accent
724:             * @param a the index of the accent glyph
725:             * @param b the index of the base glyph
726:             * @param gp the GeneralPath into which the combined glyph will be
727:             * written.
728:             */
729:            private void buildAccentChar(float x, float y, char a, char b,
730:                    GeneralPath gp) {
731:                // get the outline of the accent
732:                GeneralPath pathA = getOutline(a, getWidth(a, null));
733:
734:                try {
735:                    // undo the effect of the transform applied in read 
736:                    AffineTransform xformA = at.createInverse();
737:                    xformA.translate(x, y);
738:                    pathA.transform(xformA);
739:                } catch (NoninvertibleTransformException nte) {
740:                    pathA.transform(AffineTransform.getTranslateInstance(x, y));
741:                }
742:
743:                GeneralPath pathB = getOutline(b, getWidth(b, null));
744:
745:                try {
746:                    AffineTransform xformB = at.createInverse();
747:                    pathB.transform(xformB);
748:                } catch (NoninvertibleTransformException nte) {
749:                    // ignore
750:                }
751:
752:                gp.append(pathB, false);
753:                gp.append(pathA, false);
754:            }
755:
756:            /** 
757:             * Get the width of a given character
758:             *
759:             * This method is overridden to work if the width array hasn't been
760:             * populated (as for one of the 14 base fonts)
761:             */
762:            public float getWidth(char code, String name) {
763:                // we don't have first and last chars, so therefore no width array
764:                if (getFirstChar() == -1 || getLastChar() == -1) {
765:                    String key = chr2name[code & 0xff];
766:
767:                    // use a name if one is provided
768:                    if (name != null) {
769:                        key = name;
770:                    }
771:
772:                    if (key != null && name2outline.containsKey(key)) {
773:                        if (!name2width.containsKey(key)) {
774:                            // glyph has not yet been parsed
775:                            // getting the outline will force it to get read
776:                            getOutline(key, 0);
777:                        }
778:
779:                        FlPoint width = (FlPoint) name2width.get(key);
780:                        if (width != null) {
781:                            return width.x / getDefaultWidth();
782:                        }
783:                    }
784:
785:                    return 0;
786:                }
787:
788:                // return the width that has been specified
789:                return super .getWidth(code, name);
790:            }
791:
792:            /**
793:             * Decrypt a glyph stored in byte form
794:             */
795:            private synchronized GeneralPath parseGlyph(byte[] cs,
796:                    FlPoint advance, AffineTransform at) {
797:                GeneralPath gp = new GeneralPath();
798:                FlPoint curpoint = new FlPoint();
799:
800:                sloc = 0;
801:                parse(cs, gp, curpoint, advance);
802:
803:                gp.transform(at);
804:                return gp;
805:            }
806:
807:            /**
808:             * Get a glyph outline by name
809:             *
810:             * @param name the name of the desired glyph
811:             * @return the glyph outline, or null if unavailable
812:             */
813:            protected GeneralPath getOutline(String name, float width) {
814:                // make sure we have a valid name
815:                if (name == null || !name2outline.containsKey(name)) {
816:                    name = ".notdef";
817:                }
818:
819:                // get whatever is stored in name
820:                Object obj = name2outline.get(name);
821:
822:                // if it's a byte array, it needs to be parsed
823:                // otherwise, just return the path
824:                if (obj instanceof  GeneralPath) {
825:                    return (GeneralPath) obj;
826:                } else {
827:                    byte[] cs = (byte[]) obj;
828:                    FlPoint advance = new FlPoint();
829:
830:                    GeneralPath gp = parseGlyph(cs, advance, at);
831:
832:                    if (width != 0 && advance.x != 0) {
833:                        // scale the glyph to fit in the width
834:                        Point2D p = new Point2D.Float(advance.x, advance.y);
835:                        at.transform(p, p);
836:
837:                        double scale = width / p.getX();
838:                        AffineTransform xform = AffineTransform
839:                                .getScaleInstance(scale, 1.0);
840:                        gp.transform(xform);
841:                    }
842:
843:                    // put the parsed object in the cache
844:                    name2outline.put(name, gp);
845:                    name2width.put(name, advance);
846:                    return gp;
847:                }
848:            }
849:
850:            /**
851:             * Get a glyph outline by character code
852:             *
853:             * Note this method must always return an outline 
854:             *
855:             * @param src the character code of the desired glyph
856:             * @return the glyph outline
857:             */
858:            protected GeneralPath getOutline(char src, float width) {
859:                return getOutline(chr2name[src & 0xff], width);
860:            }
861:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.