1 18 package org.apache.batik.gvt.text; 19 20 import java.text.AttributedCharacterIterator ; 21 import java.text.AttributedString ; 22 import java.util.HashMap ; 23 import java.util.Map ; 24 25 26 35 public class ArabicTextHandler { 36 37 private final static int arabicStart = 0x0600; 38 private final static int arabicEnd = 0x06FF; 39 40 private final static Map charMap = new HashMap (54); 41 42 50 public static AttributedString assignArabicForms(AttributedString as) { 51 52 if (!containsArabic(as)) { 55 return as; 56 } 57 58 AttributedCharacterIterator aci = as.getIterator(); 63 boolean didSomeReordering = false; 64 int numChars = aci.getEndIndex() - aci.getBeginIndex(); 65 int charOrder[] = new int[numChars]; 66 for (int i = 0; i < numChars; i++) { 67 charOrder[i] = i + aci.getBeginIndex(); 68 } 69 for (int i = 1; i < numChars-1; i++) { 70 char c = aci.setIndex(aci.getBeginIndex() + i); 71 if (arabicCharTransparent(c)) { 72 char prevChar = aci.setIndex(aci.getBeginIndex() + i-1); 73 char nextChar = aci.setIndex(aci.getBeginIndex() + i+1); 74 if (charMap.get("" + prevChar + nextChar) != null) { 75 didSomeReordering = true; 77 int temp = charOrder[i]; 78 charOrder[i] = charOrder[i-1]; 79 charOrder[i-1] = temp; 80 } 81 } 82 } 83 if (didSomeReordering) { 84 String reorderedString = ""; 86 char c; 87 for (int i = 0; i < numChars; i++) { 88 c = aci.setIndex(charOrder[i]); 89 reorderedString += c; 90 } 91 AttributedString reorderedAS = new AttributedString (reorderedString); 92 for (int i = 0; i < numChars; i++) { 93 aci.setIndex(charOrder[i]); 94 Map attributes = aci.getAttributes(); 95 reorderedAS.addAttributes(attributes, i, i+1); 96 } 97 if (charOrder[0] == (aci.getBeginIndex()+1) && charOrder[1] == aci.getBeginIndex()) { 98 100 aci.first(); 101 Float x = (Float ) aci.getAttribute( 102 GVTAttributedCharacterIterator.TextAttribute.X); 103 Float y = (Float ) aci.getAttribute( 104 GVTAttributedCharacterIterator.TextAttribute.Y); 105 106 if (x != null && !x.isNaN()) { 107 reorderedAS.addAttribute(GVTAttributedCharacterIterator.TextAttribute.X, 108 new Float (Float.NaN), 1, 2); 109 reorderedAS.addAttribute(GVTAttributedCharacterIterator.TextAttribute.X, x, 0, 1); 110 } 111 if (y != null && !y.isNaN()) { 112 reorderedAS.addAttribute(GVTAttributedCharacterIterator.TextAttribute.Y, 113 new Float (Float.NaN), 1, 2); 114 reorderedAS.addAttribute(GVTAttributedCharacterIterator.TextAttribute.Y, y, 0, 1); 115 } 116 } 117 as = reorderedAS; 118 } 119 120 121 int c; 123 aci = as.getIterator(); 124 for (int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) { 125 c = aci.setIndex(i); 126 if (c >= arabicStart && c <= arabicEnd) { 127 as.addAttribute(GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM, 128 GVTAttributedCharacterIterator.TextAttribute.ARABIC_NONE, i, i+1); 129 } 130 } 131 aci.first(); 132 133 boolean moreRuns = true; 134 while (moreRuns) { 136 int start = aci.getRunStart( 137 GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 138 int end = aci.getRunLimit( 139 GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 140 141 aci.setIndex(start); 142 143 if (aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM) != null) { 144 145 147 int currentIndex = start; 148 while (currentIndex < end) { 149 150 char currentChar= aci.setIndex(currentIndex); 151 char prevChar = currentChar; 152 int prevCharIndex = currentIndex-1; 153 if (currentIndex > start) { prevChar = aci.setIndex(prevCharIndex); 155 } 156 157 while (arabicCharTransparent(currentChar) && currentIndex < end) { 158 currentIndex++; 159 currentChar = aci.setIndex(currentIndex); 160 } 161 if (currentIndex >= end) { 162 break; 163 } 164 165 if (!arabicCharTransparent(currentChar)) { 167 if (prevCharIndex >= start) { 169 if (arabicCharShapesRight(prevChar) 171 && arabicCharShapesLeft(currentChar)) { 172 173 aci.setIndex(prevCharIndex); 175 Integer prevForm = (Integer )aci.getAttribute( 176 GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 177 prevForm = new Integer (prevForm.intValue()+1); 178 179 as.addAttribute(GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM, 180 prevForm, prevCharIndex, prevCharIndex+1); 181 182 as.addAttribute(GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM, 184 GVTAttributedCharacterIterator.TextAttribute.ARABIC_INITIAL, 185 currentIndex, currentIndex+1); 186 } 187 188 if ((!arabicCharShapesRight(prevChar) || 191 !arabicCharShapesLeft(currentChar)) 192 && arabicCharShaped(currentChar)) { 193 194 as.addAttribute(GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM, 196 GVTAttributedCharacterIterator.TextAttribute.ARABIC_ISOLATED, 197 currentIndex, currentIndex+1); 198 } 199 200 } else if (arabicCharShaped(currentChar)) { 202 as.addAttribute(GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM, 204 GVTAttributedCharacterIterator.TextAttribute.ARABIC_ISOLATED, 205 currentIndex, currentIndex+1); 206 } 207 } 208 currentIndex++; 209 } 210 } 211 if (aci.setIndex(end) == AttributedCharacterIterator.DONE) { 212 moreRuns = false; 213 } 214 } 215 return as; 216 } 217 218 225 public static boolean arabicChar(char c) { 226 if (c >= arabicStart && c <= arabicEnd) { 227 return true; 228 } 229 return false; 230 } 231 232 238 public static boolean containsArabic(AttributedString as) { 239 return containsArabic(as.getIterator()); 240 } 241 242 248 public static boolean containsArabic(AttributedCharacterIterator aci) { 249 char c; 250 for (int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) { 251 c = aci.setIndex(i); 252 if (arabicChar(c)) { 253 return true; 254 } 255 } 256 return false; 257 } 258 259 265 public static boolean arabicCharTransparent(char c) { 266 int charVal = c; 267 if ((charVal >= 0x64B && charVal <= 0x655) 268 || (charVal == 0x0670) 269 || (charVal >= 0x06D6 && charVal <= 0x06E4) 270 || (charVal >= 0x06E7 && charVal <= 0x06E8) 271 || (charVal >= 0x06EA && charVal <= 0x06ED)) { 272 return true; 273 } 274 return false; 275 } 276 277 284 private static boolean arabicCharShapesRight(char c) { 285 int charVal = c; 286 if ((charVal >= 0x622 && charVal <= 0x625) 287 || (charVal == 0x627) 288 || (charVal == 0x629) 289 || (charVal >= 0x062F && charVal <= 0x0632) 290 || (charVal == 0x0648) 291 || (charVal >= 0x0671 && charVal <= 0x0673) 292 || (charVal >= 0x0675 && charVal <= 0x0677) 293 || (charVal >= 0x0688 && charVal <= 0x0699) 294 || (charVal == 0x06C0) 295 || (charVal >= 0x06C2 && charVal <= 0x06CB) 296 || (charVal == 0x06CD) 297 || (charVal == 0x06CF) 298 || (charVal >= 0x06D2 && charVal <= 0x06D3) 299 || arabicCharShapesDuel(c)) { 301 return true; 302 } 303 return false; 304 } 305 306 312 private static boolean arabicCharShapesDuel(char c) { 313 int charVal = c; 314 315 if ((charVal == 0x626) 316 || (charVal == 0x628) 317 || (charVal >= 0x062A && charVal <= 0x062E) 318 || (charVal >= 0x0633 && charVal <= 0x063A) 319 || (charVal >= 0x0641 && charVal <= 0x0647) 320 || (charVal >= 0x0649 && charVal <= 0x064A) 321 || (charVal >= 0x0678 && charVal <= 0x0687) 322 || (charVal >= 0x069A && charVal <= 0x06BF) 323 || (charVal == 0x6C1) 324 || (charVal == 0x6CC) 325 || (charVal == 0x6CE) 326 || (charVal >= 0x06D0 && charVal <= 0x06D1) 327 || (charVal >= 0x06FA && charVal <= 0x06FC)) { 328 return true; 329 } 330 return false; 331 } 332 333 340 private static boolean arabicCharShapesLeft(char c) { 341 return arabicCharShapesDuel(c); 342 } 343 344 350 private static boolean arabicCharShaped(char c) { 351 return arabicCharShapesRight(c); 352 } 353 354 355 366 public static int getSubstituteChar(String unicode, int form) { 367 if (charMap.containsKey(unicode) && form > 0) { 368 int chars[] = (int[])charMap.get(unicode); 369 if (chars[form-1] > 0) { 370 return chars[form-1]; 371 } 372 } 373 return -1; 374 } 375 376 388 public static String createSubstituteString(AttributedCharacterIterator aci) { 389 390 String substString = ""; 391 for (int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) { 392 char c = aci.setIndex(i); 393 if (arabicChar(c)) { 394 Integer form = (Integer )aci.getAttribute( 395 GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 396 397 if (charStartsLigature(c) && i < aci.getEndIndex()) { 399 char nextChar = aci.setIndex(i+1); 400 Integer nextForm = (Integer )aci.getAttribute( 401 GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM); 402 if (form != null && nextForm != null) { 403 if (form.equals(GVTAttributedCharacterIterator.TextAttribute.ARABIC_TERMINAL) 404 && nextForm.equals(GVTAttributedCharacterIterator.TextAttribute.ARABIC_INITIAL)) { 405 int substChar = ArabicTextHandler.getSubstituteChar("" + c + nextChar, 407 GVTAttributedCharacterIterator.TextAttribute.ARABIC_ISOLATED.intValue()); 408 if (substChar > -1) { 409 substString += (char)substChar; 410 i++; 411 continue; 412 } 413 } else if (form.equals(GVTAttributedCharacterIterator.TextAttribute.ARABIC_TERMINAL)) { 414 int substChar = ArabicTextHandler.getSubstituteChar("" + c + nextChar, 416 GVTAttributedCharacterIterator.TextAttribute.ARABIC_TERMINAL.intValue()); 417 if (substChar > -1) { 418 substString += (char)substChar; 419 i++; 420 continue; 421 } 422 } else if (form.equals(GVTAttributedCharacterIterator.TextAttribute.ARABIC_MEDIAL) 423 && nextForm.equals(GVTAttributedCharacterIterator.TextAttribute.ARABIC_MEDIAL)) { 424 int substChar = ArabicTextHandler.getSubstituteChar("" + c + nextChar, 426 GVTAttributedCharacterIterator.TextAttribute.ARABIC_MEDIAL.intValue()); 427 if (substChar > -1) { 428 substString += (char)substChar; 429 i++; 430 continue; 431 } 432 } 433 } 434 } 435 436 if (form != null && form.intValue() > 0) { 438 int substChar = ArabicTextHandler.getSubstituteChar(""+c, form.intValue()); 439 if (substChar > -1) { 440 substString += (char)substChar; 441 } else { 442 substString += c; 443 } 444 } else { 445 substString += c; 446 } 447 } else { 448 substString += c; 449 } 450 } 451 return substString; 452 } 453 454 461 public static boolean charStartsLigature(char c) { 462 int charVal = c; 463 if (charVal == 0x064B || charVal == 0x064C || charVal == 0x064D 464 || charVal == 0x064E || charVal == 0x064F || charVal == 0x0650 465 || charVal == 0x0651 || charVal == 0x0652 || charVal == 0x0622 466 || charVal == 0x0623 || charVal == 0x0625 || charVal == 0x0627) { 467 return true; 468 } 469 return false; 470 } 471 472 479 public static int getNumChars(char c) { 480 if (isLigature(c)) { 482 return 2; 484 } 485 return 1; 486 } 487 488 494 public static boolean isLigature(char c) { 495 int charVal = c; 496 if ((charVal >= 0xFE70 && charVal <= 0xFE72) 497 || (charVal == 0xFE74) 498 || (charVal >= 0xFE76 && charVal <= 0xFE7F) 499 || (charVal >= 0xFEF5 && charVal <= 0xFEFC)) { 500 return true; 501 } 502 return false; 503 } 504 505 506 static { 507 508 513 int chars1[] = {0xFE70, -1, -1, -1}; charMap.put(new String ("" + (char)0x064B + (char)0x0020), chars1); 515 516 int chars2[] = {-1, -1, -1, 0xFE71}; 517 charMap.put(new String ("" + (char)0x064B + (char)0x0640), chars2); 518 519 int chars3[] = {0xFE72, -1, -1, -1}; 520 charMap.put(new String ("" + (char)0x064C + (char)0x0020), chars3); 521 522 int chars4[] = {0xFE74, -1, -1, -1}; 523 charMap.put(new String ("" + (char)0x064D + (char)0x0020), chars4); 524 525 int chars5[] = {0xFE76, -1, -1, -1}; 526 charMap.put(new String ("" + (char)0x064E + (char)0x0020), chars5); 527 528 int chars6[] = {-1, -1, -1, 0xFE77}; 529 charMap.put(new String ("" + (char)0x064E + (char)0x0640), chars6); 530 531 int chars7[] = {0xFE78, -1, -1, -1}; 532 charMap.put(new String ("" + (char)0x064F + (char)0x0020), chars7); 533 534 int chars8[] = {-1, -1, -1, 0xFE79}; 535 charMap.put(new String ("" + (char)0x064F + (char)0x0640), chars8); 536 537 int chars9[] = {0xFE7A, -1, -1, -1}; 538 charMap.put(new String ("" + (char)0x0650 + (char)0x0020), chars9); 539 540 int chars10[] = {-1, -1, -1, 0xFE7B}; 541 charMap.put(new String ("" + (char)0x0650 + (char)0x0640), chars10); 542 543 int chars11[] = {0xFE7C, -1, -1, -1}; 544 charMap.put(new String ("" + (char)0x0651 + (char)0x0020), chars11); 545 546 int chars12[] = {-1, -1, -1, 0xFE7D}; 547 charMap.put(new String ("" + (char)0x0651 + (char)0x0640), chars12); 548 549 int chars13[] = {0xFE7E, -1, -1, -1}; 550 charMap.put(new String ("" + (char)0x0652 + (char)0x0020), chars13); 551 552 int chars14[] = {-1, -1, -1, 0xFE7F}; 553 charMap.put(new String ("" + (char)0x0652 + (char)0x0640), chars14); 554 555 int chars15[] = {0xFE80, -1, -1, -1}; 556 charMap.put(new String ("" + (char)0x0621), chars15); 557 558 int chars16[] = {0xFE81, 0xFE82, -1, -1}; 559 charMap.put(new String ("" + (char)0x0622), chars16); 560 561 int chars17[] = {0xFE83, 0xFE84, -1, -1}; 562 charMap.put(new String ("" + (char)0x0623), chars17); 563 564 int chars18[] = {0xFE85, 0xFE86, -1, -1}; 565 charMap.put(new String ("" + (char)0x0624), chars18); 566 567 int chars19[] = {0xFE87, 0xFE88, -1, -1}; 568 charMap.put(new String ("" + (char)0x0625), chars19); 569 570 int chars20[] = {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}; 571 charMap.put(new String ("" + (char)0x0626), chars20); 572 573 int chars21[] = {0xFE8D, 0xFE8E, -1, -1}; 574 charMap.put(new String ("" + (char)0x0627), chars21); 575 576 int chars22[] = {0xFE8F, 0xFE90, 0xFE91, 0xFE92}; 577 charMap.put(new String ("" + (char)0x0628), chars22); 578 579 int chars23[] = {0xFE93, 0xFE94, -1, -1}; 580 charMap.put(new String ("" + (char)0x0629), chars23); 581 582 int chars24[] = {0xFE95, 0xFE96, 0xFE97, 0xFE98}; 583 charMap.put(new String ("" + (char)0x062A), chars24); 584 585 int chars25[] = {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C}; 586 charMap.put(new String ("" + (char)0x062B), chars25); 587 588 int chars26[] = {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}; 589 charMap.put(new String ("" + (char)0x062C), chars26); 590 591 int chars27[] = {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4}; 592 charMap.put(new String ("" + (char)0x062D), chars27); 593 594 int chars28[] = {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}; 595 charMap.put(new String ("" + (char)0x062E), chars28); 596 597 int chars29[] = {0xFEA9, 0xFEAA, -1, -1}; 598 charMap.put(new String ("" + (char)0x062F), chars29); 599 600 int chars30[] = {0xFEAB, 0xFEAC, -1, -1}; 601 charMap.put(new String ("" + (char)0x0630), chars30); 602 603 int chars31[] = {0xFEAD, 0xFEAE, -1, -1}; 604 charMap.put(new String ("" + (char)0x0631), chars31); 605 606 int chars32[] = {0xFEAF, 0xFEB0, -1, -1}; 607 charMap.put(new String ("" + (char)0x0632), chars32); 608 609 int chars33[] = {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4}; 610 charMap.put(new String ("" + (char)0x0633), chars33); 611 612 int chars34[] = {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}; 613 charMap.put(new String ("" + (char)0x0634), chars34); 614 615 int chars35[] = {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC}; 616 charMap.put(new String ("" + (char)0x0635), chars35); 617 618 int chars36[] = {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}; 619 charMap.put(new String ("" + (char)0x0636), chars36); 620 621 int chars37[] = {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4}; 622 charMap.put(new String ("" + (char)0x0637), chars37); 623 624 int chars38[] = {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}; 625 charMap.put(new String ("" + (char)0x0638), chars38); 626 627 int chars39[] = {0xFEC9, 0xFECA, 0xFECB, 0xFECC}; 628 charMap.put(new String ("" + (char)0x0639), chars39); 629 630 int chars40[] = { 0xFECD, 0xFECE, 0xFECF, 0xFED0}; 631 charMap.put(new String ("" + (char)0x063A), chars40); 632 633 int chars41[] = {0xFED1, 0xFED2, 0xFED3, 0xFED4}; 634 charMap.put(new String ("" + (char)0x0641), chars41); 635 636 int chars42[] = {0xFED5, 0xFED6, 0xFED7, 0xFED8}; 637 charMap.put(new String ("" + (char)0x0642), chars42); 638 639 int chars43[] = {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC}; 640 charMap.put(new String ("" + (char)0x0643), chars43); 641 642 int chars44[] = {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}; 643 charMap.put(new String ("" + (char)0x0644), chars44); 644 645 int chars45[] = {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4}; 646 charMap.put(new String ("" + (char)0x0645), chars45); 647 648 int chars46[] = {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}; 649 charMap.put(new String ("" + (char)0x0646), chars46); 650 651 int chars47[] = {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC}; 652 charMap.put(new String ("" + (char)0x0647), chars47); 653 654 int chars48[] = {0xFEED, 0xFEEE, -1, -1}; 655 charMap.put(new String ("" + (char)0x0648), chars48); 656 657 int chars49[] = {0xFEEF, 0xFEF0, -1, -1}; 658 charMap.put(new String ("" + (char)0x0649), chars49); 659 660 int chars50[] = {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}; 661 charMap.put(new String ("" + (char)0x064A), chars50); 662 663 int chars51[] = {0xFEF5, 0xFEF6, -1, -1}; 664 charMap.put(new String ("" + (char)0x0622 + (char)0x0644), chars51); 665 666 int chars52[] = {0xFEF7, 0xFEF8, -1, -1}; 667 charMap.put(new String ("" + (char)0x0623 + (char)0x0644), chars52); 668 669 int chars53[] = {0xFEF9, 0xFEFA, -1, -1}; 670 charMap.put(new String ("" + (char)0x0625 + (char)0x0644), chars53); 671 672 int chars54[] = {0xFEFB, 0xFEFC, -1, -1}; 673 charMap.put(new String ("" + (char)0x0627 + (char)0x0644), chars54); 674 675 } 676 677 678 } 679 | Popular Tags |