1 50 51 package org.openlaszlo.iv.flash.api.text; 52 53 import org.openlaszlo.iv.flash.parser.Parser; 54 import org.openlaszlo.iv.flash.util.*; 55 import org.openlaszlo.iv.flash.cache.*; 56 57 import org.openlaszlo.iv.flash.api.*; 58 import java.io.*; 59 import java.awt.geom.Rectangle2D ; 60 61 68 public final class FontDef extends FlashDef { 69 70 private boolean isWriteLayout = false; private boolean isWriteAllChars = false; private Font font; private IVVector textBlocks = new IVVector(); 75 78 public FontDef() { 79 } 80 81 87 public FontDef( Font font, int id ) { 88 this.font = font; 89 setID( id ); 90 } 91 92 public int getTag() { 93 return Tag.DEFINEFONT2; 94 } 95 96 101 public String getFontName() { 102 return font.fontName; 103 } 104 105 110 public Font getFont() { 111 return font; 112 } 113 114 public void setFont( Font font ) { 115 this.font = font; 116 } 117 118 123 public void addTextBlock( TextBlock tblock ) { 124 if( tblock == null ) return; 125 textBlocks.addElement(tblock); 126 } 127 128 133 public void addTextBlocks( IVVector tblocks ) { 134 if( tblocks == null ) return; 135 for( int i=0; i<tblocks.size(); i++ ) { 136 addTextBlock( (TextBlock) tblocks.elementAt(i) ); 137 } 138 } 139 140 145 public IVVector getTextBlocks() { 146 return textBlocks; 147 } 148 149 154 public void setWriteLayout( boolean v ) { 155 isWriteLayout = v; 156 } 157 158 163 public boolean isWriteLayout() { 164 return isWriteLayout; 165 } 166 167 172 public void setWriteAllChars( boolean v ) { 173 isWriteAllChars = v; 174 } 175 176 181 public boolean isWriteAllChars() { 182 return isWriteAllChars; 183 } 184 185 188 public static FontDef parseExternalFontTag( Parser p ) { 189 int id = p.getUWord(); 190 String fontFileName = p.getString(); 191 Font font = load( fontFileName, p.getFile() ); 192 if( font != null ) return new FontDef( font, id ); 193 return null; 194 } 195 196 199 public static Font load( String fontFileName, FlashFile file ) { 200 FlashFile fontFile; 201 try { 202 fontFile = file.addExternalFile( fontFileName, true ); 203 } catch( IVException e ) { 204 Log.log(e); 205 fontFile = file.getDefaultSymbolFile(); 207 } 208 if( fontFile != null ) { 209 IVVector v = fontFile.getLocalFonts(); 210 if( v.size() == 0 ) { 211 Log.logRB( Resource.INVLEXTERNALFONT, new Object [] {fontFileName} ); 212 return null; 213 } 214 return (Font) v.elementAt(0); 215 } 216 return null; 217 } 218 219 225 public static Font load( String fontFileName ) { 226 FlashFile fontFile; 227 228 fontFileName = Util.translatePath( fontFileName ); 230 File f = new File( fontFileName ); 231 if( !f.exists() ) { 232 fontFileName = Util.concatFileNames( PropertyManager.fontPath, fontFileName ); 233 f = new File( Util.getInstallDir(), fontFileName ); 234 if ( !f.exists() ) { 235 Log.logRB( Resource.FILENOTFOUND, new Object [] {fontFileName} ); 236 return null; 237 } 238 } 239 fontFileName = f.getAbsolutePath(); 240 241 try { 243 fontFile = FlashFile.parse( fontFileName ); 244 IVVector v = fontFile.getLocalFonts(); 245 if ( v.size() == 0 ) { 246 Log.logRB( Resource.INVLEXTERNALFONT, new Object [] {fontFileName} ); 247 return null; 248 } 249 return (Font) v.elementAt(0); 250 } catch( FileNotFoundException e ) { 251 Log.logRB(Resource.FILENOTFOUND, new Object [] {fontFileName}); 252 return null; 253 } catch( IVException e ) { 254 Log.log(e); 255 return null; 256 } 257 } 258 259 269 public static FontDef parse( Parser p ) { 270 int id = p.getUWord(); 272 Font font = new Font(); 273 font.flags = Font.ANSI; 274 font.fileBuffer = p.getBuf(); 275 276 int tableOffset = p.getPos(); 278 int offset = p.getUWord(); 279 int nGlyph = offset/2; 280 281 int[] glyphOffsets = new int[nGlyph+1]; glyphOffsets[0] = tableOffset+offset; 283 for( int i=1; i<nGlyph; i++ ) glyphOffsets[i] = tableOffset+p.getUWord(); 284 285 p.skipLastTag(); glyphOffsets[nGlyph] = p.getPos(); 287 288 font.glyphOffsets = glyphOffsets; 289 290 return new FontDef( font, id ); 292 } 293 294 297 public static void parseFontInfoTag( Parser p, boolean MX ) { 298 int fontId = p.getUWord(); 300 FontDef fontDef = (FontDef) p.getDef(fontId); 301 String fontName = p.getString( p.getUByte() ); 302 int flags = (MX)? p.getUWord() : p.getUByte(); 303 String ext = ((flags&0x04)!=0?"%i":"") + ((flags&0x02)!=0?"%b":""); 304 String fontKey = fontName+ext; 305 306 309 Font font = fontDef.font; 310 font.fontName = fontName; 311 font.fontKey = fontKey; 312 font.flags = ((flags&0x04)!=0?Font.ITALIC:0) | ((flags&0x02)!=0?Font.BOLD:0) | 313 ((flags&0x20)!=0?Font.UNICODE:0) | ((flags&0x10)!=0?Font.SHIFT_JIS:0) | 314 ((flags&0x08)!=0?Font.ANSI:0) | ((flags&0x01)!=0?Font.WIDE_CODES:0); 315 int nGlyph = font.getNumGlyph(); 318 int[] codeTable = new int[nGlyph]; 319 if( (font.flags&Font.WIDE_CODES) != 0 ) { 320 for( int i=0; i<nGlyph; i++ ) codeTable[i] = p.getUWord(); 321 } else { 322 for( int i=0; i<nGlyph; i++ ) codeTable[i] = p.getUByte(); 323 } 324 font.codeTable = codeTable; 325 326 for( int i=0; i<nGlyph; i++ ) { 328 if( codeTable[i] == ' ' ) { 329 font.blankPos = i; 330 break; 331 } 332 } 333 } 334 335 338 public static void parseFontInfoTag( Parser p ) { 339 parseFontInfoTag( p, false ); 340 } 341 342 345 public static void parseFontInfoTag2( Parser p ) { 346 parseFontInfoTag( p, true ); 347 } 348 349 352 public static FontDef parse2( Parser p ) { 353 int id = p.getUWord(); 355 int flags = p.getUWord(); 357 String fontName = p.getString( p.getUByte() ); 359 360 String ext = ((flags&Font.ITALIC)!=0?"%i":"")+((flags&Font.BOLD)!=0?"%b":""); 362 String fontKey = fontName+ext; 363 364 367 Font font2 = null; 368 369 int nGlyph = p.getUWord(); 371 372 if( font2 != null ) { 376 if( nGlyph == font2.getNumGlyph() && flags == font2.flags ) { 377 return new FontDef( font2, id ); 378 } 379 } 380 381 Font font = new Font(); 382 font.flags = flags; 383 font.fontName = fontName; 384 font.fontKey = fontKey; 385 font.fileBuffer = p.getBuf(); 386 int tableOffset = p.getPos(); 387 int[] glyphOffsets = new int[nGlyph+1]; int codeOff; 389 if( (flags&Font.WIDE_OFFSETS) != 0 ) { 390 for( int i=0; i<nGlyph; i++ ) glyphOffsets[i] = tableOffset+p.getUDWord(); 391 codeOff = p.getUDWord(); 392 } else { 393 for( int i=0; i<nGlyph; i++ ) glyphOffsets[i] = tableOffset+p.getUWord(); 394 codeOff = p.getUWord(); 395 } 396 font.glyphOffsets = glyphOffsets; 397 398 p.setPos( tableOffset+codeOff ); glyphOffsets[nGlyph] = p.getPos(); 401 402 int[] codeTable = new int[nGlyph]; 404 if( (flags&Font.WIDE_CODES) != 0 ) { 405 for( int i=0; i<nGlyph; i++ ) codeTable[i] = p.getUWord(); 406 } else { 407 for( int i=0; i<nGlyph; i++ ) codeTable[i] = p.getUByte(); 408 } 409 font.codeTable = codeTable; 410 411 for( int i=0; i<nGlyph; i++ ) { 413 if( codeTable[i] == ' ' ) { 414 font.blankPos = i; 415 break; 416 } 417 } 418 419 if( (flags&Font.HAS_LAYOUT) != 0 ) { 420 font.ascent = p.getWord(); 421 font.descent = p.getWord(); 422 font.leading = p.getWord(); 423 424 int[] advanceTable = new int[nGlyph]; 426 for( int i=0; i<nGlyph; i++ ) advanceTable[i] = p.getWord(); 427 font.advanceTable = advanceTable; 428 429 font.boundsBuffer = p.getBuf(); 431 font.boundsOffset = p.getPos(); 432 for( int i=0; i<nGlyph; i++ ) p.skipRect(); 433 font.boundsLength = p.getPos()-font.boundsOffset; 434 435 int nKern = p.getUWord(); 437 font.kernLeftCodes = new int[nKern]; 438 font.kernRightCodes = new int[nKern]; 439 font.kernAdjustment = new int[nKern]; 440 if( (flags&Font.WIDE_CODES) != 0 ) { 441 for( int i=0; i<nKern; i++ ) { 442 font.kernLeftCodes[i] = p.getUWord(); 443 font.kernRightCodes[i] = p.getUWord(); 444 font.kernAdjustment[i] = p.getWord(); 445 } 446 } else { 447 for( int i=0; i<nKern; i++ ) { 448 font.kernLeftCodes[i] = p.getUByte(); 449 font.kernRightCodes[i] = p.getUByte(); 450 font.kernAdjustment[i] = p.getWord(); 451 } 452 } 453 } 454 455 458 463 464 return new FontDef( font, id ); 465 } 466 467 472 public void write( FlashOutput fob ) { 473 474 if (fob.defined( font )) { 475 return; 476 } 477 478 int pos = fob.getPos(); 479 fob.skip(6); 480 481 fob.writeFontID( font ); 482 if( isWriteLayout ) { 483 fob.writeWord( font.flags ); 484 } else { 485 fob.writeWord( font.flags&~Font.HAS_LAYOUT ); 486 } 487 fob.writeStringL( getFontName() ); 488 489 int[] indexTable = new int[font.codeTable.length]; 491 492 int[] codeTable; 494 int nGlyph; 495 if( isWriteAllChars ) { 496 codeTable = font.codeTable; 497 nGlyph = codeTable.length; 498 for( int i=0; i<indexTable.length; i++ ) indexTable[i] = i; 499 } else { 500 codeTable = new int[font.codeTable.length]; 501 nGlyph = 0; 502 } 503 504 for( int i=0; i<textBlocks.size(); i++ ) { 505 TextBlock tblock = (TextBlock) textBlocks.elementAt(i); 506 tblock.layout(); 507 IVVector trs = tblock.getTextRecords(font); 508 if( trs == null || trs.size() == 0 ) continue; 509 for( int t=0; t<trs.size(); t++ ) { 510 TextRecord tr = (TextRecord) trs.elementAt(t); 511 L1: 512 for( int c=0; c<tr.getSize(); c++ ) { 513 char ch = tr.getChar(c); 514 if( ch == '\r' || ch == '\n' ) { tr.setIndex(c, 0); continue; 517 } 518 for( int j=0; j<nGlyph; j++ ) { 520 if( codeTable[j] == ch ) { 521 tr.setIndex(c, j); 522 continue L1; 523 } 524 } 525 if( !isWriteAllChars ) { int idx = font.getIndex(ch); if( idx == -1 ) { 529 idx = font.getIndex(' '); 530 } 531 indexTable[nGlyph] = idx; 532 tr.setIndex(c, nGlyph); 533 codeTable[nGlyph] = ch; 534 ++nGlyph; 535 } 536 } 537 } 538 } 539 540 fob.writeWord(nGlyph); 541 int offsetTable = fob.getPos(); 542 int inc = (font.flags&Font.WIDE_OFFSETS)!=0? 4: 2; 543 fob.skip( nGlyph*inc ); 544 int codeOffset = fob.getPos(); 545 fob.skip( inc ); 546 for( int i=0, curOff=offsetTable; i<nGlyph; i++, curOff+=inc ) { 547 int offset = fob.getPos()-offsetTable; 548 int idx = indexTable[i]; 549 int start = font.glyphOffsets[idx]; 550 int end = font.glyphOffsets[idx+1]; 551 fob.writeArray( font.fileBuffer, start, end-start ); 552 if( inc == 2 ) 553 fob.writeWordAt( offset, curOff ); 554 else 555 fob.writeDWordAt( offset, curOff ); 556 } 557 if( inc == 2 ) 558 fob.writeWordAt(fob.getPos()-offsetTable, codeOffset); 559 else 560 fob.writeDWordAt(fob.getPos()-offsetTable, codeOffset); 561 562 for( int i=0; i<nGlyph; i++ ) { 563 if( (font.flags&Font.WIDE_CODES) != 0 ) { 564 fob.writeWord( codeTable[i] ); 565 } else { 566 fob.writeByte( codeTable[i] ); 567 } 568 } 569 570 if( isWriteLayout && ((font.flags&Font.HAS_LAYOUT) != 0) ) { 572 fob.writeWord( font.ascent ); 573 fob.writeWord( font.descent ); 574 fob.writeWord( font.leading ); 575 576 for( int i=0; i<nGlyph; i++ ) fob.writeWord( font.advanceTable[indexTable[i]] ); 578 579 if( isWriteAllChars ) { 581 fob.writeArray( font.boundsBuffer, font.boundsOffset, font.boundsLength ); 583 } else { 584 Rectangle2D [] bounds = font.getGlyphBounds(); 585 for( int i=0; i<nGlyph; i++ ) { 586 fob.write( bounds[indexTable[i]] ); 587 } 588 } 589 590 int nKern = font.kernLeftCodes.length; 593 fob.writeWord( nKern ); 594 if( (font.flags&Font.WIDE_CODES) != 0 ) { 595 for( int i=0; i<nKern; i++ ) { 596 fob.writeWord( font.kernLeftCodes[i] ); 597 fob.writeWord( font.kernRightCodes[i] ); 598 fob.writeWord( font.kernAdjustment[i] ); 599 } 600 } else { 601 for( int i=0; i<nKern; i++ ) { 602 fob.writeByte( font.kernLeftCodes[i] ); 603 fob.writeByte( font.kernRightCodes[i] ); 604 fob.writeWord( font.kernAdjustment[i] ); 605 } 606 } 607 } 608 609 fob.writeLongTagAt(Tag.DEFINEFONT2, fob.getPos()-pos-6, pos); 610 } 611 612 619 public static Font mergeFonts( Font f1, Font f2 ) { 620 int flags = f2.flags | f1.flags; 622 624 boolean f1_hasLayout = (f1.flags&Font.HAS_LAYOUT) != 0; 625 boolean f2_hasLayout = (f2.flags&Font.HAS_LAYOUT) != 0; 626 if( f1_hasLayout && !f2_hasLayout ) { 627 Font f = f1; f1 = f2; f2 = f; 628 boolean fb = f1_hasLayout; f1_hasLayout = f2_hasLayout; f2_hasLayout = fb; 629 } 630 631 int[] codeTable1 = f1.codeTable; 633 int[] codeTable2 = f2.codeTable; 634 int n = 0; 635 int[] codeTable_tmp = new int[codeTable1.length]; 636 int[] indexes = new int[codeTable1.length]; 637 for( int i=0; i<codeTable1.length; i++ ) { 638 int code = codeTable1[i]; 639 int j=0; 640 for( ; j<codeTable2.length; j++ ) { 641 if( codeTable2[j] == code ) break; 642 } 643 if( j == codeTable2.length ) { 644 codeTable_tmp[n] = code; 645 indexes[n] = i; 646 n++; 647 } 648 } 649 650 if( n == 0 ) { f2.copyTo(f1); return f2; 653 } 654 656 int nGlyph = codeTable2.length+n; 657 int[] codeTable = new int[nGlyph]; 658 System.arraycopy( codeTable2, 0, codeTable, 0, codeTable2.length ); 659 System.arraycopy( codeTable_tmp, 0, codeTable, codeTable2.length, n ); 660 661 int f1_start = f1.glyphOffsets[0]; 663 int f1_end = f1.glyphOffsets[codeTable1.length]; 664 int f2_start = f2.glyphOffsets[0]; 665 int f2_end = f2.glyphOffsets[codeTable2.length]; 666 int totalSize = f1_end-f1_start + f2_end-f2_start; 667 byte[] fileBuffer = new byte[ totalSize ]; 668 int[] glyphOffsets = new int[ nGlyph + 1 ]; 669 int offset = f2_end-f2_start; 670 System.arraycopy( f2.fileBuffer, f2_start, fileBuffer, 0, offset ); 672 int gln = 0; 673 for( ; gln<codeTable2.length; gln++ ) { 674 int off = f2.glyphOffsets[gln] - f2_start; 675 glyphOffsets[gln] = off; 676 } 677 for( int i=0; i<n; i++, gln++ ) { 679 int idx = indexes[i]; 680 int start = f1.glyphOffsets[idx]; 681 int end = f1.glyphOffsets[idx+1]; 682 int size = end-start; 683 System.arraycopy( f1.fileBuffer, start, 684 fileBuffer, offset, size ); 685 glyphOffsets[gln] = offset; 686 offset += size; 687 } 688 glyphOffsets[gln] = offset; 689 690 int[] advanceTable = null; 691 int[] kernLeftCodes = f2.kernLeftCodes; 692 int[] kernRightCodes = f2.kernRightCodes; 693 int[] kernAdjustment = f2.kernAdjustment; 694 if( f1_hasLayout || f2_hasLayout ) { 698 if( f1_hasLayout ) { 699 advanceTable = new int[nGlyph]; 702 int off = codeTable2.length; 703 System.arraycopy( f2.advanceTable, 0, advanceTable, 0, off ); 704 for( int i=0; i<n; i++, off++ ) { 705 int idx = indexes[i]; 706 int adv = f1.advanceTable[idx]; 707 advanceTable[off] = adv; 708 } 709 } else { 710 advanceTable = new int[nGlyph]; 713 System.arraycopy( f2.advanceTable, 0, advanceTable, 0, codeTable2.length ); 714 for( int i=codeTable2.length; i<nGlyph; i++ ) { 715 advanceTable[i] = 500; 716 } 717 } 718 } 719 720 synchronized(f2) { 721 for( int i=0; i<nGlyph; i++ ) { 723 if( codeTable[i] == ' ' ) { 724 f2.blankPos = i; 725 break; 726 } 727 } 728 f2.kernAdjustment = kernAdjustment; 729 f2.kernLeftCodes = kernLeftCodes; 730 f2.kernRightCodes = kernRightCodes; 731 f2.advanceTable = advanceTable; 732 f2.flags = flags; 733 f2.codeTable = codeTable; 734 f2.glyphOffsets = glyphOffsets; 735 f2.fileBuffer = fileBuffer; 736 737 741 f2.copyTo(f1); } 743 744 return f2; 745 } 746 747 public void printContent( PrintStream out, String indent ) { 748 font.printContent(out, indent, getID()); 749 } 750 751 public boolean isConstant() { 752 return true; 753 } 754 755 protected FlashItem copyInto( FlashItem item, ScriptCopier copier ) { 756 super.copyInto( item, copier ); 757 ((FontDef)item).font = font; 758 ((FontDef)item).isWriteAllChars = isWriteAllChars; 759 ((FontDef)item).isWriteLayout = isWriteLayout; 760 return item; 762 } 763 764 public FlashItem getCopy( ScriptCopier copier ) { 765 return copyInto( new FontDef(), copier ); 766 } 767 768 774 public static void changeRecordsFont( IVVector records, Font old_font, Font new_font ) { 775 Font last_font = null; 777 for( int i=0; i<records.size(); i++ ) { 778 Object o = records.elementAt(i); 779 if( o instanceof TextRecord ) { 780 if( last_font == old_font ) { 781 ((TextRecord)o).updateIndexes(new_font); 782 } 783 } else { 784 TextStyleChangeRecord trs = (TextStyleChangeRecord) o; 785 Font font = trs.getFont(); 786 if( font != null ) { 787 last_font = font; 788 if( last_font == old_font ) { 789 trs.setFont(new_font); 790 } 791 } 792 } 793 } 794 } 795 } 796 | Popular Tags |