1 18 package org.apache.batik.bridge; 19 20 import java.awt.Font ; 21 import java.awt.Paint ; 22 import java.awt.Stroke ; 23 import java.awt.font.FontRenderContext ; 24 import java.awt.font.TextAttribute ; 25 import java.text.AttributedCharacterIterator ; 26 import java.text.CharacterIterator ; 27 import java.text.StringCharacterIterator ; 28 import java.util.StringTokenizer ; 29 import java.util.Vector ; 30 31 import org.apache.batik.css.engine.SVGCSSEngine; 32 import org.apache.batik.css.engine.value.Value; 33 import org.apache.batik.dom.util.XMLSupport; 34 import org.apache.batik.gvt.font.GVTFont; 35 import org.apache.batik.gvt.font.GVTFontFace; 36 import org.apache.batik.gvt.font.GVTGlyphVector; 37 import org.apache.batik.gvt.font.GVTLineMetrics; 38 import org.apache.batik.gvt.font.Glyph; 39 import org.apache.batik.gvt.font.Kern; 40 import org.apache.batik.gvt.font.KerningTable; 41 import org.apache.batik.gvt.font.SVGGVTGlyphVector; 42 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; 43 import org.apache.batik.gvt.text.TextPaintInfo; 44 import org.apache.batik.util.SVGConstants; 45 import org.w3c.dom.Element ; 46 47 53 public final class SVGGVTFont implements GVTFont, SVGConstants { 54 55 public static final AttributedCharacterIterator.Attribute PAINT_INFO 56 = GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO; 57 58 private float fontSize; 59 private GVTFontFace fontFace; 60 private String [] glyphUnicodes; 61 private String [] glyphNames; 62 private String [] glyphLangs; 63 private String [] glyphOrientations; 64 private String [] glyphForms; 65 private Element [] glyphElements; 66 private Element [] hkernElements; 67 private Element [] vkernElements; 68 private BridgeContext ctx; 69 private Element textElement; 70 private Element missingGlyphElement; 71 private KerningTable hKerningTable; 72 private KerningTable vKerningTable; 73 private String language; 74 private String orientation; 75 private float scale; 76 private GVTLineMetrics lineMetrics=null; 77 78 99 public SVGGVTFont(float fontSize, 100 GVTFontFace fontFace, 101 String [] glyphUnicodes, 102 String [] glyphNames, 103 String [] glyphLangs, 104 String [] glyphOrientations, 105 String [] glyphForms, 106 BridgeContext ctx, 107 Element [] glyphElements, 108 Element missingGlyphElement, 109 Element [] hkernElements, 110 Element [] vkernElements, 111 Element textElement) { 112 this.fontFace = fontFace; 113 this.fontSize = fontSize; 114 this.glyphUnicodes = glyphUnicodes; 115 this.glyphNames = glyphNames; 116 this.glyphLangs = glyphLangs; 117 this.glyphOrientations = glyphOrientations; 118 this.glyphForms = glyphForms; 119 this.ctx = ctx; 120 this.glyphElements = glyphElements; 121 this.missingGlyphElement = missingGlyphElement; 122 this.hkernElements = hkernElements; 123 this.vkernElements = vkernElements; 124 this.scale = fontSize/fontFace.getUnitsPerEm(); 125 this.textElement = textElement; 126 127 this.language = XMLSupport.getXMLLang(textElement); 128 129 Value v = CSSUtilities.getComputedStyle 130 (textElement, SVGCSSEngine.WRITING_MODE_INDEX); 131 if (v.getStringValue().startsWith(CSS_TB_VALUE)) { 132 this.orientation = SVG_V_VALUE; 134 } else { 135 this.orientation = SVG_H_VALUE; 136 } 137 138 createKerningTables(); 139 } 140 141 142 147 private void createKerningTables() { 148 149 Kern[] hEntries = new Kern[hkernElements.length]; 150 for (int i = 0; i < hkernElements.length; i++) { 151 Element hkernElement = hkernElements[i]; 152 SVGHKernElementBridge hkernBridge = 153 (SVGHKernElementBridge)ctx.getBridge(hkernElement); 154 Kern hkern = hkernBridge.createKern(ctx, hkernElement, this); 155 hEntries[i] = hkern; 156 } 157 hKerningTable = new KerningTable(hEntries); 158 159 Kern[] vEntries = new Kern[vkernElements.length]; 160 for (int i = 0; i < vkernElements.length; i++) { 161 Element vkernElement = vkernElements[i]; 162 SVGVKernElementBridge vkernBridge = 163 (SVGVKernElementBridge)ctx.getBridge(vkernElement); 164 Kern vkern = vkernBridge.createKern(ctx, vkernElement, this); 165 vEntries[i] = vkern; 166 } 167 vKerningTable = new KerningTable(vEntries); 168 169 } 170 171 181 public float getHKern(int glyphCode1, int glyphCode2) { 182 if (glyphCode1 < 0 || glyphCode1 >= glyphUnicodes.length 183 || glyphCode2 < 0 || glyphCode2 >= glyphUnicodes.length) { 184 return 0f; 185 } 186 float ret; 187 ret = hKerningTable.getKerningValue(glyphCode1, glyphCode2, 188 glyphUnicodes[glyphCode1], 189 glyphUnicodes[glyphCode2]); 190 return ret*scale; 191 } 192 193 203 public float getVKern(int glyphCode1, int glyphCode2) { 204 if (glyphCode1 < 0 || glyphCode1 >= glyphUnicodes.length 205 || glyphCode2 < 0 || glyphCode2 >= glyphUnicodes.length) { 206 return 0f; 207 } 208 float ret; 209 ret = vKerningTable.getKerningValue(glyphCode1, glyphCode2, 210 glyphUnicodes[glyphCode1], 211 glyphUnicodes[glyphCode2]); 212 return ret*scale; 213 } 214 215 223 public int[] getGlyphCodesForName(String name) { 224 Vector glyphCodes = new Vector (); 225 for (int i = 0; i < glyphNames.length; i++) { 226 if (glyphNames[i] != null && glyphNames[i].equals(name)) { 227 glyphCodes.add(new Integer (i)); 228 } 229 } 230 int[] glyphCodeArray = new int[glyphCodes.size()]; 231 for (int i = 0; i < glyphCodes.size(); i++) { 232 glyphCodeArray[i] = ((Integer )glyphCodes.elementAt(i)).intValue(); 233 } 234 return glyphCodeArray; 235 } 236 237 245 public int[] getGlyphCodesForUnicode(String unicode) { 246 Vector glyphCodes = new Vector (); 247 for (int i = 0; i < glyphUnicodes.length; i++) { 248 if (glyphUnicodes[i] != null && glyphUnicodes[i].equals(unicode)) { 249 glyphCodes.add(new Integer (i)); 250 } 251 } 252 int[] glyphCodeArray = new int[glyphCodes.size()]; 253 for (int i = 0; i < glyphCodes.size(); i++) { 254 glyphCodeArray[i] = ((Integer )glyphCodes.elementAt(i)).intValue(); 255 } 256 return glyphCodeArray; 257 } 258 259 272 private boolean languageMatches(String glyphLang) { 273 if (glyphLang == null || glyphLang.length() == 0) { 274 return true; } 276 StringTokenizer st = new StringTokenizer (glyphLang, ","); 277 while (st.hasMoreTokens()) { 278 String s = st.nextToken(); 279 if (s.equals(language) 280 || (s.startsWith(language) && s.length() > language.length() 281 && s.charAt(language.length()) == '-')) { 282 return true; 283 } 284 } 285 return false; 286 } 287 288 298 private boolean orientationMatches(String glyphOrientation) { 299 if (glyphOrientation == null || glyphOrientation.length() == 0) { 300 return true; 301 } 302 return glyphOrientation.equals(orientation); 303 } 304 305 306 315 private boolean formMatches(String glyphUnicode, 316 String glyphForm, 317 AttributedCharacterIterator aci, 318 int currentIndex) { 319 if (aci == null || glyphForm == null || glyphForm.length() == 0) { 320 return true; 323 } 324 325 char c = aci.setIndex(currentIndex); 326 Integer form = (Integer )aci.getAttribute 327 (GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 328 329 if (form == null || form.equals 330 (GVTAttributedCharacterIterator.TextAttribute.ARABIC_NONE)) { 331 return false; 334 } 335 336 if (glyphUnicode.length() > 1) { 338 339 boolean matched = true; 340 for (int j = 1; j < glyphUnicode.length(); j++) { 341 c = aci.next(); 342 if (glyphUnicode.charAt(j) != c) { 343 matched = false; 344 break; 345 } 346 } 347 348 aci.setIndex(currentIndex); 350 351 if (matched) { 352 353 aci.setIndex(currentIndex + glyphUnicode.length() - 1); 355 Integer lastForm = (Integer )aci.getAttribute( 356 GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 357 358 aci.setIndex(currentIndex); 360 361 if (form != null && lastForm != null) { 362 if (form.equals(GVTAttributedCharacterIterator. 363 TextAttribute.ARABIC_TERMINAL) && 364 lastForm.equals(GVTAttributedCharacterIterator. 365 TextAttribute.ARABIC_INITIAL)) { 366 return glyphForm.equals 368 (SVGConstants.SVG_ISOLATED_VALUE); 369 370 } else if (form.equals(GVTAttributedCharacterIterator. 371 TextAttribute.ARABIC_TERMINAL)) { 372 return glyphForm.equals 374 (SVGConstants.SVG_TERMINAL_VALUE); 375 376 } else if (form.equals(GVTAttributedCharacterIterator. 377 TextAttribute.ARABIC_MEDIAL) && 378 lastForm.equals(GVTAttributedCharacterIterator. 379 TextAttribute.ARABIC_MEDIAL)) { 380 return glyphForm.equals(SVGConstants.SVG_MEDIAL_VALUE); 382 } 383 } 385 } 386 } 387 388 if (form.equals(GVTAttributedCharacterIterator. 389 TextAttribute.ARABIC_ISOLATED)) { 390 return glyphForm.equals(SVGConstants.SVG_ISOLATED_VALUE); 391 } 392 if (form.equals(GVTAttributedCharacterIterator. 393 TextAttribute.ARABIC_TERMINAL)) { 394 return glyphForm.equals(SVGConstants.SVG_TERMINAL_VALUE); 395 } 396 if (form.equals(GVTAttributedCharacterIterator. 397 TextAttribute.ARABIC_INITIAL)) { 398 return glyphForm.equals(SVGConstants.SVG_INITIAL_VALUE); 399 } 400 if (form.equals(GVTAttributedCharacterIterator. 401 TextAttribute.ARABIC_MEDIAL)) { 402 return glyphForm.equals(SVGConstants.SVG_MEDIAL_VALUE); 403 } 404 return false; 405 } 406 407 415 public boolean canDisplayGivenName(String name) { 416 for (int i = 0; i < glyphNames.length; i++) { 417 if (glyphNames[i] != null && glyphNames[i].equals(name) 418 && languageMatches(glyphLangs[i]) 419 && orientationMatches(glyphOrientations[i])) { 420 return true; 421 } 422 } 423 return false; 424 } 425 426 427 435 public boolean canDisplay(char c) { 436 for (int i = 0; i < glyphUnicodes.length; i++) { 437 if (glyphUnicodes[i].indexOf(c) != -1 438 && languageMatches(glyphLangs[i]) 439 && orientationMatches(glyphOrientations[i])) { 440 return true; 441 } 442 } 443 return false; 444 } 445 446 457 public int canDisplayUpTo(char[] text, int start, int limit) { 458 StringCharacterIterator sci = 459 new StringCharacterIterator (new String (text)); 460 return canDisplayUpTo(sci, start, limit); 461 } 462 463 474 public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { 475 476 AttributedCharacterIterator aci = null; 477 if (iter instanceof AttributedCharacterIterator ) { 478 aci = (AttributedCharacterIterator )iter; 479 } 480 481 char c = iter.setIndex(start); 482 int currentIndex = start; 483 484 while (c != CharacterIterator.DONE && currentIndex < limit) { 485 486 boolean foundMatchingGlyph = false; 487 488 for (int i = 0; i < glyphUnicodes.length; i++) { 489 if (glyphUnicodes[i].indexOf(c) == 0 490 && languageMatches(glyphLangs[i]) 491 && orientationMatches(glyphOrientations[i]) 492 && formMatches(glyphUnicodes[i], glyphForms[i], 493 aci, currentIndex)) { 494 496 if (glyphUnicodes[i].length() == 1) { foundMatchingGlyph = true; 498 break; 499 500 } else { 501 boolean matched = true; 504 for (int j = 1; j < glyphUnicodes[i].length(); j++) { 505 c = iter.next(); 506 if (glyphUnicodes[i].charAt(j) != c) { 507 matched = false; 508 break; 509 } 510 } 511 if (matched) { foundMatchingGlyph = true; 513 break; 514 515 } else { 516 c = iter.setIndex(currentIndex); 519 } 520 } 521 } 522 } 523 if (!foundMatchingGlyph) { 524 return currentIndex; 525 } 526 c = iter.next(); 527 currentIndex = iter.getIndex(); 528 } 529 return -1; 530 } 531 532 541 public int canDisplayUpTo(String str) { 542 StringCharacterIterator sci = new StringCharacterIterator (str); 543 return canDisplayUpTo(sci, 0, str.length()); 544 } 545 546 555 public GVTGlyphVector createGlyphVector(FontRenderContext frc, 556 char[] chars) { 557 StringCharacterIterator sci = 558 new StringCharacterIterator (new String (chars)); 559 return createGlyphVector(frc, sci); 560 } 561 562 571 public GVTGlyphVector createGlyphVector(FontRenderContext frc, 572 CharacterIterator ci) { 573 574 AttributedCharacterIterator aci = null; 575 if (ci instanceof AttributedCharacterIterator ) { 576 aci = (AttributedCharacterIterator )ci; 577 } 578 579 Vector glyphs = new Vector (); 580 char c = ci.first(); 581 while (c != CharacterIterator.DONE) { 582 boolean foundMatchingGlyph = false; 583 for (int i = 0; i < glyphUnicodes.length; i++) { 584 if (glyphUnicodes[i].indexOf(c) == 0 && 585 languageMatches(glyphLangs[i]) && 586 orientationMatches(glyphOrientations[i]) && 587 formMatches(glyphUnicodes[i], glyphForms[i], aci, 588 ci.getIndex())) { 590 if (glyphUnicodes[i].length() == 1) { Element glyphElement = glyphElements[i]; 592 SVGGlyphElementBridge glyphBridge = 593 (SVGGlyphElementBridge)ctx.getBridge(glyphElement); 594 TextPaintInfo tpi = null; 595 if (aci != null) { 596 tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO); 597 } 598 Glyph glyph = glyphBridge.createGlyph 599 (ctx, glyphElement, textElement, i, 600 fontSize, fontFace, tpi); 601 glyphs.add(glyph); 602 foundMatchingGlyph = true; 603 break; 604 } else { 605 int current = ci.getIndex(); 608 boolean matched = true; 609 for (int j = 1; j < glyphUnicodes[i].length(); j++) { 610 c = ci.next(); 611 if (glyphUnicodes[i].charAt(j) != c) { 612 matched = false; 613 break; 614 } 615 } 616 if (matched) { 618 Element glyphElement = glyphElements[i]; 619 SVGGlyphElementBridge glyphBridge 620 = (SVGGlyphElementBridge)ctx.getBridge 621 (glyphElement); 622 TextPaintInfo tpi = null; 623 if (aci != null) { 624 aci.setIndex(ci.getIndex()); 625 tpi = (TextPaintInfo)aci.getAttribute 626 (PAINT_INFO); 627 } 628 Glyph glyph = glyphBridge.createGlyph 629 (ctx, glyphElement, textElement, i, 630 fontSize, fontFace, tpi); 631 glyphs.add(glyph); 632 foundMatchingGlyph = true; 633 break; 634 635 } else { 636 c = ci.setIndex(current); 639 } 640 } 641 } 642 } 643 if (!foundMatchingGlyph) { 644 SVGGlyphElementBridge glyphBridge = 646 (SVGGlyphElementBridge)ctx.getBridge(missingGlyphElement); 647 TextPaintInfo tpi = null; 648 if (aci != null) { 649 aci.setIndex(ci.getIndex()); 650 tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO); 651 } 652 Glyph glyph = glyphBridge.createGlyph 653 (ctx, missingGlyphElement, textElement, -1, 654 fontSize, fontFace, tpi); 655 glyphs.add(glyph); 656 } 657 c = ci.next(); 658 } 659 660 int numGlyphs = glyphs.size(); 662 Glyph[] glyphArray = new Glyph[numGlyphs]; 663 for (int i =0; i < numGlyphs; i++) { 664 glyphArray[i] = (Glyph)glyphs.get(i); 665 } 666 return new SVGGVTGlyphVector(this, glyphArray, frc); 668 } 669 670 680 public GVTGlyphVector createGlyphVector(FontRenderContext frc, 681 int[] glyphCodes, 682 CharacterIterator ci) { 683 String str = ""; 685 for (int i = 0; i < glyphCodes.length; i++) { 686 str += glyphUnicodes[glyphCodes[i]]; 687 } 688 StringCharacterIterator sci = new StringCharacterIterator (str); 689 return createGlyphVector(frc, sci); 690 } 691 692 700 public GVTGlyphVector createGlyphVector(FontRenderContext frc, 701 String str) { 702 StringCharacterIterator sci = new StringCharacterIterator (str); 703 return createGlyphVector(frc, sci); 704 } 705 706 714 public GVTFont deriveFont(float size) { 715 return new SVGGVTFont(size, fontFace, glyphUnicodes, glyphNames, 716 glyphLangs, glyphOrientations, glyphForms, ctx, 717 glyphElements, missingGlyphElement, 718 hkernElements, vkernElements, textElement); 719 } 720 721 protected GVTLineMetrics getLineMetrics(int beginIndex, int limit) { 722 if (lineMetrics != null) 723 return lineMetrics; 724 725 float fontHeight = fontFace.getUnitsPerEm(); 726 float scale = fontSize/fontHeight; 727 728 float ascent = fontFace.getAscent() * scale; 729 float descent = fontFace.getDescent() * scale; 730 731 float[] baselineOffsets = new float[3]; 732 baselineOffsets[Font.ROMAN_BASELINE] = 0; 733 baselineOffsets[Font.CENTER_BASELINE] = (ascent+descent)/2-ascent; 734 baselineOffsets[Font.HANGING_BASELINE] = -ascent; 735 736 float stOffset = fontFace.getStrikethroughPosition() * -scale; 737 float stThickness = fontFace.getStrikethroughThickness() * scale; 738 float ulOffset = fontFace.getUnderlinePosition() * scale; 739 float ulThickness = fontFace.getUnderlineThickness() * scale; 740 float olOffset = fontFace.getOverlinePosition() * -scale; 741 float olThickness = fontFace.getOverlineThickness() * scale; 742 743 744 lineMetrics = new GVTLineMetrics 745 (ascent, Font.ROMAN_BASELINE, baselineOffsets, descent, 746 fontHeight, fontHeight, limit-beginIndex, 747 stOffset, stThickness, 748 ulOffset, ulThickness, 749 olOffset, olThickness); 750 return lineMetrics; 751 } 752 753 763 public GVTLineMetrics getLineMetrics(char[] chars, int beginIndex, 764 int limit, 765 FontRenderContext frc) { 766 return getLineMetrics(beginIndex, limit); 767 } 768 769 779 public GVTLineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, 780 int limit, FontRenderContext frc) { 781 return getLineMetrics(beginIndex, limit); 782 } 783 784 792 public GVTLineMetrics getLineMetrics(String str, FontRenderContext frc) { 793 StringCharacterIterator sci = new StringCharacterIterator (str); 794 return getLineMetrics(sci, 0, str.length(), frc); 795 } 796 797 807 public GVTLineMetrics getLineMetrics(String str, int beginIndex, int limit, 808 FontRenderContext frc) { 809 StringCharacterIterator sci = new StringCharacterIterator (str); 810 return getLineMetrics(sci, beginIndex, limit, frc); 811 } 812 813 818 public float getSize() { 819 return fontSize; 820 } 821 822 828 public String toString() { 829 return fontFace.getFamilyName() + " " + fontFace.getFontWeight() + " " 830 + fontFace.getFontStyle(); 831 } 832 } 833 | Popular Tags |