1 /*
2 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 /*
26 *******************************************************************************
27 * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved *
28 * *
29 * The original version of this source code and documentation is copyrighted *
30 * and owned by IBM, These materials are provided under terms of a License *
31 * Agreement between IBM and Sun. This technology is protected by multiple *
32 * US and International patents. This notice and attribution to IBM may not *
33 * to removed. *
34 *******************************************************************************
35 */
36 /* Written by Simon Montagu, Matitiahu Allouche
37 * (ported from C code written by Markus W. Scherer)
38 */
39
40 package sun.text.bidi;
41
42 import java.text.Bidi;
43 import java.util.Arrays;
44
45 public final class BidiLine {
46
47 /*
48 * General remarks about the functions in this file:
49 *
50 * These functions deal with the aspects of potentially mixed-directional
51 * text in a single paragraph or in a line of a single paragraph
52 * which has already been processed according to
53 * the Unicode 3.0 Bidi algorithm as defined in
54 * http://www.unicode.org/unicode/reports/tr9/ , version 13,
55 * also described in The Unicode Standard, Version 4.0.1 .
56 *
57 * This means that there is a Bidi object with a levels
58 * and a dirProps array.
59 * paraLevel and direction are also set.
60 * Only if the length of the text is zero, then levels==dirProps==NULL.
61 *
62 * The overall directionality of the paragraph
63 * or line is used to bypass the reordering steps if possible.
64 * Even purely RTL text does not need reordering there because
65 * the getLogical/VisualIndex() methods can compute the
105 * To make subsequent operations easier, we also include the run
106 * before the WS if it is at the paraLevel - we merge the two here.
107 *
108 * This method is called only from setLine(), so paraLevel is
109 * set correctly for the line even when contextual multiple paragraphs.
110 */
111
112 static void setTrailingWSStart(BidiBase bidiBase)
113 {
114 byte[] dirProps = bidiBase.dirProps;
115 byte[] levels = bidiBase.levels;
116 int start = bidiBase.length;
117 byte paraLevel = bidiBase.paraLevel;
118
119 /* If the line is terminated by a block separator, all preceding WS etc...
120 are already set to paragraph level.
121 Setting trailingWSStart to pBidi->length will avoid changing the
122 level of B chars from 0 to paraLevel in getLevels when
123 orderParagraphsLTR==TRUE
124 */
125 if (BidiBase.NoContextRTL(dirProps[start - 1]) == BidiBase.B) {
126 bidiBase.trailingWSStart = start; /* currently == bidiBase.length */
127 return;
128 }
129 /* go backwards across all WS, BN, explicit codes */
130 while (start > 0 &&
131 (BidiBase.DirPropFlagNC(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) {
132 --start;
133 }
134
135 /* if the WS run can be merged with the previous run then do so here */
136 while (start > 0 && levels[start - 1] == paraLevel) {
137 --start;
138 }
139
140 bidiBase.trailingWSStart=start;
141 }
142
143 public static Bidi setLine(Bidi bidi, BidiBase paraBidi,
144 Bidi newBidi, BidiBase newBidiBase,
145 int start, int limit) {
146 int length;
147
148 BidiBase lineBidi = newBidiBase;
149
150 /* set the values in lineBidi from its paraBidi parent */
151 /* class members are already initialized to 0 */
152 // lineBidi.paraBidi = null; /* mark unfinished setLine */
153 // lineBidi.flags = 0;
154 // lineBidi.controlCount = 0;
155
156 length = lineBidi.length = lineBidi.originalLength =
157 lineBidi.resultLength = limit - start;
158
159 lineBidi.text = new char[length];
160 System.arraycopy(paraBidi.text, start, lineBidi.text, 0, length);
161 lineBidi.paraLevel = paraBidi.GetParaLevelAt(start);
162 lineBidi.paraCount = paraBidi.paraCount;
163 lineBidi.runs = new BidiRun[0];
164 if (paraBidi.controlCount > 0) {
165 int j;
166 for (j = start; j < limit; j++) {
167 if (BidiBase.IsBidiControlChar(paraBidi.text[j])) {
168 lineBidi.controlCount++;
169 }
170 }
171 lineBidi.resultLength -= lineBidi.controlCount;
172 }
173 /* copy proper subset of DirProps */
174 lineBidi.getDirPropsMemory(length);
175 lineBidi.dirProps = lineBidi.dirPropsMemory;
176 System.arraycopy(paraBidi.dirProps, start, lineBidi.dirProps, 0,
177 length);
178 /* copy proper subset of Levels */
179 lineBidi.getLevelsMemory(length);
180 lineBidi.levels = lineBidi.levelsMemory;
181 System.arraycopy(paraBidi.levels, start, lineBidi.levels, 0,
182 length);
183 lineBidi.runCount = -1;
189 /*
190 * The parent's levels are all either
191 * implicitly or explicitly ==paraLevel;
192 * do the same here.
193 */
194 if (paraBidi.trailingWSStart <= start) {
195 lineBidi.trailingWSStart = 0;
196 } else if (paraBidi.trailingWSStart < limit) {
197 lineBidi.trailingWSStart = paraBidi.trailingWSStart - start;
198 } else {
199 lineBidi.trailingWSStart = length;
200 }
201 } else {
202 byte[] levels = lineBidi.levels;
203 int i, trailingWSStart;
204 byte level;
205
206 setTrailingWSStart(lineBidi);
207 trailingWSStart = lineBidi.trailingWSStart;
208
209 /* recalculate lineBidi.direction */
210 if (trailingWSStart == 0) {
211 /* all levels are at paraLevel */
212 lineBidi.direction = (byte)(lineBidi.paraLevel & 1);
213 } else {
214 /* get the level of the first character */
215 level = (byte)(levels[0] & 1);
216
217 /* if there is anything of a different level, then the line
218 is mixed */
219 if (trailingWSStart < length &&
220 (lineBidi.paraLevel & 1) != level) {
221 /* the trailing WS is at paraLevel, which differs from
222 levels[0] */
223 lineBidi.direction = BidiBase.MIXED;
224 } else {
225 /* see if levels[1..trailingWSStart-1] have the same
226 direction as levels[0] and paraLevel */
227 for (i = 1; ; i++) {
228 if (i == trailingWSStart) {
229 /* the direction values match those in level */
243 lineBidi.paraLevel = (byte)
244 ((lineBidi.paraLevel + 1) & ~1);
245
246 /* all levels are implicitly at paraLevel (important for
247 getLevels()) */
248 lineBidi.trailingWSStart = 0;
249 break;
250 case Bidi.DIRECTION_RIGHT_TO_LEFT:
251 /* make sure paraLevel is odd */
252 lineBidi.paraLevel |= 1;
253
254 /* all levels are implicitly at paraLevel (important for
255 getLevels()) */
256 lineBidi.trailingWSStart = 0;
257 break;
258 default:
259 break;
260 }
261 }
262
263 newBidiBase.paraBidi = paraBidi; /* mark successful setLine */
264 return newBidi;
265 }
266
267 static byte getLevelAt(BidiBase bidiBase, int charIndex)
268 {
269 /* return paraLevel if in the trailing WS run, otherwise the real level */
270 if (bidiBase.direction != BidiBase.MIXED || charIndex >= bidiBase.trailingWSStart) {
271 return bidiBase.GetParaLevelAt(charIndex);
272 } else {
273 return bidiBase.levels[charIndex];
274 }
275 }
276
277 static byte[] getLevels(BidiBase bidiBase)
278 {
279 int start = bidiBase.trailingWSStart;
280 int length = bidiBase.length;
281
282 if (start != length) {
283 /* the current levels array does not reflect the WS run */
286 * has an implicit trailing WS run and therefore does not fully
287 * reflect itself all the levels.
288 * This must be a Bidi object for a line, and
289 * we need to create a new levels array.
290 */
291 /* bidiBase.paraLevel is ok even if contextual multiple paragraphs,
292 since bidiBase is a line object */
293 Arrays.fill(bidiBase.levels, start, length, bidiBase.paraLevel);
294
295 /* this new levels array is set for the line and reflects the WS run */
296 bidiBase.trailingWSStart = length;
297 }
298 if (length < bidiBase.levels.length) {
299 byte[] levels = new byte[length];
300 System.arraycopy(bidiBase.levels, 0, levels, 0, length);
301 return levels;
302 }
303 return bidiBase.levels;
304 }
305
306 static BidiRun getLogicalRun(BidiBase bidiBase, int logicalPosition)
307 {
308 /* this is done based on runs rather than on levels since levels have
309 a special interpretation when REORDER_RUNS_ONLY
310 */
311 BidiRun newRun = new BidiRun(), iRun;
312 getRuns(bidiBase);
313 int runCount = bidiBase.runCount;
314 int visualStart = 0, logicalLimit = 0;
315 iRun = bidiBase.runs[0];
316
317 for (int i = 0; i < runCount; i++) {
318 iRun = bidiBase.runs[i];
319 logicalLimit = iRun.start + iRun.limit - visualStart;
320 if ((logicalPosition >= iRun.start) &&
321 (logicalPosition < logicalLimit)) {
322 break;
323 }
324 visualStart = iRun.limit;
325 }
326 newRun.start = iRun.start;
327 newRun.limit = logicalLimit;
328 newRun.level = iRun.level;
329 return newRun;
330 }
331
332 /* in trivial cases there is only one trivial run; called by getRuns() */
333 private static void getSingleRun(BidiBase bidiBase, byte level) {
334 /* simple, single-run case */
335 bidiBase.runs = bidiBase.simpleRuns;
336 bidiBase.runCount = 1;
337
338 /* fill and reorder the single run */
339 bidiBase.runs[0] = new BidiRun(0, bidiBase.length, level);
340 }
341
342 /* reorder the runs array (L2) ---------------------------------------------- */
343
344 /*
345 * Reorder the same-level runs in the runs array.
346 * Here, runCount>1 and maxLevel>=minLevel>=paraLevel.
347 * All the visualStart fields=logical start before reordering.
348 * The "odd" bits are not set yet.
349 *
485 * If option OPTION_REMOVE_CONTROLS is set, insertRemove will contain the
486 * negative number of BiDi control characters within this run.
487 */
488 static void getRuns(BidiBase bidiBase) {
489 /*
490 * This method returns immediately if the runs are already set. This
491 * includes the case of length==0 (handled in setPara)..
492 */
493 if (bidiBase.runCount >= 0) {
494 return;
495 }
496 if (bidiBase.direction != BidiBase.MIXED) {
497 /* simple, single-run case - this covers length==0 */
498 /* bidiBase.paraLevel is ok even for contextual multiple paragraphs */
499 getSingleRun(bidiBase, bidiBase.paraLevel);
500 } else /* BidiBase.MIXED, length>0 */ {
501 /* mixed directionality */
502 int length = bidiBase.length, limit;
503 byte[] levels = bidiBase.levels;
504 int i, runCount;
505 byte level = BidiBase.INTERNAL_LEVEL_DEFAULT_LTR; /* initialize with no valid level */
506 /*
507 * If there are WS characters at the end of the line
508 * and the run preceding them has a level different from
509 * paraLevel, then they will form their own run at paraLevel (L1).
510 * Count them separately.
511 * We need some special treatment for this in order to not
512 * modify the levels array which a line Bidi object shares
513 * with its paragraph parent and its other line siblings.
514 * In other words, for the trailing WS, it may be
515 * levels[]!=paraLevel but we have to treat it like it were so.
516 */
517 limit = bidiBase.trailingWSStart;
518 /* count the runs, there is at least one non-WS run, and limit>0 */
519 runCount = 0;
520 for (i = 0; i < limit; ++i) {
521 /* increment runCount at the start of each run */
522 if (levels[i] != level) {
523 ++runCount;
524 level = levels[i];
525 }
634 bidiBase.runs[runIndex].insertRemove--;
635 }
636 }
637 }
638 }
639
640 static int[] prepareReorder(byte[] levels, byte[] pMinLevel, byte[] pMaxLevel)
641 {
642 int start;
643 byte level, minLevel, maxLevel;
644
645 if (levels == null || levels.length <= 0) {
646 return null;
647 }
648
649 /* determine minLevel and maxLevel */
650 minLevel = BidiBase.MAX_EXPLICIT_LEVEL + 1;
651 maxLevel = 0;
652 for (start = levels.length; start>0; ) {
653 level = levels[--start];
654 if (level > BidiBase.MAX_EXPLICIT_LEVEL + 1) {
655 return null;
656 }
657 if (level < minLevel) {
658 minLevel = level;
659 }
660 if (level > maxLevel) {
661 maxLevel = level;
662 }
663 }
664 pMinLevel[0] = minLevel;
665 pMaxLevel[0] = maxLevel;
666
667 /* initialize the index map */
668 int[] indexMap = new int[levels.length];
669 for (start = levels.length; start > 0; ) {
670 --start;
671 indexMap[start] = start;
672 }
673
674 return indexMap;
|
1 /*
2 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /*
27 *******************************************************************************
28 * Copyright (C) 2001-2014, International Business Machines
29 * Corporation and others. All Rights Reserved.
30 *******************************************************************************
31 */
32 /* Written by Simon Montagu, Matitiahu Allouche
33 * (ported from C code written by Markus W. Scherer)
34 */
35
36 package sun.text.bidi;
37
38 import java.text.Bidi;
39 import java.util.Arrays;
40
41 final class BidiLine {
42
43 /*
44 * General remarks about the functions in this file:
45 *
46 * These functions deal with the aspects of potentially mixed-directional
47 * text in a single paragraph or in a line of a single paragraph
48 * which has already been processed according to
49 * the Unicode 3.0 Bidi algorithm as defined in
50 * http://www.unicode.org/unicode/reports/tr9/ , version 13,
51 * also described in The Unicode Standard, Version 4.0.1 .
52 *
53 * This means that there is a Bidi object with a levels
54 * and a dirProps array.
55 * paraLevel and direction are also set.
56 * Only if the length of the text is zero, then levels==dirProps==NULL.
57 *
58 * The overall directionality of the paragraph
59 * or line is used to bypass the reordering steps if possible.
60 * Even purely RTL text does not need reordering there because
61 * the getLogical/VisualIndex() methods can compute the
101 * To make subsequent operations easier, we also include the run
102 * before the WS if it is at the paraLevel - we merge the two here.
103 *
104 * This method is called only from setLine(), so paraLevel is
105 * set correctly for the line even when contextual multiple paragraphs.
106 */
107
108 static void setTrailingWSStart(BidiBase bidiBase)
109 {
110 byte[] dirProps = bidiBase.dirProps;
111 byte[] levels = bidiBase.levels;
112 int start = bidiBase.length;
113 byte paraLevel = bidiBase.paraLevel;
114
115 /* If the line is terminated by a block separator, all preceding WS etc...
116 are already set to paragraph level.
117 Setting trailingWSStart to pBidi->length will avoid changing the
118 level of B chars from 0 to paraLevel in getLevels when
119 orderParagraphsLTR==TRUE
120 */
121 if (dirProps[start - 1] == BidiBase.B) {
122 bidiBase.trailingWSStart = start; /* currently == bidiBase.length */
123 return;
124 }
125 /* go backwards across all WS, BN, explicit codes */
126 while (start > 0 &&
127 (BidiBase.DirPropFlag(dirProps[start - 1]) & BidiBase.MASK_WS) != 0) {
128 --start;
129 }
130
131 /* if the WS run can be merged with the previous run then do so here */
132 while (start > 0 && levels[start - 1] == paraLevel) {
133 --start;
134 }
135
136 bidiBase.trailingWSStart=start;
137 }
138
139 static Bidi setLine(BidiBase paraBidi,
140 Bidi newBidi, BidiBase lineBidi,
141 int start, int limit) {
142 int length;
143
144 /* set the values in lineBidi from its paraBidi parent */
145 /* class members are already initialized to 0 */
146 // lineBidi.paraBidi = null; /* mark unfinished setLine */
147 // lineBidi.flags = 0;
148 // lineBidi.controlCount = 0;
149
150 length = lineBidi.length = lineBidi.originalLength =
151 lineBidi.resultLength = limit - start;
152
153 lineBidi.text = new char[length];
154 System.arraycopy(paraBidi.text, start, lineBidi.text, 0, length);
155 lineBidi.paraLevel = paraBidi.GetParaLevelAt(start);
156 lineBidi.paraCount = paraBidi.paraCount;
157 lineBidi.runs = new BidiRun[0];
158 lineBidi.reorderingMode = paraBidi.reorderingMode;
159 lineBidi.reorderingOptions = paraBidi.reorderingOptions;
160 if (paraBidi.controlCount > 0) {
161 int j;
162 for (j = start; j < limit; j++) {
163 if (BidiBase.IsBidiControlChar(paraBidi.text[j])) {
164 lineBidi.controlCount++;
165 }
166 }
167 lineBidi.resultLength -= lineBidi.controlCount;
168 }
169 /* copy proper subset of DirProps */
170 lineBidi.getDirPropsMemory(length);
171 lineBidi.dirProps = lineBidi.dirPropsMemory;
172 System.arraycopy(paraBidi.dirProps, start, lineBidi.dirProps, 0,
173 length);
174 /* copy proper subset of Levels */
175 lineBidi.getLevelsMemory(length);
176 lineBidi.levels = lineBidi.levelsMemory;
177 System.arraycopy(paraBidi.levels, start, lineBidi.levels, 0,
178 length);
179 lineBidi.runCount = -1;
185 /*
186 * The parent's levels are all either
187 * implicitly or explicitly ==paraLevel;
188 * do the same here.
189 */
190 if (paraBidi.trailingWSStart <= start) {
191 lineBidi.trailingWSStart = 0;
192 } else if (paraBidi.trailingWSStart < limit) {
193 lineBidi.trailingWSStart = paraBidi.trailingWSStart - start;
194 } else {
195 lineBidi.trailingWSStart = length;
196 }
197 } else {
198 byte[] levels = lineBidi.levels;
199 int i, trailingWSStart;
200 byte level;
201
202 setTrailingWSStart(lineBidi);
203 trailingWSStart = lineBidi.trailingWSStart;
204
205 /* recalculate lineBidiBase.direction */
206 if (trailingWSStart == 0) {
207 /* all levels are at paraLevel */
208 lineBidi.direction = (byte)(lineBidi.paraLevel & 1);
209 } else {
210 /* get the level of the first character */
211 level = (byte)(levels[0] & 1);
212
213 /* if there is anything of a different level, then the line
214 is mixed */
215 if (trailingWSStart < length &&
216 (lineBidi.paraLevel & 1) != level) {
217 /* the trailing WS is at paraLevel, which differs from
218 levels[0] */
219 lineBidi.direction = BidiBase.MIXED;
220 } else {
221 /* see if levels[1..trailingWSStart-1] have the same
222 direction as levels[0] and paraLevel */
223 for (i = 1; ; i++) {
224 if (i == trailingWSStart) {
225 /* the direction values match those in level */
239 lineBidi.paraLevel = (byte)
240 ((lineBidi.paraLevel + 1) & ~1);
241
242 /* all levels are implicitly at paraLevel (important for
243 getLevels()) */
244 lineBidi.trailingWSStart = 0;
245 break;
246 case Bidi.DIRECTION_RIGHT_TO_LEFT:
247 /* make sure paraLevel is odd */
248 lineBidi.paraLevel |= 1;
249
250 /* all levels are implicitly at paraLevel (important for
251 getLevels()) */
252 lineBidi.trailingWSStart = 0;
253 break;
254 default:
255 break;
256 }
257 }
258
259 lineBidi.paraBidi = paraBidi; /* mark successful setLine */
260
261 return newBidi;
262 }
263
264 static byte getLevelAt(BidiBase bidiBase, int charIndex)
265 {
266 /* return paraLevel if in the trailing WS run, otherwise the real level */
267 if (bidiBase.direction != BidiBase.MIXED || charIndex >= bidiBase.trailingWSStart) {
268 return bidiBase.GetParaLevelAt(charIndex);
269 } else {
270 return bidiBase.levels[charIndex];
271 }
272 }
273
274 static byte[] getLevels(BidiBase bidiBase)
275 {
276 int start = bidiBase.trailingWSStart;
277 int length = bidiBase.length;
278
279 if (start != length) {
280 /* the current levels array does not reflect the WS run */
283 * has an implicit trailing WS run and therefore does not fully
284 * reflect itself all the levels.
285 * This must be a Bidi object for a line, and
286 * we need to create a new levels array.
287 */
288 /* bidiBase.paraLevel is ok even if contextual multiple paragraphs,
289 since bidiBase is a line object */
290 Arrays.fill(bidiBase.levels, start, length, bidiBase.paraLevel);
291
292 /* this new levels array is set for the line and reflects the WS run */
293 bidiBase.trailingWSStart = length;
294 }
295 if (length < bidiBase.levels.length) {
296 byte[] levels = new byte[length];
297 System.arraycopy(bidiBase.levels, 0, levels, 0, length);
298 return levels;
299 }
300 return bidiBase.levels;
301 }
302
303 static BidiRun getVisualRun(BidiBase bidiBase, int runIndex) {
304 int start = bidiBase.runs[runIndex].start;
305 int limit;
306 byte level = bidiBase.runs[runIndex].level;
307
308 if (runIndex > 0) {
309 limit = start +
310 bidiBase.runs[runIndex].limit -
311 bidiBase.runs[runIndex - 1].limit;
312 } else {
313 limit = start + bidiBase.runs[0].limit;
314 }
315 return new BidiRun(start, limit, level);
316 }
317
318 /* in trivial cases there is only one trivial run; called by getRuns() */
319 private static void getSingleRun(BidiBase bidiBase, byte level) {
320 /* simple, single-run case */
321 bidiBase.runs = bidiBase.simpleRuns;
322 bidiBase.runCount = 1;
323
324 /* fill and reorder the single run */
325 bidiBase.runs[0] = new BidiRun(0, bidiBase.length, level);
326 }
327
328 /* reorder the runs array (L2) ---------------------------------------------- */
329
330 /*
331 * Reorder the same-level runs in the runs array.
332 * Here, runCount>1 and maxLevel>=minLevel>=paraLevel.
333 * All the visualStart fields=logical start before reordering.
334 * The "odd" bits are not set yet.
335 *
471 * If option OPTION_REMOVE_CONTROLS is set, insertRemove will contain the
472 * negative number of BiDi control characters within this run.
473 */
474 static void getRuns(BidiBase bidiBase) {
475 /*
476 * This method returns immediately if the runs are already set. This
477 * includes the case of length==0 (handled in setPara)..
478 */
479 if (bidiBase.runCount >= 0) {
480 return;
481 }
482 if (bidiBase.direction != BidiBase.MIXED) {
483 /* simple, single-run case - this covers length==0 */
484 /* bidiBase.paraLevel is ok even for contextual multiple paragraphs */
485 getSingleRun(bidiBase, bidiBase.paraLevel);
486 } else /* BidiBase.MIXED, length>0 */ {
487 /* mixed directionality */
488 int length = bidiBase.length, limit;
489 byte[] levels = bidiBase.levels;
490 int i, runCount;
491 byte level = -1; /* initialize with no valid level */
492 /*
493 * If there are WS characters at the end of the line
494 * and the run preceding them has a level different from
495 * paraLevel, then they will form their own run at paraLevel (L1).
496 * Count them separately.
497 * We need some special treatment for this in order to not
498 * modify the levels array which a line Bidi object shares
499 * with its paragraph parent and its other line siblings.
500 * In other words, for the trailing WS, it may be
501 * levels[]!=paraLevel but we have to treat it like it were so.
502 */
503 limit = bidiBase.trailingWSStart;
504 /* count the runs, there is at least one non-WS run, and limit>0 */
505 runCount = 0;
506 for (i = 0; i < limit; ++i) {
507 /* increment runCount at the start of each run */
508 if (levels[i] != level) {
509 ++runCount;
510 level = levels[i];
511 }
620 bidiBase.runs[runIndex].insertRemove--;
621 }
622 }
623 }
624 }
625
626 static int[] prepareReorder(byte[] levels, byte[] pMinLevel, byte[] pMaxLevel)
627 {
628 int start;
629 byte level, minLevel, maxLevel;
630
631 if (levels == null || levels.length <= 0) {
632 return null;
633 }
634
635 /* determine minLevel and maxLevel */
636 minLevel = BidiBase.MAX_EXPLICIT_LEVEL + 1;
637 maxLevel = 0;
638 for (start = levels.length; start>0; ) {
639 level = levels[--start];
640 if (level < 0 || level > (BidiBase.MAX_EXPLICIT_LEVEL + 1)) {
641 return null;
642 }
643 if (level < minLevel) {
644 minLevel = level;
645 }
646 if (level > maxLevel) {
647 maxLevel = level;
648 }
649 }
650 pMinLevel[0] = minLevel;
651 pMaxLevel[0] = maxLevel;
652
653 /* initialize the index map */
654 int[] indexMap = new int[levels.length];
655 for (start = levels.length; start > 0; ) {
656 --start;
657 indexMap[start] = start;
658 }
659
660 return indexMap;
|