001: /*
002: * $Id: FontDef.java,v 1.3 2002/02/24 02:10:19 skavish Exp $
003: *
004: * ==========================================================================
005: *
006: * The JGenerator Software License, Version 1.0
007: *
008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
009: *
010: * Redistribution and use in source and binary forms, with or without
011: * modification, are permitted provided that the following conditions are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowlegement:
023: * "This product includes software developed by Dmitry Skavish
024: * (skavish@usa.net, http://www.flashgap.com/)."
025: * Alternately, this acknowlegement may appear in the software itself,
026: * if and wherever such third-party acknowlegements normally appear.
027: *
028: * 4. The name "The JGenerator" must not be used to endorse or promote
029: * products derived from this software without prior written permission.
030: * For written permission, please contact skavish@usa.net.
031: *
032: * 5. Products derived from this software may not be called "The JGenerator"
033: * nor may "The JGenerator" appear in their names without prior written
034: * permission of Dmitry Skavish.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: *
049: */
050:
051: package org.openlaszlo.iv.flash.api.text;
052:
053: import org.openlaszlo.iv.flash.parser.Parser;
054: import org.openlaszlo.iv.flash.util.*;
055: import org.openlaszlo.iv.flash.cache.*;
056:
057: import org.openlaszlo.iv.flash.api.*;
058: import java.io.*;
059: import java.awt.geom.Rectangle2D;
060:
061: /**
062: * Instance of Font in particular flash file.
063: * <p>
064: * There may be several instances of one font in one file.
065: *
066: * @author Dmitry Skavish
067: */
068: public final class FontDef extends FlashDef {
069:
070: private boolean isWriteLayout = false; // if true - write font outlines as well
071: private boolean isWriteAllChars = false; // if true - write full set of characters, otherwise only used ones
072: private Font font; // font
073: private IVVector textBlocks = new IVVector(); // vector of TextBlock's using this font
074:
075: /**
076: * Creates empty font definition
077: */
078: public FontDef() {
079: }
080:
081: /**
082: * Creates font definition of specified font and ID
083: *
084: * @param font specified font
085: * @param id ID of font definition to be created
086: */
087: public FontDef(Font font, int id) {
088: this .font = font;
089: setID(id);
090: }
091:
092: public int getTag() {
093: return Tag.DEFINEFONT2;
094: }
095:
096: /**
097: * Returns font name
098: *
099: * @return font name
100: */
101: public String getFontName() {
102: return font.fontName;
103: }
104:
105: /**
106: * Returns font
107: *
108: * @return font
109: */
110: public Font getFont() {
111: return font;
112: }
113:
114: public void setFont(Font font) {
115: this .font = font;
116: }
117:
118: /**
119: * Adds specified text block to this fontdef
120: *
121: * @param tblock specified text block
122: */
123: public void addTextBlock(TextBlock tblock) {
124: if (tblock == null)
125: return;
126: textBlocks.addElement(tblock);
127: }
128:
129: /**
130: * Adds vector of text blocks to this fontdef
131: *
132: * @param tblocks vector of text blocks
133: */
134: public void addTextBlocks(IVVector tblocks) {
135: if (tblocks == null)
136: return;
137: for (int i = 0; i < tblocks.size(); i++) {
138: addTextBlock((TextBlock) tblocks.elementAt(i));
139: }
140: }
141:
142: /**
143: * Returns all text blocks added to this fontdef
144: *
145: * @return all text blocks added to this fontdef
146: */
147: public IVVector getTextBlocks() {
148: return textBlocks;
149: }
150:
151: /**
152: * Specifies whether to write layout information when generating this font or not
153: *
154: * @param v true - write layout
155: */
156: public void setWriteLayout(boolean v) {
157: isWriteLayout = v;
158: }
159:
160: /**
161: * Returns true if layout information is going to generated
162: *
163: * @return true if layout information is going to generated
164: */
165: public boolean isWriteLayout() {
166: return isWriteLayout;
167: }
168:
169: /**
170: * Specifies whether to write all font's character or only used (in text blocks) ones.
171: *
172: * @param v true - write all characters
173: */
174: public void setWriteAllChars(boolean v) {
175: isWriteAllChars = v;
176: }
177:
178: /**
179: * Returns true if all font's character are going to be generated
180: *
181: * @return true if all font's character are going to be generated
182: */
183: public boolean isWriteAllChars() {
184: return isWriteAllChars;
185: }
186:
187: /**
188: * Parses External font tag
189: */
190: public static FontDef parseExternalFontTag(Parser p) {
191: int id = p.getUWord();
192: String fontFileName = p.getString();
193: Font font = load(fontFileName, p.getFile());
194: if (font != null)
195: return new FontDef(font, id);
196: return null;
197: }
198:
199: /**
200: * Loads external font to the specified file
201: */
202: public static Font load(String fontFileName, FlashFile file) {
203: FlashFile fontFile;
204: try {
205: fontFile = file.addExternalFile(fontFileName, true);
206: } catch (IVException e) {
207: Log.log(e);
208: // load default symbol file and pick first font from it
209: fontFile = file.getDefaultSymbolFile();
210: }
211: if (fontFile != null) {
212: IVVector v = fontFile.getLocalFonts();
213: if (v.size() == 0) {
214: Log.logRB(Resource.INVLEXTERNALFONT,
215: new Object[] { fontFileName });
216: return null;
217: }
218: return (Font) v.elementAt(0);
219: }
220: return null;
221: }
222:
223: /**
224: * Loads font from file (FFT)
225: *
226: * @param fontFileName font file name
227: * @return loaded font
228: */
229: public static Font load(String fontFileName) {
230: FlashFile fontFile;
231:
232: // Find the font
233: fontFileName = Util.translatePath(fontFileName);
234: File f = new File(fontFileName);
235: if (!f.exists()) {
236: fontFileName = Util.concatFileNames(
237: PropertyManager.fontPath, fontFileName);
238: f = new File(Util.getInstallDir(), fontFileName);
239: if (!f.exists()) {
240: Log.logRB(Resource.FILENOTFOUND,
241: new Object[] { fontFileName });
242: return null;
243: }
244: }
245: fontFileName = f.getAbsolutePath();
246:
247: // Load the font
248: try {
249: fontFile = FlashFile.parse(fontFileName);
250: IVVector v = fontFile.getLocalFonts();
251: if (v.size() == 0) {
252: Log.logRB(Resource.INVLEXTERNALFONT,
253: new Object[] { fontFileName });
254: return null;
255: }
256: return (Font) v.elementAt(0);
257: } catch (FileNotFoundException e) {
258: Log.logRB(Resource.FILENOTFOUND,
259: new Object[] { fontFileName });
260: return null;
261: } catch (IVException e) {
262: Log.log(e);
263: return null;
264: }
265: }
266:
267: /**
268: * Parses DefineFont tag.
269: * <P>
270: * We expect that after DefineFont tag, DefineFontInfo tag will follow
271: * which will define codetable for this font.<br>
272: * This is not always true of course, but in majority of cases it is.
273: *
274: * @param p parser
275: * @return font def
276: */
277: public static FontDef parse(Parser p) {
278: // get id
279: int id = p.getUWord();
280: Font font = new Font();
281: font.flags = Font.ANSI;
282: font.fileBuffer = p.getBuf();
283:
284: // get offset table and shape table
285: int tableOffset = p.getPos();
286: int offset = p.getUWord();
287: int nGlyph = offset / 2;
288:
289: int[] glyphOffsets = new int[nGlyph + 1]; // +1 because we need last offset
290: glyphOffsets[0] = tableOffset + offset;
291: for (int i = 1; i < nGlyph; i++)
292: glyphOffsets[i] = tableOffset + p.getUWord();
293:
294: p.skipLastTag(); // skip all shapes
295: glyphOffsets[nGlyph] = p.getPos();
296:
297: font.glyphOffsets = glyphOffsets;
298:
299: // there is no need to cache font, fontinfo will take care of it
300: return new FontDef(font, id);
301: }
302:
303: /**
304: * Parse DefineFontInfo tag
305: */
306: public static void parseFontInfoTag(Parser p, boolean MX) {
307: // get id
308: int fontId = p.getUWord();
309: FontDef fontDef = (FontDef) p.getDef(fontId);
310: String fontName = p.getString(p.getUByte());
311: int flags = (MX) ? p.getUWord() : p.getUByte();
312: String ext = ((flags & 0x04) != 0 ? "%i" : "")
313: + ((flags & 0x02) != 0 ? "%b" : "");
314: String fontKey = fontName + ext;
315:
316: // do not put this font into cache
317: // later on we will try to merge it into some probably existing in cache font
318:
319: Font font = fontDef.font;
320: font.fontName = fontName;
321: font.fontKey = fontKey;
322: font.flags = ((flags & 0x04) != 0 ? Font.ITALIC : 0)
323: | ((flags & 0x02) != 0 ? Font.BOLD : 0)
324: | ((flags & 0x20) != 0 ? Font.UNICODE : 0)
325: | ((flags & 0x10) != 0 ? Font.SHIFT_JIS : 0)
326: | ((flags & 0x08) != 0 ? Font.ANSI : 0)
327: | ((flags & 0x01) != 0 ? Font.WIDE_CODES : 0);
328: //Log.logRB( Resource.STR, "parseInfo: font="+fontName+", font2="+font2+", flags="+Util.w2h(font.flags) );
329: // get code table
330: int nGlyph = font.getNumGlyph();
331: int[] codeTable = new int[nGlyph];
332: if ((font.flags & Font.WIDE_CODES) != 0) {
333: for (int i = 0; i < nGlyph; i++)
334: codeTable[i] = p.getUWord();
335: } else {
336: for (int i = 0; i < nGlyph; i++)
337: codeTable[i] = p.getUByte();
338: }
339: font.codeTable = codeTable;
340:
341: // find 'blank'
342: for (int i = 0; i < nGlyph; i++) {
343: if (codeTable[i] == ' ') {
344: font.blankPos = i;
345: break;
346: }
347: }
348: }
349:
350: /**
351: * Parse DefineFontInfo tag
352: */
353: public static void parseFontInfoTag(Parser p) {
354: parseFontInfoTag(p, false);
355: }
356:
357: /**
358: * Parse DefineFontInfo2 tag
359: */
360: public static void parseFontInfoTag2(Parser p) {
361: parseFontInfoTag(p, true);
362: }
363:
364: /**
365: * Parse DefineFont2 tag
366: */
367: public static FontDef parse2(Parser p) {
368: // get id
369: int id = p.getUWord();
370: // get flags
371: int flags = p.getUWord();
372: // get name of the font
373: String fontName = p.getString(p.getUByte());
374:
375: // check if this font is in cache
376: String ext = ((flags & Font.ITALIC) != 0 ? "%i" : "")
377: + ((flags & Font.BOLD) != 0 ? "%b" : "");
378: String fontKey = fontName + ext;
379: /* NOTE LASZLO: [2003-09-22 bloch] disable font cache (see bug 2109) */
380: /*
381: Font font2 = FontCache.getFont( fontKey );
382: */
383: Font font2 = null;
384:
385: // get offset table and shape table
386: int nGlyph = p.getUWord();
387:
388: // if these fonts have the same number of glyphs and the same flags then
389: // we guess that this is the same font and don't parse it further
390: // (we may be wrong, but it's very unlikely)
391: if (font2 != null) {
392: if (nGlyph == font2.getNumGlyph() && flags == font2.flags) {
393: return new FontDef(font2, id);
394: }
395: }
396:
397: Font font = new Font();
398: font.flags = flags;
399: font.fontName = fontName;
400: font.fontKey = fontKey;
401: font.fileBuffer = p.getBuf();
402: int tableOffset = p.getPos();
403: int[] glyphOffsets = new int[nGlyph + 1]; // +1 because we need last offset
404: int codeOff;
405: if ((flags & Font.WIDE_OFFSETS) != 0) {
406: for (int i = 0; i < nGlyph; i++)
407: glyphOffsets[i] = tableOffset + p.getUDWord();
408: codeOff = p.getUDWord();
409: } else {
410: for (int i = 0; i < nGlyph; i++)
411: glyphOffsets[i] = tableOffset + p.getUWord();
412: codeOff = p.getUWord();
413: }
414: font.glyphOffsets = glyphOffsets;
415:
416: // do not parse shapes, delay until we really need them
417: p.setPos(tableOffset + codeOff); // skip shapes
418: glyphOffsets[nGlyph] = p.getPos();
419:
420: // get code table
421: int[] codeTable = new int[nGlyph];
422: if ((flags & Font.WIDE_CODES) != 0) {
423: for (int i = 0; i < nGlyph; i++)
424: codeTable[i] = p.getUWord();
425: } else {
426: for (int i = 0; i < nGlyph; i++)
427: codeTable[i] = p.getUByte();
428: }
429: font.codeTable = codeTable;
430:
431: // find 'blank'
432: for (int i = 0; i < nGlyph; i++) {
433: if (codeTable[i] == ' ') {
434: font.blankPos = i;
435: break;
436: }
437: }
438:
439: if ((flags & Font.HAS_LAYOUT) != 0) {
440: font.ascent = p.getWord();
441: font.descent = p.getWord();
442: font.leading = p.getWord();
443:
444: // get advance table
445: int[] advanceTable = new int[nGlyph];
446: for (int i = 0; i < nGlyph; i++)
447: advanceTable[i] = p.getWord();
448: font.advanceTable = advanceTable;
449:
450: // skip bounds table, delay until we need them
451: font.boundsBuffer = p.getBuf();
452: font.boundsOffset = p.getPos();
453: for (int i = 0; i < nGlyph; i++)
454: p.skipRect();
455: font.boundsLength = p.getPos() - font.boundsOffset;
456:
457: // get kerning table
458: int nKern = p.getUWord();
459: font.kernLeftCodes = new int[nKern];
460: font.kernRightCodes = new int[nKern];
461: font.kernAdjustment = new int[nKern];
462: if ((flags & Font.WIDE_CODES) != 0) {
463: for (int i = 0; i < nKern; i++) {
464: font.kernLeftCodes[i] = p.getUWord();
465: font.kernRightCodes[i] = p.getUWord();
466: font.kernAdjustment[i] = p.getWord();
467: }
468: } else {
469: for (int i = 0; i < nKern; i++) {
470: font.kernLeftCodes[i] = p.getUByte();
471: font.kernRightCodes[i] = p.getUByte();
472: font.kernAdjustment[i] = p.getWord();
473: }
474: }
475: }
476:
477: // cache only if there is no already such font in cache, font has a layout and number of
478: // glyphs >= 200
479: /* NOTE LASZLO: [2003-09-22 bloch] disable font cache (see bug 2109) */
480: /*
481: if( font2 == null && (flags&Font.HAS_LAYOUT) != 0 && nGlyph >= 200 ) {
482: FontCache.addFont( fontKey, font );
483: }
484: */
485:
486: return new FontDef(font, id);
487: }
488:
489: /**
490: * Builds and generates this font into buffer
491: *
492: * @param fob flash buffer
493: */
494: public void write(FlashOutput fob) {
495:
496: if (fob.defined(font)) {
497: return;
498: }
499:
500: int pos = fob.getPos();
501: fob.skip(6);
502:
503: fob.writeFontID(font);
504: if (isWriteLayout) {
505: fob.writeWord(font.flags);
506: } else {
507: fob.writeWord(font.flags & ~Font.HAS_LAYOUT);
508: }
509: fob.writeStringL(getFontName());
510:
511: // create index table
512: int[] indexTable = new int[font.codeTable.length];
513:
514: // create codetable from registered text blocks
515: int[] codeTable;
516: int nGlyph;
517: if (isWriteAllChars) {
518: codeTable = font.codeTable;
519: nGlyph = codeTable.length;
520: for (int i = 0; i < indexTable.length; i++)
521: indexTable[i] = i;
522: } else {
523: codeTable = new int[font.codeTable.length];
524: nGlyph = 0;
525: }
526:
527: for (int i = 0; i < textBlocks.size(); i++) {
528: TextBlock tblock = (TextBlock) textBlocks.elementAt(i);
529: tblock.layout();
530: IVVector trs = tblock.getTextRecords(font);
531: if (trs == null || trs.size() == 0)
532: continue;
533: for (int t = 0; t < trs.size(); t++) {
534: TextRecord tr = (TextRecord) trs.elementAt(t);
535: L1: for (int c = 0; c < tr.getSize(); c++) {
536: char ch = tr.getChar(c);
537: if (ch == '\r' || ch == '\n') { // how come we see this chars here ?
538: tr.setIndex(c, 0); // ???
539: continue;
540: }
541: // find this char in our codetable
542: for (int j = 0; j < nGlyph; j++) {
543: if (codeTable[j] == ch) {
544: tr.setIndex(c, j);
545: continue L1;
546: }
547: }
548: // char has not been not found, add it
549: if (!isWriteAllChars) { // should always be true here!
550: int idx = font.getIndex(ch); // get original index
551: if (idx == -1) {
552: idx = font.getIndex(' ');
553: }
554: indexTable[nGlyph] = idx;
555: tr.setIndex(c, nGlyph);
556: codeTable[nGlyph] = ch;
557: ++nGlyph;
558: }
559: }
560: }
561: }
562:
563: fob.writeWord(nGlyph);
564: int offsetTable = fob.getPos();
565: int inc = (font.flags & Font.WIDE_OFFSETS) != 0 ? 4 : 2;
566: fob.skip(nGlyph * inc);
567: int codeOffset = fob.getPos();
568: fob.skip(inc);
569: for (int i = 0, curOff = offsetTable; i < nGlyph; i++, curOff += inc) {
570: int offset = fob.getPos() - offsetTable;
571: int idx = indexTable[i];
572: int start = font.glyphOffsets[idx];
573: int end = font.glyphOffsets[idx + 1];
574: fob.writeArray(font.fileBuffer, start, end - start);
575: if (inc == 2)
576: fob.writeWordAt(offset, curOff);
577: else
578: fob.writeDWordAt(offset, curOff);
579: }
580: if (inc == 2)
581: fob.writeWordAt(fob.getPos() - offsetTable, codeOffset);
582: else
583: fob.writeDWordAt(fob.getPos() - offsetTable, codeOffset);
584:
585: for (int i = 0; i < nGlyph; i++) {
586: if ((font.flags & Font.WIDE_CODES) != 0) {
587: fob.writeWord(codeTable[i]);
588: } else {
589: fob.writeByte(codeTable[i]);
590: }
591: }
592:
593: // write layout
594: if (isWriteLayout && ((font.flags & Font.HAS_LAYOUT) != 0)) {
595: fob.writeWord(font.ascent);
596: fob.writeWord(font.descent);
597: fob.writeWord(font.leading);
598:
599: // write advance table
600: for (int i = 0; i < nGlyph; i++)
601: fob.writeWord(font.advanceTable[indexTable[i]]);
602:
603: // copy bounds table
604: if (isWriteAllChars) {
605: // just for the sake of perfomance, because font.getGlyphBounds() causes parsing of all bounds
606: fob.writeArray(font.boundsBuffer, font.boundsOffset,
607: font.boundsLength);
608: } else {
609: Rectangle2D[] bounds = font.getGlyphBounds();
610: for (int i = 0; i < nGlyph; i++) {
611: fob.write(bounds[indexTable[i]]);
612: }
613: }
614:
615: // write kerning tables
616: // probably we need to restrict writing only to codes from codetable
617: int nKern = font.kernLeftCodes.length;
618: fob.writeWord(nKern);
619: if ((font.flags & Font.WIDE_CODES) != 0) {
620: for (int i = 0; i < nKern; i++) {
621: fob.writeWord(font.kernLeftCodes[i]);
622: fob.writeWord(font.kernRightCodes[i]);
623: fob.writeWord(font.kernAdjustment[i]);
624: }
625: } else {
626: for (int i = 0; i < nKern; i++) {
627: fob.writeByte(font.kernLeftCodes[i]);
628: fob.writeByte(font.kernRightCodes[i]);
629: fob.writeWord(font.kernAdjustment[i]);
630: }
631: }
632: }
633:
634: fob
635: .writeLongTagAt(Tag.DEFINEFONT2,
636: fob.getPos() - pos - 6, pos);
637: }
638:
639: /**
640: * Merge two fonts
641: *
642: * @param f1 font to merge
643: * @param f2 font to merge
644: * @return new merged font
645: */
646: public static Font mergeFonts(Font f1, Font f2) {
647: //System.out.println( "Merging fonts: "+f2.getFontName() );
648: int flags = f2.flags | f1.flags;
649: //System.out.println( "f2_flags: "+Util.w2h(f2.flags)+", f1_flags: "+Util.w2h(f2.flags) );
650:
651: boolean f1_hasLayout = (f1.flags & Font.HAS_LAYOUT) != 0;
652: boolean f2_hasLayout = (f2.flags & Font.HAS_LAYOUT) != 0;
653: if (f1_hasLayout && !f2_hasLayout) {
654: Font f = f1;
655: f1 = f2;
656: f2 = f;
657: boolean fb = f1_hasLayout;
658: f1_hasLayout = f2_hasLayout;
659: f2_hasLayout = fb;
660: }
661:
662: // merge code tables
663: int[] codeTable1 = f1.codeTable;
664: int[] codeTable2 = f2.codeTable;
665: int n = 0;
666: int[] codeTable_tmp = new int[codeTable1.length];
667: int[] indexes = new int[codeTable1.length];
668: for (int i = 0; i < codeTable1.length; i++) {
669: int code = codeTable1[i];
670: int j = 0;
671: for (; j < codeTable2.length; j++) {
672: if (codeTable2[j] == code)
673: break;
674: }
675: if (j == codeTable2.length) {
676: codeTable_tmp[n] = code;
677: indexes[n] = i;
678: n++;
679: }
680: }
681:
682: if (n == 0) { // no new characters in f1
683: f2.copyTo(f1); // no need!!!
684: return f2;
685: }
686: //System.out.println( "continue merge" );
687:
688: int nGlyph = codeTable2.length + n;
689: int[] codeTable = new int[nGlyph];
690: System
691: .arraycopy(codeTable2, 0, codeTable, 0,
692: codeTable2.length);
693: System.arraycopy(codeTable_tmp, 0, codeTable,
694: codeTable2.length, n);
695:
696: // merge glyphs
697: int f1_start = f1.glyphOffsets[0];
698: int f1_end = f1.glyphOffsets[codeTable1.length];
699: int f2_start = f2.glyphOffsets[0];
700: int f2_end = f2.glyphOffsets[codeTable2.length];
701: int totalSize = f1_end - f1_start + f2_end - f2_start;
702: byte[] fileBuffer = new byte[totalSize];
703: int[] glyphOffsets = new int[nGlyph + 1];
704: int offset = f2_end - f2_start;
705: // copy glyphoffset and shapes from f2
706: System
707: .arraycopy(f2.fileBuffer, f2_start, fileBuffer, 0,
708: offset);
709: int gln = 0;
710: for (; gln < codeTable2.length; gln++) {
711: int off = f2.glyphOffsets[gln] - f2_start;
712: glyphOffsets[gln] = off;
713: }
714: // copy glyphoffsets and shapes from f1
715: for (int i = 0; i < n; i++, gln++) {
716: int idx = indexes[i];
717: int start = f1.glyphOffsets[idx];
718: int end = f1.glyphOffsets[idx + 1];
719: int size = end - start;
720: System.arraycopy(f1.fileBuffer, start, fileBuffer, offset,
721: size);
722: glyphOffsets[gln] = offset;
723: offset += size;
724: }
725: glyphOffsets[gln] = offset;
726:
727: int[] advanceTable = null;
728: int[] kernLeftCodes = f2.kernLeftCodes;
729: int[] kernRightCodes = f2.kernRightCodes;
730: int[] kernAdjustment = f2.kernAdjustment;
731: // 2 cases:
732: // - no fonts have layouts
733: // - at least f2 has layout
734: if (f1_hasLayout || f2_hasLayout) {
735: if (f1_hasLayout) {
736: // merge two layouts
737: // extend advancetable and boundstable
738: advanceTable = new int[nGlyph];
739: int off = codeTable2.length;
740: System.arraycopy(f2.advanceTable, 0, advanceTable, 0,
741: off);
742: for (int i = 0; i < n; i++, off++) {
743: int idx = indexes[i];
744: int adv = f1.advanceTable[idx];
745: advanceTable[off] = adv;
746: }
747: } else {
748: // use f2 layout
749: // extend advancetable and boundstable
750: advanceTable = new int[nGlyph];
751: System.arraycopy(f2.advanceTable, 0, advanceTable, 0,
752: codeTable2.length);
753: for (int i = codeTable2.length; i < nGlyph; i++) {
754: advanceTable[i] = 500;
755: }
756: }
757: }
758:
759: synchronized (f2) {
760: // store new data to f2 font
761: for (int i = 0; i < nGlyph; i++) {
762: if (codeTable[i] == ' ') {
763: f2.blankPos = i;
764: break;
765: }
766: }
767: f2.kernAdjustment = kernAdjustment;
768: f2.kernLeftCodes = kernLeftCodes;
769: f2.kernRightCodes = kernRightCodes;
770: f2.advanceTable = advanceTable;
771: f2.flags = flags;
772: f2.codeTable = codeTable;
773: f2.glyphOffsets = glyphOffsets;
774: f2.fileBuffer = fileBuffer;
775:
776: // need to copy bounds buffer too !!!
777: // .....
778: // ....
779:
780: f2.copyTo(f1); // no need !!!
781: }
782:
783: return f2;
784: }
785:
786: public void printContent(PrintStream out, String indent) {
787: font.printContent(out, indent, getID());
788: }
789:
790: public boolean isConstant() {
791: return true;
792: }
793:
794: protected FlashItem copyInto(FlashItem item, ScriptCopier copier) {
795: super .copyInto(item, copier);
796: ((FontDef) item).font = font;
797: ((FontDef) item).isWriteAllChars = isWriteAllChars;
798: ((FontDef) item).isWriteLayout = isWriteLayout;
799: // nothing else
800: return item;
801: }
802:
803: public FlashItem getCopy(ScriptCopier copier) {
804: return copyInto(new FontDef(), copier);
805: }
806:
807: /**
808: * Change font in all specified records to new one
809: *
810: * @param records vector containing TextRecord and TextStyleChangeRecord
811: * @param new_font new font
812: */
813: public static void changeRecordsFont(IVVector records,
814: Font old_font, Font new_font) {
815: //System.out.println( "changeRecordsFont:" );
816: Font last_font = null;
817: for (int i = 0; i < records.size(); i++) {
818: Object o = records.elementAt(i);
819: if (o instanceof TextRecord) {
820: if (last_font == old_font) {
821: ((TextRecord) o).updateIndexes(new_font);
822: }
823: } else {
824: TextStyleChangeRecord trs = (TextStyleChangeRecord) o;
825: Font font = trs.getFont();
826: if (font != null) {
827: last_font = font;
828: if (last_font == old_font) {
829: trs.setFont(new_font);
830: }
831: }
832: }
833: }
834: }
835: }
|