1 7 8 17 18 package java.text; 19 20 import java.awt.Toolkit ; 21 import java.awt.font.TextAttribute ; 22 import java.awt.font.NumericShaper ; 23 import sun.text.CodePointIterator; 24 25 46 public final class Bidi { 47 byte dir; 48 byte baselevel; 49 int length; 50 int[] runs; 51 int[] cws; 52 53 static { 54 java.security.AccessController.doPrivileged( 55 new sun.security.action.LoadLibraryAction("awt")); 56 java.security.AccessController.doPrivileged( 57 new sun.security.action.LoadLibraryAction("fontmanager")); 58 } 59 60 61 public static final int DIRECTION_LEFT_TO_RIGHT = 0; 62 63 64 public static final int DIRECTION_RIGHT_TO_LEFT = 1; 65 66 72 public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2; 73 74 80 public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1; 81 82 private static final int DIR_MIXED = 2; 83 84 92 public Bidi(String paragraph, int flags) { 93 if (paragraph == null) { 94 throw new IllegalArgumentException ("paragraph is null"); 95 } 96 97 nativeBidiChars(this, paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags); 98 } 99 100 125 public Bidi(AttributedCharacterIterator paragraph) { 126 if (paragraph == null) { 127 throw new IllegalArgumentException ("paragraph is null"); 128 } 129 130 int flags = DIRECTION_DEFAULT_LEFT_TO_RIGHT; 131 byte[] embeddings = null; 132 133 int start = paragraph.getBeginIndex(); 134 int limit = paragraph.getEndIndex(); 135 int length = limit - start; 136 int n = 0; 137 char[] text = new char[length]; 138 for (char c = paragraph.first(); c != paragraph.DONE; c = paragraph.next()) { 139 text[n++] = c; 140 } 141 142 paragraph.first(); 143 try { 144 Boolean runDirection = (Boolean )paragraph.getAttribute(TextAttribute.RUN_DIRECTION); 145 if (runDirection != null) { 146 if (TextAttribute.RUN_DIRECTION_LTR.equals(runDirection)) { 147 flags = DIRECTION_LEFT_TO_RIGHT; } else { 149 flags = DIRECTION_RIGHT_TO_LEFT; 150 } 151 } 152 } 153 catch (ClassCastException e) { 154 } 155 156 try { 157 NumericShaper shaper = (NumericShaper )paragraph.getAttribute(TextAttribute.NUMERIC_SHAPING); 158 if (shaper != null) { 159 shaper.shape(text, 0, text.length); 160 } 161 } 162 catch (ClassCastException e) { 163 } 164 165 int pos = start; 166 do { 167 paragraph.setIndex(pos); 168 Object embeddingLevel = paragraph.getAttribute(TextAttribute.BIDI_EMBEDDING); 169 int newpos = paragraph.getRunLimit(TextAttribute.BIDI_EMBEDDING); 170 171 if (embeddingLevel != null) { 172 try { 173 int intLevel = ((Integer )embeddingLevel).intValue(); 174 if (intLevel >= -61 && intLevel < 61) { 175 byte level = (byte)(intLevel < 0 ? (-intLevel | 0x80) : intLevel); 176 if (embeddings == null) { 177 embeddings = new byte[length]; 178 } 179 for (int i = pos - start; i < newpos - start; ++i) { 180 embeddings[i] = level; 181 } 182 } 183 } 184 catch (ClassCastException e) { 185 } 186 } 187 pos = newpos; 188 } while (pos < limit); 189 190 nativeBidiChars(this, text, 0, embeddings, 0, text.length, flags); 191 } 192 193 210 public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) { 211 if (text == null) { 212 throw new IllegalArgumentException ("text is null"); 213 } 214 if (paragraphLength < 0) { 215 throw new IllegalArgumentException ("bad length: " + paragraphLength); 216 } 217 if (textStart < 0 || paragraphLength > text.length - textStart) { 218 throw new IllegalArgumentException ("bad range: " + textStart + 219 " length: " + paragraphLength + 220 " for text of length: " + text.length); 221 } 222 if (embeddings != null && (embStart < 0 || paragraphLength > embeddings.length - embStart)) { 223 throw new IllegalArgumentException ("bad range: " + embStart + 224 " length: " + paragraphLength + 225 " for embeddings of length: " + text.length); 226 } 227 228 if (embeddings != null) { 229 231 for (int i = embStart, embLimit = embStart + paragraphLength; i < embLimit; ++i) { 232 if (embeddings[i] < 0) { 233 byte[] temp = new byte[paragraphLength]; 234 System.arraycopy(embeddings, embStart, temp, 0, paragraphLength); 235 236 for (i -= embStart; i < paragraphLength; ++i) { 237 if (temp[i] < 0) { 238 temp[i] = (byte)(-temp[i] | 0x80); 239 } 240 } 241 242 embeddings = temp; 243 embStart = 0; 244 break; 245 } 246 } 247 } 248 249 nativeBidiChars(this, text, textStart, embeddings, embStart, paragraphLength, flags); 250 } 251 252 255 private Bidi(int dir, int baseLevel, int length, int[] data, int[] cws) { 256 reset(dir, baseLevel, length, data, cws); 257 } 258 259 262 private void reset(int dir, int baselevel, int length, int[] data, int[] cws) { 263 this.dir = (byte)dir; 264 this.baselevel = (byte)baselevel; 265 this.length = length; 266 this.runs = data; 267 this.cws = cws; 268 } 269 270 277 public Bidi createLineBidi(int lineStart, int lineLimit) { 278 if (lineStart == 0 && lineLimit == length) { 279 return this; 280 } 281 282 int lineLength = lineLimit - lineStart; 283 if (lineStart < 0 || 284 lineLimit < lineStart || 285 lineLimit > length) { 286 throw new IllegalArgumentException ("range " + lineStart + 287 " to " + lineLimit + 288 " is invalid for paragraph of length " + length); 289 } 290 291 if (runs == null) { 292 return new Bidi (dir, baselevel, lineLength, null, null); 293 } else { 294 int cwspos = -1; 295 int[] ncws = null; 296 if (cws != null) { 297 int cwss = 0; 298 int cwsl = cws.length; 299 while (cwss < cwsl) { 300 if (cws[cwss] >= lineStart) { 301 cwsl = cwss; 302 while (cwsl < cws.length && cws[cwsl] < lineLimit) { 303 cwsl++; 304 } 305 int ll = lineLimit-1; 306 while (cwsl > cwss && cws[cwsl-1] == ll) { 307 cwspos = ll; --cwsl; 309 --ll; 310 } 311 312 if (cwspos == lineStart) { return new Bidi (dir, baselevel, lineLength, null, null); 314 } 315 316 int ncwslen = cwsl - cwss; 317 if (ncwslen > 0) { 318 ncws = new int[ncwslen]; 319 for (int i = 0; i < ncwslen; ++i) { 320 ncws[i] = cws[cwss+i] - lineStart; 321 } 322 } 323 break; 324 } 325 ++cwss; 326 } 327 } 328 329 int[] nruns = null; 330 int nlevel = baselevel; 331 int limit = cwspos == -1 ? lineLimit : cwspos; 332 int rs = 0; 333 int rl = runs.length; 334 int ndir = dir; 335 for (; rs < runs.length; rs += 2) { 336 if (runs[rs] > lineStart) { 337 rl = rs; 338 while (rl < runs.length && runs[rl] < limit) { 339 rl += 2; 340 } 341 if ((rl > rs) || (runs[rs+1] != baselevel)) { 342 rl += 2; 343 344 if (cwspos != -1 && rl > rs && runs[rl-1] != baselevel) { nruns = new int[rl - rs + 2]; 346 nruns[rl - rs] = lineLength; 347 nruns[rl - rs + 1] = baselevel; 348 } else { 349 limit = lineLimit; 350 nruns = new int[rl - rs]; 351 } 352 353 int n = 0; 354 for (int i = rs; i < rl; i += 2) { 355 nruns[n++] = runs[i] - lineStart; 356 nruns[n++] = runs[i+1]; 357 } 358 nruns[n-2] = limit - lineStart; 359 } else { 360 ndir = (runs[rs+1] & 0x1) == 0 ? DIRECTION_LEFT_TO_RIGHT : DIRECTION_RIGHT_TO_LEFT; 361 } 362 break; 363 } 364 } 365 366 return new Bidi (ndir, baselevel, lineLength, nruns, ncws); 367 } 368 } 369 370 375 public boolean isMixed() { 376 return dir == DIR_MIXED; 377 } 378 379 383 public boolean isLeftToRight() { 384 return dir == DIRECTION_LEFT_TO_RIGHT; 385 } 386 387 391 public boolean isRightToLeft() { 392 return dir == DIRECTION_RIGHT_TO_LEFT; 393 } 394 395 399 public int getLength() { 400 return length; 401 } 402 403 407 public boolean baseIsLeftToRight() { 408 return (baselevel & 0x1) == 0; 409 } 410 411 415 public int getBaseLevel() { 416 return baselevel; 417 } 418 419 425 public int getLevelAt(int offset) { 426 if (runs == null || offset < 0 || offset >= length) { 427 return baselevel; 428 } else { 429 int i = 0; 430 do { 431 if (offset < runs[i]) { 432 return runs[i+1]; 433 } 434 i += 2; 435 } while (true); 436 } 437 } 438 439 443 public int getRunCount() { 444 return runs == null ? 1 : runs.length / 2; 445 } 446 447 452 public int getRunLevel(int run) { 453 return runs == null ? baselevel : runs[run * 2 + 1]; 454 } 455 456 462 public int getRunStart(int run) { 463 return (runs == null || run == 0) ? 0 : runs[run * 2 - 2]; 464 } 465 466 473 public int getRunLimit(int run) { 474 return runs == null ? length : runs[run * 2]; 475 } 476 477 488 public static boolean requiresBidi(char[] text, int start, int limit) { 489 CodePointIterator cpi = CodePointIterator.create(text, start, limit); 490 for (int cp = cpi.next(); cp != CodePointIterator.DONE; cp = cpi.next()) { 491 if (cp > 0x0590) { 492 int dc = nativeGetDirectionCode(cp); 493 if ((RMASK & (1 << dc)) != 0) { 494 return true; 495 } 496 } 497 } 498 return false; 499 } 500 501 517 public static void reorderVisually(byte[] levels, int levelStart, Object [] objects, int objectStart, int count) { 518 519 if (count < 0) { 520 throw new IllegalArgumentException ("count " + count + " must be >= 0"); 521 } 522 if (levelStart < 0 || levelStart + count > levels.length) { 523 throw new IllegalArgumentException ("levelStart " + levelStart + " and count " + count + 524 " out of range [0, " + levels.length + "]"); 525 } 526 if (objectStart < 0 || objectStart + count > objects.length) { 527 throw new IllegalArgumentException ("objectStart " + objectStart + " and count " + count + 528 " out of range [0, " + objects.length + "]"); 529 } 530 531 byte lowestOddLevel = (byte)(NUMLEVELS + 1); 532 byte highestLevel = 0; 533 534 536 int levelLimit = levelStart + count; 537 for (int i = levelStart; i < levelLimit; i++) { 538 byte level = levels[i]; 539 if (level > highestLevel) { 540 highestLevel = level; 541 } 542 543 if ((level & 0x01) != 0 && level < lowestOddLevel) { 544 lowestOddLevel = level; 545 } 546 } 547 548 int delta = objectStart - levelStart; 549 550 while (highestLevel >= lowestOddLevel) { 551 int i = levelStart; 552 553 for (;;) { 554 while (i < levelLimit && levels[i] < highestLevel) { 555 i++; 556 } 557 int begin = i++; 558 559 if (begin == levelLimit) { 560 break; } 562 563 while (i < levelLimit && levels[i] >= highestLevel) { 564 i++; 565 } 566 int end = i - 1; 567 568 begin += delta; 569 end += delta; 570 while (begin < end) { 571 Object temp = objects[begin]; 572 objects[begin] = objects[end]; 573 objects[end] = temp; 574 ++begin; 575 --end; 576 } 577 } 578 579 --highestLevel; 580 } 581 } 582 583 private static final char NUMLEVELS = 62; 584 585 private static final int RMASK = 586 (1 << 1 ) | 587 (1 << 5 ) | 588 (1 << 13 ) | 589 (1 << 14 ) | 590 (1 << 15 ); 591 592 593 private static native int nativeGetDirectionCode(int cp); 594 595 596 private static synchronized native void nativeBidiChars(Bidi bidi, char[] text, int textStart, 597 byte[] embeddings, int embeddingStart, 598 int length, int flags); 599 600 603 public String toString() { 604 StringBuffer buf = new StringBuffer (super.toString()); 605 buf.append("[dir: " + dir); 606 buf.append(" baselevel: " + baselevel); 607 buf.append(" length: " + length); 608 if (runs == null) { 609 buf.append(" runs: null"); 610 } else { 611 buf.append(" runs: ["); 612 for (int i = 0; i < runs.length; i += 2) { 613 if (i != 0) { 614 buf.append(' '); 615 } 616 buf.append(runs[i]); buf.append('/'); 618 buf.append(runs[i+1]); } 620 buf.append(']'); 621 } 622 if (cws == null) { 623 buf.append(" cws: null"); 624 } else { 625 buf.append(" cws: ["); 626 for (int i = 0; i < cws.length; ++i) { 627 if (i != 0) { 628 buf.append(' '); 629 } 630 buf.append(Integer.toHexString(cws[i])); 631 } 632 buf.append(']'); 633 } 634 buf.append(']'); 635 636 return buf.toString(); 637 } 638 } 639 640 | Popular Tags |