1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 5 package ohos.global.icu.text; 6 7 import ohos.global.icu.lang.UCharacter; 8 9 /** 10 * Bidi Layout Transformation Engine. 11 * 12 * @author Lina Kemmel 13 * 14 * @hide exposed on OHOS 15 */ 16 public class BidiTransform 17 { 18 /** 19 * <code>{@link Order}</code> indicates the order of text. 20 * <p> 21 * This bidi transformation engine supports all possible combinations (4 in 22 * total) of input and output text order: 23 * <ul> 24 * <li>{logical input, visual output}: unless the output direction is RTL, 25 * this corresponds to a normal operation of the Bidi algorithm as 26 * described in the Unicode Technical Report and implemented by 27 * <code>{@link Bidi}</code> when the reordering mode is set to 28 * <code>Bidi#REORDER_DEFAULT</code>. Visual RTL mode is not supported by 29 * <code>{@link Bidi}</code> and is accomplished through reversing a visual 30 * LTR string,</li> 31 * <li>{visual input, logical output}: unless the input direction is RTL, 32 * this corresponds to an "inverse bidi algorithm" in 33 * <code>{@link Bidi}</code> with the reordering mode set to 34 * <code>{@link Bidi#REORDER_INVERSE_LIKE_DIRECT}</code>. Visual RTL mode 35 * is not not supported by <code>{@link Bidi}</code> and is accomplished 36 * through reversing a visual LTR string,</li> 37 * <li>{logical input, logical output}: if the input and output base 38 * directions mismatch, this corresponds to the <code>{@link Bidi}</code> 39 * implementation with the reordering mode set to 40 * <code>{@link Bidi#REORDER_RUNS_ONLY}</code>; and if the input and output 41 * base directions are identical, the transformation engine will only 42 * handle character mirroring and Arabic shaping operations without 43 * reordering,</li> 44 * <li>{visual input, visual output}: this reordering mode is not supported 45 * by the <code>{@link Bidi}</code> engine; it implies character mirroring, 46 * Arabic shaping, and - if the input/output base directions mismatch - 47 * string reverse operations.</li> 48 * </ul> 49 * 50 * @see Bidi#setInverse 51 * @see Bidi#setReorderingMode 52 * @see Bidi#REORDER_DEFAULT 53 * @see Bidi#REORDER_INVERSE_LIKE_DIRECT 54 * @see Bidi#REORDER_RUNS_ONLY 55 * @hide exposed on OHOS 56 */ 57 public enum Order { 58 /** 59 * Constant indicating a logical order. 60 */ 61 LOGICAL, 62 /** 63 * Constant indicating a visual order. 64 */ 65 VISUAL; 66 } 67 68 /** 69 * <code>{@link Mirroring}</code> indicates whether or not characters with 70 * the "mirrored" property in RTL runs should be replaced with their 71 * mirror-image counterparts. 72 * 73 * @see Bidi#DO_MIRRORING 74 * @see Bidi#setReorderingOptions 75 * @see Bidi#writeReordered 76 * @see Bidi#writeReverse 77 * @hide exposed on OHOS 78 */ 79 public enum Mirroring { 80 /** 81 * Constant indicating that character mirroring should not be 82 * performed. 83 */ 84 OFF, 85 /** 86 * Constant indicating that character mirroring should be performed. 87 * <p> 88 * This corresponds to calling <code>{@link Bidi#writeReordered}</code> 89 * or <code>{@link Bidi#writeReverse}</code> with the 90 * <code>{@link Bidi#DO_MIRRORING}</code> option bit set. 91 */ 92 ON; 93 } 94 95 private Bidi bidi; 96 private String text; 97 private int reorderingOptions; 98 private int shapingOptions; 99 100 /** 101 * <code>{@link BidiTransform}</code> default constructor. 102 */ BidiTransform()103 public BidiTransform() 104 { 105 } 106 107 /** 108 * Performs transformation of text from the bidi layout defined by the 109 * input ordering scheme to the bidi layout defined by the output ordering 110 * scheme, and applies character mirroring and Arabic shaping operations. 111 * <p> 112 * In terms of <code>{@link Bidi}</code> class, such a transformation 113 * implies: 114 * <ul> 115 * <li>calling <code>{@link Bidi#setReorderingMode}</code> as needed (when 116 * the reordering mode is other than normal),</li> 117 * <li>calling <code>{@link Bidi#setInverse}</code> as needed (when text 118 * should be transformed from a visual to a logical form),</li> 119 * <li>resolving embedding levels of each character in the input text by 120 * calling <code>{@link Bidi#setPara}</code>,</li> 121 * <li>reordering the characters based on the computed embedding levels, 122 * also performing character mirroring as needed, and streaming the result 123 * to the output, by calling <code>{@link Bidi#writeReordered}</code>,</li> 124 * <li>performing Arabic digit and letter shaping on the output text by 125 * calling <code>{@link ArabicShaping#shape}</code>.</li> 126 * </ul><p> 127 * An "ordering scheme" encompasses the base direction and the order of 128 * text, and these characteristics must be defined by the caller for both 129 * input and output explicitly .<p> 130 * There are 36 possible combinations of {input, output} ordering schemes, 131 * which are partially supported by <code>{@link Bidi}</code> already. 132 * Examples of the currently supported combinations: 133 * <ul> 134 * <li>{Logical LTR, Visual LTR}: this is equivalent to calling 135 * <code>{@link Bidi#setPara}</code> with 136 * <code>paraLevel == {@link Bidi#LTR}</code>,</li> 137 * <li>{Logical RTL, Visual LTR}: this is equivalent to calling 138 * <code>{@link Bidi#setPara}</code> with 139 * <code>paraLevel == {@link Bidi#RTL}</code>,</li> 140 * <li>{Logical Default ("Auto") LTR, Visual LTR}: this is equivalent to 141 * calling <code>{@link Bidi#setPara}</code> with 142 * <code>paraLevel == {@link Bidi#LEVEL_DEFAULT_LTR}</code>,</li> 143 * <li>{Logical Default ("Auto") RTL, Visual LTR}: this is equivalent to 144 * calling <code>{@link Bidi#setPara}</code> with 145 * <code>paraLevel == {@link Bidi#LEVEL_DEFAULT_RTL}</code>,</li> 146 * <li>{Visual LTR, Logical LTR}: this is equivalent to 147 * calling <code>{@link Bidi#setInverse}(true)</code> and then 148 * <code>{@link Bidi#setPara}</code> with 149 * <code>paraLevel == {@link Bidi#LTR}</code>,</li> 150 * <li>{Visual LTR, Logical RTL}: this is equivalent to calling 151 * <code>{@link Bidi#setInverse}(true)</code> and then 152 * <code>{@link Bidi#setPara}</code> with 153 * <code>paraLevel == {@link Bidi#RTL}</code>.</li> 154 * </ul><p> 155 * All combinations that involve the Visual RTL scheme are unsupported by 156 * <code>{@link Bidi}</code>, for instance: 157 * <ul> 158 * <li>{Logical LTR, Visual RTL},</li> 159 * <li>{Visual RTL, Logical RTL}.</li> 160 * </ul> 161 * <p>Example of usage of the transformation engine:</p> 162 * <pre> 163 * BidiTransform bidiTransform = new BidiTransform(); 164 * String in = "abc \u06f0123"; // "abc \\u06f0123" 165 * // Run a transformation. 166 * String out = bidiTransform.transform(in, 167 * Bidi.LTR, Order.VISUAL, 168 * Bidi.RTL, Order.LOGICAL, 169 * Mirroring.OFF, 170 * ArabicShaping.DIGITS_AN2EN | ArabicShaping.DIGIT_TYPE_AN_EXTENDED); 171 * // Result: "0123 abc". 172 * // Do something with out. 173 * out = out.replace('0', '4'); 174 * // Result: "4123 abc". 175 * // Run a reverse transformation. 176 * String inNew = bidiTransform.transform(out, 177 * Bidi.RTL, Order.LOGICAL, 178 * Bidi.LTR, Order.VISUAL, 179 * Mirroring.OFF, 180 * ArabicShaping.DIGITS_EN2AN | ArabicShaping.DIGIT_TYPE_AN_EXTENDED); 181 * // Result: "abc \\u06f4\\u06f1\\u06f2\\u06f3" 182 * </pre> 183 * 184 * @param text An input character sequence that the Bidi layout 185 * transformations will be performed on. 186 * @param inParaLevel A base embedding level of the input as defined in 187 * <code>{@link Bidi#setPara(String, byte, byte[])}</code> 188 * documentation for the <code>paraLevel</code> parameter. 189 * @param inOrder An order of the input, which can be one of the 190 * <code>{@link Order}</code> values. 191 * @param outParaLevel A base embedding level of the output as defined in 192 * <code>{@link Bidi#setPara(String, byte, byte[])}</code> 193 * documentation for the <code>paraLevel</code> parameter. 194 * @param outOrder An order of the output, which can be one of the 195 * <code>{@link Order}</code> values. 196 * @param doMirroring Indicates whether or not to perform character 197 * mirroring, and can accept one of the 198 * <code>{@link Mirroring}</code> values. 199 * @param shapingOptions Arabic digit and letter shaping options defined in 200 * the <code>{@link ArabicShaping}</code> documentation. 201 * <p><strong>Note:</strong> Direction indicator options are 202 * computed by the transformation engine based on the effective 203 * ordering schemes, so user-defined direction indicators will be 204 * ignored. 205 * @return The output string, which is the result of the layout 206 * transformation. 207 * @throws IllegalArgumentException if <code>text</code>, 208 * <code>inOrder</code>, <code>outOrder</code>, or 209 * <code>doMirroring</code> parameter is <code>null</code>. 210 */ transform(CharSequence text, byte inParaLevel, Order inOrder, byte outParaLevel, Order outOrder, Mirroring doMirroring, int shapingOptions)211 public String transform(CharSequence text, 212 byte inParaLevel, Order inOrder, 213 byte outParaLevel, Order outOrder, 214 Mirroring doMirroring, int shapingOptions) 215 { 216 if (text == null || inOrder == null || outOrder == null || doMirroring == null) { 217 throw new IllegalArgumentException(); 218 } 219 this.text = text.toString(); 220 221 byte[] levels = {inParaLevel, outParaLevel}; 222 resolveBaseDirection(levels); 223 224 ReorderingScheme currentScheme = findMatchingScheme(levels[0], inOrder, 225 levels[1], outOrder); 226 if (currentScheme != null) { 227 this.bidi = new Bidi(); 228 this.reorderingOptions = Mirroring.ON.equals(doMirroring) 229 ? Bidi.DO_MIRRORING : Bidi.REORDER_DEFAULT; 230 231 /* Ignore TEXT_DIRECTION_* flags, as we apply our own depending on the 232 text scheme at the time shaping is invoked. */ 233 this.shapingOptions = shapingOptions & ~ArabicShaping.TEXT_DIRECTION_MASK; 234 currentScheme.doTransform(this); 235 } 236 return this.text; 237 } 238 239 /** 240 * When the direction option is 241 * <code>{@link Bidi#LEVEL_DEFAULT_LTR}</code> or 242 * <code>{@link Bidi#LEVEL_DEFAULT_RTL}</code>, resolves the base 243 * direction according to that of the first strong directional character in 244 * the text. 245 * 246 * @param levels Byte array, where levels[0] is an input level levels[1] is 247 * an output level. Resolved levels override these. 248 */ resolveBaseDirection(byte[] levels)249 private void resolveBaseDirection(byte[] levels) { 250 if (Bidi.IsDefaultLevel(levels[0])) { 251 byte level = Bidi.getBaseDirection(text); 252 levels[0] = level != Bidi.NEUTRAL ? level 253 : levels[0] == Bidi.LEVEL_DEFAULT_RTL ? Bidi.RTL : Bidi.LTR; 254 } else { 255 levels[0] &= 1; 256 } 257 if (Bidi.IsDefaultLevel(levels[1])) { 258 levels[1] = levels[0]; 259 } else { 260 levels[1] &= 1; 261 } 262 } 263 264 /** 265 * Finds a valid <code>{@link ReorderingScheme}</code> matching the 266 * caller-defined scheme. 267 * 268 * @return A valid <code>ReorderingScheme</code> object or null 269 */ findMatchingScheme(byte inLevel, Order inOrder, byte outLevel, Order outOrder)270 private ReorderingScheme findMatchingScheme(byte inLevel, Order inOrder, 271 byte outLevel, Order outOrder) { 272 for (ReorderingScheme scheme : ReorderingScheme.values()) { 273 if (scheme.matches(inLevel, inOrder, outLevel, outOrder)) { 274 return scheme; 275 } 276 } 277 return null; 278 } 279 280 /** 281 * Performs bidi resolution of text. 282 * 283 * @param level Base embedding level 284 * @param options Reordering options 285 */ resolve(byte level, int options)286 private void resolve(byte level, int options) { 287 bidi.setInverse((options & Bidi.REORDER_INVERSE_LIKE_DIRECT) != 0); 288 bidi.setReorderingMode(options); 289 bidi.setPara(text, level, null); 290 } 291 292 /** 293 * Performs basic reordering of text (Logical LTR or RTL to Visual LTR). 294 * 295 */ reorder()296 private void reorder() { 297 text = bidi.writeReordered(reorderingOptions); 298 reorderingOptions = Bidi.REORDER_DEFAULT; 299 } 300 301 /** 302 * Performs string reverse. 303 */ reverse()304 private void reverse() { 305 text = Bidi.writeReverse(text, Bidi.OPTION_DEFAULT); 306 } 307 308 /** 309 * Performs character mirroring without reordering. When this method is 310 * called, <code>{@link #text}</code> should be in a Logical form. 311 */ mirror()312 private void mirror() { 313 if ((reorderingOptions & Bidi.DO_MIRRORING) == 0) { 314 return; 315 } 316 StringBuffer sb = new StringBuffer(text); 317 byte[] levels = bidi.getLevels(); 318 for (int i = 0, n = levels.length; i < n;) { 319 int ch = UTF16.charAt(sb, i); 320 if ((levels[i] & 1) != 0) { 321 UTF16.setCharAt(sb, i, UCharacter.getMirror(ch)); 322 } 323 i += UTF16.getCharCount(ch); 324 } 325 text = sb.toString(); 326 reorderingOptions &= ~Bidi.DO_MIRRORING; 327 } 328 329 /** 330 * Performs digit and letter shaping 331 * 332 * @param digitsDir Digit shaping option that indicates whether the text 333 * should be treated as logical or visual. 334 * @param lettersDir Letter shaping option that indicates whether the text 335 * should be treated as logical or visual form (can mismatch the digit 336 * option). 337 */ shapeArabic(int digitsDir, int lettersDir)338 private void shapeArabic(int digitsDir, int lettersDir) { 339 if (digitsDir == lettersDir) { 340 shapeArabic(shapingOptions | digitsDir); 341 } else { 342 /* Honor all shape options other than letters (not necessarily digits 343 only) */ 344 shapeArabic((shapingOptions & ~ArabicShaping.LETTERS_MASK) | digitsDir); 345 346 /* Honor all shape options other than digits (not necessarily letters 347 only) */ 348 shapeArabic((shapingOptions & ~ArabicShaping.DIGITS_MASK) | lettersDir); 349 } 350 } 351 352 /** 353 * Performs digit and letter shaping 354 * 355 * @param options Shaping options covering both letters and digits 356 */ shapeArabic(int options)357 private void shapeArabic(int options) { 358 if (options != 0) { 359 ArabicShaping shaper = new ArabicShaping(options); 360 try { 361 text = shaper.shape(text); 362 } catch(ArabicShapingException e) { 363 } 364 } 365 } 366 367 private enum ReorderingScheme { 368 LOG_LTR_TO_VIS_LTR { 369 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)370 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 371 return IsLTR(inLevel) && IsLogical(inOrder) 372 && IsLTR(outLevel) && IsVisual(outOrder); 373 } 374 @Override doTransform(BidiTransform transform)375 void doTransform(BidiTransform transform) { 376 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 377 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 378 transform.reorder(); 379 } 380 }, 381 LOG_RTL_TO_VIS_LTR { 382 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)383 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 384 return IsRTL(inLevel) && IsLogical(inOrder) 385 && IsLTR(outLevel) && IsVisual(outOrder); 386 } 387 @Override doTransform(BidiTransform transform)388 void doTransform(BidiTransform transform) { 389 transform.resolve(Bidi.RTL, Bidi.REORDER_DEFAULT); 390 transform.reorder(); 391 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 392 } 393 }, 394 LOG_LTR_TO_VIS_RTL { 395 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)396 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 397 return IsLTR(inLevel) && IsLogical(inOrder) 398 && IsRTL(outLevel) && IsVisual(outOrder); 399 } 400 @Override doTransform(BidiTransform transform)401 void doTransform(BidiTransform transform) { 402 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 403 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 404 transform.reorder(); 405 transform.reverse(); 406 } 407 }, 408 LOG_RTL_TO_VIS_RTL { 409 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)410 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 411 return IsRTL(inLevel) && IsLogical(inOrder) 412 && IsRTL(outLevel) && IsVisual(outOrder); 413 } 414 @Override doTransform(BidiTransform transform)415 void doTransform(BidiTransform transform) { 416 transform.resolve(Bidi.RTL, Bidi.REORDER_DEFAULT); 417 transform.reorder(); 418 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 419 transform.reverse(); 420 } 421 }, 422 VIS_LTR_TO_LOG_RTL { 423 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)424 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 425 return IsLTR(inLevel) && IsVisual(inOrder) 426 && IsRTL(outLevel) && IsLogical(outOrder); 427 } 428 @Override doTransform(BidiTransform transform)429 void doTransform(BidiTransform transform) { 430 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 431 transform.resolve(Bidi.RTL, Bidi.REORDER_INVERSE_LIKE_DIRECT); 432 transform.reorder(); 433 } 434 }, 435 VIS_RTL_TO_LOG_RTL { 436 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)437 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 438 return IsRTL(inLevel) && IsVisual(inOrder) 439 && IsRTL(outLevel) && IsLogical(outOrder); 440 } 441 @Override doTransform(BidiTransform transform)442 void doTransform(BidiTransform transform) { 443 transform.reverse(); 444 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 445 transform.resolve(Bidi.RTL, Bidi.REORDER_INVERSE_LIKE_DIRECT); 446 transform.reorder(); 447 } 448 }, 449 VIS_LTR_TO_LOG_LTR { 450 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)451 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 452 return IsLTR(inLevel) && IsVisual(inOrder) 453 && IsLTR(outLevel) && IsLogical(outOrder); 454 } 455 @Override doTransform(BidiTransform transform)456 void doTransform(BidiTransform transform) { 457 transform.resolve(Bidi.LTR, Bidi.REORDER_INVERSE_LIKE_DIRECT); 458 transform.reorder(); 459 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 460 } 461 }, 462 VIS_RTL_TO_LOG_LTR { 463 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)464 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 465 return IsRTL(inLevel) && IsVisual(inOrder) 466 && IsLTR(outLevel) && IsLogical(outOrder); 467 } 468 @Override doTransform(BidiTransform transform)469 void doTransform(BidiTransform transform) { 470 transform.reverse(); 471 transform.resolve(Bidi.LTR, Bidi.REORDER_INVERSE_LIKE_DIRECT); 472 transform.reorder(); 473 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 474 } 475 }, 476 LOG_LTR_TO_LOG_RTL { 477 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)478 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 479 return IsLTR(inLevel) && IsLogical(inOrder) 480 && IsRTL(outLevel) && IsLogical(outOrder); 481 } 482 @Override doTransform(BidiTransform transform)483 void doTransform(BidiTransform transform) { 484 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 485 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 486 transform.mirror(); 487 transform.resolve(Bidi.LTR, Bidi.REORDER_RUNS_ONLY); 488 transform.reorder(); 489 } 490 }, 491 LOG_RTL_TO_LOG_LTR { 492 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)493 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 494 return IsRTL(inLevel) && IsLogical(inOrder) 495 && IsLTR(outLevel) && IsLogical(outOrder); 496 } 497 @Override doTransform(BidiTransform transform)498 void doTransform(BidiTransform transform) { 499 transform.resolve(Bidi.RTL, Bidi.REORDER_DEFAULT); 500 transform.mirror(); 501 transform.resolve(Bidi.RTL, Bidi.REORDER_RUNS_ONLY); 502 transform.reorder(); 503 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 504 } 505 }, 506 VIS_LTR_TO_VIS_RTL { 507 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)508 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 509 return IsLTR(inLevel) && IsVisual(inOrder) 510 && IsRTL(outLevel) && IsVisual(outOrder); 511 } 512 @Override doTransform(BidiTransform transform)513 void doTransform(BidiTransform transform) { 514 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 515 transform.mirror(); 516 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 517 transform.reverse(); 518 } 519 }, 520 VIS_RTL_TO_VIS_LTR { 521 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)522 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 523 return IsRTL(inLevel) && IsVisual(inOrder) 524 && IsLTR(outLevel) && IsVisual(outOrder); 525 } 526 @Override doTransform(BidiTransform transform)527 void doTransform(BidiTransform transform) { 528 transform.reverse(); 529 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 530 transform.mirror(); 531 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 532 } 533 }, 534 LOG_LTR_TO_LOG_LTR { 535 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)536 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 537 return IsLTR(inLevel) && IsLogical(inOrder) 538 && IsLTR(outLevel) && IsLogical(outOrder); 539 } 540 @Override doTransform(BidiTransform transform)541 void doTransform(BidiTransform transform) { 542 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 543 transform.mirror(); 544 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_LOGICAL); 545 } 546 }, 547 LOG_RTL_TO_LOG_RTL { 548 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)549 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 550 return IsRTL(inLevel) && IsLogical(inOrder) 551 && IsRTL(outLevel) && IsLogical(outOrder); 552 } 553 @Override doTransform(BidiTransform transform)554 void doTransform(BidiTransform transform) { 555 transform.resolve(Bidi.RTL, Bidi.REORDER_DEFAULT); 556 transform.mirror(); 557 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_VISUAL_LTR, ArabicShaping.TEXT_DIRECTION_LOGICAL); 558 } 559 }, 560 VIS_LTR_TO_VIS_LTR { 561 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)562 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 563 return IsLTR(inLevel) && IsVisual(inOrder) 564 && IsLTR(outLevel) && IsVisual(outOrder); 565 } 566 @Override doTransform(BidiTransform transform)567 void doTransform(BidiTransform transform) { 568 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 569 transform.mirror(); 570 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 571 } 572 }, 573 VIS_RTL_TO_VIS_RTL { 574 @Override matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)575 boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder) { 576 return IsRTL(inLevel) && IsVisual(inOrder) 577 && IsRTL(outLevel) && IsVisual(outOrder); 578 } 579 @Override doTransform(BidiTransform transform)580 void doTransform(BidiTransform transform) { 581 transform.reverse(); 582 transform.resolve(Bidi.LTR, Bidi.REORDER_DEFAULT); 583 transform.mirror(); 584 transform.shapeArabic(ArabicShaping.TEXT_DIRECTION_LOGICAL, ArabicShaping.TEXT_DIRECTION_VISUAL_LTR); 585 transform.reverse(); 586 } 587 }; 588 589 /** 590 * Indicates whether this scheme matches another one in terms of 591 * equality of base direction and ordering scheme. 592 * 593 * @param inLevel Base level of the input text 594 * @param inOrder Order of the input text 595 * @param outLevel Base level of the output text 596 * @param outOrder Order of the output text 597 * 598 * @return <code>true</code> if it's a match, <code>false</code> 599 * otherwise 600 */ matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder)601 abstract boolean matches(byte inLevel, Order inOrder, byte outLevel, Order outOrder); 602 603 /** 604 * Performs a series of bidi layout transformations unique for the current 605 * scheme. 606 607 * @param transform Bidi transformation engine 608 */ doTransform(BidiTransform transform)609 abstract void doTransform(BidiTransform transform); 610 } 611 612 /** 613 * Is level LTR? convenience method 614 615 * @param level Embedding level 616 */ IsLTR(byte level)617 private static boolean IsLTR(byte level) { 618 return (level & 1) == 0; 619 } 620 621 /** 622 * Is level RTL? convenience method 623 624 * @param level Embedding level 625 */ IsRTL(byte level)626 private static boolean IsRTL(byte level) { 627 return (level & 1) == 1; 628 } 629 630 /** 631 * Is order logical? convenience method 632 633 * @param level Order value 634 */ IsLogical(Order order)635 private static boolean IsLogical(Order order) { 636 return Order.LOGICAL.equals(order); 637 } 638 639 /** 640 * Is order visual? convenience method 641 642 * @param level Order value 643 */ IsVisual(Order order)644 private static boolean IsVisual(Order order) { 645 return Order.VISUAL.equals(order); 646 } 647 648 } 649