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
;
639 open_stack
= malloc(sizeof(WCHAR
) * iso_run
->length
);
640 stack_index
= malloc(sizeof(int) * iso_run
->length
);
641 out
= malloc(sizeof(BracketPair
) * iso_run
->length
);
643 if (!open_stack
|| !stack_index
|| !out
) {
652 for (i
= 0; i
< iso_run
->length
; i
++) {
653 unsigned short ubv
= get_table_entry_16(bidi_bracket_table
, iso_run
->item
[i
].ch
);
656 if ((ubv
>> 8) == 0) {
658 open_stack
[stack_top
] = iso_run
->item
[i
].ch
+ (signed char)(ubv
& 0xff);
659 /* deal with canonical equivalent U+2329/232A and U+3008/3009 */
660 if (open_stack
[stack_top
] == 0x232A)
661 open_stack
[stack_top
] = 0x3009;
662 stack_index
[stack_top
] = i
;
664 else if ((ubv
>> 8) == 1) {
667 if (stack_top
== iso_run
->length
) continue;
668 for (j
= stack_top
; j
< iso_run
->length
; j
++) {
669 WCHAR c
= iso_run
->item
[i
].ch
;
670 if (c
== 0x232A) c
= 0x3009;
671 if (c
== open_stack
[j
]) {
672 out
[pair_count
].start
= stack_index
[j
];
673 out
[pair_count
].end
= i
;
675 out
[pair_count
].start
= -1;
688 else if (pair_count
> 1)
689 qsort(out
, pair_count
, sizeof(BracketPair
), bracketpair_compr
);
696 static inline UINT8
get_rule_N0_class(UINT8
class)
698 return (class == AN
|| class == EN
) ? R
: class;
701 /*------------------------------------------------------------------------
702 Function: bidi_resolve_neutrals
704 Resolves the directionality of neutral character types.
706 Implements rules N1 and N2 of the Unicode Bidi Algorithm.
708 Input: Array of embedding levels
712 In/Out: Array of directional classes
714 Note: On input only these directional classes are expected
715 R, L, NI, AN, EN and BN
717 W8 resolves a number of ENs to L
718 ------------------------------------------------------------------------*/
719 static void bidi_resolve_neutrals(IsolatedRun
*run
)
724 /* Translate isolates into NI */
725 for (i
= 0; i
< run
->length
; i
++) {
726 switch (*run
->item
[i
].class) {
733 case PDI
: *run
->item
[i
].class = NI
;
736 /* "Only NI, L, R, AN, EN and BN are allowed" */
737 ASSERT(*run
->item
[i
].class <= EN
|| *run
->item
[i
].class == BN
);
740 /* N0: Skipping bracketed pairs for now */
741 pairs
= bidi_compute_bracket_pairs(run
);
743 BracketPair
*p
= pairs
;
745 while (p
->start
>= 0) {
746 UINT8 e
= get_embedding_direction(run
->e
);
747 UINT8 o
= get_embedding_direction(run
->e
+ 1);
751 TRACE("Bracket Pair [%i - %i]\n", p
->start
, p
->end
);
754 for (j
= p
->start
+1; j
< p
->end
; j
++) {
755 if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
756 *run
->item
[p
->start
].class = e
;
757 *run
->item
[p
->end
].class = e
;
760 else if (get_rule_N0_class(*run
->item
[j
].class) == o
)
764 if (j
== p
->end
&& flag_o
) {
765 for (j
= p
->start
; j
>= 0; j
--) {
766 if (get_rule_N0_class(*run
->item
[j
].class) == o
) {
767 *run
->item
[p
->start
].class = o
;
768 *run
->item
[p
->end
].class = o
;
771 else if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
772 *run
->item
[p
->start
].class = e
;
773 *run
->item
[p
->end
].class = e
;
778 *run
->item
[p
->start
].class = run
->sos
;
779 *run
->item
[p
->end
].class = run
->sos
;
790 for (i
= 0; i
< run
->length
; i
++) {
793 if (*run
->item
[i
].class == NI
) {
794 int b
= get_prev_valid_char_from_run(run
, i
);
802 if (*run
->item
[b
].class == R
|| *run
->item
[b
].class == AN
|| *run
->item
[b
].class == EN
)
804 else if (*run
->item
[b
].class == L
)
806 else /* No string type */
809 j
= get_next_valid_char_from_run(run
, i
);
810 while (j
> -1 && *run
->item
[j
].class == NI
) j
= get_next_valid_char_from_run(run
, j
);
815 else if (*run
->item
[j
].class == R
|| *run
->item
[j
].class == AN
|| *run
->item
[j
].class == EN
)
817 else if (*run
->item
[j
].class == L
)
819 else /* No string type */
823 for (b
= i
; b
< j
&& b
< run
->length
; b
++)
824 *run
->item
[b
].class = r
;
830 for (i
= 0; i
< run
->length
; i
++) {
831 if (*run
->item
[i
].class == NI
) {
835 *run
->item
[i
].class = get_embedding_direction(run
->e
);
836 if (b
> -1 && *run
->item
[b
].class == BN
)
837 *run
->item
[b
].class = get_embedding_direction(run
->e
);
838 if (f
< run
->length
&& *run
->item
[f
].class == BN
)
839 *run
->item
[f
].class = get_embedding_direction(run
->e
);
844 /*------------------------------------------------------------------------
845 Function: bidi_resolve_implicit
847 Recursively resolves implicit embedding levels.
848 Implements rules I1 and I2 of the Unicode Bidirectional Algorithm.
850 Note: levels may exceed 15 on output.
851 Accepted subset of direction classes
853 ------------------------------------------------------------------------*/
854 static void bidi_resolve_implicit(struct bidi_char
*chars
, unsigned int count
)
859 for (i
= 0; i
< count
; ++i
)
861 struct bidi_char
*c
= &chars
[i
];
863 if (c
->bidi_class
== BN
)
866 ASSERT(c
->bidi_class
!= ON
); /* "No Neutrals allowed to survive here." */
867 ASSERT(c
->bidi_class
<= EN
); /* "Out of range." */
869 if (odd(c
->resolved
) && (c
->bidi_class
== L
|| c
->bidi_class
== EN
|| c
->bidi_class
== AN
))
871 else if (!odd(c
->resolved
) && c
->bidi_class
== R
)
873 else if (!odd(c
->resolved
) && (c
->bidi_class
== EN
|| c
->bidi_class
== AN
))
878 static inline BOOL
is_rule_L1_reset_class(UINT8
class)
898 static void bidi_resolve_resolved(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
)
900 int i
, sos
= 0, eos
= count
- 1;
903 for (i
= sos
; i
<= eos
; i
++)
905 switch (chars
[i
].nominal_bidi_class
)
911 while (i
> sos
&& j
>= sos
&& is_rule_L1_reset_class(chars
[j
].nominal_bidi_class
))
912 chars
[j
--].resolved
= baselevel
;
913 chars
[i
].resolved
= baselevel
;
916 case LRE
: case RLE
: case LRO
: case RLO
: case PDF
: case BN
:
917 chars
[i
].resolved
= i
? chars
[i
- 1].resolved
: baselevel
;
923 if (i
== eos
&& is_rule_L1_reset_class(chars
[i
].nominal_bidi_class
))
926 while (j
>= sos
&& is_rule_L1_reset_class(chars
[j
].nominal_bidi_class
))
927 chars
[j
--].resolved
= baselevel
;
932 static HRESULT
bidi_compute_isolating_runs_set(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
, struct list
*set
)
934 int run_start
, run_end
, i
;
939 if (!(runs
= calloc(count
, sizeof(*runs
))))
940 return E_OUTOFMEMORY
;
946 while (run_start
< count
)
948 run_end
= get_next_valid_char_index(chars
, run_start
, count
);
949 while (run_end
< count
&& chars
[run_end
].resolved
== chars
[run_start
].resolved
)
950 run_end
= get_next_valid_char_index(chars
, run_end
, count
);
952 runs
[run_count
].start
= run_start
;
953 runs
[run_count
].end
= run_end
;
954 runs
[run_count
].e
= chars
[run_start
].resolved
;
955 run_start
= get_next_valid_char_index(chars
, run_end
, count
);
959 /* Build Isolating Runs */
961 while (i
< run_count
)
964 if (runs
[k
].start
>= 0)
966 IsolatedRun
*current_isolated
;
967 int type_fence
, real_end
;
970 if (!(current_isolated
= malloc(sizeof(IsolatedRun
) + sizeof(RunChar
)*count
)))
976 run_start
= runs
[k
].start
;
977 current_isolated
->e
= runs
[k
].e
;
978 current_isolated
->length
= (runs
[k
].end
- runs
[k
].start
)+1;
980 for (j
= 0; j
< current_isolated
->length
; ++j
)
982 current_isolated
->item
[j
].class = &chars
[runs
[k
].start
+j
].bidi_class
;
983 current_isolated
->item
[j
].ch
= chars
[runs
[k
].start
+j
].ch
;
986 run_end
= runs
[k
].end
;
988 TRACE("{ [%i -- %i]",run_start
, run_end
);
990 if (chars
[run_end
].bidi_class
== BN
)
991 run_end
= get_prev_valid_char_index(chars
, run_end
, runs
[k
].start
);
993 while (run_end
< count
&& (chars
[run_end
].bidi_class
== RLI
|| chars
[run_end
].bidi_class
== LRI
|| chars
[run_end
].bidi_class
== FSI
))
997 while (j
< run_count
&& chars
[runs
[j
].start
].bidi_class
!= PDI
) j
++;
998 if (j
< run_count
&& runs
[i
].e
!= runs
[j
].e
) {
1005 int l
= current_isolated
->length
;
1008 current_isolated
->length
+= (runs
[j
].end
- runs
[j
].start
)+1;
1009 for (m
= 0; l
< current_isolated
->length
; l
++, m
++) {
1010 current_isolated
->item
[l
].class = &chars
[runs
[j
].start
+ m
].bidi_class
;
1011 current_isolated
->item
[l
].ch
= chars
[runs
[j
].start
+ m
].ch
;
1014 TRACE("[%i -- %i]", runs
[j
].start
, runs
[j
].end
);
1016 run_end
= runs
[j
].end
;
1017 if (chars
[run_end
].bidi_class
== BN
)
1018 run_end
= get_prev_valid_char_index(chars
, run_end
, runs
[i
].start
);
1028 type_fence
= get_prev_valid_char_index(chars
, run_start
, -1);
1030 if (type_fence
== -1)
1031 current_isolated
->sos
= max(baselevel
, chars
[run_start
].resolved
);
1033 current_isolated
->sos
= max(chars
[type_fence
].resolved
, chars
[run_start
].resolved
);
1035 current_isolated
->sos
= get_embedding_direction(current_isolated
->sos
);
1037 if (run_end
== count
)
1038 current_isolated
->eos
= current_isolated
->sos
;
1041 /* eos could be an BN */
1042 if (chars
[run_end
].resolved
== BN
)
1044 real_end
= get_prev_valid_char_index(chars
, run_end
, run_start
- 1);
1045 if (real_end
< run_start
)
1046 real_end
= run_start
;
1051 type_fence
= get_next_valid_char_index(chars
, run_end
, count
);
1052 if (type_fence
== count
)
1053 current_isolated
->eos
= max(baselevel
, chars
[real_end
].resolved
);
1055 current_isolated
->eos
= max(chars
[type_fence
].resolved
, chars
[real_end
].resolved
);
1057 current_isolated
->eos
= get_embedding_direction(current_isolated
->eos
);
1060 list_add_tail(set
, ¤t_isolated
->entry
);
1061 TRACE(" } level %i {%s <--> %s}\n", current_isolated
->e
, debug_type
[current_isolated
->sos
], debug_type
[current_isolated
->eos
]);
1070 HRESULT
bidi_computelevels(struct bidi_char
*chars
, unsigned int count
, UINT8 baselevel
)
1072 IsolatedRun
*iso_run
, *next
;
1073 struct list IsolatingRuns
;
1076 if (TRACE_ON(bidi
)) bidi_dump_types("start ", chars
, 0, count
);
1078 bidi_resolve_explicit(chars
, count
, baselevel
);
1080 if (TRACE_ON(bidi
)) bidi_dump_types("after explicit", chars
, 0, count
);
1082 /* X10/BD13: Compute Isolating runs */
1083 if (FAILED(hr
= bidi_compute_isolating_runs_set(chars
, count
, baselevel
, &IsolatingRuns
)))
1085 WARN("Failed to compute isolating runs set, hr %#lx.\n", hr
);
1089 LIST_FOR_EACH_ENTRY_SAFE(iso_run
, next
, &IsolatingRuns
, IsolatedRun
, entry
)
1091 if (TRACE_ON(bidi
)) iso_dump_types("run", iso_run
);
1093 bidi_resolve_weak(iso_run
);
1094 if (TRACE_ON(bidi
)) iso_dump_types("after weak", iso_run
);
1096 bidi_resolve_neutrals(iso_run
);
1097 if (TRACE_ON(bidi
)) iso_dump_types("after neutrals", iso_run
);
1099 list_remove(&iso_run
->entry
);
1103 if (TRACE_ON(bidi
)) bidi_dump_types("before implicit", chars
, 0, count
);
1104 bidi_resolve_implicit(chars
, count
);
1106 bidi_resolve_resolved(chars
, count
, baselevel
);