1 /******************************************************************************* 2 * Copyright (c) 2011 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 ******************************************************************************/ 14 package org.eclipse.equinox.bidi.custom; 15 16 import org.eclipse.equinox.bidi.advanced.IStructuredTextExpert; 17 import org.eclipse.equinox.bidi.advanced.StructuredTextEnvironment; 18 19 /** 20 * Provides services related to the bidi classification of characters. 21 */ 22 public class StructuredTextCharTypes { 23 24 // In the following lines, B, L, R and AL represent bidi categories 25 // as defined in the Unicode Bidirectional Algorithm 26 // ( http://www.unicode.org/reports/tr9/ ). 27 // B represents the category Block Separator. 28 // L represents the category Left to Right character. 29 // R represents the category Right to Left character. 30 // AL represents the category Arabic Letter. 31 // AN represents the category Arabic Number. 32 // EN represents the category European Number. 33 static final byte B = Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR; 34 static final byte L = Character.DIRECTIONALITY_LEFT_TO_RIGHT; 35 static final byte R = Character.DIRECTIONALITY_RIGHT_TO_LEFT; 36 static final byte AL = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC; 37 static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER; 38 static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER; 39 40 private static final int CHARTYPES_ADD = 2; 41 42 /** 43 * The IStructuredTextExpert instance which created this instance. 44 */ 45 final protected IStructuredTextExpert expert; 46 /** 47 * The StructuredTextTypeHandler instance utilized by the expert. 48 */ 49 final protected StructuredTextTypeHandler handler; 50 /** 51 * The environment associated with the expert. 52 */ 53 final protected StructuredTextEnvironment environment; 54 /** 55 * The source text whose characters are analyzed. 56 */ 57 final protected String text; 58 59 // 1 byte for each char in text 60 private byte[] types; 61 62 // structured text direction. -1 means not yet computed; -2 means within handler.getDirection 63 private int direction = -1; 64 65 /** 66 * Constructor 67 * 68 * @param expert IStructuredTextExpert instance through which this handler 69 * is invoked. The handler can use IStructuredTextExpert methods to 70 * query items stored in the expert instance, like the current 71 * {@link StructuredTextEnvironment environment}. 72 * 73 * @param text is the text whose characters are analyzed. 74 */ StructuredTextCharTypes(IStructuredTextExpert expert, String text)75 public StructuredTextCharTypes(IStructuredTextExpert expert, String text) { 76 this.expert = expert; 77 this.handler = expert.getTypeHandler(); 78 this.environment = expert.getEnvironment(); 79 this.text = text; 80 types = new byte[text.length()]; 81 } 82 83 /** 84 * Indicates the base text direction appropriate for an instance of 85 * structured text. 86 * 87 * @return the base direction of the structured text. This direction 88 * may not be the same depending on the environment and on 89 * whether the structured text contains Arabic or Hebrew 90 * letters.<br> 91 * The value returned is either 92 * {@link IStructuredTextExpert#DIR_LTR DIR_LTR} or 93 * {@link IStructuredTextExpert#DIR_RTL DIR_RTL}. 94 */ getDirection()95 public int getDirection() { 96 if (direction < 0) 97 direction = handler.getDirection(expert, text, this); 98 return direction; 99 } 100 getCachedTypeAt(int index)101 private byte getCachedTypeAt(int index) { 102 return (byte) (types[index] - CHARTYPES_ADD); 103 } 104 hasCachedTypeAt(int i)105 private boolean hasCachedTypeAt(int i) { 106 return (types[i] != 0); // "0" means "unknown" 107 } 108 109 /** 110 * Gets the directionality of the character in the original string 111 * at the specified index. 112 * 113 * @param index position of the character in the <i>lean</i> text 114 * 115 * @return the bidi type of the character. It is one of the 116 * values which can be returned by 117 * {@link Character#getDirectionality(char)}. 118 */ getBidiTypeAt(int index)119 public byte getBidiTypeAt(int index) { 120 if (hasCachedTypeAt(index)) 121 return getCachedTypeAt(index); 122 byte charType = Character.getDirectionality(text.charAt(index)); 123 if (charType == B) { 124 if (direction < 0) { 125 if (direction < -1) // called by handler.getDirection 126 return charType; // avoid infinite recursion 127 direction = -2; // signal we go within handler.getDirection 128 direction = handler.getDirection(expert, text, this); 129 } 130 charType = (direction == StructuredTextEnvironment.ORIENT_RTL) ? R : L; 131 } 132 setBidiTypeAt(index, charType); 133 return charType; 134 } 135 136 /** 137 * Forces a bidi type on a character. 138 * 139 * @param index position of the character whose bidi type is set. 140 * 141 * @param charType bidirectional type of the character. It must be 142 * one of the values which can be returned by 143 * <code>java.lang.Character.getDirectionality</code>. 144 */ setBidiTypeAt(int index, byte charType)145 public void setBidiTypeAt(int index, byte charType) { 146 types[index] = (byte) (charType + CHARTYPES_ADD); 147 } 148 149 /** 150 * Gets the orientation of the component in which the text will 151 * be displayed. 152 * 153 * @return the orientation as either 154 * {@link StructuredTextEnvironment#ORIENT_LTR}, 155 * {@link StructuredTextEnvironment#ORIENT_RTL}, 156 * {@link StructuredTextEnvironment#ORIENT_UNKNOWN} or 157 * {@link StructuredTextEnvironment#ORIENT_IGNORE}. 158 */ resolveOrientation()159 public int resolveOrientation() { 160 int orient = environment.getOrientation(); 161 if ((orient & StructuredTextEnvironment.ORIENT_CONTEXTUAL) == 0) { // absolute orientation 162 return orient; 163 } 164 // contextual orientation: 165 orient &= ~StructuredTextEnvironment.ORIENT_CONTEXTUAL; // initiate to the default orientation minus contextual bit 166 int len = text.length(); 167 byte charType; 168 for (int i = 0; i < len; i++) { 169 if (!hasCachedTypeAt(i)) { 170 charType = Character.getDirectionality(text.charAt(i)); 171 if (charType == B) // B char resolves to L or R depending on orientation 172 continue; 173 setBidiTypeAt(i, charType); 174 } else 175 charType = getCachedTypeAt(i); 176 if (charType == L) 177 return StructuredTextEnvironment.ORIENT_LTR; 178 if (charType == R || charType == AL) 179 return StructuredTextEnvironment.ORIENT_RTL; 180 } 181 return orient; 182 } 183 184 } 185