1 48 49 package com.lowagie.text.pdf; 50 51 import java.util.ArrayList ; 52 53 import com.lowagie.text.Chunk; 54 55 59 public class BidiLine { 60 61 protected int runDirection; 62 protected int pieceSize = 2048; 63 protected char text[] = new char[pieceSize]; 64 protected PdfChunk detailChunks[] = new PdfChunk[pieceSize]; 65 protected int totalTextLength = 0; 66 67 protected byte orderLevels[] = new byte[pieceSize]; 68 protected int indexChars[] = new int[pieceSize]; 69 70 protected ArrayList chunks = new ArrayList (); 71 protected int indexChunk = 0; 72 protected int indexChunkChar = 0; 73 protected int currentChar = 0; 74 75 protected int storedRunDirection; 76 protected char storedText[] = new char[0]; 77 protected PdfChunk storedDetailChunks[] = new PdfChunk[0]; 78 protected int storedTotalTextLength = 0; 79 80 protected byte storedOrderLevels[] = new byte[0]; 81 protected int storedIndexChars[] = new int[0]; 82 83 protected int storedIndexChunk = 0; 84 protected int storedIndexChunkChar = 0; 85 protected int storedCurrentChar = 0; 86 87 protected boolean shortStore; 88 protected static final IntHashtable mirrorChars = new IntHashtable(); 90 protected int arabicOptions; 91 92 93 public BidiLine() { 94 } 95 96 public BidiLine(BidiLine org) { 97 runDirection = org.runDirection; 98 pieceSize = org.pieceSize; 99 text = (char[])org.text.clone(); 100 detailChunks = (PdfChunk[])org.detailChunks.clone(); 101 totalTextLength = org.totalTextLength; 102 103 orderLevels = (byte[])org.orderLevels.clone(); 104 indexChars = (int[])org.indexChars.clone(); 105 106 chunks = new ArrayList (org.chunks); 107 indexChunk = org.indexChunk; 108 indexChunkChar = org.indexChunkChar; 109 currentChar = org.currentChar; 110 111 storedRunDirection = org.storedRunDirection; 112 storedText = (char[])org.storedText.clone(); 113 storedDetailChunks = (PdfChunk[])org.storedDetailChunks.clone(); 114 storedTotalTextLength = org.storedTotalTextLength; 115 116 storedOrderLevels = (byte[])org.storedOrderLevels.clone(); 117 storedIndexChars = (int[])org.storedIndexChars.clone(); 118 119 storedIndexChunk = org.storedIndexChunk; 120 storedIndexChunkChar = org.storedIndexChunkChar; 121 storedCurrentChar = org.storedCurrentChar; 122 123 shortStore = org.shortStore; 124 arabicOptions = org.arabicOptions; 125 } 126 127 public boolean isEmpty() { 128 return (currentChar >= totalTextLength && indexChunk >= chunks.size()); 129 } 130 131 public void clearChunks() { 132 chunks.clear(); 133 totalTextLength = 0; 134 currentChar = 0; 135 } 136 137 public boolean getParagraph(int runDirection) { 138 this.runDirection = runDirection; 139 currentChar = 0; 140 totalTextLength = 0; 141 boolean hasText = false; 142 char c; 143 char uniC; 144 BaseFont bf; 145 for (; indexChunk < chunks.size(); ++indexChunk) { 146 PdfChunk ck = (PdfChunk)chunks.get(indexChunk); 147 bf = ck.font().getFont(); 148 String s = ck.toString(); 149 int len = s.length(); 150 for (; indexChunkChar < len; ++indexChunkChar) { 151 c = s.charAt(indexChunkChar); 152 uniC = bf.getUnicodeEquivalent(c); 153 if (uniC == '\r' || uniC == '\n') { 154 if (uniC == '\r' && indexChunkChar + 1 < len && s.charAt(indexChunkChar + 1) == '\n') 156 ++indexChunkChar; 157 ++indexChunkChar; 158 if (indexChunkChar >= len) { 159 indexChunkChar = 0; 160 ++indexChunk; 161 } 162 hasText = true; 163 if (totalTextLength == 0) 164 detailChunks[0] = ck; 165 break; 166 } 167 addPiece(c, ck); 168 } 169 if (hasText) 170 break; 171 indexChunkChar = 0; 172 } 173 if (totalTextLength == 0) 174 return hasText; 175 176 totalTextLength = trimRight(0, totalTextLength - 1) + 1; 178 if (totalTextLength == 0) 179 return true; 180 181 if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { 182 if (orderLevels.length < totalTextLength) { 183 orderLevels = new byte[pieceSize]; 184 indexChars = new int[pieceSize]; 185 } 186 ArabicLigaturizer.processNumbers(text, 0, totalTextLength, arabicOptions); 187 BidiOrder order = new BidiOrder(text, 0, totalTextLength, (byte)(runDirection == PdfWriter.RUN_DIRECTION_RTL ? 1 : 0)); 188 byte od[] = order.getLevels(); 189 for (int k = 0; k < totalTextLength; ++k) { 190 orderLevels[k] = od[k]; 191 indexChars[k] = k; 192 } 193 doArabicShapping(); 194 mirrorGlyphs(); 195 } 196 totalTextLength = trimRightEx(0, totalTextLength - 1) + 1; 197 return true; 198 } 199 200 public void addChunk(PdfChunk chunk) { 201 chunks.add(chunk); 202 } 203 204 public void addChunks(ArrayList chunks) { 205 this.chunks.addAll(chunks); 206 } 207 208 public void addPiece(char c, PdfChunk chunk) { 209 if (totalTextLength >= pieceSize) { 210 char tempText[] = text; 211 PdfChunk tempDetailChunks[] = detailChunks; 212 pieceSize *= 2; 213 text = new char[pieceSize]; 214 detailChunks = new PdfChunk[pieceSize]; 215 System.arraycopy(tempText, 0, text, 0, totalTextLength); 216 System.arraycopy(tempDetailChunks, 0, detailChunks, 0, totalTextLength); 217 } 218 text[totalTextLength] = c; 219 detailChunks[totalTextLength++] = chunk; 220 } 221 222 public void save() { 223 if (indexChunk > 0) { 224 if (indexChunk >= chunks.size()) 225 chunks.clear(); 226 else { 227 for (--indexChunk; indexChunk >= 0; --indexChunk) 228 chunks.remove(indexChunk); 229 } 230 indexChunk = 0; 231 } 232 storedRunDirection = runDirection; 233 storedTotalTextLength = totalTextLength; 234 storedIndexChunk = indexChunk; 235 storedIndexChunkChar = indexChunkChar; 236 storedCurrentChar = currentChar; 237 shortStore = (currentChar < totalTextLength); 238 if (!shortStore) { 239 if (storedText.length < totalTextLength) { 241 storedText = new char[totalTextLength]; 242 storedDetailChunks = new PdfChunk[totalTextLength]; 243 } 244 System.arraycopy(text, 0, storedText, 0, totalTextLength); 245 System.arraycopy(detailChunks, 0, storedDetailChunks, 0, totalTextLength); 246 } 247 if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { 248 if (storedOrderLevels.length < totalTextLength) { 249 storedOrderLevels = new byte[totalTextLength]; 250 storedIndexChars = new int[totalTextLength]; 251 } 252 System.arraycopy(orderLevels, currentChar, storedOrderLevels, currentChar, totalTextLength - currentChar); 253 System.arraycopy(indexChars, currentChar, storedIndexChars, currentChar, totalTextLength - currentChar); 254 } 255 } 256 257 public void restore() { 258 runDirection = storedRunDirection; 259 totalTextLength = storedTotalTextLength; 260 indexChunk = storedIndexChunk; 261 indexChunkChar = storedIndexChunkChar; 262 currentChar = storedCurrentChar; 263 if (!shortStore) { 264 System.arraycopy(storedText, 0, text, 0, totalTextLength); 266 System.arraycopy(storedDetailChunks, 0, detailChunks, 0, totalTextLength); 267 } 268 if (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL) { 269 System.arraycopy(storedOrderLevels, currentChar, orderLevels, currentChar, totalTextLength - currentChar); 270 System.arraycopy(storedIndexChars, currentChar, indexChars, currentChar, totalTextLength - currentChar); 271 } 272 } 273 274 public void mirrorGlyphs() { 275 for (int k = 0; k < totalTextLength; ++k) { 276 if ((orderLevels[k] & 1) == 1) { 277 int mirror = mirrorChars.get(text[k]); 278 if (mirror != 0) 279 text[k] = (char)mirror; 280 } 281 } 282 } 283 284 public void doArabicShapping() { 285 int src = 0; 286 int dest = 0; 287 for (;;) { 288 while (src < totalTextLength) { 289 char c = text[src]; 290 if (c >= 0x0600 && c <= 0x06ff) 291 break; 292 if (src != dest) { 293 text[dest] = text[src]; 294 detailChunks[dest] = detailChunks[src]; 295 orderLevels[dest] = orderLevels[src]; 296 } 297 ++src; 298 ++dest; 299 } 300 if (src >= totalTextLength) { 301 totalTextLength = dest; 302 return; 303 } 304 int startArabicIdx = src; 305 ++src; 306 while (src < totalTextLength) { 307 char c = text[src]; 308 if (c < 0x0600 || c > 0x06ff) 309 break; 310 ++src; 311 } 312 int arabicWordSize = src - startArabicIdx; 313 int size = ArabicLigaturizer.arabic_shape(text, startArabicIdx, arabicWordSize, text, dest, arabicWordSize, arabicOptions ); 314 if (startArabicIdx != dest) { 315 for (int k = 0; k < size; ++k) { 316 detailChunks[dest] = detailChunks[startArabicIdx]; 317 orderLevels[dest++] = orderLevels[startArabicIdx++]; 318 } 319 } 320 else 321 dest += size; 322 } 323 } 324 325 public PdfLine processLine(float width, int alignment, int runDirection, int arabicOptions) { 326 this.arabicOptions = arabicOptions; 327 save(); 328 boolean isRTL = (runDirection == PdfWriter.RUN_DIRECTION_RTL); 329 if (currentChar >= totalTextLength) { 330 boolean hasText = getParagraph(runDirection); 331 if (!hasText) 332 return null; 333 if (totalTextLength == 0) { 334 ArrayList ar = new ArrayList (); 335 PdfChunk ck = new PdfChunk("", detailChunks[0]); 336 ar.add(ck); 337 return new PdfLine(0, 0, alignment, true, ar, isRTL); 338 } 339 } 340 float originalWidth = width; 341 int lastSplit = -1; 342 if (currentChar != 0) 343 currentChar = trimLeftEx(currentChar, totalTextLength - 1); 344 int oldCurrentChar = currentChar; 345 char c = 0; 346 char uniC = 0; 347 PdfChunk ck = null; 348 float charWidth = 0; 349 PdfChunk lastValidChunk = null; 350 for (; currentChar < totalTextLength; ++currentChar) { 351 c = text[currentChar]; 352 ck = detailChunks[currentChar]; 353 uniC = ck.getUnicodeEquivalent(c); 354 if (PdfChunk.noPrint(uniC)) 355 continue; 356 charWidth = ck.getCharWidth(c); 357 if (ck.isExtSplitCharacter(oldCurrentChar, currentChar, totalTextLength, text, detailChunks)) 358 lastSplit = currentChar; 359 if (width - charWidth < 0) 360 break; 361 width -= charWidth; 362 lastValidChunk = ck; 363 } 364 if (lastValidChunk == null) { 365 ++currentChar; 367 return new PdfLine(0, 0, alignment, false, createArrayOfPdfChunks(currentChar - 1, currentChar - 1), isRTL); 368 } 369 if (currentChar >= totalTextLength) { 370 return new PdfLine(0, width, alignment, true, createArrayOfPdfChunks(oldCurrentChar, totalTextLength - 1), isRTL); 372 } 373 int newCurrentChar = trimRightEx(oldCurrentChar, currentChar - 1); 374 if (newCurrentChar < oldCurrentChar) { 375 return new PdfLine(0, width, alignment, false, createArrayOfPdfChunks(oldCurrentChar, currentChar - 1), isRTL); 377 } 378 if (newCurrentChar == currentChar - 1) { HyphenationEvent he = (HyphenationEvent)lastValidChunk.getAttribute(Chunk.HYPHENATION); 380 if (he != null) { 381 int word[] = getWord(oldCurrentChar, newCurrentChar); 382 if (word != null) { 383 float testWidth = width + getWidth(word[0], currentChar - 1); 384 String pre = he.getHyphenatedWordPre(new String (text, word[0], word[1] - word[0]), lastValidChunk.font().getFont(), lastValidChunk.font().size(), testWidth); 385 String post = he.getHyphenatedWordPost(); 386 if (pre.length() > 0) { 387 PdfChunk extra = new PdfChunk(pre, lastValidChunk); 388 currentChar = word[1] - post.length(); 389 return new PdfLine(0, testWidth - lastValidChunk.font().width(pre), alignment, false, createArrayOfPdfChunks(oldCurrentChar, word[0] - 1, extra), isRTL); 390 } 391 } 392 } 393 } 394 if (lastSplit == -1 || lastSplit >= newCurrentChar) { 395 return new PdfLine(0, width + getWidth(newCurrentChar + 1, currentChar - 1), alignment, false, createArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); 397 } 398 currentChar = lastSplit + 1; 400 newCurrentChar = trimRightEx(oldCurrentChar, lastSplit); 401 if (newCurrentChar < oldCurrentChar) { 402 newCurrentChar = currentChar - 1; 404 } 405 return new PdfLine(0, originalWidth - getWidth(oldCurrentChar, newCurrentChar), alignment, false, createArrayOfPdfChunks(oldCurrentChar, newCurrentChar), isRTL); 406 } 407 408 413 public float getWidth(int startIdx, int lastIdx) { 414 char c = 0; 415 char uniC; 416 PdfChunk ck = null; 417 float width = 0; 418 for (; startIdx <= lastIdx; ++startIdx) { 419 c = text[startIdx]; 420 ck = detailChunks[startIdx]; 421 uniC = ck.getUnicodeEquivalent(c); 422 if (PdfChunk.noPrint(uniC)) 423 continue; 424 width += detailChunks[startIdx].getCharWidth(c); 425 } 426 return width; 427 } 428 429 public ArrayList createArrayOfPdfChunks(int startIdx, int endIdx) { 430 return createArrayOfPdfChunks(startIdx, endIdx, null); 431 } 432 433 public ArrayList createArrayOfPdfChunks(int startIdx, int endIdx, PdfChunk extraPdfChunk) { 434 boolean bidi = (runDirection == PdfWriter.RUN_DIRECTION_LTR || runDirection == PdfWriter.RUN_DIRECTION_RTL); 435 if (bidi) 436 reorder(startIdx, endIdx); 437 ArrayList ar = new ArrayList (); 438 PdfChunk refCk = detailChunks[startIdx]; 439 PdfChunk ck = null; 440 StringBuffer buf = new StringBuffer (); 441 char c; 442 int idx = 0; 443 for (; startIdx <= endIdx; ++startIdx) { 444 idx = bidi ? indexChars[startIdx] : startIdx; 445 c = text[idx]; 446 ck = detailChunks[idx]; 447 if (PdfChunk.noPrint(ck.getUnicodeEquivalent(c))) 448 continue; 449 if (ck.isImage()) { 450 if (buf.length() > 0) { 451 ar.add(new PdfChunk(buf.toString(), refCk)); 452 buf = new StringBuffer (); 453 } 454 ar.add(ck); 455 } 456 else if (ck == refCk) { 457 buf.append(c); 458 } 459 else { 460 if (buf.length() > 0) { 461 ar.add(new PdfChunk(buf.toString(), refCk)); 462 buf = new StringBuffer (); 463 } 464 if (!ck.isImage()) 465 buf.append(c); 466 refCk = ck; 467 } 468 } 469 if (buf.length() > 0) { 470 ar.add(new PdfChunk(buf.toString(), refCk)); 471 } 472 if (extraPdfChunk != null) 473 ar.add(extraPdfChunk); 474 return ar; 475 } 476 477 public int[] getWord(int startIdx, int idx) { 478 int last = idx; 479 int first = idx; 480 for (; last < totalTextLength; ++last) { 482 if (!Character.isLetter(text[last])) 483 break; 484 } 485 if (last == idx) 486 return null; 487 for (; first >= startIdx; --first) { 489 if (!Character.isLetter(text[first])) 490 break; 491 } 492 ++first; 493 return new int[]{first, last}; 494 } 495 496 public int trimRight(int startIdx, int endIdx) { 497 int idx = endIdx; 498 char c; 499 for (; idx >= startIdx; --idx) { 500 c = detailChunks[idx].getUnicodeEquivalent(text[idx]); 501 if (!isWS(c)) 502 break; 503 } 504 return idx; 505 } 506 507 public int trimLeft(int startIdx, int endIdx) { 508 int idx = startIdx; 509 char c; 510 for (; idx <= endIdx; ++idx) { 511 c = detailChunks[idx].getUnicodeEquivalent(text[idx]); 512 if (!isWS(c)) 513 break; 514 } 515 return idx; 516 } 517 518 public int trimRightEx(int startIdx, int endIdx) { 519 int idx = endIdx; 520 char c = 0; 521 for (; idx >= startIdx; --idx) { 522 c = detailChunks[idx].getUnicodeEquivalent(text[idx]); 523 if (!isWS(c) && !PdfChunk.noPrint(c)) 524 break; 525 } 526 return idx; 527 } 528 529 public int trimLeftEx(int startIdx, int endIdx) { 530 int idx = startIdx; 531 char c = 0; 532 for (; idx <= endIdx; ++idx) { 533 c = detailChunks[idx].getUnicodeEquivalent(text[idx]); 534 if (!isWS(c) && !PdfChunk.noPrint(c)) 535 break; 536 } 537 return idx; 538 } 539 540 public void reorder(int start, int end) { 541 byte maxLevel = orderLevels[start]; 542 byte minLevel = maxLevel; 543 byte onlyOddLevels = maxLevel; 544 byte onlyEvenLevels = maxLevel; 545 for (int k = start + 1; k <= end; ++k) { 546 byte b = orderLevels[k]; 547 if (b > maxLevel) 548 maxLevel = b; 549 else if (b < minLevel) 550 minLevel = b; 551 onlyOddLevels &= b; 552 onlyEvenLevels |= b; 553 } 554 if ((onlyEvenLevels & 1) == 0) return; 556 if ((onlyOddLevels & 1) == 1) { flip(start, end + 1); 558 return; 559 } 560 minLevel |= 1; 561 for (; maxLevel >= minLevel; --maxLevel) { 562 int pstart = start; 563 for (;;) { 564 for (;pstart <= end; ++pstart) { 565 if (orderLevels[pstart] >= maxLevel) 566 break; 567 } 568 if (pstart > end) 569 break; 570 int pend = pstart + 1; 571 for (; pend <= end; ++pend) { 572 if (orderLevels[pend] < maxLevel) 573 break; 574 } 575 flip(pstart, pend); 576 pstart = pend + 1; 577 } 578 } 579 } 580 581 public void flip(int start, int end) { 582 int mid = (start + end) / 2; 583 --end; 584 for (; start < mid; ++start, --end) { 585 int temp = indexChars[start]; 586 indexChars[start] = indexChars[end]; 587 indexChars[end] = temp; 588 } 589 } 590 591 public static boolean isWS(char c) { 592 return (c <= ' '); 593 } 594 595 static { 596 mirrorChars.put(0x0028, 0x0029); mirrorChars.put(0x0029, 0x0028); mirrorChars.put(0x003C, 0x003E); mirrorChars.put(0x003E, 0x003C); mirrorChars.put(0x005B, 0x005D); mirrorChars.put(0x005D, 0x005B); mirrorChars.put(0x007B, 0x007D); mirrorChars.put(0x007D, 0x007B); mirrorChars.put(0x00AB, 0x00BB); mirrorChars.put(0x00BB, 0x00AB); mirrorChars.put(0x2039, 0x203A); mirrorChars.put(0x203A, 0x2039); mirrorChars.put(0x2045, 0x2046); mirrorChars.put(0x2046, 0x2045); mirrorChars.put(0x207D, 0x207E); mirrorChars.put(0x207E, 0x207D); mirrorChars.put(0x208D, 0x208E); mirrorChars.put(0x208E, 0x208D); mirrorChars.put(0x2208, 0x220B); mirrorChars.put(0x2209, 0x220C); mirrorChars.put(0x220A, 0x220D); mirrorChars.put(0x220B, 0x2208); mirrorChars.put(0x220C, 0x2209); mirrorChars.put(0x220D, 0x220A); mirrorChars.put(0x2215, 0x29F5); mirrorChars.put(0x223C, 0x223D); mirrorChars.put(0x223D, 0x223C); mirrorChars.put(0x2243, 0x22CD); mirrorChars.put(0x2252, 0x2253); mirrorChars.put(0x2253, 0x2252); mirrorChars.put(0x2254, 0x2255); mirrorChars.put(0x2255, 0x2254); mirrorChars.put(0x2264, 0x2265); mirrorChars.put(0x2265, 0x2264); mirrorChars.put(0x2266, 0x2267); mirrorChars.put(0x2267, 0x2266); mirrorChars.put(0x2268, 0x2269); mirrorChars.put(0x2269, 0x2268); mirrorChars.put(0x226A, 0x226B); mirrorChars.put(0x226B, 0x226A); mirrorChars.put(0x226E, 0x226F); mirrorChars.put(0x226F, 0x226E); mirrorChars.put(0x2270, 0x2271); mirrorChars.put(0x2271, 0x2270); mirrorChars.put(0x2272, 0x2273); mirrorChars.put(0x2273, 0x2272); mirrorChars.put(0x2274, 0x2275); mirrorChars.put(0x2275, 0x2274); mirrorChars.put(0x2276, 0x2277); mirrorChars.put(0x2277, 0x2276); mirrorChars.put(0x2278, 0x2279); mirrorChars.put(0x2279, 0x2278); mirrorChars.put(0x227A, 0x227B); mirrorChars.put(0x227B, 0x227A); mirrorChars.put(0x227C, 0x227D); mirrorChars.put(0x227D, 0x227C); mirrorChars.put(0x227E, 0x227F); mirrorChars.put(0x227F, 0x227E); mirrorChars.put(0x2280, 0x2281); mirrorChars.put(0x2281, 0x2280); mirrorChars.put(0x2282, 0x2283); mirrorChars.put(0x2283, 0x2282); mirrorChars.put(0x2284, 0x2285); mirrorChars.put(0x2285, 0x2284); mirrorChars.put(0x2286, 0x2287); mirrorChars.put(0x2287, 0x2286); mirrorChars.put(0x2288, 0x2289); mirrorChars.put(0x2289, 0x2288); mirrorChars.put(0x228A, 0x228B); mirrorChars.put(0x228B, 0x228A); mirrorChars.put(0x228F, 0x2290); mirrorChars.put(0x2290, 0x228F); mirrorChars.put(0x2291, 0x2292); mirrorChars.put(0x2292, 0x2291); mirrorChars.put(0x2298, 0x29B8); mirrorChars.put(0x22A2, 0x22A3); mirrorChars.put(0x22A3, 0x22A2); mirrorChars.put(0x22A6, 0x2ADE); mirrorChars.put(0x22A8, 0x2AE4); mirrorChars.put(0x22A9, 0x2AE3); mirrorChars.put(0x22AB, 0x2AE5); mirrorChars.put(0x22B0, 0x22B1); mirrorChars.put(0x22B1, 0x22B0); mirrorChars.put(0x22B2, 0x22B3); mirrorChars.put(0x22B3, 0x22B2); mirrorChars.put(0x22B4, 0x22B5); mirrorChars.put(0x22B5, 0x22B4); mirrorChars.put(0x22B6, 0x22B7); mirrorChars.put(0x22B7, 0x22B6); mirrorChars.put(0x22C9, 0x22CA); mirrorChars.put(0x22CA, 0x22C9); mirrorChars.put(0x22CB, 0x22CC); mirrorChars.put(0x22CC, 0x22CB); mirrorChars.put(0x22CD, 0x2243); mirrorChars.put(0x22D0, 0x22D1); mirrorChars.put(0x22D1, 0x22D0); mirrorChars.put(0x22D6, 0x22D7); mirrorChars.put(0x22D7, 0x22D6); mirrorChars.put(0x22D8, 0x22D9); mirrorChars.put(0x22D9, 0x22D8); mirrorChars.put(0x22DA, 0x22DB); mirrorChars.put(0x22DB, 0x22DA); mirrorChars.put(0x22DC, 0x22DD); mirrorChars.put(0x22DD, 0x22DC); mirrorChars.put(0x22DE, 0x22DF); mirrorChars.put(0x22DF, 0x22DE); mirrorChars.put(0x22E0, 0x22E1); mirrorChars.put(0x22E1, 0x22E0); mirrorChars.put(0x22E2, 0x22E3); mirrorChars.put(0x22E3, 0x22E2); mirrorChars.put(0x22E4, 0x22E5); mirrorChars.put(0x22E5, 0x22E4); mirrorChars.put(0x22E6, 0x22E7); mirrorChars.put(0x22E7, 0x22E6); mirrorChars.put(0x22E8, 0x22E9); mirrorChars.put(0x22E9, 0x22E8); mirrorChars.put(0x22EA, 0x22EB); mirrorChars.put(0x22EB, 0x22EA); mirrorChars.put(0x22EC, 0x22ED); mirrorChars.put(0x22ED, 0x22EC); mirrorChars.put(0x22F0, 0x22F1); mirrorChars.put(0x22F1, 0x22F0); mirrorChars.put(0x22F2, 0x22FA); mirrorChars.put(0x22F3, 0x22FB); mirrorChars.put(0x22F4, 0x22FC); mirrorChars.put(0x22F6, 0x22FD); mirrorChars.put(0x22F7, 0x22FE); mirrorChars.put(0x22FA, 0x22F2); mirrorChars.put(0x22FB, 0x22F3); mirrorChars.put(0x22FC, 0x22F4); mirrorChars.put(0x22FD, 0x22F6); mirrorChars.put(0x22FE, 0x22F7); mirrorChars.put(0x2308, 0x2309); mirrorChars.put(0x2309, 0x2308); mirrorChars.put(0x230A, 0x230B); mirrorChars.put(0x230B, 0x230A); mirrorChars.put(0x2329, 0x232A); mirrorChars.put(0x232A, 0x2329); mirrorChars.put(0x2768, 0x2769); mirrorChars.put(0x2769, 0x2768); mirrorChars.put(0x276A, 0x276B); mirrorChars.put(0x276B, 0x276A); mirrorChars.put(0x276C, 0x276D); mirrorChars.put(0x276D, 0x276C); mirrorChars.put(0x276E, 0x276F); mirrorChars.put(0x276F, 0x276E); mirrorChars.put(0x2770, 0x2771); mirrorChars.put(0x2771, 0x2770); mirrorChars.put(0x2772, 0x2773); mirrorChars.put(0x2773, 0x2772); mirrorChars.put(0x2774, 0x2775); mirrorChars.put(0x2775, 0x2774); mirrorChars.put(0x27D5, 0x27D6); mirrorChars.put(0x27D6, 0x27D5); mirrorChars.put(0x27DD, 0x27DE); mirrorChars.put(0x27DE, 0x27DD); mirrorChars.put(0x27E2, 0x27E3); mirrorChars.put(0x27E3, 0x27E2); mirrorChars.put(0x27E4, 0x27E5); mirrorChars.put(0x27E5, 0x27E4); mirrorChars.put(0x27E6, 0x27E7); mirrorChars.put(0x27E7, 0x27E6); mirrorChars.put(0x27E8, 0x27E9); mirrorChars.put(0x27E9, 0x27E8); mirrorChars.put(0x27EA, 0x27EB); mirrorChars.put(0x27EB, 0x27EA); mirrorChars.put(0x2983, 0x2984); mirrorChars.put(0x2984, 0x2983); mirrorChars.put(0x2985, 0x2986); mirrorChars.put(0x2986, 0x2985); mirrorChars.put(0x2987, 0x2988); mirrorChars.put(0x2988, 0x2987); mirrorChars.put(0x2989, 0x298A); mirrorChars.put(0x298A, 0x2989); mirrorChars.put(0x298B, 0x298C); mirrorChars.put(0x298C, 0x298B); mirrorChars.put(0x298D, 0x2990); mirrorChars.put(0x298E, 0x298F); mirrorChars.put(0x298F, 0x298E); mirrorChars.put(0x2990, 0x298D); mirrorChars.put(0x2991, 0x2992); mirrorChars.put(0x2992, 0x2991); mirrorChars.put(0x2993, 0x2994); mirrorChars.put(0x2994, 0x2993); mirrorChars.put(0x2995, 0x2996); mirrorChars.put(0x2996, 0x2995); mirrorChars.put(0x2997, 0x2998); mirrorChars.put(0x2998, 0x2997); mirrorChars.put(0x29B8, 0x2298); mirrorChars.put(0x29C0, 0x29C1); mirrorChars.put(0x29C1, 0x29C0); mirrorChars.put(0x29C4, 0x29C5); mirrorChars.put(0x29C5, 0x29C4); mirrorChars.put(0x29CF, 0x29D0); mirrorChars.put(0x29D0, 0x29CF); mirrorChars.put(0x29D1, 0x29D2); mirrorChars.put(0x29D2, 0x29D1); mirrorChars.put(0x29D4, 0x29D5); mirrorChars.put(0x29D5, 0x29D4); mirrorChars.put(0x29D8, 0x29D9); mirrorChars.put(0x29D9, 0x29D8); mirrorChars.put(0x29DA, 0x29DB); mirrorChars.put(0x29DB, 0x29DA); mirrorChars.put(0x29F5, 0x2215); mirrorChars.put(0x29F8, 0x29F9); mirrorChars.put(0x29F9, 0x29F8); mirrorChars.put(0x29FC, 0x29FD); mirrorChars.put(0x29FD, 0x29FC); mirrorChars.put(0x2A2B, 0x2A2C); mirrorChars.put(0x2A2C, 0x2A2B); mirrorChars.put(0x2A2D, 0x2A2C); mirrorChars.put(0x2A2E, 0x2A2D); mirrorChars.put(0x2A34, 0x2A35); mirrorChars.put(0x2A35, 0x2A34); mirrorChars.put(0x2A3C, 0x2A3D); mirrorChars.put(0x2A3D, 0x2A3C); mirrorChars.put(0x2A64, 0x2A65); mirrorChars.put(0x2A65, 0x2A64); mirrorChars.put(0x2A79, 0x2A7A); mirrorChars.put(0x2A7A, 0x2A79); mirrorChars.put(0x2A7D, 0x2A7E); mirrorChars.put(0x2A7E, 0x2A7D); mirrorChars.put(0x2A7F, 0x2A80); mirrorChars.put(0x2A80, 0x2A7F); mirrorChars.put(0x2A81, 0x2A82); mirrorChars.put(0x2A82, 0x2A81); mirrorChars.put(0x2A83, 0x2A84); mirrorChars.put(0x2A84, 0x2A83); mirrorChars.put(0x2A8B, 0x2A8C); mirrorChars.put(0x2A8C, 0x2A8B); mirrorChars.put(0x2A91, 0x2A92); mirrorChars.put(0x2A92, 0x2A91); mirrorChars.put(0x2A93, 0x2A94); mirrorChars.put(0x2A94, 0x2A93); mirrorChars.put(0x2A95, 0x2A96); mirrorChars.put(0x2A96, 0x2A95); mirrorChars.put(0x2A97, 0x2A98); mirrorChars.put(0x2A98, 0x2A97); mirrorChars.put(0x2A99, 0x2A9A); mirrorChars.put(0x2A9A, 0x2A99); mirrorChars.put(0x2A9B, 0x2A9C); mirrorChars.put(0x2A9C, 0x2A9B); mirrorChars.put(0x2AA1, 0x2AA2); mirrorChars.put(0x2AA2, 0x2AA1); mirrorChars.put(0x2AA6, 0x2AA7); mirrorChars.put(0x2AA7, 0x2AA6); mirrorChars.put(0x2AA8, 0x2AA9); mirrorChars.put(0x2AA9, 0x2AA8); mirrorChars.put(0x2AAA, 0x2AAB); mirrorChars.put(0x2AAB, 0x2AAA); mirrorChars.put(0x2AAC, 0x2AAD); mirrorChars.put(0x2AAD, 0x2AAC); mirrorChars.put(0x2AAF, 0x2AB0); mirrorChars.put(0x2AB0, 0x2AAF); mirrorChars.put(0x2AB3, 0x2AB4); mirrorChars.put(0x2AB4, 0x2AB3); mirrorChars.put(0x2ABB, 0x2ABC); mirrorChars.put(0x2ABC, 0x2ABB); mirrorChars.put(0x2ABD, 0x2ABE); mirrorChars.put(0x2ABE, 0x2ABD); mirrorChars.put(0x2ABF, 0x2AC0); mirrorChars.put(0x2AC0, 0x2ABF); mirrorChars.put(0x2AC1, 0x2AC2); mirrorChars.put(0x2AC2, 0x2AC1); mirrorChars.put(0x2AC3, 0x2AC4); mirrorChars.put(0x2AC4, 0x2AC3); mirrorChars.put(0x2AC5, 0x2AC6); mirrorChars.put(0x2AC6, 0x2AC5); mirrorChars.put(0x2ACD, 0x2ACE); mirrorChars.put(0x2ACE, 0x2ACD); mirrorChars.put(0x2ACF, 0x2AD0); mirrorChars.put(0x2AD0, 0x2ACF); mirrorChars.put(0x2AD1, 0x2AD2); mirrorChars.put(0x2AD2, 0x2AD1); mirrorChars.put(0x2AD3, 0x2AD4); mirrorChars.put(0x2AD4, 0x2AD3); mirrorChars.put(0x2AD5, 0x2AD6); mirrorChars.put(0x2AD6, 0x2AD5); mirrorChars.put(0x2ADE, 0x22A6); mirrorChars.put(0x2AE3, 0x22A9); mirrorChars.put(0x2AE4, 0x22A8); mirrorChars.put(0x2AE5, 0x22AB); mirrorChars.put(0x2AEC, 0x2AED); mirrorChars.put(0x2AED, 0x2AEC); mirrorChars.put(0x2AF7, 0x2AF8); mirrorChars.put(0x2AF8, 0x2AF7); mirrorChars.put(0x2AF9, 0x2AFA); mirrorChars.put(0x2AFA, 0x2AF9); mirrorChars.put(0x3008, 0x3009); mirrorChars.put(0x3009, 0x3008); mirrorChars.put(0x300A, 0x300B); mirrorChars.put(0x300B, 0x300A); mirrorChars.put(0x300C, 0x300D); mirrorChars.put(0x300D, 0x300C); mirrorChars.put(0x300E, 0x300F); mirrorChars.put(0x300F, 0x300E); mirrorChars.put(0x3010, 0x3011); mirrorChars.put(0x3011, 0x3010); mirrorChars.put(0x3014, 0x3015); mirrorChars.put(0x3015, 0x3014); mirrorChars.put(0x3016, 0x3017); mirrorChars.put(0x3017, 0x3016); mirrorChars.put(0x3018, 0x3019); mirrorChars.put(0x3019, 0x3018); mirrorChars.put(0x301A, 0x301B); mirrorChars.put(0x301B, 0x301A); mirrorChars.put(0xFF08, 0xFF09); mirrorChars.put(0xFF09, 0xFF08); mirrorChars.put(0xFF1C, 0xFF1E); mirrorChars.put(0xFF1E, 0xFF1C); mirrorChars.put(0xFF3B, 0xFF3D); mirrorChars.put(0xFF3D, 0xFF3B); mirrorChars.put(0xFF5B, 0xFF5D); mirrorChars.put(0xFF5D, 0xFF5B); mirrorChars.put(0xFF5F, 0xFF60); mirrorChars.put(0xFF60, 0xFF5F); mirrorChars.put(0xFF62, 0xFF63); mirrorChars.put(0xFF63, 0xFF62); } 915 } | Popular Tags |