View | Details | Raw Unified | Return to bug 183164 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/equinox/bidi/custom/STextCharTypes.java (-59 / +102 lines)
Lines 33-118 Link Here
33
	static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER;
33
	static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER;
34
	static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
34
	static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
35
35
36
	private static final int DIRPROPS_ADD = 2;
36
	private static final int CHARTYPES_ADD = 2;
37
37
38
	final protected STextProcessor processor;
39
	final protected STextEnvironment environment;
38
	final protected String text;
40
	final protected String text;
39
41
40
	// 1 byte for each char in text
42
	// 1 byte for each char in text
41
	private byte[] dirProps;
43
	private byte[] types;
42
44
43
	// current orientation
45
	// structured text direction. -1 means not yet computed; -2 means within processor.getDirection
44
	private int orientation = -1; // "-1" means "unknown"
46
	private int direction = -1;
45
47
46
	public STextCharTypes(String text) {
48
	/**
49
	 *  Constructor
50
	 *  
51
	 *  @param  processor is the processor handling this occurrence of
52
	 *          structured text.
53
	 *          
54
	 *  @param  environment the current environment, which may affect the behavior of
55
	 *          the processor. This parameter may be specified as
56
	 *          <code>null</code>, in which case the
57
	 *          {@link STextEnvironment#DEFAULT DEFAULT}
58
	 *          environment should be assumed.
59
	 *  
60
	 *  @param text is the text whose characters are analyzed.
61
	 */
62
	public STextCharTypes(STextProcessor processor, STextEnvironment environment, String text) {
63
		this.processor = processor;
64
		this.environment = environment;
47
		this.text = text;
65
		this.text = text;
48
		dirProps = new byte[text.length()];
66
		types = new byte[text.length()];
49
	}
67
	}
50
68
51
	private byte getCachedDirectionAt(int index) {
69
	public int getDirection() {
52
		return (byte) (dirProps[index] - DIRPROPS_ADD);
70
		if (direction < 0)
71
			direction = processor.getDirection(environment, text, this);
72
		return direction;
73
	}
74
75
	private byte getCachedTypeAt(int index) {
76
		return (byte) (types[index] - CHARTYPES_ADD);
53
	}
77
	}
54
78
55
	private boolean hasCachedDirectionAt(int i) {
79
	private boolean hasCachedTypeAt(int i) {
56
		return (dirProps[i] != 0); // "0" means "unknown"
80
		return (types[i] != 0); // "0" means "unknown"
57
	}
81
	}
58
82
59
	/**
83
	/**
60
	 * @param  dirProp bidirectional class of the character. It must be
84
	 *  Returns directionality of the character in the original string at
61
	 *         one of the values which can be returned by
85
	 *  the specified index.
62
	 *         <code>java.lang.Character.getDirectionality</code>.
86
	 *  
87
	 *  @param  index position of the character in the <i>lean</i> text
88
	 *  
89
	 *  @return the bidi type of the character. It is one of the
90
	 *          values which can be returned by 
91
	 *          {@link Character#getDirectionality(char)}.
63
	 */
92
	 */
64
	public void setBidiTypeAt(int i, byte dirProp) {
93
	public byte getBidiTypeAt(int index) {
65
		dirProps[i] = (byte) (dirProp + DIRPROPS_ADD);
94
		if (hasCachedTypeAt(index))
95
			return getCachedTypeAt(index);
96
		byte charType = Character.getDirectionality(text.charAt(index));
97
		if (charType == B) {
98
			if (direction < 0) {
99
				if (direction < -1) // called by processor.getDirection
100
					return charType; // avoid infinite recursion
101
				direction = -2; // signal we go within processor.getDirection
102
				direction = processor.getDirection(environment, text, this);
103
			}
104
			charType = (direction == STextEnvironment.ORIENT_RTL) ? R : L;
105
		}
106
		setBidiTypeAt(index, charType);
107
		return charType;
66
	}
108
	}
67
109
68
	public int getOrientation(STextEnvironment environment) {
110
	/**
69
		int result;
111
	 *  Force a bidi type on a character.
70
		int orient = environment.getOrientation();
112
	 *  
71
		if ((orient & STextEnvironment.ORIENT_CONTEXTUAL_LTR) == 0) { // absolute orientation
113
	 *  @param  index is the index of the character whose bidi type is set.
72
			result = orient;
114
	 *   
73
		} else { // contextual orientation:
115
	 *  @param  charType bidirectional type of the character. It must be
74
			result = orient & 1; // initiate to the default orientation minus contextual bit
116
	 *          one of the values which can be returned by
75
			int len = text.length();
117
	 *          <code>java.lang.Character.getDirectionality</code>.
76
			byte dirProp;
118
	 */
77
			for (int i = 0; i < len; i++) {
119
	public void setBidiTypeAt(int index, byte charType) {
78
				if (!hasCachedDirectionAt(i)) {
120
		types[index] = (byte) (charType + CHARTYPES_ADD);
79
					dirProp = Character.getDirectionality(text.charAt(i));
80
					if (dirProp == B) // B char resolves to L or R depending on orientation
81
						continue;
82
					setBidiTypeAt(i, dirProp);
83
				} else {
84
					dirProp = getCachedDirectionAt(i);
85
				}
86
				if (dirProp == L) {
87
					result = STextEnvironment.ORIENT_LTR;
88
					break;
89
				}
90
				if (dirProp == R || dirProp == AL) {
91
					result = STextEnvironment.ORIENT_RTL;
92
					break;
93
				}
94
			}
95
		}
96
		orientation = result;
97
		return result;
98
	}
121
	}
99
122
100
	/**
123
	/**
101
	 * Returns directionality of the character in the original string at
124
	 *  Get the orientation of the component in which the text will
102
	 * the specified index.
125
	 *  be displayed.
103
	 * @param index position of the character in the <i>lean</i> text
126
	 *  
104
	 * @return the bidirectional class of the character. It is one of the
127
	 *  @param  envir is the current environment, which may affect the behavior of
105
	 * values which can be returned by {@link Character#getDirectionality(char)}
128
	 *          the processor. This parameter may be specified as
129
	 *          <code>null</code>, in which case the
130
	 *          {@link STextEnvironment#DEFAULT DEFAULT}
131
	 *          environment should be assumed.
132
	 *  
133
	 *  @return the orientation as either 
134
	 *          {@link STextEnvironment#ORIENT_LTR} or
135
	 *          {@link STextEnvironment#ORIENT_RTL}.
106
	 */
136
	 */
107
	public byte getBidiTypeAt(int index) {
137
	public int resolveOrientation(STextEnvironment envir) {
108
		if (hasCachedDirectionAt(index))
138
		int orient = envir.getOrientation();
109
			return getCachedDirectionAt(index);
139
		if ((orient & STextEnvironment.ORIENT_CONTEXTUAL_LTR) == 0) { // absolute orientation
110
		byte dirProp = Character.getDirectionality(text.charAt(index));
140
			return orient;
111
		if (dirProp == B) {
141
		}
112
			dirProp = (orientation == STextEnvironment.ORIENT_RTL) ? R : L;
142
		// contextual orientation:
143
		orient &= 1; // initiate to the default orientation minus contextual bit
144
		int len = text.length();
145
		byte charType;
146
		for (int i = 0; i < len; i++) {
147
			if (!hasCachedTypeAt(i)) {
148
				charType = Character.getDirectionality(text.charAt(i));
149
				if (charType == B) // B char resolves to L or R depending on orientation
150
					continue;
151
				setBidiTypeAt(i, charType);
152
			} else
153
				charType = getCachedTypeAt(i);
154
			if (charType == L)
155
				return STextEnvironment.ORIENT_LTR;
156
			if (charType == R || charType == AL)
157
				return STextEnvironment.ORIENT_RTL;
113
		}
158
		}
114
		setBidiTypeAt(index, dirProp);
159
		return orient;
115
		return dirProp;
116
	}
160
	}
117
118
}
161
}
(-)src/org/eclipse/equinox/bidi/custom/STextOffsets.java (+126 lines)
Added Link Here
1
package org.eclipse.equinox.bidi.custom;
2
3
public class STextOffsets {
4
	static final byte L = Character.DIRECTIONALITY_LEFT_TO_RIGHT;
5
	static final byte R = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
6
	static final byte AL = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
7
	static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER;
8
	static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
9
	static final byte[] STRONGS = {L, R};
10
	static final int OFFSET_SIZE = 20;
11
	int[] offsets = new int[OFFSET_SIZE];
12
	int count; // number of used entries
13
	int direction = -1; // STT direction
14
	int prefixLength;
15
16
	/**
17
	 *  @return the stored prefix length
18
	 */
19
	public int getPrefixLength() {
20
		return prefixLength;
21
	}
22
23
	/**
24
	 *  Store the prefix length
25
	 */
26
	public void setPrefixLength(int prefLen) {
27
		prefixLength = prefLen;
28
	}
29
30
	/**
31
	 *  @return the number of used entries in the offsets array.
32
	 */
33
	public int getCount() {
34
		return count;
35
	}
36
37
	/**
38
	 *  Mark that all entries in the offsets array are unused.
39
	 */
40
	public void resetCount() {
41
		count = 0;
42
	}
43
44
	/**
45
	 *  Get the value of a specified entry in the offsets array.
46
	 *  
47
	 *  @param  index is the index of the entry of interest.
48
	 *  
49
	 *  @return the value of the specified entry.
50
	 */
51
	public int getOffset(int index) {
52
		return offsets[index];
53
	}
54
55
	/**
56
	 *  Insert an offset value in the offset array so that the array 
57
	 *  stays in ascending order.
58
	 *  
59
	 *  @param  procData is a group of data accessible to processors.
60
	 *  
61
	 *  @param  offset is the value to insert.
62
	 */
63
	public void insertOffset(STextCharTypes charTypes, int offset) {
64
		int index = count - 1; // index of greatest member <= offset
65
		// look up after which member the new offset should be inserted
66
		while (index >= 0) {
67
			int wrkOffset = offsets[index];
68
			if (offset > wrkOffset)
69
				break;
70
			if (offset == wrkOffset)
71
				return; // avoid duplicates
72
			index--;
73
		}
74
		index++; // index now points at where to insert
75
		int length = count - index; // number of members to move up
76
		if (length > 0) // shift right all members greater than offset
77
			System.arraycopy(offsets, index, offsets, index + 1, length);
78
		offsets[index] = offset;
79
		count++; // number of used entries
80
		// if the offset is 0, adding a mark does not change anything
81
		if (offset < 1)
82
			return;
83
		if (charTypes == null)
84
			return;
85
86
		byte charType = charTypes.getBidiTypeAt(offset);
87
		// if the current char is a strong one or a digit, we change the
88
		//   charType of the previous char to account for the inserted mark.
89
		if (charType == L || charType == R || charType == AL || charType == EN || charType == AN)
90
			index = offset - 1;
91
		else
92
			// if the current char is a neutral, we change its own charType
93
			index = offset;
94
95
		if (direction < 0)
96
			direction = charTypes.getDirection();
97
		charTypes.setBidiTypeAt(index, STRONGS[direction]);
98
		return;
99
100
	}
101
102
	/**
103
	 *  Make sure that there is at least 3 free entries in the offsets array.
104
	 */
105
	public void ensureRoom() {
106
		// make sure there are at least 3 empty slots in offsets
107
		if ((offsets.length - count) < 3) {
108
			int[] newOffsets = new int[offsets.length * 2];
109
			System.arraycopy(offsets, 0, newOffsets, 0, count);
110
			offsets = newOffsets;
111
		}
112
	}
113
114
	/**
115
	 *  Get all and only the used offset entries.
116
	 *  
117
	 *  @return the current used entries of the offsets array.
118
	 */
119
	public int[] getArray() {
120
		if (count == offsets.length)
121
			return offsets;
122
		int[] array = new int[count];
123
		System.arraycopy(offsets, 0, array, 0, count);
124
		return array;
125
	}
126
}
(-)src/org/eclipse/equinox/bidi/custom/STextProcessor.java (-16 / +16 lines)
Lines 98-104 Link Here
98
	 * @param  text is the structured text string before
98
	 * @param  text is the structured text string before
99
	 *         addition of any directional formatting characters.
99
	 *         addition of any directional formatting characters.
100
	 *
100
	 *
101
	 * @param  dirProps is a parameter received by <code>indexOfSpecial</code>
101
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
102
	 *         uniquely to be used as argument for calls to methods which
102
	 *         uniquely to be used as argument for calls to methods which
103
	 *         need it.
103
	 *         need it.
104
	 *
104
	 *
Lines 132-138 Link Here
132
	 * number of special cases is zero, which means that
132
	 * number of special cases is zero, which means that
133
	 * <code>indexOfSpecial</code> should never be called for them.
133
	 * <code>indexOfSpecial</code> should never be called for them.
134
	 */
134
	 */
135
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int caseNumber, int fromIndex) {
135
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int caseNumber, int fromIndex) {
136
		// This method must be overridden by all subclasses with special cases.
136
		// This method must be overridden by all subclasses with special cases.
137
		throw new IllegalStateException("A processor with specialsCount > 0 must have an indexOfSpecial() method."); //$NON-NLS-1$
137
		throw new IllegalStateException("A processor with specialsCount > 0 must have an indexOfSpecial() method."); //$NON-NLS-1$
138
	}
138
	}
Lines 167-173 Link Here
167
	 * @param  text is the structured text string before
167
	 * @param  text is the structured text string before
168
	 *         addition of any directional formatting characters.
168
	 *         addition of any directional formatting characters.
169
	 *
169
	 *
170
	 * @param  dirProps is a parameter received by <code>processSpecial</code>
170
	 * @param  charTypes is a parameter received by <code>processSpecial</code>
171
	 *         uniquely to be used as argument for calls to methods which
171
	 *         uniquely to be used as argument for calls to methods which
172
	 *         need it.
172
	 *         need it.
173
	 *
173
	 *
Lines 216-222 Link Here
216
	 * number of special cases is zero, which means that
216
	 * number of special cases is zero, which means that
217
	 * <code>processSpecial</code> should never be called for them.
217
	 * <code>processSpecial</code> should never be called for them.
218
	 */
218
	 */
219
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
219
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
220
		// This method must be overridden by all subclasses with any special case.
220
		// This method must be overridden by all subclasses with any special case.
221
		throw new IllegalStateException("A processor with specialsCount > 0 must have a processSpecial() method."); //$NON-NLS-1$
221
		throw new IllegalStateException("A processor with specialsCount > 0 must have a processSpecial() method."); //$NON-NLS-1$
222
	}
222
	}
Lines 236-242 Link Here
236
	 *         parameter to <code>indexOfSpecial</code> or
236
	 *         parameter to <code>indexOfSpecial</code> or
237
	 *         <code>processSpecial</code>.
237
	 *         <code>processSpecial</code>.
238
	 *
238
	 *
239
	 * @param  dirProps is a parameter received by <code>indexOfSpecial</code>
239
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
240
	 *         or <code>processSpecial</code>, uniquely to be used as argument
240
	 *         or <code>processSpecial</code>, uniquely to be used as argument
241
	 *         for calls to <code>insertMark</code> and other methods used
241
	 *         for calls to <code>insertMark</code> and other methods used
242
	 *         by processors.
242
	 *         by processors.
Lines 252-259 Link Here
252
	 *         For the benefit of efficiency, it is better to insert
252
	 *         For the benefit of efficiency, it is better to insert
253
	 *         multiple marks in ascending order of the offsets.
253
	 *         multiple marks in ascending order of the offsets.
254
	 */
254
	 */
255
	public static final void insertMark(String text, STextCharTypes dirProps, int[] offsets, int offset) {
255
	public static final void insertMark(String text, STextCharTypes charTypes, STextOffsets offsets, int offset) {
256
		STextImpl.insertMark(text, dirProps, offsets, offset);
256
		offsets.insertOffset(charTypes, offset);
257
	}
257
	}
258
258
259
	/**
259
	/**
Lines 273-279 Link Here
273
	 *         parameter to <code>indexOfSpecial</code> or
273
	 *         parameter to <code>indexOfSpecial</code> or
274
	 *         <code>processSpecial</code>.
274
	 *         <code>processSpecial</code>.
275
	 *
275
	 *
276
	 * @param  dirProps is a parameter received by <code>indexOfSpecial</code>
276
	 * @param  charTypes is a parameter received by <code>indexOfSpecial</code>
277
	 *         or <code>processSpecial</code>, uniquely to be used as argument
277
	 *         or <code>processSpecial</code>, uniquely to be used as argument
278
	 *         for calls to <code>processSeparator</code> and other methods used
278
	 *         for calls to <code>processSeparator</code> and other methods used
279
	 *         by processors.
279
	 *         by processors.
Lines 287-294 Link Here
287
	 *         It must be a non-negative number smaller than the length
287
	 *         It must be a non-negative number smaller than the length
288
	 *         of the <i>lean</i> text.
288
	 *         of the <i>lean</i> text.
289
	 */
289
	 */
290
	public static final void processSeparator(String text, STextCharTypes dirProps, int[] offsets, int separLocation) {
290
	public static final void processSeparator(String text, STextCharTypes charTypes, STextOffsets offsets, int separLocation) {
291
		STextImpl.processSeparator(text, dirProps, offsets, separLocation);
291
		STextImpl.processSeparator(text, charTypes, offsets, separLocation);
292
	}
292
	}
293
293
294
	/**
294
	/**
Lines 349-356 Link Here
349
	 *
349
	 *
350
	 * @param  text is the structured text string to process.
350
	 * @param  text is the structured text string to process.
351
	 *
351
	 *
352
	 * @param  dirProps is a parameter received uniquely to be used as argument
352
	 * @param  charTypes is a parameter received uniquely to be used as argument
353
	 *         for calls to <code>getDirProp</code> and other methods used
353
	 *         for calls to <code>getCharType</code> and other methods used
354
	 *         by processors.
354
	 *         by processors.
355
	 *
355
	 *
356
	 * @return the base direction of the structured text. This direction
356
	 * @return the base direction of the structured text. This direction
Lines 360-366 Link Here
360
	 *         The value returned is either
360
	 *         The value returned is either
361
	 *         {@link STextEngine#DIR_LTR DIR_LTR} or {@link STextEngine#DIR_RTL DIR_RTL}.
361
	 *         {@link STextEngine#DIR_LTR DIR_LTR} or {@link STextEngine#DIR_RTL DIR_RTL}.
362
	 */
362
	 */
363
	public int getDirection(STextEnvironment environment, String text, STextCharTypes dirProps) {
363
	public int getDirection(STextEnvironment environment, String text, STextCharTypes charTypes) {
364
		return STextEngine.DIR_LTR;
364
		return STextEngine.DIR_LTR;
365
	}
365
	}
366
366
Lines 407-421 Link Here
407
	 *
407
	 *
408
	 * @param  text is the structured text string to process.
408
	 * @param  text is the structured text string to process.
409
	 *
409
	 *
410
	 * @param  dirProps is a parameter received uniquely to be used as argument
410
	 * @param  charTypes is a parameter received uniquely to be used as argument
411
	 *         for calls to <code>getDirProp</code> and other methods used
411
	 *         for calls to <code>getCharType</code> and other methods used
412
	 *         by processors.
412
	 *         by processors.
413
	 *
413
	 *
414
	 * @return a flag indicating if there is no need to process the structured
414
	 * @return a flag indicating if there is no need to process the structured
415
	 *         text to add directional formatting characters.
415
	 *         text to add directional formatting characters.
416
	 *
416
	 *
417
	 */
417
	 */
418
	public boolean skipProcessing(STextEnvironment environment, String text, STextCharTypes dirProps) {
418
	public boolean skipProcessing(STextEnvironment environment, String text, STextCharTypes charTypes) {
419
		return false;
419
		return false;
420
	}
420
	}
421
421
(-)src/org/eclipse/equinox/bidi/internal/STextDelims.java (-5 / +4 lines)
Lines 11-18 Link Here
11
package org.eclipse.equinox.bidi.internal;
11
package org.eclipse.equinox.bidi.internal;
12
12
13
import org.eclipse.equinox.bidi.STextEnvironment;
13
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.custom.STextCharTypes;
14
import org.eclipse.equinox.bidi.custom.*;
15
import org.eclipse.equinox.bidi.custom.STextProcessor;
16
15
17
/**
16
/**
18
 *  A base processor for structured text composed of text segments separated 
17
 *  A base processor for structured text composed of text segments separated 
Lines 44-50 Link Here
44
	 *
43
	 *
45
	 *  @see #getDelimiters
44
	 *  @see #getDelimiters
46
	 */
45
	 */
47
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int caseNumber, int fromIndex) {
46
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int caseNumber, int fromIndex) {
48
		char delim = getDelimiters().charAt((caseNumber - 1) * 2);
47
		char delim = getDelimiters().charAt((caseNumber - 1) * 2);
49
		return text.indexOf(delim, fromIndex);
48
		return text.indexOf(delim, fromIndex);
50
	}
49
	}
Lines 59-66 Link Here
59
	 *  @return the position after the matching end delimiter, or the length
58
	 *  @return the position after the matching end delimiter, or the length
60
	 *          of <code>text</code> if no end delimiter is found.
59
	 *          of <code>text</code> if no end delimiter is found.
61
	 */
60
	 */
62
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
61
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
63
		STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
62
		STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
64
		int loc = separLocation + 1;
63
		int loc = separLocation + 1;
65
		char delim = getDelimiters().charAt((caseNumber * 2) - 1);
64
		char delim = getDelimiters().charAt((caseNumber * 2) - 1);
66
		loc = text.indexOf(delim, loc);
65
		loc = text.indexOf(delim, loc);
(-)src/org/eclipse/equinox/bidi/internal/STextDelimsEsc.java (-4 / +3 lines)
Lines 11-18 Link Here
11
package org.eclipse.equinox.bidi.internal;
11
package org.eclipse.equinox.bidi.internal;
12
12
13
import org.eclipse.equinox.bidi.STextEnvironment;
13
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.custom.STextCharTypes;
14
import org.eclipse.equinox.bidi.custom.*;
15
import org.eclipse.equinox.bidi.custom.STextProcessor;
16
15
17
/**
16
/**
18
 *  A base processor for structured text composed of text segments separated 
17
 *  A base processor for structured text composed of text segments separated 
Lines 50-57 Link Here
50
	 *  and skips until after the matching end delimiter,
49
	 *  and skips until after the matching end delimiter,
51
	 *  ignoring possibly escaped end delimiters.
50
	 *  ignoring possibly escaped end delimiters.
52
	 */
51
	 */
53
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
52
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
54
		STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
53
		STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
55
		int location = separLocation + 1;
54
		int location = separLocation + 1;
56
		char delim = getDelimiters().charAt((caseNumber * 2) - 1);
55
		char delim = getDelimiters().charAt((caseNumber * 2) - 1);
57
		while (true) {
56
		while (true) {
(-)src/org/eclipse/equinox/bidi/internal/STextImpl.java (-136 / +70 lines)
Lines 12-19 Link Here
12
12
13
import org.eclipse.equinox.bidi.STextEngine;
13
import org.eclipse.equinox.bidi.STextEngine;
14
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.STextEnvironment;
15
import org.eclipse.equinox.bidi.custom.STextCharTypes;
15
import org.eclipse.equinox.bidi.custom.*;
16
import org.eclipse.equinox.bidi.custom.STextProcessor;
17
16
18
/**
17
/**
19
 *  <code>STextImpl</code> provides the code which implements the API in
18
 *  <code>STextImpl</code> provides the code which implements the API in
Lines 50-71 Link Here
50
	static final char PDF = 0x202C;
49
	static final char PDF = 0x202C;
51
	static final char[] MARKS = {LRM, RLM};
50
	static final char[] MARKS = {LRM, RLM};
52
	static final char[] EMBEDS = {LRE, RLE};
51
	static final char[] EMBEDS = {LRE, RLE};
53
	static final byte[] STRONGS = {L, R};
54
	static final int PREFIX_LENGTH = 2;
52
	static final int PREFIX_LENGTH = 2;
55
	static final int SUFFIX_LENGTH = 2;
53
	static final int SUFFIX_LENGTH = 2;
56
	static final int FIXES_LENGTH = PREFIX_LENGTH + SUFFIX_LENGTH;
54
	static final int FIXES_LENGTH = PREFIX_LENGTH + SUFFIX_LENGTH;
57
	static final int OFFSETS_SHIFT = 3;
58
	static final int[] EMPTY_INT_ARRAY = new int[0];
55
	static final int[] EMPTY_INT_ARRAY = new int[0];
59
	static final STextEnvironment IGNORE_ENVIRONMENT = new STextEnvironment(null, false, STextEnvironment.ORIENT_IGNORE);
56
	static final STextEnvironment IGNORE_ENVIRONMENT = new STextEnvironment(null, false, STextEnvironment.ORIENT_IGNORE);
60
57
61
	/**
58
	/**
62
	 *  Prevent creation of a STextEngine instance
59
	 *  Prevent creation of a STextImpl instance
63
	 */
60
	 */
64
	private STextImpl() {
61
	private STextImpl() {
65
		// nothing to do
62
		// nothing to do
66
	}
63
	}
67
64
68
	static long computeNextLocation(STextProcessor processor, STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] locations, int[] state, int curPos) {
65
	static long computeNextLocation(STextProcessor processor, STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] locations, int curPos) {
69
		String separators = processor.getSeparators(environment);
66
		String separators = processor.getSeparators(environment);
70
		int separCount = separators.length();
67
		int separCount = separators.length();
71
		int specialsCount = processor.getSpecialsCount(environment);
68
		int specialsCount = processor.getSpecialsCount(environment);
Lines 77-84 Link Here
77
		for (int i = 0; i < specialsCount; i++) {
74
		for (int i = 0; i < specialsCount; i++) {
78
			int location = locations[separCount + i];
75
			int location = locations[separCount + i];
79
			if (location < curPos) {
76
			if (location < curPos) {
80
				offsets = ensureRoomInOffsets(offsets);
77
				offsets.ensureRoom();
81
				location = processor.indexOfSpecial(environment, text, dirProps, offsets, i + 1, curPos);
78
				location = processor.indexOfSpecial(environment, text, charTypes, offsets, i + 1, curPos);
82
				if (location < 0)
79
				if (location < 0)
83
					location = len;
80
					location = len;
84
				locations[separCount + i] = location;
81
				locations[separCount + i] = location;
Lines 107-128 Link Here
107
	/**
104
	/**
108
	 *  @see STextProcessor#processSeparator STextProcessor.processSeparator
105
	 *  @see STextProcessor#processSeparator STextProcessor.processSeparator
109
	 */
106
	 */
110
	public static void processSeparator(String text, STextCharTypes dirProps, int[] offsets, int separLocation) {
107
	public static void processSeparator(String text, STextCharTypes charTypes, STextOffsets offsets, int separLocation) {
111
		int len = text.length();
108
		int len = text.length();
112
		// offsets[2] contains the structured text direction
109
		int direction = charTypes.getDirection();
113
		if (offsets[2] == STextEngine.DIR_RTL) {
110
		if (direction == STextEngine.DIR_RTL) {
114
			// the structured text base direction is RTL
111
			// the structured text base direction is RTL
115
			for (int i = separLocation - 1; i >= 0; i--) {
112
			for (int i = separLocation - 1; i >= 0; i--) {
116
				byte dirProp = dirProps.getBidiTypeAt(i);
113
				byte charType = charTypes.getBidiTypeAt(i);
117
				if (dirProp == R || dirProp == AL)
114
				if (charType == R || charType == AL)
118
					return;
115
					return;
119
				if (dirProp == L) {
116
				if (charType == L) {
120
					for (int j = separLocation; j < len; j++) {
117
					for (int j = separLocation; j < len; j++) {
121
						dirProp = dirProps.getBidiTypeAt(j);
118
						charType = charTypes.getBidiTypeAt(j);
122
						if (dirProp == R || dirProp == AL)
119
						if (charType == R || charType == AL)
123
							return;
120
							return;
124
						if (dirProp == L || dirProp == EN) {
121
						if (charType == L || charType == EN) {
125
							insertMark(text, dirProps, offsets, separLocation);
122
							offsets.insertOffset(charTypes, separLocation);
126
							return;
123
							return;
127
						}
124
						}
128
					}
125
					}
Lines 135-162 Link Here
135
		// the structured text base direction is LTR
132
		// the structured text base direction is LTR
136
		boolean doneAN = false;
133
		boolean doneAN = false;
137
		for (int i = separLocation - 1; i >= 0; i--) {
134
		for (int i = separLocation - 1; i >= 0; i--) {
138
			byte dirProp = dirProps.getBidiTypeAt(i);
135
			byte charType = charTypes.getBidiTypeAt(i);
139
			if (dirProp == L)
136
			if (charType == L)
140
				return;
137
				return;
141
			if (dirProp == R || dirProp == AL) {
138
			if (charType == R || charType == AL) {
142
				for (int j = separLocation; j < len; j++) {
139
				for (int j = separLocation; j < len; j++) {
143
					dirProp = dirProps.getBidiTypeAt(j);
140
					charType = charTypes.getBidiTypeAt(j);
144
					if (dirProp == L)
141
					if (charType == L)
145
						return;
142
						return;
146
					if (dirProp == R || dirProp == EN || dirProp == AL || dirProp == AN) {
143
					if (charType == R || charType == EN || charType == AL || charType == AN) {
147
						insertMark(text, dirProps, offsets, separLocation);
144
						offsets.insertOffset(charTypes, separLocation);
148
						return;
145
						return;
149
					}
146
					}
150
				}
147
				}
151
				return;
148
				return;
152
			}
149
			}
153
			if (dirProp == AN && !doneAN) {
150
			if (charType == AN && !doneAN) {
154
				for (int j = separLocation; j < len; j++) {
151
				for (int j = separLocation; j < len; j++) {
155
					dirProp = dirProps.getBidiTypeAt(j);
152
					charType = charTypes.getBidiTypeAt(j);
156
					if (dirProp == L)
153
					if (charType == L)
157
						return;
154
						return;
158
					if (dirProp == AL || dirProp == AN || dirProp == R) {
155
					if (charType == AL || charType == AN || charType == R) {
159
						insertMark(text, dirProps, offsets, separLocation);
156
						offsets.insertOffset(charTypes, separLocation);
160
						return;
157
						return;
161
					}
158
					}
162
				}
159
				}
Lines 212-221 Link Here
212
		int len = text.length();
209
		int len = text.length();
213
		if (len == 0)
210
		if (len == 0)
214
			return text;
211
			return text;
215
		STextCharTypes dirProps = new STextCharTypes(text);
212
		STextCharTypes charTypes = new STextCharTypes(processor, environment, text);
216
		int[] offsets = leanToFullCommon(processor, environment, text, state, dirProps);
213
		STextOffsets offsets = leanToFullCommon(processor, environment, text, state, charTypes);
217
		int prefixLength = offsets[1];
214
		int prefixLength = offsets.getPrefixLength();
218
		int count = offsets[0] - OFFSETS_SHIFT;
215
		int count = offsets.getCount();
219
		if (count == 0 && prefixLength == 0)
216
		if (count == 0 && prefixLength == 0)
220
			return text;
217
			return text;
221
		int newLen = len + count;
218
		int newLen = len + count;
Lines 226-237 Link Here
226
		char[] fullChars = new char[newLen];
223
		char[] fullChars = new char[newLen];
227
		int added = prefixLength;
224
		int added = prefixLength;
228
		// add marks at offsets
225
		// add marks at offsets
229
		int direction = offsets[2];
226
		int direction = charTypes.getDirection();
230
		char curMark = MARKS[direction];
227
		char curMark = MARKS[direction];
231
		for (int i = 0, j = OFFSETS_SHIFT; i < len; i++) {
228
		for (int i = 0, j = 0; i < len; i++) {
232
			char c = text.charAt(i);
229
			char c = text.charAt(i);
233
			// offsets[0] contains the number of used entries
230
			if (j < count && i == offsets.getOffset(j)) {
234
			if (j < offsets[0] && i == offsets[j]) {
235
				fullChars[i + added] = curMark;
231
				fullChars[i + added] = curMark;
236
				added++;
232
				added++;
237
				j++;
233
				j++;
Lines 263-276 Link Here
263
		int len = text.length();
259
		int len = text.length();
264
		if (len == 0)
260
		if (len == 0)
265
			return EMPTY_INT_ARRAY;
261
			return EMPTY_INT_ARRAY;
266
		STextCharTypes dirProps = new STextCharTypes(text);
262
		STextCharTypes charTypes = new STextCharTypes(processor, environment, text);
267
		int[] offsets = leanToFullCommon(processor, environment, text, state, dirProps);
263
		STextOffsets offsets = leanToFullCommon(processor, environment, text, state, charTypes);
268
		int prefixLength = offsets[1];
264
		int prefixLength = offsets.getPrefixLength();
269
		int[] map = new int[len];
265
		int[] map = new int[len];
270
		int count = offsets[0]; // number of used entries
266
		int count = offsets.getCount(); // number of used entries
271
		int added = prefixLength;
267
		int added = prefixLength;
272
		for (int pos = 0, i = OFFSETS_SHIFT; pos < len; pos++) {
268
		for (int pos = 0, i = 0; pos < len; pos++) {
273
			if (i < count && pos == offsets[i]) {
269
			if (i < count && pos == offsets.getOffset(i)) {
274
				added++;
270
				added++;
275
				i++;
271
				i++;
276
			}
272
			}
Lines 286-301 Link Here
286
		int len = text.length();
282
		int len = text.length();
287
		if (len == 0)
283
		if (len == 0)
288
			return EMPTY_INT_ARRAY;
284
			return EMPTY_INT_ARRAY;
289
		STextCharTypes dirProps = new STextCharTypes(text);
285
		STextCharTypes charTypes = new STextCharTypes(processor, environment, text);
290
		int[] offsets = leanToFullCommon(processor, environment, text, state, dirProps);
286
		STextOffsets offsets = leanToFullCommon(processor, environment, text, state, charTypes);
291
		// offsets[0] contains the number of used entries
287
		return offsets.getArray();
292
		int count = offsets[0] - OFFSETS_SHIFT;
293
		int[] result = new int[count];
294
		System.arraycopy(offsets, OFFSETS_SHIFT, result, 0, count);
295
		return result;
296
	}
288
	}
297
289
298
	static int[] leanToFullCommon(STextProcessor processor, STextEnvironment environment, String text, int[] state, STextCharTypes dirProps) {
290
	static STextOffsets leanToFullCommon(STextProcessor processor, STextEnvironment environment, String text, int[] state, STextCharTypes charTypes) {
299
		if (environment == null)
291
		if (environment == null)
300
			environment = STextEnvironment.DEFAULT;
292
			environment = STextEnvironment.DEFAULT;
301
		if (state == null) {
293
		if (state == null) {
Lines 303-317 Link Here
303
			state[0] = STextEngine.STATE_INITIAL;
295
			state[0] = STextEngine.STATE_INITIAL;
304
		}
296
		}
305
		int len = text.length();
297
		int len = text.length();
306
		int orient = dirProps.getOrientation(environment);
298
		int direction = processor.getDirection(environment, text, charTypes);
307
		int direction = processor.getDirection(environment, text, dirProps);
299
		STextOffsets offsets = new STextOffsets();
308
		// offsets of marks to add. Entry 0 is the number of used slots;
300
		if (!processor.skipProcessing(environment, text, charTypes)) {
309
		//  entry 1 is reserved to pass prefixLength.
310
		//  entry 2 is reserved to pass direction..
311
		int[] offsets = new int[20];
312
		offsets[0] = OFFSETS_SHIFT;
313
		offsets[2] = direction;
314
		if (!processor.skipProcessing(environment, text, dirProps)) {
315
			// initialize locations
301
			// initialize locations
316
			int separCount = processor.getSeparators(environment).length();
302
			int separCount = processor.getSeparators(environment).length();
317
			int[] locations = new int[separCount + processor.getSpecialsCount(environment)];
303
			int[] locations = new int[separCount + processor.getSpecialsCount(environment)];
Lines 321-366 Link Here
321
			// current position
307
			// current position
322
			int curPos = 0;
308
			int curPos = 0;
323
			if (state[0] > STextEngine.STATE_INITIAL) {
309
			if (state[0] > STextEngine.STATE_INITIAL) {
324
				offsets = ensureRoomInOffsets(offsets);
310
				offsets.ensureRoom();
325
				int initState = state[0];
311
				int initState = state[0];
326
				state[0] = STextEngine.STATE_INITIAL;
312
				state[0] = STextEngine.STATE_INITIAL;
327
				curPos = processor.processSpecial(environment, text, dirProps, offsets, state, initState, -1);
313
				curPos = processor.processSpecial(environment, text, charTypes, offsets, state, initState, -1);
328
			}
314
			}
329
			while (true) {
315
			while (true) {
330
				// location of next token to handle
316
				// location of next token to handle
331
				int nextLocation;
317
				int nextLocation;
332
				// index of next token to handle (if < separCount, this is a separator; otherwise a special case
318
				// index of next token to handle (if < separCount, this is a separator; otherwise a special case
333
				int idxLocation;
319
				int idxLocation;
334
				long res = computeNextLocation(processor, environment, text, dirProps, offsets, locations, state, curPos);
320
				long res = computeNextLocation(processor, environment, text, charTypes, offsets, locations, curPos);
335
				nextLocation = (int) (res & 0x00000000FFFFFFFF); /* low word */
321
				nextLocation = (int) (res & 0x00000000FFFFFFFF); /* low word */
336
				if (nextLocation >= len)
322
				if (nextLocation >= len)
337
					break;
323
					break;
324
				offsets.ensureRoom();
338
				idxLocation = (int) (res >> 32); /* high word */
325
				idxLocation = (int) (res >> 32); /* high word */
339
				if (idxLocation < separCount) {
326
				if (idxLocation < separCount) {
340
					offsets = ensureRoomInOffsets(offsets);
327
					processSeparator(text, charTypes, offsets, nextLocation);
341
					processSeparator(text, dirProps, offsets, nextLocation);
342
					curPos = nextLocation + 1;
328
					curPos = nextLocation + 1;
343
				} else {
329
				} else {
344
					offsets = ensureRoomInOffsets(offsets);
345
					idxLocation -= (separCount - 1); // because caseNumber starts from 1
330
					idxLocation -= (separCount - 1); // because caseNumber starts from 1
346
					curPos = processor.processSpecial(environment, text, dirProps, offsets, state, idxLocation, nextLocation);
331
					curPos = processor.processSpecial(environment, text, charTypes, offsets, state, idxLocation, nextLocation);
347
				}
332
				}
348
				if (curPos >= len)
333
				if (curPos >= len)
349
					break;
334
					break;
350
			} // end while
335
			} // end while
351
		} // end if (!processor.skipProcessing())
336
		} // end if (!processor.skipProcessing())
352
		if (orient == STextEnvironment.ORIENT_IGNORE)
337
		int prefixLength;
353
			offsets[1] = 0;
338
		int orientation = environment.getOrientation();
339
		if (orientation == STextEnvironment.ORIENT_IGNORE)
340
			prefixLength = 0;
354
		else {
341
		else {
355
			// recompute orient since it may have changed if contextual
342
			int resolvedOrientation = charTypes.resolveOrientation(environment);
356
			orient = dirProps.getOrientation(environment);
343
			if (orientation != STextEnvironment.ORIENT_UNKNOWN && resolvedOrientation == direction)
357
			if (orient == direction && orient != STextEnvironment.ORIENT_UNKNOWN)
344
				prefixLength = 0;
358
				offsets[1] = 0;
345
			else if ((orientation & STextEnvironment.ORIENT_CONTEXTUAL_LTR) != 0)
359
			else if ((environment.getOrientation() & STextEnvironment.ORIENT_CONTEXTUAL_LTR) != 0)
346
				prefixLength = 1;
360
				offsets[1] = 1;
361
			else
347
			else
362
				offsets[1] = 2;
348
				prefixLength = 2;
363
		}
349
		}
350
		offsets.setPrefixLength(prefixLength);
364
		return offsets;
351
		return offsets;
365
	}
352
	}
366
353
Lines 501-508 Link Here
501
		if (lenFull == 0)
488
		if (lenFull == 0)
502
			return EMPTY_INT_ARRAY;
489
			return EMPTY_INT_ARRAY;
503
		String lean = fullToLeanText(processor, environment, full, state);
490
		String lean = fullToLeanText(processor, environment, full, state);
504
		int[] offsets = new int[20];
491
		STextOffsets offsets = new STextOffsets();
505
		offsets[0] = OFFSETS_SHIFT;
506
		int lenLean = lean.length();
492
		int lenLean = lean.length();
507
		int idxLean, idxFull;
493
		int idxLean, idxFull;
508
		// lean must be a subset of Full, so we only check on iLean < leanLen
494
		// lean must be a subset of Full, so we only check on iLean < leanLen
Lines 510-575 Link Here
510
			if (full.charAt(idxFull) == lean.charAt(idxLean))
496
			if (full.charAt(idxFull) == lean.charAt(idxLean))
511
				idxLean++;
497
				idxLean++;
512
			else {
498
			else {
513
				offsets = ensureRoomInOffsets(offsets);
499
				offsets.ensureRoom();
514
				insertMark(lean, null, offsets, idxFull);
500
				offsets.insertOffset(null, idxFull);
515
			}
501
			}
516
		}
502
		}
517
		for (; idxFull < lenFull; idxFull++) {
503
		for (; idxFull < lenFull; idxFull++) {
518
			offsets = ensureRoomInOffsets(offsets);
504
			offsets.ensureRoom();
519
			insertMark(lean, null, offsets, idxFull);
505
			offsets.insertOffset(null, idxFull);
520
		}
506
		}
521
		int[] result = new int[offsets[0] - OFFSETS_SHIFT];
507
		return offsets.getArray();
522
		System.arraycopy(offsets, OFFSETS_SHIFT, result, 0, result.length);
523
		return result;
524
	}
525
526
	static int[] ensureRoomInOffsets(int[] offsets) {
527
		// make sure
528
		if ((offsets.length - offsets[0]) < 3) {
529
			int[] newOffsets = new int[offsets.length * 2];
530
			System.arraycopy(offsets, 0, newOffsets, 0, offsets[0]);
531
			return newOffsets;
532
		}
533
		return offsets;
534
	}
535
536
	/**
537
	 *  @see STextProcessor#insertMark STextProcessor.insertMark
538
	 */
539
	public static void insertMark(String text, STextCharTypes dirProps, int[] offsets, int offset) {
540
		int count = offsets[0];// number of used entries
541
		int index = count - 1; // index of greatest member <= offset
542
		// look up after which member the new offset should be inserted
543
		while (index >= OFFSETS_SHIFT) {
544
			int wrkOffset = offsets[index];
545
			if (offset > wrkOffset)
546
				break;
547
			if (offset == wrkOffset)
548
				return; // avoid duplicates
549
			index--;
550
		}
551
		index++; // index now points at where to insert
552
		int length = count - index; // number of members to move up
553
		if (length > 0) // shift right all members greater than offset
554
			System.arraycopy(offsets, index, offsets, index + 1, length);
555
		offsets[index] = offset;
556
		offsets[0]++; // number of used entries
557
		// if the offset is 0, adding a mark does not change anything
558
		if (dirProps == null || offset < 1)
559
			return;
560
561
		byte dirProp = dirProps.getBidiTypeAt(offset);
562
		// if the current char is a strong one or a digit, we change the
563
		//   dirProp of the previous char to account for the inserted mark.
564
		if (dirProp == L || dirProp == R || dirProp == AL || dirProp == EN || dirProp == AN)
565
			index = offset - 1;
566
		else
567
			// if the current char is a neutral, we change its own dirProp
568
			index = offset;
569
570
		int dir = offsets[2]; // current structured text direction
571
		dirProps.setBidiTypeAt(index, STRONGS[dir]);
572
		return;
573
	}
508
	}
574
575
}
509
}
(-)src/org/eclipse/equinox/bidi/internal/STextSingle.java (-5 / +4 lines)
Lines 11-18 Link Here
11
package org.eclipse.equinox.bidi.internal;
11
package org.eclipse.equinox.bidi.internal;
12
12
13
import org.eclipse.equinox.bidi.STextEnvironment;
13
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.custom.STextCharTypes;
14
import org.eclipse.equinox.bidi.custom.*;
15
import org.eclipse.equinox.bidi.custom.STextProcessor;
16
15
17
/**
16
/**
18
 *  A base processor for structured text composed of two parts separated by a separator.
17
 *  A base processor for structured text composed of two parts separated by a separator.
Lines 41-47 Link Here
41
	 *
40
	 *
42
	 *  @see #getSeparators getSeparators
41
	 *  @see #getSeparators getSeparators
43
	 */
42
	 */
44
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int caseNumber, int fromIndex) {
43
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int caseNumber, int fromIndex) {
45
		return text.indexOf(this.getSeparators(environment).charAt(0), fromIndex);
44
		return text.indexOf(this.getSeparators(environment).charAt(0), fromIndex);
46
	}
45
	}
47
46
Lines 51-58 Link Here
51
	 *
50
	 *
52
	 *  @return the length of <code>text</code>.
51
	 *  @return the length of <code>text</code>.
53
	 */
52
	 */
54
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
53
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
55
		STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
54
		STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
56
		return text.length();
55
		return text.length();
57
	}
56
	}
58
57
(-)src/org/eclipse/equinox/bidi/internal/consumable/STextEmail.java (-4 / +4 lines)
Lines 28-34 Link Here
28
	}
28
	}
29
29
30
	public int getDirection(STextEnvironment environment, String text) {
30
	public int getDirection(STextEnvironment environment, String text) {
31
		return getDirection(environment, text, new STextCharTypes(text));
31
		return getDirection(environment, text, new STextCharTypes(this, environment, text));
32
	}
32
	}
33
33
34
	/**
34
	/**
Lines 42-48 Link Here
42
	 *          </ul>
42
	 *          </ul>
43
	 *          Otherwise, returns {@link STextEngine#DIR_LTR DIR_LTR}.
43
	 *          Otherwise, returns {@link STextEngine#DIR_LTR DIR_LTR}.
44
	 */
44
	 */
45
	public int getDirection(STextEnvironment environment, String text, STextCharTypes dirProps) {
45
	public int getDirection(STextEnvironment environment, String text, STextCharTypes charTypes) {
46
		String language = environment.getLanguage();
46
		String language = environment.getLanguage();
47
		if (!language.equals("ar")) //$NON-NLS-1$
47
		if (!language.equals("ar")) //$NON-NLS-1$
48
			return STextEngine.DIR_LTR;
48
			return STextEngine.DIR_LTR;
Lines 51-58 Link Here
51
		if (domainStart < 0)
51
		if (domainStart < 0)
52
			domainStart = 0;
52
			domainStart = 0;
53
		for (int i = domainStart; i < text.length(); i++) {
53
		for (int i = domainStart; i < text.length(); i++) {
54
			byte dirProp = dirProps.getBidiTypeAt(i);
54
			byte charType = charTypes.getBidiTypeAt(i);
55
			if (dirProp == AL || dirProp == R)
55
			if (charType == AL || charType == R)
56
				return STextEngine.DIR_RTL;
56
				return STextEngine.DIR_RTL;
57
		}
57
		}
58
		return STextEngine.DIR_LTR;
58
		return STextEngine.DIR_LTR;
(-)src/org/eclipse/equinox/bidi/internal/consumable/STextJava.java (-7 / +6 lines)
Lines 12-19 Link Here
12
12
13
import org.eclipse.equinox.bidi.STextEngine;
13
import org.eclipse.equinox.bidi.STextEngine;
14
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.STextEnvironment;
15
import org.eclipse.equinox.bidi.custom.STextCharTypes;
15
import org.eclipse.equinox.bidi.custom.*;
16
import org.eclipse.equinox.bidi.custom.STextProcessor;
17
import org.eclipse.equinox.bidi.internal.STextActivator;
16
import org.eclipse.equinox.bidi.internal.STextActivator;
18
17
19
/**
18
/**
Lines 59-65 Link Here
59
	     *    <li>comments starting with slash-slash</li>
58
	     *    <li>comments starting with slash-slash</li>
60
	     *  </ol>
59
	     *  </ol>
61
	     */
60
	     */
62
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int caseNumber, int fromIndex) {
61
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int caseNumber, int fromIndex) {
63
		switch (caseNumber) {
62
		switch (caseNumber) {
64
			case 1 : /* space */
63
			case 1 : /* space */
65
				return text.indexOf(' ', fromIndex);
64
				return text.indexOf(' ', fromIndex);
Lines 83-97 Link Here
83
	     *    <li>skip until after a line separator</li>
82
	     *    <li>skip until after a line separator</li>
84
	     *  </ol>
83
	     *  </ol>
85
	 */
84
	 */
86
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
85
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
87
		int location, counter, i;
86
		int location, counter, i;
88
87
89
		STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
88
		STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
90
		switch (caseNumber) {
89
		switch (caseNumber) {
91
			case 1 : /* space */
90
			case 1 : /* space */
92
				separLocation++;
91
				separLocation++;
93
				while (separLocation < text.length() && text.charAt(separLocation) == ' ') {
92
				while (separLocation < text.length() && text.charAt(separLocation) == ' ') {
94
					dirProps.setBidiTypeAt(separLocation, WS);
93
					charTypes.setBidiTypeAt(separLocation, WS);
95
					separLocation++;
94
					separLocation++;
96
				}
95
				}
97
				return separLocation;
96
				return separLocation;
Lines 120-126 Link Here
120
				}
119
				}
121
				// we need to call processSeparator since text may follow the
120
				// we need to call processSeparator since text may follow the
122
				//  end of comment immediately without even a space
121
				//  end of comment immediately without even a space
123
				STextProcessor.processSeparator(text, dirProps, offsets, location);
122
				STextProcessor.processSeparator(text, charTypes, offsets, location);
124
				return location + 2;
123
				return location + 2;
125
			case 4 : /* slash-slash comment */
124
			case 4 : /* slash-slash comment */
126
				location = text.indexOf(lineSep, separLocation + 2);
125
				location = text.indexOf(lineSep, separLocation + 2);
(-)src/org/eclipse/equinox/bidi/internal/consumable/STextMath.java (-7 / +6 lines)
Lines 30-36 Link Here
30
	}
30
	}
31
31
32
	public int getDirection(STextEnvironment environment, String text) {
32
	public int getDirection(STextEnvironment environment, String text) {
33
		return getDirection(environment, text, new STextCharTypes(text));
33
		return getDirection(environment, text, new STextCharTypes(this, environment, text));
34
	}
34
	}
35
35
36
	/**
36
	/**
Lines 45-67 Link Here
45
	 *          </ul>
45
	 *          </ul>
46
	 *          Otherwise, returns {@link STextEngine#DIR_LTR DIR_LTR}.
46
	 *          Otherwise, returns {@link STextEngine#DIR_LTR DIR_LTR}.
47
	 */
47
	 */
48
	public int getDirection(STextEnvironment environment, String text, STextCharTypes dirProps) {
48
	public int getDirection(STextEnvironment environment, String text, STextCharTypes charTypes) {
49
		String language = environment.getLanguage();
49
		String language = environment.getLanguage();
50
		if (!language.equals("ar")) //$NON-NLS-1$
50
		if (!language.equals("ar")) //$NON-NLS-1$
51
			return STextEngine.DIR_LTR;
51
			return STextEngine.DIR_LTR;
52
		boolean flagAN = false;
52
		boolean flagAN = false;
53
		for (int i = 0; i < text.length(); i++) {
53
		for (int i = 0; i < text.length(); i++) {
54
			byte dirProp = dirProps.getBidiTypeAt(i);
54
			byte charType = charTypes.getBidiTypeAt(i);
55
			if (dirProp == AL)
55
			if (charType == AL)
56
				return STextEngine.DIR_RTL;
56
				return STextEngine.DIR_RTL;
57
			if (dirProp == L || dirProp == R)
57
			if (charType == L || charType == R)
58
				return STextEngine.DIR_LTR;
58
				return STextEngine.DIR_LTR;
59
			if (dirProp == AN)
59
			if (charType == AN)
60
				flagAN = true;
60
				flagAN = true;
61
		}
61
		}
62
		if (flagAN)
62
		if (flagAN)
63
			return STextEngine.DIR_RTL;
63
			return STextEngine.DIR_RTL;
64
		return STextEngine.DIR_LTR;
64
		return STextEngine.DIR_LTR;
65
	}
65
	}
66
67
}
66
}
(-)src/org/eclipse/equinox/bidi/internal/consumable/STextRegex.java (-23 / +22 lines)
Lines 12-19 Link Here
12
12
13
import org.eclipse.equinox.bidi.STextEngine;
13
import org.eclipse.equinox.bidi.STextEngine;
14
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.STextEnvironment;
15
import org.eclipse.equinox.bidi.custom.STextCharTypes;
15
import org.eclipse.equinox.bidi.custom.*;
16
import org.eclipse.equinox.bidi.custom.STextProcessor;
17
16
18
/**
17
/**
19
 *  <code>STextRegex</code> is a processor for regular expressions.
18
 *  <code>STextRegex</code> is a processor for regular expressions.
Lines 77-83 Link Here
77
	 *  This method locates occurrences of the syntactic strings and of
76
	 *  This method locates occurrences of the syntactic strings and of
78
	 *  R, AL, EN, AN characters.
77
	 *  R, AL, EN, AN characters.
79
	 */
78
	 */
80
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int caseNumber, int fromIndex) {
79
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int caseNumber, int fromIndex) {
81
		// In this method, L, R, AL, AN and EN represent bidi categories
80
		// In this method, L, R, AL, AN and EN represent bidi categories
82
		// as defined in the Unicode Bidirectional Algorithm
81
		// as defined in the Unicode Bidirectional Algorithm
83
		// ( http://www.unicode.org/reports/tr9/ ).
82
		// ( http://www.unicode.org/reports/tr9/ ).
Lines 86-92 Link Here
86
		// AL represents the category Arabic Letter.
85
		// AL represents the category Arabic Letter.
87
		// AN represents the category Arabic Number.
86
		// AN represents the category Arabic Number.
88
		// EN  represents the category European Number.
87
		// EN  represents the category European Number.
89
		byte dirProp;
88
		byte charType;
90
89
91
		if (caseNumber < numberOfStrings) {
90
		if (caseNumber < numberOfStrings) {
92
			/*  1 *//* comment (?#...) */
91
			/*  1 *//* comment (?#...) */
Lines 113-139 Link Here
113
			fromIndex = 1;
112
			fromIndex = 1;
114
		// look for R, AL, AN, EN which are potentially needing a mark
113
		// look for R, AL, AN, EN which are potentially needing a mark
115
		for (; fromIndex < text.length(); fromIndex++) {
114
		for (; fromIndex < text.length(); fromIndex++) {
116
			dirProp = dirProps.getBidiTypeAt(fromIndex);
115
			charType = charTypes.getBidiTypeAt(fromIndex);
117
			// R and AL will always be examined using processSeparator()
116
			// R and AL will always be examined using processSeparator()
118
			if (dirProp == R || dirProp == AL)
117
			if (charType == R || charType == AL)
119
				return fromIndex;
118
				return fromIndex;
120
119
121
			if (dirProp == EN || dirProp == AN) {
120
			if (charType == EN || charType == AN) {
122
				// no need for a mark after the first digit in a number
121
				// no need for a mark after the first digit in a number
123
				if (dirProps.getBidiTypeAt(fromIndex - 1) == dirProp)
122
				if (charTypes.getBidiTypeAt(fromIndex - 1) == charType)
124
					continue;
123
					continue;
125
124
126
				for (int i = fromIndex - 1; i >= 0; i--) {
125
				for (int i = fromIndex - 1; i >= 0; i--) {
127
					dirProp = dirProps.getBidiTypeAt(i);
126
					charType = charTypes.getBidiTypeAt(i);
128
					// after a L char, no need for a mark
127
					// after a L char, no need for a mark
129
					if (dirProp == L)
128
					if (charType == L)
130
						continue;
129
						continue;
131
130
132
					// digit after R or AL or AN need a mark, except for EN
131
					// digit after R or AL or AN need a mark, except for EN
133
					//   following AN, but this is a contrived case, so we
132
					//   following AN, but this is a contrived case, so we
134
					//   don't check for it (and calling processSeparator()
133
					//   don't check for it (and calling processSeparator()
135
					//   for it will do no harm)
134
					//   for it will do no harm)
136
					if (dirProp == R || dirProp == AL || dirProp == AN)
135
					if (charType == R || charType == AL || charType == AN)
137
						return fromIndex;
136
						return fromIndex;
138
				}
137
				}
139
				continue;
138
				continue;
Lines 145-151 Link Here
145
	/**
144
	/**
146
	 *  This method process the special cases.
145
	 *  This method process the special cases.
147
	 */
146
	 */
148
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
147
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
149
		int location;
148
		int location;
150
149
151
		switch (caseNumber) {
150
		switch (caseNumber) {
Lines 154-160 Link Here
154
					// initial state from previous line
153
					// initial state from previous line
155
					location = 0;
154
					location = 0;
156
				} else {
155
				} else {
157
					STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
156
					STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
158
					// skip the opening "(?#"
157
					// skip the opening "(?#"
159
					location = separLocation + 3;
158
					location = separLocation + 3;
160
				}
159
				}
Lines 170-176 Link Here
170
			case 5 : /* conditional named back reference (?(<name>) */
169
			case 5 : /* conditional named back reference (?(<name>) */
171
			case 6 : /* conditional named back reference (?('name') */
170
			case 6 : /* conditional named back reference (?('name') */
172
			case 7 : /* named parentheses reference (?&name) */
171
			case 7 : /* named parentheses reference (?&name) */
173
				STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
172
				STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
174
				// no need for calling processSeparator() for the following cases
173
				// no need for calling processSeparator() for the following cases
175
				//   since the starting string contains a L char
174
				//   since the starting string contains a L char
176
			case 8 : /* named group (?P<name> */
175
			case 8 : /* named group (?P<name> */
Lines 194-200 Link Here
194
					// initial state from previous line
193
					// initial state from previous line
195
					location = 0;
194
					location = 0;
196
				} else {
195
				} else {
197
					STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
196
					STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
198
					// skip the opening "\Q"
197
					// skip the opening "\Q"
199
					location = separLocation + 2;
198
					location = separLocation + 2;
200
				}
199
				}
Lines 203-213 Link Here
203
					state[0] = caseNumber;
202
					state[0] = caseNumber;
204
					return text.length();
203
					return text.length();
205
				}
204
				}
206
				// set the dirProp for the "E" to L (Left to Right character)
205
				// set the charType for the "E" to L (Left to Right character)
207
				dirProps.setBidiTypeAt(location + 1, L);
206
				charTypes.setBidiTypeAt(location + 1, L);
208
				return location + 2;
207
				return location + 2;
209
			case 18 : /* R, AL, AN, EN */
208
			case 18 : /* R, AL, AN, EN */
210
				STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
209
				STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
211
				return separLocation + 1;
210
				return separLocation + 1;
212
211
213
		}
212
		}
Lines 216-222 Link Here
216
	}
215
	}
217
216
218
	public int getDirection(STextEnvironment environment, String text) {
217
	public int getDirection(STextEnvironment environment, String text) {
219
		return getDirection(environment, text, new STextCharTypes(text));
218
		return getDirection(environment, text, new STextCharTypes(this, environment, text));
220
	}
219
	}
221
220
222
	/**
221
	/**
Lines 231-245 Link Here
231
	 *          </ul>
230
	 *          </ul>
232
	 *          Otherwise, returns {@link STextEngine#DIR_LTR DIR_LTR}.
231
	 *          Otherwise, returns {@link STextEngine#DIR_LTR DIR_LTR}.
233
	 */
232
	 */
234
	public int getDirection(STextEnvironment environment, String text, STextCharTypes dirProps) {
233
	public int getDirection(STextEnvironment environment, String text, STextCharTypes charTypes) {
235
		String language = environment.getLanguage();
234
		String language = environment.getLanguage();
236
		if (!language.equals("ar")) //$NON-NLS-1$
235
		if (!language.equals("ar")) //$NON-NLS-1$
237
			return STextEngine.DIR_LTR;
236
			return STextEngine.DIR_LTR;
238
		for (int i = 0; i < text.length(); i++) {
237
		for (int i = 0; i < text.length(); i++) {
239
			byte dirProp = dirProps.getBidiTypeAt(i);
238
			byte charType = charTypes.getBidiTypeAt(i);
240
			if (dirProp == AL || dirProp == R)
239
			if (charType == AL || charType == R)
241
				return STextEngine.DIR_RTL;
240
				return STextEngine.DIR_RTL;
242
			if (dirProp == L)
241
			if (charType == L)
243
				return STextEngine.DIR_LTR;
242
				return STextEngine.DIR_LTR;
244
		}
243
		}
245
		if (environment.getMirrored())
244
		if (environment.getMirrored())
(-)src/org/eclipse/equinox/bidi/internal/consumable/STextSql.java (-7 / +6 lines)
Lines 12-19 Link Here
12
12
13
import org.eclipse.equinox.bidi.STextEngine;
13
import org.eclipse.equinox.bidi.STextEngine;
14
import org.eclipse.equinox.bidi.STextEnvironment;
14
import org.eclipse.equinox.bidi.STextEnvironment;
15
import org.eclipse.equinox.bidi.custom.STextCharTypes;
15
import org.eclipse.equinox.bidi.custom.*;
16
import org.eclipse.equinox.bidi.custom.STextProcessor;
17
import org.eclipse.equinox.bidi.internal.STextActivator;
16
import org.eclipse.equinox.bidi.internal.STextActivator;
18
17
19
/**
18
/**
Lines 60-66 Link Here
60
	  *    <li>comments starting with hyphen-hyphen</li>
59
	  *    <li>comments starting with hyphen-hyphen</li>
61
	  *  </ol>
60
	  *  </ol>
62
	  */
61
	  */
63
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int caseNumber, int fromIndex) {
62
	public int indexOfSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int caseNumber, int fromIndex) {
64
		switch (caseNumber) {
63
		switch (caseNumber) {
65
			case 1 : /* space */
64
			case 1 : /* space */
66
				return text.indexOf(" ", fromIndex); //$NON-NLS-1$
65
				return text.indexOf(" ", fromIndex); //$NON-NLS-1$
Lines 87-101 Link Here
87
	     *    <li>skip until after a line separator</li>
86
	     *    <li>skip until after a line separator</li>
88
	     *  </ol>
87
	     *  </ol>
89
	 */
88
	 */
90
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes dirProps, int[] offsets, int[] state, int caseNumber, int separLocation) {
89
	public int processSpecial(STextEnvironment environment, String text, STextCharTypes charTypes, STextOffsets offsets, int[] state, int caseNumber, int separLocation) {
91
		int location;
90
		int location;
92
91
93
		STextProcessor.processSeparator(text, dirProps, offsets, separLocation);
92
		STextProcessor.processSeparator(text, charTypes, offsets, separLocation);
94
		switch (caseNumber) {
93
		switch (caseNumber) {
95
			case 1 : /* space */
94
			case 1 : /* space */
96
				separLocation++;
95
				separLocation++;
97
				while (separLocation < text.length() && text.charAt(separLocation) == ' ') {
96
				while (separLocation < text.length() && text.charAt(separLocation) == ' ') {
98
					dirProps.setBidiTypeAt(separLocation, WS);
97
					charTypes.setBidiTypeAt(separLocation, WS);
99
					separLocation++;
98
					separLocation++;
100
				}
99
				}
101
				return separLocation;
100
				return separLocation;
Lines 138-144 Link Here
138
				}
137
				}
139
				// we need to call processSeparator since text may follow the
138
				// we need to call processSeparator since text may follow the
140
				//  end of comment immediately without even a space
139
				//  end of comment immediately without even a space
141
				STextProcessor.processSeparator(text, dirProps, offsets, location);
140
				STextProcessor.processSeparator(text, charTypes, offsets, location);
142
				return location + 2;
141
				return location + 2;
143
			case 5 : /* hyphen-hyphen comment */
142
			case 5 : /* hyphen-hyphen comment */
144
				location = text.indexOf(lineSep, separLocation + 2);
143
				location = text.indexOf(lineSep, separLocation + 2);

Return to bug 183164