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 |
} |