2 * Unicode Bidirectional Algorithm implementation
4 * Copyright 2003 Shachar Shemesh
5 * Copyright 2007 Maarten Lankhorst
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Code derived from the modified reference implementation
23 * that was found in revision 17 of http://unicode.org/reports/tr9/
24 * "Unicode Standard Annex #9: THE BIDIRECTIONAL ALGORITHM"
26 * -- Copyright (C) 1999-2005, ASMUS, Inc.
28 * Permission is hereby granted, free of charge, to any person obtaining a
29 * copy of the Unicode data files and any associated documentation (the
30 * "Data Files") or Unicode software and any associated documentation (the
31 * "Software") to deal in the Data Files or Software without restriction,
32 * including without limitation the rights to use, copy, modify, merge,
33 * publish, distribute, and/or sell copies of the Data Files or Software,
34 * and to permit persons to whom the Data Files or Software are furnished
35 * to do so, provided that (a) the above copyright notice(s) and this
36 * permission notice appear with all copies of the Data Files or Software,
37 * (b) both the above copyright notice(s) and this permission notice appear
38 * in associated documentation, and (c) there is clear notice in each
39 * modified Data File or in the Software as well as in the documentation
40 * associated with the Data File(s) or Software that the data or software
48 #include "wine/debug.h"
50 #include "dwrite_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(bidi
);
54 extern const unsigned short bidi_bracket_table
[] DECLSPEC_HIDDEN
;
55 extern const unsigned short bidi_direction_table
[] DECLSPEC_HIDDEN
;
57 #define ASSERT(x) do { if (!(x)) FIXME("assert failed: %s\n", #x); } while(0)
60 #define odd(x) ((x) & 1)
62 /*------------------------------------------------------------------------
63 Bidirectional Character Types
65 as defined by the Unicode Bidirectional Algorithm Table 3-7.
69 The list of bidirectional character types here is not grouped the
70 same way as the table 3-7, since the numeric values for the types
71 are chosen to keep the state and action tables compact.
72 ------------------------------------------------------------------------*/
76 /* ON MUST be zero, code relies on ON = NI = 0 */
77 ON
= 0, /* Other Neutral */
80 AN
, /* Arabic Number */
81 EN
, /* European Number */
82 AL
, /* Arabic Letter (Right-to-left) */
83 NSM
, /* Non-spacing Mark */
84 CS
, /* Common Separator */
85 ES
, /* European Separator */
86 ET
, /* European Terminator (post/prefix e.g. $ and %) */
89 BN
, /* Boundary neutral (type of RLE etc after explicit levels) */
92 S
, /* Segment Separator (TAB) // used only in L1 */
93 WS
, /* White space // used only in L1 */
94 B
, /* Paragraph Separator (aka as PS) */
96 /* types for explicit controls */
97 RLO
, /* these are used only in X1-X9 */
103 LRI
, /* Isolate formatting characters new with 6.3 */
108 /* resolved types, also resolved directions */
109 NI
= ON
, /* alias, where ON, WS, S and Isolates are treated the same */
112 static const char debug_type
[][4] =
114 "ON", /* Other Neutral */
115 "L", /* Left Letter */
116 "R", /* Right Letter */
117 "AN", /* Arabic Number */
118 "EN", /* European Number */
119 "AL", /* Arabic Letter (Right-to-left) */
120 "NSM", /* Non-spacing Mark */
121 "CS", /* Common Separator */
122 "ES", /* European Separator */
123 "ET", /* European Terminator (post/prefix e.g. $ and %) */
124 "BN", /* Boundary neutral (type of RLE etc after explicit levels) */
125 "S", /* Segment Separator (TAB) used only in L1 */
126 "WS", /* White space used only in L1 */
127 "B", /* Paragraph Separator (aka as PS) */
128 "RLO", /* these are used only in X1-X9 */
133 "LRI", /* Isolate formatting characters new with 6.3 */
139 static inline void bidi_dump_types(const char* header
, const struct bidi_char
*chars
, UINT32 start
, UINT32 end
)
142 TRACE("%s:", header
);
143 for (i
= start
; i
< end
&& len
< 200; i
++) {
144 TRACE(" %s", debug_type
[chars
[i
].bidi_class
]);
145 len
+= strlen(debug_type
[chars
[i
].bidi_class
]) + 1;
152 /* RESOLVE EXPLICIT */
154 static inline UINT8
get_greater_even_level(UINT8 level
)
156 return odd(level
) ? level
+ 1 : level
+ 2;
159 static inline UINT8
get_greater_odd_level(UINT8 level
)
161 return odd(level
) ? level
+ 2 : level
+ 1;
164 static inline UINT8
get_embedding_direction(UINT8 level
)
166 return odd(level
) ? R
: L
;
169 /*------------------------------------------------------------------------
170 Function: bidi_resolve_explicit
172 Recursively resolves explicit embedding levels and overrides.
173 Implements rules X1-X9, of the Unicode Bidirectional Algorithm.
175 Note: The function uses two simple counters to keep track of
176 matching explicit codes and PDF. Use the default argument for
177 the outermost call. The nesting counter counts the recursion
178 depth and not the embedding level.
179 ------------------------------------------------------------------------*/
180 typedef struct tagStackItem
187 #define push_stack(l,o,i) \
189 stack[stack_top].level = l; \
190 stack[stack_top].override = o; \
191 stack[stack_top].isolate = i;} while(0)
193 #define pop_stack() do { stack_top++; } while(0)
195 #define valid_level(x) (x <= MAX_DEPTH && overflow_isolate_count == 0 && overflow_embedding_count == 0)
197 static void bidi_resolve_explicit(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
)
200 int overflow_isolate_count
= 0;
201 int overflow_embedding_count
= 0;
202 int valid_isolate_count
= 0;
205 StackItem stack
[MAX_DEPTH
+2];
206 int stack_top
= MAX_DEPTH
+1;
208 stack
[stack_top
].level
= baselevel
;
209 stack
[stack_top
].override
= NI
;
210 stack
[stack_top
].isolate
= FALSE
;
212 for (i
= 0; i
< count
; ++i
)
214 struct bidi_char
*c
= &chars
[i
];
215 UINT8 least_odd
, least_even
;
217 switch (c
->bidi_class
)
222 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
223 c
->resolved
= valid_level(least_odd
) ? least_odd
: stack
[stack_top
].level
;
224 if (valid_level(least_odd
))
225 push_stack(least_odd
, NI
, FALSE
);
226 else if (overflow_isolate_count
== 0)
227 overflow_embedding_count
++;
232 least_even
= get_greater_even_level(stack
[stack_top
].level
);
233 c
->resolved
= valid_level(least_even
) ? least_even
: stack
[stack_top
].level
;
234 if (valid_level(least_even
))
235 push_stack(least_even
, NI
, FALSE
);
236 else if (overflow_isolate_count
== 0)
237 overflow_embedding_count
++;
242 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
243 c
->resolved
= stack
[stack_top
].level
;
244 if (valid_level(least_odd
))
245 push_stack(least_odd
, R
, FALSE
);
246 else if (overflow_isolate_count
== 0)
247 overflow_embedding_count
++;
252 least_even
= get_greater_even_level(stack
[stack_top
].level
);
253 c
->resolved
= stack
[stack_top
].level
;
254 if (valid_level(least_even
))
255 push_stack(least_even
, L
, FALSE
);
256 else if (overflow_isolate_count
== 0)
257 overflow_embedding_count
++;
262 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
263 c
->resolved
= stack
[stack_top
].level
;
264 if (valid_level(least_odd
))
266 valid_isolate_count
++;
267 push_stack(least_odd
, NI
, TRUE
);
270 overflow_isolate_count
++;
275 least_even
= get_greater_even_level(stack
[stack_top
].level
);
276 c
->resolved
= stack
[stack_top
].level
;
277 if (valid_level(least_even
))
279 valid_isolate_count
++;
280 push_stack(least_even
, NI
, TRUE
);
283 overflow_isolate_count
++;
293 c
->resolved
= stack
[stack_top
].level
;
294 for (j
= i
+1; j
< count
; j
++)
296 const struct bidi_char
*p
= &chars
[j
];
298 if (p
->bidi_class
== LRI
|| p
->bidi_class
== RLI
|| p
->bidi_class
== FSI
)
303 else if (p
->bidi_class
== PDI
)
312 if (skipping
) continue;
314 if (p
->bidi_class
== L
)
319 else if (p
->bidi_class
== R
|| p
->bidi_class
== AL
)
327 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
328 if (valid_level(least_odd
))
330 valid_isolate_count
++;
331 push_stack(least_odd
, NI
, TRUE
);
334 overflow_isolate_count
++;
338 least_even
= get_greater_even_level(stack
[stack_top
].level
);
339 if (valid_level(least_even
))
341 valid_isolate_count
++;
342 push_stack(least_even
, NI
, TRUE
);
345 overflow_isolate_count
++;
363 c
->resolved
= stack
[stack_top
].level
;
364 if (stack
[stack_top
].override
!= NI
)
365 c
->resolved
= stack
[stack_top
].override
;
370 if (overflow_isolate_count
) overflow_isolate_count
--;
371 else if (!valid_isolate_count
) {/* do nothing */}
374 overflow_embedding_count
= 0;
375 while (!stack
[stack_top
].isolate
) pop_stack();
377 valid_isolate_count
--;
379 c
->resolved
= stack
[stack_top
].level
;
384 c
->resolved
= stack
[stack_top
].level
;
385 if (overflow_isolate_count
) {/* do nothing */}
386 else if (overflow_embedding_count
) overflow_embedding_count
--;
387 else if (!stack
[stack_top
].isolate
&& stack_top
< (MAX_DEPTH
+1))
393 c
->resolved
= baselevel
;
397 c
->explicit = c
->resolved
;
400 /* X9: Based on 5.2 Retaining Explicit Formatting Characters */
401 for (i
= 0; i
< count
; ++i
)
403 switch (chars
[i
].bidi_class
)
410 chars
[i
].bidi_class
= BN
;
418 static inline int get_prev_valid_char_index(const struct bidi_char
*chars
, int index
, int back_fence
)
420 if (index
== -1 || index
== back_fence
) return index
;
422 while (index
> back_fence
&& chars
[index
].bidi_class
== BN
) index
--;
426 static inline int get_next_valid_char_index(const struct bidi_char
*chars
, int index
, int front_fence
)
428 if (index
== front_fence
) return index
;
430 while (index
< front_fence
&& chars
[index
].bidi_class
== BN
) index
++;
434 typedef struct tagRun
441 typedef struct tagRunChar
447 typedef struct tagIsolatedRun
458 static inline int get_next_valid_char_from_run(IsolatedRun
*run
, int index
)
460 if (index
>= (run
->length
-1)) return -1;
462 while (index
< run
->length
&& *run
->item
[index
].class == BN
) index
++;
463 if (index
== run
->length
) return -1;
467 static inline int get_prev_valid_char_from_run(IsolatedRun
*run
, int index
)
469 if (index
<= 0) return -1;
471 while (index
> -1 && *run
->item
[index
].class == BN
) index
--;
475 static inline void iso_dump_types(const char* header
, IsolatedRun
*run
)
480 for (i
= 0; i
< run
->length
&& len
< 200; i
++) {
481 TRACE(" %s", debug_type
[*run
->item
[i
].class]);
482 len
+= strlen(debug_type
[*run
->item
[i
].class])+1;
484 if (i
!= run
->length
)
489 /*------------------------------------------------------------------------
490 Function: bidi_resolve_weak
492 Resolves the directionality of numeric and other weak character types
494 Implements rules X10 and W1-W6 of the Unicode Bidirectional Algorithm.
496 Input: Array of embedding levels
499 In/Out: Array of directional classes
501 Note: On input only these directional classes are expected
502 AL, HL, R, L, ON, BN, NSM, AN, EN, ES, ET, CS,
503 ------------------------------------------------------------------------*/
504 static BOOL
bidi_is_isolate(UINT8
class)
506 return class == LRI
|| class == RLI
|| class == FSI
|| class == PDI
;
509 static void bidi_resolve_weak(IsolatedRun
*iso_run
)
514 for (i
=0; i
< iso_run
->length
; i
++) {
515 if (*iso_run
->item
[i
].class == NSM
) {
516 int j
= get_prev_valid_char_from_run(iso_run
, i
);
518 *iso_run
->item
[i
].class = iso_run
->sos
;
519 else if (bidi_is_isolate(*iso_run
->item
[j
].class))
520 *iso_run
->item
[i
].class = ON
;
522 *iso_run
->item
[i
].class = *iso_run
->item
[j
].class;
527 for (i
= 0; i
< iso_run
->length
; i
++) {
528 if (*iso_run
->item
[i
].class == EN
) {
529 int j
= get_prev_valid_char_from_run(iso_run
, i
);
531 if (*iso_run
->item
[j
].class == R
|| *iso_run
->item
[j
].class == L
|| *iso_run
->item
[j
].class == AL
) {
532 if (*iso_run
->item
[j
].class == AL
)
533 *iso_run
->item
[i
].class = AN
;
536 j
= get_prev_valid_char_from_run(iso_run
, j
);
542 for (i
= 0; i
< iso_run
->length
; i
++) {
543 if (*iso_run
->item
[i
].class == AL
)
544 *iso_run
->item
[i
].class = R
;
548 for (i
= 0; i
< iso_run
->length
; i
++) {
549 if (*iso_run
->item
[i
].class == ES
) {
550 int b
= get_prev_valid_char_from_run(iso_run
, i
);
551 int f
= get_next_valid_char_from_run(iso_run
, i
);
553 if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == EN
&& *iso_run
->item
[f
].class == EN
)
554 *iso_run
->item
[i
].class = EN
;
556 else if (*iso_run
->item
[i
].class == CS
) {
557 int b
= get_prev_valid_char_from_run(iso_run
, i
);
558 int f
= get_next_valid_char_from_run(iso_run
, i
);
560 if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == EN
&& *iso_run
->item
[f
].class == EN
)
561 *iso_run
->item
[i
].class = EN
;
562 else if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == AN
&& *iso_run
->item
[f
].class == AN
)
563 *iso_run
->item
[i
].class = AN
;
568 for (i
= 0; i
< iso_run
->length
; i
++) {
569 if (*iso_run
->item
[i
].class == ET
) {
571 for (j
= i
-1 ; j
> -1; j
--) {
572 if (*iso_run
->item
[j
].class == BN
) continue;
573 if (*iso_run
->item
[j
].class == ET
) continue;
574 else if (*iso_run
->item
[j
].class == EN
) *iso_run
->item
[i
].class = EN
;
577 if (*iso_run
->item
[i
].class == ET
) {
578 for (j
= i
+1; j
< iso_run
->length
; j
++) {
579 if (*iso_run
->item
[j
].class == BN
) continue;
580 if (*iso_run
->item
[j
].class == ET
) continue;
581 else if (*iso_run
->item
[j
].class == EN
) *iso_run
->item
[i
].class = EN
;
589 for (i
= 0; i
< iso_run
->length
; i
++) {
590 if (*iso_run
->item
[i
].class == ET
|| *iso_run
->item
[i
].class == ES
|| *iso_run
->item
[i
].class == CS
|| *iso_run
->item
[i
].class == ON
)
594 if (b
> -1 && *iso_run
->item
[b
].class == BN
)
595 *iso_run
->item
[b
].class = ON
;
596 if (f
< iso_run
->length
&& *iso_run
->item
[f
].class == BN
)
597 *iso_run
->item
[f
].class = ON
;
599 *iso_run
->item
[i
].class = ON
;
604 for (i
= 0; i
< iso_run
->length
; i
++) {
605 if (*iso_run
->item
[i
].class == EN
) {
607 for (j
= get_prev_valid_char_from_run(iso_run
, i
); j
> -1; j
= get_prev_valid_char_from_run(iso_run
, j
))
608 if (*iso_run
->item
[j
].class == R
|| *iso_run
->item
[j
].class == L
) {
609 if (*iso_run
->item
[j
].class == L
)
610 *iso_run
->item
[i
].class = L
;
613 if (iso_run
->sos
== L
&& j
== -1)
614 *iso_run
->item
[i
].class = L
;
619 typedef struct tagBracketPair
625 static int __cdecl
bracketpair_compr(const void *a
, const void* b
)
627 return ((BracketPair
*)a
)->start
- ((BracketPair
*)b
)->start
;
630 static BracketPair
*bidi_compute_bracket_pairs(IsolatedRun
*iso_run
)
634 int stack_top
= iso_run
->length
;
635 BracketPair
*out
= NULL
;
639 open_stack
= malloc(sizeof(WCHAR
) * iso_run
->length
);
640 stack_index
= malloc(sizeof(int) * iso_run
->length
);
642 for (i
= 0; i
< iso_run
->length
; i
++) {
643 unsigned short ubv
= get_table_entry_16(bidi_bracket_table
, iso_run
->item
[i
].ch
);
648 out
= malloc(sizeof(BracketPair
));
652 if ((ubv
>> 8) == 0) {
654 open_stack
[stack_top
] = iso_run
->item
[i
].ch
+ (signed char)(ubv
& 0xff);
655 /* deal with canonical equivalent U+2329/232A and U+3008/3009 */
656 if (open_stack
[stack_top
] == 0x232A)
657 open_stack
[stack_top
] = 0x3009;
658 stack_index
[stack_top
] = i
;
660 else if ((ubv
>> 8) == 1) {
663 if (stack_top
== iso_run
->length
) continue;
664 for (j
= stack_top
; j
< iso_run
->length
; j
++) {
665 WCHAR c
= iso_run
->item
[i
].ch
;
666 if (c
== 0x232A) c
= 0x3009;
667 if (c
== open_stack
[j
]) {
668 out
[pair_count
].start
= stack_index
[j
];
669 out
[pair_count
].end
= i
;
671 out
= realloc(out
, sizeof(BracketPair
) * (pair_count
+1));
672 out
[pair_count
].start
= -1;
685 else if (pair_count
> 1)
686 qsort(out
, pair_count
, sizeof(BracketPair
), bracketpair_compr
);
693 static inline UINT8
get_rule_N0_class(UINT8
class)
695 return (class == AN
|| class == EN
) ? R
: class;
698 /*------------------------------------------------------------------------
699 Function: bidi_resolve_neutrals
701 Resolves the directionality of neutral character types.
703 Implements rules N1 and N2 of the Unicode Bidi Algorithm.
705 Input: Array of embedding levels
709 In/Out: Array of directional classes
711 Note: On input only these directional classes are expected
712 R, L, NI, AN, EN and BN
714 W8 resolves a number of ENs to L
715 ------------------------------------------------------------------------*/
716 static void bidi_resolve_neutrals(IsolatedRun
*run
)
721 /* Translate isolates into NI */
722 for (i
= 0; i
< run
->length
; i
++) {
723 switch (*run
->item
[i
].class) {
730 case PDI
: *run
->item
[i
].class = NI
;
733 /* "Only NI, L, R, AN, EN and BN are allowed" */
734 ASSERT(*run
->item
[i
].class <= EN
|| *run
->item
[i
].class == BN
);
737 /* N0: Skipping bracketed pairs for now */
738 pairs
= bidi_compute_bracket_pairs(run
);
740 BracketPair
*p
= pairs
;
742 while (p
->start
>= 0) {
743 UINT8 e
= get_embedding_direction(run
->e
);
744 UINT8 o
= get_embedding_direction(run
->e
+ 1);
748 TRACE("Bracket Pair [%i - %i]\n", p
->start
, p
->end
);
751 for (j
= p
->start
+1; j
< p
->end
; j
++) {
752 if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
753 *run
->item
[p
->start
].class = e
;
754 *run
->item
[p
->end
].class = e
;
757 else if (get_rule_N0_class(*run
->item
[j
].class) == o
)
761 if (j
== p
->end
&& flag_o
) {
762 for (j
= p
->start
; j
>= 0; j
--) {
763 if (get_rule_N0_class(*run
->item
[j
].class) == o
) {
764 *run
->item
[p
->start
].class = o
;
765 *run
->item
[p
->end
].class = o
;
768 else if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
769 *run
->item
[p
->start
].class = e
;
770 *run
->item
[p
->end
].class = e
;
775 *run
->item
[p
->start
].class = run
->sos
;
776 *run
->item
[p
->end
].class = run
->sos
;
787 for (i
= 0; i
< run
->length
; i
++) {
790 if (*run
->item
[i
].class == NI
) {
791 int b
= get_prev_valid_char_from_run(run
, i
);
799 if (*run
->item
[b
].class == R
|| *run
->item
[b
].class == AN
|| *run
->item
[b
].class == EN
)
801 else if (*run
->item
[b
].class == L
)
803 else /* No string type */
806 j
= get_next_valid_char_from_run(run
, i
);
807 while (j
> -1 && *run
->item
[j
].class == NI
) j
= get_next_valid_char_from_run(run
, j
);
812 else if (*run
->item
[j
].class == R
|| *run
->item
[j
].class == AN
|| *run
->item
[j
].class == EN
)
814 else if (*run
->item
[j
].class == L
)
816 else /* No string type */
820 for (b
= i
; b
< j
&& b
< run
->length
; b
++)
821 *run
->item
[b
].class = r
;
827 for (i
= 0; i
< run
->length
; i
++) {
828 if (*run
->item
[i
].class == NI
) {
832 *run
->item
[i
].class = get_embedding_direction(run
->e
);
833 if (b
> -1 && *run
->item
[b
].class == BN
)
834 *run
->item
[b
].class = get_embedding_direction(run
->e
);
835 if (f
< run
->length
&& *run
->item
[f
].class == BN
)
836 *run
->item
[f
].class = get_embedding_direction(run
->e
);
841 /*------------------------------------------------------------------------
842 Function: bidi_resolve_implicit
844 Recursively resolves implicit embedding levels.
845 Implements rules I1 and I2 of the Unicode Bidirectional Algorithm.
847 Note: levels may exceed 15 on output.
848 Accepted subset of direction classes
850 ------------------------------------------------------------------------*/
851 static void bidi_resolve_implicit(struct bidi_char
*chars
, unsigned int count
)
856 for (i
= 0; i
< count
; ++i
)
858 struct bidi_char
*c
= &chars
[i
];
860 if (c
->bidi_class
== BN
)
863 ASSERT(c
->bidi_class
!= ON
); /* "No Neutrals allowed to survive here." */
864 ASSERT(c
->bidi_class
<= EN
); /* "Out of range." */
866 if (odd(c
->resolved
) && (c
->bidi_class
== L
|| c
->bidi_class
== EN
|| c
->bidi_class
== AN
))
868 else if (!odd(c
->resolved
) && c
->bidi_class
== R
)
870 else if (!odd(c
->resolved
) && (c
->bidi_class
== EN
|| c
->bidi_class
== AN
))
875 static inline BOOL
is_rule_L1_reset_class(UINT8
class)
895 static void bidi_resolve_resolved(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
)
897 int i
, sos
= 0, eos
= count
- 1;
900 for (i
= sos
; i
<= eos
; i
++)
902 switch (chars
[i
].nominal_bidi_class
)
908 while (i
> sos
&& j
>= sos
&& is_rule_L1_reset_class(chars
[j
].nominal_bidi_class
))
909 chars
[j
--].resolved
= baselevel
;
910 chars
[i
].resolved
= baselevel
;
913 case LRE
: case RLE
: case LRO
: case RLO
: case PDF
: case BN
:
914 chars
[i
].resolved
= i
? chars
[i
- 1].resolved
: baselevel
;
920 if (i
== eos
&& is_rule_L1_reset_class(chars
[i
].nominal_bidi_class
))
923 while (j
>= sos
&& is_rule_L1_reset_class(chars
[j
].nominal_bidi_class
))
924 chars
[j
--].resolved
= baselevel
;
929 static HRESULT
bidi_compute_isolating_runs_set(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
, struct list
*set
)
931 int run_start
, run_end
, i
;
936 if (!(runs
= calloc(count
, sizeof(*runs
))))
937 return E_OUTOFMEMORY
;
943 while (run_start
< count
)
945 run_end
= get_next_valid_char_index(chars
, run_start
, count
);
946 while (run_end
< count
&& chars
[run_end
].resolved
== chars
[run_start
].resolved
)
947 run_end
= get_next_valid_char_index(chars
, run_end
, count
);
949 runs
[run_count
].start
= run_start
;
950 runs
[run_count
].end
= run_end
;
951 runs
[run_count
].e
= chars
[run_start
].resolved
;
952 run_start
= get_next_valid_char_index(chars
, run_end
, count
);
956 /* Build Isolating Runs */
958 while (i
< run_count
)
961 if (runs
[k
].start
>= 0)
963 IsolatedRun
*current_isolated
;
964 int type_fence
, real_end
;
967 if (!(current_isolated
= malloc(sizeof(IsolatedRun
) + sizeof(RunChar
)*count
)))
973 run_start
= runs
[k
].start
;
974 current_isolated
->e
= runs
[k
].e
;
975 current_isolated
->length
= (runs
[k
].end
- runs
[k
].start
)+1;
977 for (j
= 0; j
< current_isolated
->length
; ++j
)
979 current_isolated
->item
[j
].class = &chars
[runs
[k
].start
+j
].bidi_class
;
980 current_isolated
->item
[j
].ch
= chars
[runs
[k
].start
+j
].ch
;
983 run_end
= runs
[k
].end
;
985 TRACE("{ [%i -- %i]",run_start
, run_end
);
987 if (chars
[run_end
].bidi_class
== BN
)
988 run_end
= get_prev_valid_char_index(chars
, run_end
, runs
[k
].start
);
990 while (run_end
< count
&& (chars
[run_end
].bidi_class
== RLI
|| chars
[run_end
].bidi_class
== LRI
|| chars
[run_end
].bidi_class
== FSI
))
994 while (j
< run_count
&& chars
[runs
[j
].start
].bidi_class
!= PDI
) j
++;
995 if (j
< run_count
&& runs
[i
].e
!= runs
[j
].e
) {
1002 int l
= current_isolated
->length
;
1005 current_isolated
->length
+= (runs
[j
].end
- runs
[j
].start
)+1;
1006 for (m
= 0; l
< current_isolated
->length
; l
++, m
++) {
1007 current_isolated
->item
[l
].class = &chars
[runs
[j
].start
+ m
].bidi_class
;
1008 current_isolated
->item
[l
].ch
= chars
[runs
[j
].start
+ m
].ch
;
1011 TRACE("[%i -- %i]", runs
[j
].start
, runs
[j
].end
);
1013 run_end
= runs
[j
].end
;
1014 if (chars
[run_end
].bidi_class
== BN
)
1015 run_end
= get_prev_valid_char_index(chars
, run_end
, runs
[i
].start
);
1025 type_fence
= get_prev_valid_char_index(chars
, run_start
, -1);
1027 if (type_fence
== -1)
1028 current_isolated
->sos
= max(baselevel
, chars
[run_start
].resolved
);
1030 current_isolated
->sos
= max(chars
[type_fence
].resolved
, chars
[run_start
].resolved
);
1032 current_isolated
->sos
= get_embedding_direction(current_isolated
->sos
);
1034 if (run_end
== count
)
1035 current_isolated
->eos
= current_isolated
->sos
;
1038 /* eos could be an BN */
1039 if (chars
[run_end
].resolved
== BN
)
1041 real_end
= get_prev_valid_char_index(chars
, run_end
, run_start
- 1);
1042 if (real_end
< run_start
)
1043 real_end
= run_start
;
1048 type_fence
= get_next_valid_char_index(chars
, run_end
, count
);
1049 if (type_fence
== count
)
1050 current_isolated
->eos
= max(baselevel
, chars
[real_end
].resolved
);
1052 current_isolated
->eos
= max(chars
[type_fence
].resolved
, chars
[real_end
].resolved
);
1054 current_isolated
->eos
= get_embedding_direction(current_isolated
->eos
);
1057 list_add_tail(set
, ¤t_isolated
->entry
);
1058 TRACE(" } level %i {%s <--> %s}\n", current_isolated
->e
, debug_type
[current_isolated
->sos
], debug_type
[current_isolated
->eos
]);
1067 HRESULT
bidi_computelevels(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
)
1069 IsolatedRun
*iso_run
, *next
;
1070 struct list IsolatingRuns
;
1073 if (TRACE_ON(bidi
)) bidi_dump_types("start ", chars
, 0, count
);
1075 bidi_resolve_explicit(chars
, count
, baselevel
);
1077 if (TRACE_ON(bidi
)) bidi_dump_types("after explicit", chars
, 0, count
);
1079 /* X10/BD13: Compute Isolating runs */
1080 if (FAILED(hr
= bidi_compute_isolating_runs_set(chars
, count
, baselevel
, &IsolatingRuns
)))
1082 WARN("Failed to compute isolating runs set, hr %#lx.\n", hr
);
1086 LIST_FOR_EACH_ENTRY_SAFE(iso_run
, next
, &IsolatingRuns
, IsolatedRun
, entry
)
1088 if (TRACE_ON(bidi
)) iso_dump_types("run", iso_run
);
1090 bidi_resolve_weak(iso_run
);
1091 if (TRACE_ON(bidi
)) iso_dump_types("after weak", iso_run
);
1093 bidi_resolve_neutrals(iso_run
);
1094 if (TRACE_ON(bidi
)) iso_dump_types("after neutrals", iso_run
);
1096 list_remove(&iso_run
->entry
);
1100 if (TRACE_ON(bidi
)) bidi_dump_types("before implicit", chars
, 0, count
);
1101 bidi_resolve_implicit(chars
, count
);
1103 bidi_resolve_resolved(chars
, count
, baselevel
);