/src/icu/icu4c/source/common/ubidiwrt.cpp
Line | Count | Source |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | /* |
4 | | ****************************************************************************** |
5 | | * |
6 | | * Copyright (C) 2000-2015, International Business Machines |
7 | | * Corporation and others. All Rights Reserved. |
8 | | * |
9 | | ****************************************************************************** |
10 | | * file name: ubidiwrt.c |
11 | | * encoding: UTF-8 |
12 | | * tab size: 8 (not used) |
13 | | * indentation:4 |
14 | | * |
15 | | * created on: 1999aug06 |
16 | | * created by: Markus W. Scherer, updated by Matitiahu Allouche |
17 | | * |
18 | | * This file contains implementations for BiDi functions that use |
19 | | * the core algorithm and core API to write reordered text. |
20 | | */ |
21 | | |
22 | | #include "unicode/utypes.h" |
23 | | #include "unicode/ustring.h" |
24 | | #include "unicode/uchar.h" |
25 | | #include "unicode/ubidi.h" |
26 | | #include "unicode/utf16.h" |
27 | | #include "cmemory.h" |
28 | | #include "ustr_imp.h" |
29 | | #include "ubidiimp.h" |
30 | | |
31 | | /* |
32 | | * The function implementations in this file are designed |
33 | | * for UTF-16 and UTF-32, not for UTF-8. |
34 | | * |
35 | | * Assumptions that are not true for UTF-8: |
36 | | * - Any code point always needs the same number of code units |
37 | | * ("minimum-length-problem" of UTF-8) |
38 | | * - The BiDi control characters need only one code unit each |
39 | | * |
40 | | * Further assumptions for all UTFs: |
41 | | * - u_charMirror(c) needs the same number of code units as c |
42 | | */ |
43 | | #if defined(UTF_SIZE) && UTF_SIZE==8 |
44 | | # error reimplement ubidi_writeReordered() for UTF-8, see comment above |
45 | | #endif |
46 | | |
47 | 15.5k | #define IS_COMBINING(type) ((1UL<<(type))&(1UL<<U_NON_SPACING_MARK|1UL<<U_COMBINING_SPACING_MARK|1UL<<U_ENCLOSING_MARK)) |
48 | | |
49 | | /* |
50 | | * When we have UBIDI_OUTPUT_REVERSE set on ubidi_writeReordered(), then we |
51 | | * semantically write RTL runs in reverse and later reverse them again. |
52 | | * Instead, we actually write them in forward order to begin with. |
53 | | * However, if the RTL run was to be mirrored, we need to mirror here now |
54 | | * since the implicit second reversal must not do it. |
55 | | * It looks strange to do mirroring in LTR output, but it is only because |
56 | | * we are writing RTL output in reverse. |
57 | | */ |
58 | | static int32_t |
59 | | doWriteForward(const char16_t *src, int32_t srcLength, |
60 | | char16_t *dest, int32_t destSize, |
61 | | uint16_t options, |
62 | 16.3k | UErrorCode *pErrorCode) { |
63 | 16.3k | if (srcLength<=0) { |
64 | 0 | *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
65 | 0 | return 0; |
66 | 0 | } |
67 | | /* optimize for several combinations of options */ |
68 | 16.3k | switch(options&(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING)) { |
69 | 4.78k | case 0: { |
70 | | /* simply copy the LTR run to the destination */ |
71 | 4.78k | int32_t length=srcLength; |
72 | 4.78k | if(destSize<length) { |
73 | 1.94k | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
74 | 1.94k | return srcLength; |
75 | 1.94k | } |
76 | 7.18k | do { |
77 | 7.18k | *dest++=*src++; |
78 | 7.18k | } while(--length>0); |
79 | 2.84k | return srcLength; |
80 | 4.78k | } |
81 | 2.38k | case UBIDI_DO_MIRRORING: { |
82 | | /* do mirroring */ |
83 | 2.38k | int32_t i=0, j=0; |
84 | 2.38k | UChar32 c; |
85 | | |
86 | 2.38k | if(destSize<srcLength) { |
87 | 823 | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
88 | 823 | return srcLength; |
89 | 823 | } |
90 | 4.47k | do { |
91 | 4.47k | U16_NEXT(src, i, srcLength, c); |
92 | 4.47k | c=u_charMirror(c); |
93 | 4.47k | U16_APPEND_UNSAFE(dest, j, c); |
94 | 4.47k | } while(i<srcLength); |
95 | 1.55k | return srcLength; |
96 | 2.38k | } |
97 | 5.26k | case UBIDI_REMOVE_BIDI_CONTROLS: { |
98 | | /* copy the LTR run and remove any BiDi control characters */ |
99 | 5.26k | int32_t remaining=destSize; |
100 | 5.26k | char16_t c; |
101 | 17.3k | do { |
102 | 17.3k | c=*src++; |
103 | 17.3k | if(!IS_BIDI_CONTROL_CHAR(c)) { |
104 | 8.34k | if(--remaining<0) { |
105 | 1.04k | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
106 | | |
107 | | /* preflight the length */ |
108 | 4.94k | while(--srcLength>0) { |
109 | 3.90k | c=*src++; |
110 | 3.90k | if(!IS_BIDI_CONTROL_CHAR(c)) { |
111 | 3.10k | --remaining; |
112 | 3.10k | } |
113 | 3.90k | } |
114 | 1.04k | return destSize-remaining; |
115 | 1.04k | } |
116 | 7.29k | *dest++=c; |
117 | 7.29k | } |
118 | 17.3k | } while(--srcLength>0); |
119 | 4.21k | return destSize-remaining; |
120 | 5.26k | } |
121 | 3.91k | default: { |
122 | | /* remove BiDi control characters and do mirroring */ |
123 | 3.91k | int32_t remaining=destSize; |
124 | 3.91k | int32_t i, j=0; |
125 | 3.91k | UChar32 c; |
126 | 13.6k | do { |
127 | 13.6k | i=0; |
128 | 13.6k | U16_NEXT(src, i, srcLength, c); |
129 | 13.6k | src+=i; |
130 | 13.6k | srcLength-=i; |
131 | 13.6k | if(!IS_BIDI_CONTROL_CHAR(c)) { |
132 | 7.98k | remaining-=i; |
133 | 7.98k | if(remaining<0) { |
134 | 1.16k | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
135 | | |
136 | | /* preflight the length */ |
137 | 3.80k | while(srcLength>0) { |
138 | 2.63k | c=*src++; |
139 | 2.63k | if(!IS_BIDI_CONTROL_CHAR(c)) { |
140 | 1.74k | --remaining; |
141 | 1.74k | } |
142 | 2.63k | --srcLength; |
143 | 2.63k | } |
144 | 1.16k | return destSize-remaining; |
145 | 1.16k | } |
146 | 6.81k | c=u_charMirror(c); |
147 | 6.81k | U16_APPEND_UNSAFE(dest, j, c); |
148 | 6.81k | } |
149 | 13.6k | } while(srcLength>0); |
150 | 2.74k | return j; |
151 | 3.91k | } |
152 | 16.3k | } /* end of switch */ |
153 | 16.3k | } |
154 | | |
155 | | static int32_t |
156 | | doWriteReverse(const char16_t *src, int32_t srcLength, |
157 | | char16_t *dest, int32_t destSize, |
158 | | uint16_t options, |
159 | 15.2k | UErrorCode *pErrorCode) { |
160 | | /* |
161 | | * RTL run - |
162 | | * |
163 | | * RTL runs need to be copied to the destination in reverse order |
164 | | * of code points, not code units, to keep Unicode characters intact. |
165 | | * |
166 | | * The general strategy for this is to read the source text |
167 | | * in backward order, collect all code units for a code point |
168 | | * (and optionally following combining characters, see below), |
169 | | * and copy all these code units in ascending order |
170 | | * to the destination for this run. |
171 | | * |
172 | | * Several options request whether combining characters |
173 | | * should be kept after their base characters, |
174 | | * whether BiDi control characters should be removed, and |
175 | | * whether characters should be replaced by their mirror-image |
176 | | * equivalent Unicode characters. |
177 | | */ |
178 | 15.2k | int32_t i, j; |
179 | 15.2k | UChar32 c; |
180 | | |
181 | 15.2k | if(srcLength<=0) { |
182 | 0 | *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
183 | 0 | return 0; |
184 | 0 | } |
185 | | |
186 | | /* optimize for several combinations of options */ |
187 | 15.2k | switch(options&(UBIDI_REMOVE_BIDI_CONTROLS|UBIDI_DO_MIRRORING|UBIDI_KEEP_BASE_COMBINING)) { |
188 | 2.74k | case 0: |
189 | | /* |
190 | | * With none of the "complicated" options set, the destination |
191 | | * run will have the same length as the source run, |
192 | | * and there is no mirroring and no keeping combining characters |
193 | | * with their base characters. |
194 | | */ |
195 | 2.74k | if(destSize<srcLength) { |
196 | 782 | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
197 | 782 | return srcLength; |
198 | 782 | } |
199 | 1.96k | destSize=srcLength; |
200 | | |
201 | | /* preserve character integrity */ |
202 | 5.99k | do { |
203 | | /* i is always after the last code unit known to need to be kept in this segment */ |
204 | 5.99k | i=srcLength; |
205 | | |
206 | | /* collect code units for one base character */ |
207 | 5.99k | U16_BACK_1(src, 0, srcLength); |
208 | | |
209 | | /* copy this base character */ |
210 | 5.99k | j=srcLength; |
211 | 6.26k | do { |
212 | 6.26k | *dest++=src[j++]; |
213 | 6.26k | } while(j<i); |
214 | 5.99k | } while(srcLength>0); |
215 | 1.96k | break; |
216 | 2.72k | case UBIDI_KEEP_BASE_COMBINING: |
217 | | /* |
218 | | * Here, too, the destination |
219 | | * run will have the same length as the source run, |
220 | | * and there is no mirroring. |
221 | | * We do need to keep combining characters with their base characters. |
222 | | */ |
223 | 2.72k | if(destSize<srcLength) { |
224 | 914 | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
225 | 914 | return srcLength; |
226 | 914 | } |
227 | 1.80k | destSize=srcLength; |
228 | | |
229 | | /* preserve character integrity */ |
230 | 4.86k | do { |
231 | | /* i is always after the last code unit known to need to be kept in this segment */ |
232 | 4.86k | i=srcLength; |
233 | | |
234 | | /* collect code units and modifier letters for one base character */ |
235 | 5.41k | do { |
236 | 5.41k | U16_PREV(src, 0, srcLength, c); |
237 | 5.41k | } while(srcLength>0 && IS_COMBINING(u_charType(c))); |
238 | | |
239 | | /* copy this "user character" */ |
240 | 4.86k | j=srcLength; |
241 | 5.64k | do { |
242 | 5.64k | *dest++=src[j++]; |
243 | 5.64k | } while(j<i); |
244 | 4.86k | } while(srcLength>0); |
245 | 1.80k | break; |
246 | 9.82k | default: |
247 | | /* |
248 | | * With several "complicated" options set, this is the most |
249 | | * general and the slowest copying of an RTL run. |
250 | | * We will do mirroring, remove BiDi controls, and |
251 | | * keep combining characters with their base characters |
252 | | * as requested. |
253 | | */ |
254 | 9.82k | if(!(options&UBIDI_REMOVE_BIDI_CONTROLS)) { |
255 | 1.56k | i=srcLength; |
256 | 8.26k | } else { |
257 | | /* we need to find out the destination length of the run, |
258 | | which will not include the BiDi control characters */ |
259 | 8.26k | int32_t length=srcLength; |
260 | 8.26k | char16_t ch; |
261 | | |
262 | 8.26k | i=0; |
263 | 27.3k | do { |
264 | 27.3k | ch=*src++; |
265 | 27.3k | if(!IS_BIDI_CONTROL_CHAR(ch)) { |
266 | 18.5k | ++i; |
267 | 18.5k | } |
268 | 27.3k | } while(--length>0); |
269 | 8.26k | src-=srcLength; |
270 | 8.26k | } |
271 | | |
272 | 9.82k | if(destSize<i) { |
273 | 2.46k | *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
274 | 2.46k | return i; |
275 | 2.46k | } |
276 | 7.36k | destSize=i; |
277 | | |
278 | | /* preserve character integrity */ |
279 | 22.5k | do { |
280 | | /* i is always after the last code unit known to need to be kept in this segment */ |
281 | 22.5k | i=srcLength; |
282 | | |
283 | | /* collect code units for one base character */ |
284 | 22.5k | U16_PREV(src, 0, srcLength, c); |
285 | 22.5k | if(options&UBIDI_KEEP_BASE_COMBINING) { |
286 | | /* collect modifier letters for this base character */ |
287 | 17.9k | while(srcLength>0 && IS_COMBINING(u_charType(c))) { |
288 | 1.26k | U16_PREV(src, 0, srcLength, c); |
289 | 1.26k | } |
290 | 16.6k | } |
291 | | |
292 | 22.5k | if(options&UBIDI_REMOVE_BIDI_CONTROLS && IS_BIDI_CONTROL_CHAR(c)) { |
293 | | /* do not copy this BiDi control character */ |
294 | 8.47k | continue; |
295 | 8.47k | } |
296 | | |
297 | | /* copy this "user character" */ |
298 | 14.0k | j=srcLength; |
299 | 14.0k | if(options&UBIDI_DO_MIRRORING) { |
300 | | /* mirror only the base character */ |
301 | 3.00k | int32_t k=0; |
302 | 3.00k | c=u_charMirror(c); |
303 | 3.00k | U16_APPEND_UNSAFE(dest, k, c); |
304 | 3.00k | dest+=k; |
305 | 3.00k | j+=k; |
306 | 3.00k | } |
307 | 26.8k | while(j<i) { |
308 | 12.7k | *dest++=src[j++]; |
309 | 12.7k | } |
310 | 22.5k | } while(srcLength>0); |
311 | 7.36k | break; |
312 | 15.2k | } /* end of switch */ |
313 | | |
314 | 11.1k | return destSize; |
315 | 15.2k | } |
316 | | |
317 | | U_CAPI int32_t U_EXPORT2 |
318 | | ubidi_writeReverse(const char16_t *src, int32_t srcLength, |
319 | | char16_t *dest, int32_t destSize, |
320 | | uint16_t options, |
321 | 0 | UErrorCode *pErrorCode) { |
322 | 0 | int32_t destLength; |
323 | |
|
324 | 0 | if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) { |
325 | 0 | return 0; |
326 | 0 | } |
327 | | |
328 | | /* more error checking */ |
329 | 0 | if( src==nullptr || srcLength<-1 || |
330 | 0 | destSize<0 || (destSize>0 && dest==nullptr)) |
331 | 0 | { |
332 | 0 | *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
333 | 0 | return 0; |
334 | 0 | } |
335 | | |
336 | | /* do input and output overlap? */ |
337 | 0 | if( dest!=nullptr && |
338 | 0 | ((src>=dest && src<dest+destSize) || |
339 | 0 | (dest>=src && dest<src+srcLength))) |
340 | 0 | { |
341 | 0 | *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
342 | 0 | return 0; |
343 | 0 | } |
344 | | |
345 | 0 | if(srcLength==-1) { |
346 | 0 | srcLength=u_strlen(src); |
347 | 0 | } |
348 | 0 | if(srcLength>0) { |
349 | 0 | destLength=doWriteReverse(src, srcLength, dest, destSize, options, pErrorCode); |
350 | 0 | } else { |
351 | | /* nothing to do */ |
352 | 0 | destLength=0; |
353 | 0 | } |
354 | |
|
355 | 0 | return u_terminateUChars(dest, destSize, destLength, pErrorCode); |
356 | 0 | } |
357 | | |
358 | | // Ticket 20907 - The optimizer in MSVC/Visual Studio versions below 16.4 has trouble with this |
359 | | // function on Windows ARM64. As a work-around, we disable optimizations for this function. |
360 | | // This work-around could/should be removed once the following versions of Visual Studio are no |
361 | | // longer supported: All versions of VS2017, and versions of VS2019 below 16.4. |
362 | | #if (defined(_MSC_VER) && (defined(_M_ARM64)) && (_MSC_VER < 1924)) |
363 | | #pragma optimize( "", off ) |
364 | | #endif |
365 | | U_CAPI int32_t U_EXPORT2 |
366 | | ubidi_writeReordered(UBiDi *pBiDi, |
367 | | char16_t *dest, int32_t destSize, |
368 | | uint16_t options, |
369 | 4.08k | UErrorCode *pErrorCode) { |
370 | 4.08k | const char16_t *text; |
371 | 4.08k | char16_t *saveDest; |
372 | 4.08k | int32_t length, destCapacity; |
373 | 4.08k | int32_t run, runCount, logicalStart, runLength; |
374 | | |
375 | 4.08k | if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) { |
376 | 0 | return 0; |
377 | 0 | } |
378 | | |
379 | | /* more error checking */ |
380 | 4.08k | if( pBiDi==nullptr || |
381 | 4.08k | (text=pBiDi->text)==nullptr || (length=pBiDi->length)<0 || |
382 | 4.08k | destSize<0 || (destSize>0 && dest==nullptr)) |
383 | 0 | { |
384 | 0 | *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
385 | 0 | return 0; |
386 | 0 | } |
387 | | |
388 | | /* do input and output overlap? */ |
389 | 4.08k | if( dest!=nullptr && |
390 | 4.08k | ((text>=dest && text<dest+destSize) || |
391 | 4.08k | (dest>=text && dest<text+pBiDi->originalLength))) |
392 | 0 | { |
393 | 0 | *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
394 | 0 | return 0; |
395 | 0 | } |
396 | | |
397 | 4.08k | if(length==0) { |
398 | | /* nothing to do */ |
399 | 40 | return u_terminateUChars(dest, destSize, 0, pErrorCode); |
400 | 40 | } |
401 | | |
402 | 4.04k | runCount=ubidi_countRuns(pBiDi, pErrorCode); |
403 | 4.04k | if(U_FAILURE(*pErrorCode)) { |
404 | 0 | return 0; |
405 | 0 | } |
406 | | |
407 | | /* destSize shrinks, later destination length=destCapacity-destSize */ |
408 | 4.04k | saveDest=dest; |
409 | 4.04k | destCapacity=destSize; |
410 | 4.04k | runLength = 0; |
411 | | |
412 | | /* |
413 | | * Option "insert marks" implies UBIDI_INSERT_LRM_FOR_NUMERIC if the |
414 | | * reordering mode (checked below) is appropriate. |
415 | | */ |
416 | 4.04k | if(pBiDi->reorderingOptions & UBIDI_OPTION_INSERT_MARKS) { |
417 | 0 | options|=UBIDI_INSERT_LRM_FOR_NUMERIC; |
418 | 0 | options&=~UBIDI_REMOVE_BIDI_CONTROLS; |
419 | 0 | } |
420 | | /* |
421 | | * Option "remove controls" implies UBIDI_REMOVE_BIDI_CONTROLS |
422 | | * and cancels UBIDI_INSERT_LRM_FOR_NUMERIC. |
423 | | */ |
424 | 4.04k | if(pBiDi->reorderingOptions & UBIDI_OPTION_REMOVE_CONTROLS) { |
425 | 0 | options|=UBIDI_REMOVE_BIDI_CONTROLS; |
426 | 0 | options&=~UBIDI_INSERT_LRM_FOR_NUMERIC; |
427 | 0 | } |
428 | | /* |
429 | | * If we do not perform the "inverse BiDi" algorithm, then we |
430 | | * don't need to insert any LRMs, and don't need to test for it. |
431 | | */ |
432 | 4.04k | if((pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_NUMBERS_AS_L) && |
433 | 3.23k | (pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_LIKE_DIRECT) && |
434 | 3.23k | (pBiDi->reorderingMode != UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL) && |
435 | 3.23k | (pBiDi->reorderingMode != UBIDI_REORDER_RUNS_ONLY)) { |
436 | 3.23k | options&=~UBIDI_INSERT_LRM_FOR_NUMERIC; |
437 | 3.23k | } |
438 | | /* |
439 | | * Iterate through all visual runs and copy the run text segments to |
440 | | * the destination, according to the options. |
441 | | * |
442 | | * The tests for where to insert LRMs ignore the fact that there may be |
443 | | * BN codes or non-BMP code points at the beginning and end of a run; |
444 | | * they may insert LRMs unnecessarily but the tests are faster this way |
445 | | * (this would have to be improved for UTF-8). |
446 | | * |
447 | | * Note that the only errors that are set by doWriteXY() are buffer overflow |
448 | | * errors. Ignore them until the end, and continue for preflighting. |
449 | | */ |
450 | 4.04k | if(!(options&UBIDI_OUTPUT_REVERSE)) { |
451 | | /* forward output */ |
452 | 1.86k | if(!(options&UBIDI_INSERT_LRM_FOR_NUMERIC)) { |
453 | | /* do not insert BiDi controls */ |
454 | 11.3k | for(run=0; run<runCount; ++run) { |
455 | 9.74k | if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength)) { |
456 | 6.33k | runLength=doWriteForward(text+logicalStart, runLength, |
457 | 6.33k | dest, destSize, |
458 | 6.33k | (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode); |
459 | 6.33k | } else { |
460 | 3.40k | runLength=doWriteReverse(text+logicalStart, runLength, |
461 | 3.40k | dest, destSize, |
462 | 3.40k | options, pErrorCode); |
463 | 3.40k | } |
464 | 9.74k | if(dest!=nullptr) { |
465 | 9.74k | dest+=runLength; |
466 | 9.74k | } |
467 | 9.74k | destSize-=runLength; |
468 | 9.74k | } |
469 | 1.58k | } else { |
470 | | /* insert BiDi controls for "inverse BiDi" */ |
471 | 282 | const DirProp *dirProps=pBiDi->dirProps; |
472 | 282 | const char16_t *src; |
473 | 282 | char16_t uc; |
474 | 282 | UBiDiDirection dir; |
475 | 282 | int32_t markFlag; |
476 | | |
477 | 5.00k | for(run=0; run<runCount; ++run) { |
478 | 4.72k | dir=ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength); |
479 | 4.72k | src=text+logicalStart; |
480 | | /* check if something relevant in insertPoints */ |
481 | 4.72k | markFlag=pBiDi->runs[run].insertRemove; |
482 | 4.72k | if(markFlag<0) { /* BiDi controls count */ |
483 | 0 | markFlag=0; |
484 | 0 | } |
485 | | |
486 | 4.72k | if(UBIDI_LTR==dir) { |
487 | 2.38k | if((pBiDi->isInverse) && |
488 | 2.38k | (/*run>0 &&*/ dirProps[logicalStart]!=L)) { |
489 | 1.56k | markFlag |= LRM_BEFORE; |
490 | 1.56k | } |
491 | 2.38k | if (markFlag & LRM_BEFORE) { |
492 | 1.56k | uc=LRM_CHAR; |
493 | 1.56k | } |
494 | 829 | else if (markFlag & RLM_BEFORE) { |
495 | 0 | uc=RLM_CHAR; |
496 | 0 | } |
497 | 829 | else uc=0; |
498 | 2.38k | if(uc) { |
499 | 1.56k | if(destSize>0) { |
500 | 350 | *dest++=uc; |
501 | 350 | } |
502 | 1.56k | --destSize; |
503 | 1.56k | } |
504 | | |
505 | 2.38k | runLength=doWriteForward(src, runLength, |
506 | 2.38k | dest, destSize, |
507 | 2.38k | (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode); |
508 | 2.38k | if(dest!=nullptr) { |
509 | 2.38k | dest+=runLength; |
510 | 2.38k | } |
511 | 2.38k | destSize-=runLength; |
512 | | |
513 | 2.38k | if((pBiDi->isInverse) && |
514 | 2.38k | (/*run<runCount-1 &&*/ |
515 | 2.38k | runLength > 0 && // doWriteForward may return 0 if src |
516 | | // only include bidi control chars |
517 | 1.96k | dirProps[logicalStart+runLength-1]!=L)) { |
518 | 1.46k | markFlag |= LRM_AFTER; |
519 | 1.46k | } |
520 | 2.38k | if (markFlag & LRM_AFTER) { |
521 | 1.46k | uc=LRM_CHAR; |
522 | 1.46k | } |
523 | 927 | else if (markFlag & RLM_AFTER) { |
524 | 0 | uc=RLM_CHAR; |
525 | 0 | } |
526 | 927 | else uc=0; |
527 | 2.38k | if(uc) { |
528 | 1.46k | if(destSize>0) { |
529 | 235 | *dest++=uc; |
530 | 235 | } |
531 | 1.46k | --destSize; |
532 | 1.46k | } |
533 | 2.38k | } else { /* RTL run */ |
534 | 2.33k | if((pBiDi->isInverse) && |
535 | 2.33k | (/*run>0 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart+runLength-1])))) { |
536 | 1.51k | markFlag |= RLM_BEFORE; |
537 | 1.51k | } |
538 | 2.33k | if (markFlag & LRM_BEFORE) { |
539 | 0 | uc=LRM_CHAR; |
540 | 0 | } |
541 | 2.33k | else if (markFlag & RLM_BEFORE) { |
542 | 1.51k | uc=RLM_CHAR; |
543 | 1.51k | } |
544 | 815 | else uc=0; |
545 | 2.33k | if(uc) { |
546 | 1.51k | if(destSize>0) { |
547 | 236 | *dest++=uc; |
548 | 236 | } |
549 | 1.51k | --destSize; |
550 | 1.51k | } |
551 | | |
552 | 2.33k | runLength=doWriteReverse(src, runLength, |
553 | 2.33k | dest, destSize, |
554 | 2.33k | options, pErrorCode); |
555 | 2.33k | if(dest!=nullptr) { |
556 | 2.33k | dest+=runLength; |
557 | 2.33k | } |
558 | 2.33k | destSize-=runLength; |
559 | | |
560 | 2.33k | if((pBiDi->isInverse) && |
561 | 2.33k | (/*run<runCount-1 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart])))) { |
562 | 1.52k | markFlag |= RLM_AFTER; |
563 | 1.52k | } |
564 | 2.33k | if (markFlag & LRM_AFTER) { |
565 | 0 | uc=LRM_CHAR; |
566 | 0 | } |
567 | 2.33k | else if (markFlag & RLM_AFTER) { |
568 | 1.52k | uc=RLM_CHAR; |
569 | 1.52k | } |
570 | 808 | else uc=0; |
571 | 2.33k | if(uc) { |
572 | 1.52k | if(destSize>0) { |
573 | 229 | *dest++=uc; |
574 | 229 | } |
575 | 1.52k | --destSize; |
576 | 1.52k | } |
577 | 2.33k | } |
578 | 4.72k | } |
579 | 282 | } |
580 | 2.18k | } else { |
581 | | /* reverse output */ |
582 | 2.18k | if(!(options&UBIDI_INSERT_LRM_FOR_NUMERIC)) { |
583 | | /* do not insert BiDi controls */ |
584 | 13.9k | for(run=runCount; --run>=0;) { |
585 | 12.1k | if(UBIDI_LTR==ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength)) { |
586 | 7.05k | runLength=doWriteReverse(text+logicalStart, runLength, |
587 | 7.05k | dest, destSize, |
588 | 7.05k | (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode); |
589 | 7.05k | } else { |
590 | 5.09k | runLength=doWriteForward(text+logicalStart, runLength, |
591 | 5.09k | dest, destSize, |
592 | 5.09k | options, pErrorCode); |
593 | 5.09k | } |
594 | 12.1k | if(dest!=nullptr) { |
595 | 12.1k | dest+=runLength; |
596 | 12.1k | } |
597 | 12.1k | destSize-=runLength; |
598 | 12.1k | } |
599 | 1.80k | } else { |
600 | | /* insert BiDi controls for "inverse BiDi" */ |
601 | 371 | const DirProp *dirProps=pBiDi->dirProps; |
602 | 371 | const char16_t *src; |
603 | 371 | UBiDiDirection dir; |
604 | | |
605 | 5.39k | for(run=runCount; --run>=0;) { |
606 | | /* reverse output */ |
607 | 5.02k | dir=ubidi_getVisualRun(pBiDi, run, &logicalStart, &runLength); |
608 | 5.02k | src=text+logicalStart; |
609 | | |
610 | 5.02k | if(UBIDI_LTR==dir) { |
611 | 2.50k | if(/*run<runCount-1 &&*/ dirProps[logicalStart+runLength-1]!=L) { |
612 | 1.41k | if(destSize>0) { |
613 | 321 | *dest++=LRM_CHAR; |
614 | 321 | } |
615 | 1.41k | --destSize; |
616 | 1.41k | } |
617 | | |
618 | 2.50k | runLength=doWriteReverse(src, runLength, |
619 | 2.50k | dest, destSize, |
620 | 2.50k | (uint16_t)(options&~UBIDI_DO_MIRRORING), pErrorCode); |
621 | 2.50k | if(dest!=nullptr) { |
622 | 2.50k | dest+=runLength; |
623 | 2.50k | } |
624 | 2.50k | destSize-=runLength; |
625 | | |
626 | 2.50k | if(/*run>0 &&*/ dirProps[logicalStart]!=L) { |
627 | 1.51k | if(destSize>0) { |
628 | 406 | *dest++=LRM_CHAR; |
629 | 406 | } |
630 | 1.51k | --destSize; |
631 | 1.51k | } |
632 | 2.51k | } else { |
633 | 2.51k | if(/*run<runCount-1 &&*/ !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart]))) { |
634 | 1.51k | if(destSize>0) { |
635 | 373 | *dest++=RLM_CHAR; |
636 | 373 | } |
637 | 1.51k | --destSize; |
638 | 1.51k | } |
639 | | |
640 | 2.51k | runLength=doWriteForward(src, runLength, |
641 | 2.51k | dest, destSize, |
642 | 2.51k | options, pErrorCode); |
643 | 2.51k | if(dest!=nullptr) { |
644 | 2.51k | dest+=runLength; |
645 | 2.51k | } |
646 | 2.51k | destSize-=runLength; |
647 | | |
648 | 2.51k | if(/*run>0 &&*/ |
649 | 2.51k | runLength > 0 && // doWriteForward may return 0 if src |
650 | | // only include bidi control chars |
651 | 2.28k | !(MASK_R_AL&DIRPROP_FLAG(dirProps[logicalStart+runLength-1]))) { |
652 | 1.49k | if(destSize>0) { |
653 | 342 | *dest++=RLM_CHAR; |
654 | 342 | } |
655 | 1.49k | --destSize; |
656 | 1.49k | } |
657 | 2.51k | } |
658 | 5.02k | } |
659 | 371 | } |
660 | 2.18k | } |
661 | | |
662 | 4.04k | return u_terminateUChars(saveDest, destCapacity, destCapacity-destSize, pErrorCode); |
663 | 4.04k | } |
664 | | #if (defined(_MSC_VER) && (defined(_M_ARM64)) && (_MSC_VER < 1924)) |
665 | | #pragma optimize( "", on ) |
666 | | #endif |