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 UINT8
*types
, UINT32 start
, UINT32 end
)
142 TRACE("%s:", header
);
143 for (i
= start
; i
< end
&& len
< 200; i
++) {
144 TRACE(" %s", debug_type
[types
[i
]]);
145 len
+= strlen(debug_type
[types
[i
]])+1;
152 /* Convert the libwine information to the direction enum */
153 static void bidi_classify(const WCHAR
*string
, UINT8
*chartype
, UINT32 count
)
157 for (i
= 0; i
< count
; ++i
)
158 chartype
[i
] = get_table_entry( bidi_direction_table
, string
[i
] );
161 /* RESOLVE EXPLICIT */
163 static inline UINT8
get_greater_even_level(UINT8 level
)
165 return odd(level
) ? level
+ 1 : level
+ 2;
168 static inline UINT8
get_greater_odd_level(UINT8 level
)
170 return odd(level
) ? level
+ 2 : level
+ 1;
173 static inline UINT8
get_embedding_direction(UINT8 level
)
175 return odd(level
) ? R
: L
;
178 /*------------------------------------------------------------------------
179 Function: bidi_resolve_explicit
181 Recursively resolves explicit embedding levels and overrides.
182 Implements rules X1-X9, of the Unicode Bidirectional Algorithm.
184 Input: Base embedding level and direction
187 Output: Array of embedding levels
189 In/Out: Array of direction classes
192 Note: The function uses two simple counters to keep track of
193 matching explicit codes and PDF. Use the default argument for
194 the outermost call. The nesting counter counts the recursion
195 depth and not the embedding level.
196 ------------------------------------------------------------------------*/
197 typedef struct tagStackItem
204 #define push_stack(l,o,i) \
206 stack[stack_top].level = l; \
207 stack[stack_top].override = o; \
208 stack[stack_top].isolate = i;} while(0)
210 #define pop_stack() do { stack_top++; } while(0)
212 #define valid_level(x) (x <= MAX_DEPTH && overflow_isolate_count == 0 && overflow_embedding_count == 0)
214 static void bidi_resolve_explicit(UINT8 baselevel
, UINT8
*classes
, UINT8
*levels
, UINT32 count
)
217 int overflow_isolate_count
= 0;
218 int overflow_embedding_count
= 0;
219 int valid_isolate_count
= 0;
222 StackItem stack
[MAX_DEPTH
+2];
223 int stack_top
= MAX_DEPTH
+1;
225 stack
[stack_top
].level
= baselevel
;
226 stack
[stack_top
].override
= NI
;
227 stack
[stack_top
].isolate
= FALSE
;
229 for (i
= 0; i
< count
; i
++) {
230 UINT8 least_odd
, least_even
;
232 switch (classes
[i
]) {
236 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
237 levels
[i
] = valid_level(least_odd
) ? least_odd
: stack
[stack_top
].level
;
238 if (valid_level(least_odd
))
239 push_stack(least_odd
, NI
, FALSE
);
240 else if (overflow_isolate_count
== 0)
241 overflow_embedding_count
++;
246 least_even
= get_greater_even_level(stack
[stack_top
].level
);
247 levels
[i
] = valid_level(least_even
) ? least_even
: stack
[stack_top
].level
;
248 if (valid_level(least_even
))
249 push_stack(least_even
, NI
, FALSE
);
250 else if (overflow_isolate_count
== 0)
251 overflow_embedding_count
++;
256 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
257 levels
[i
] = stack
[stack_top
].level
;
258 if (valid_level(least_odd
))
259 push_stack(least_odd
, R
, FALSE
);
260 else if (overflow_isolate_count
== 0)
261 overflow_embedding_count
++;
266 least_even
= get_greater_even_level(stack
[stack_top
].level
);
267 levels
[i
] = stack
[stack_top
].level
;
268 if (valid_level(least_even
))
269 push_stack(least_even
, L
, FALSE
);
270 else if (overflow_isolate_count
== 0)
271 overflow_embedding_count
++;
276 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
277 levels
[i
] = stack
[stack_top
].level
;
278 if (valid_level(least_odd
))
280 valid_isolate_count
++;
281 push_stack(least_odd
, NI
, TRUE
);
284 overflow_isolate_count
++;
289 least_even
= get_greater_even_level(stack
[stack_top
].level
);
290 levels
[i
] = stack
[stack_top
].level
;
291 if (valid_level(least_even
))
293 valid_isolate_count
++;
294 push_stack(least_even
, NI
, TRUE
);
297 overflow_isolate_count
++;
307 levels
[i
] = stack
[stack_top
].level
;
308 for (j
= i
+1; j
< count
; j
++)
310 if (classes
[j
] == LRI
|| classes
[j
] == RLI
|| classes
[j
] == FSI
)
315 else if (classes
[j
] == PDI
)
324 if (skipping
) continue;
331 else if (classes
[j
] == R
|| classes
[j
] == AL
)
339 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
340 if (valid_level(least_odd
))
342 valid_isolate_count
++;
343 push_stack(least_odd
, NI
, TRUE
);
346 overflow_isolate_count
++;
350 least_even
= get_greater_even_level(stack
[stack_top
].level
);
351 if (valid_level(least_even
))
353 valid_isolate_count
++;
354 push_stack(least_even
, NI
, TRUE
);
357 overflow_isolate_count
++;
375 levels
[i
] = stack
[stack_top
].level
;
376 if (stack
[stack_top
].override
!= NI
)
377 classes
[i
] = stack
[stack_top
].override
;
382 if (overflow_isolate_count
) overflow_isolate_count
--;
383 else if (!valid_isolate_count
) {/* do nothing */}
386 overflow_embedding_count
= 0;
387 while (!stack
[stack_top
].isolate
) pop_stack();
389 valid_isolate_count
--;
391 levels
[i
] = stack
[stack_top
].level
;
396 levels
[i
] = stack
[stack_top
].level
;
397 if (overflow_isolate_count
) {/* do nothing */}
398 else if (overflow_embedding_count
) overflow_embedding_count
--;
399 else if (!stack
[stack_top
].isolate
&& stack_top
< (MAX_DEPTH
+1))
405 levels
[i
] = baselevel
;
409 /* X9: Based on 5.2 Retaining Explicit Formatting Characters */
410 for (i
= 0; i
< count
; i
++)
411 if (classes
[i
] == RLE
|| classes
[i
] == LRE
|| classes
[i
] == RLO
|| classes
[i
] == LRO
|| classes
[i
] == PDF
)
415 static inline int get_prev_valid_char_index(const UINT8
*classes
, int index
, int back_fence
)
417 if (index
== -1 || index
== back_fence
) return index
;
419 while (index
> back_fence
&& classes
[index
] == BN
) index
--;
423 static inline int get_next_valid_char_index(const UINT8
*classes
, int index
, int front_fence
)
425 if (index
== front_fence
) return index
;
427 while (index
< front_fence
&& classes
[index
] == BN
) index
++;
431 typedef struct tagRun
438 typedef struct tagRunChar
444 typedef struct tagIsolatedRun
455 static inline int get_next_valid_char_from_run(IsolatedRun
*run
, int index
)
457 if (index
>= (run
->length
-1)) return -1;
459 while (index
< run
->length
&& *run
->item
[index
].class == BN
) index
++;
460 if (index
== run
->length
) return -1;
464 static inline int get_prev_valid_char_from_run(IsolatedRun
*run
, int index
)
466 if (index
<= 0) return -1;
468 while (index
> -1 && *run
->item
[index
].class == BN
) index
--;
472 static inline void iso_dump_types(const char* header
, IsolatedRun
*run
)
477 for (i
= 0; i
< run
->length
&& len
< 200; i
++) {
478 TRACE(" %s", debug_type
[*run
->item
[i
].class]);
479 len
+= strlen(debug_type
[*run
->item
[i
].class])+1;
481 if (i
!= run
->length
)
486 /*------------------------------------------------------------------------
487 Function: bidi_resolve_weak
489 Resolves the directionality of numeric and other weak character types
491 Implements rules X10 and W1-W6 of the Unicode Bidirectional Algorithm.
493 Input: Array of embedding levels
496 In/Out: Array of directional classes
498 Note: On input only these directional classes are expected
499 AL, HL, R, L, ON, BN, NSM, AN, EN, ES, ET, CS,
500 ------------------------------------------------------------------------*/
501 static BOOL
bidi_is_isolate(UINT8
class)
503 return class == LRI
|| class == RLI
|| class == FSI
|| class == PDI
;
506 static void bidi_resolve_weak(IsolatedRun
*iso_run
)
511 for (i
=0; i
< iso_run
->length
; i
++) {
512 if (*iso_run
->item
[i
].class == NSM
) {
513 int j
= get_prev_valid_char_from_run(iso_run
, i
);
515 *iso_run
->item
[i
].class = iso_run
->sos
;
516 else if (bidi_is_isolate(*iso_run
->item
[j
].class))
517 *iso_run
->item
[i
].class = ON
;
519 *iso_run
->item
[i
].class = *iso_run
->item
[j
].class;
524 for (i
= 0; i
< iso_run
->length
; i
++) {
525 if (*iso_run
->item
[i
].class == EN
) {
526 int j
= get_prev_valid_char_from_run(iso_run
, i
);
528 if (*iso_run
->item
[j
].class == R
|| *iso_run
->item
[j
].class == L
|| *iso_run
->item
[j
].class == AL
) {
529 if (*iso_run
->item
[j
].class == AL
)
530 *iso_run
->item
[i
].class = AN
;
533 j
= get_prev_valid_char_from_run(iso_run
, j
);
539 for (i
= 0; i
< iso_run
->length
; i
++) {
540 if (*iso_run
->item
[i
].class == AL
)
541 *iso_run
->item
[i
].class = R
;
545 for (i
= 0; i
< iso_run
->length
; i
++) {
546 if (*iso_run
->item
[i
].class == ES
) {
547 int b
= get_prev_valid_char_from_run(iso_run
, i
);
548 int f
= get_next_valid_char_from_run(iso_run
, i
);
550 if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == EN
&& *iso_run
->item
[f
].class == EN
)
551 *iso_run
->item
[i
].class = EN
;
553 else if (*iso_run
->item
[i
].class == CS
) {
554 int b
= get_prev_valid_char_from_run(iso_run
, i
);
555 int f
= get_next_valid_char_from_run(iso_run
, i
);
557 if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == EN
&& *iso_run
->item
[f
].class == EN
)
558 *iso_run
->item
[i
].class = EN
;
559 else if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == AN
&& *iso_run
->item
[f
].class == AN
)
560 *iso_run
->item
[i
].class = AN
;
565 for (i
= 0; i
< iso_run
->length
; i
++) {
566 if (*iso_run
->item
[i
].class == ET
) {
568 for (j
= i
-1 ; j
> -1; j
--) {
569 if (*iso_run
->item
[j
].class == BN
) continue;
570 if (*iso_run
->item
[j
].class == ET
) continue;
571 else if (*iso_run
->item
[j
].class == EN
) *iso_run
->item
[i
].class = EN
;
574 if (*iso_run
->item
[i
].class == ET
) {
575 for (j
= i
+1; j
< iso_run
->length
; j
++) {
576 if (*iso_run
->item
[j
].class == BN
) continue;
577 if (*iso_run
->item
[j
].class == ET
) continue;
578 else if (*iso_run
->item
[j
].class == EN
) *iso_run
->item
[i
].class = EN
;
586 for (i
= 0; i
< iso_run
->length
; i
++) {
587 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
)
591 if (b
> -1 && *iso_run
->item
[b
].class == BN
)
592 *iso_run
->item
[b
].class = ON
;
593 if (f
< iso_run
->length
&& *iso_run
->item
[f
].class == BN
)
594 *iso_run
->item
[f
].class = ON
;
596 *iso_run
->item
[i
].class = ON
;
601 for (i
= 0; i
< iso_run
->length
; i
++) {
602 if (*iso_run
->item
[i
].class == EN
) {
604 for (j
= get_prev_valid_char_from_run(iso_run
, i
); j
> -1; j
= get_prev_valid_char_from_run(iso_run
, j
))
605 if (*iso_run
->item
[j
].class == R
|| *iso_run
->item
[j
].class == L
) {
606 if (*iso_run
->item
[j
].class == L
)
607 *iso_run
->item
[i
].class = L
;
610 if (iso_run
->sos
== L
&& j
== -1)
611 *iso_run
->item
[i
].class = L
;
616 typedef struct tagBracketPair
622 static int bracketpair_compr(const void *a
, const void* b
)
624 return ((BracketPair
*)a
)->start
- ((BracketPair
*)b
)->start
;
627 static BracketPair
*bidi_compute_bracket_pairs(IsolatedRun
*iso_run
)
631 int stack_top
= iso_run
->length
;
632 BracketPair
*out
= NULL
;
636 open_stack
= heap_alloc(sizeof(WCHAR
) * iso_run
->length
);
637 stack_index
= heap_alloc(sizeof(int) * iso_run
->length
);
639 for (i
= 0; i
< iso_run
->length
; i
++) {
640 unsigned short ubv
= get_table_entry(bidi_bracket_table
, iso_run
->item
[i
].ch
);
643 out
= heap_alloc(sizeof(BracketPair
));
647 if ((ubv
>> 8) == 0) {
649 open_stack
[stack_top
] = iso_run
->item
[i
].ch
+ (signed char)(ubv
& 0xff);
650 /* deal with canonical equivalent U+2329/232A and U+3008/3009 */
651 if (open_stack
[stack_top
] == 0x232A)
652 open_stack
[stack_top
] = 0x3009;
653 stack_index
[stack_top
] = i
;
655 else if ((ubv
>> 8) == 1) {
658 if (stack_top
== iso_run
->length
) continue;
659 for (j
= stack_top
; j
< iso_run
->length
; j
++) {
660 WCHAR c
= iso_run
->item
[i
].ch
;
661 if (c
== 0x232A) c
= 0x3009;
662 if (c
== open_stack
[j
]) {
663 out
[pair_count
].start
= stack_index
[j
];
664 out
[pair_count
].end
= i
;
666 out
= heap_realloc(out
, sizeof(BracketPair
) * (pair_count
+1));
667 out
[pair_count
].start
= -1;
675 if (pair_count
== 0) {
679 else if (pair_count
> 1)
680 qsort(out
, pair_count
, sizeof(BracketPair
), bracketpair_compr
);
682 heap_free(open_stack
);
683 heap_free(stack_index
);
687 static inline UINT8
get_rule_N0_class(UINT8
class)
689 return (class == AN
|| class == EN
) ? R
: class;
692 /*------------------------------------------------------------------------
693 Function: bidi_resolve_neutrals
695 Resolves the directionality of neutral character types.
697 Implements rules N1 and N2 of the Unicode Bidi Algorithm.
699 Input: Array of embedding levels
703 In/Out: Array of directional classes
705 Note: On input only these directional classes are expected
706 R, L, NI, AN, EN and BN
708 W8 resolves a number of ENs to L
709 ------------------------------------------------------------------------*/
710 static void bidi_resolve_neutrals(IsolatedRun
*run
)
715 /* Translate isolates into NI */
716 for (i
= 0; i
< run
->length
; i
++) {
717 switch (*run
->item
[i
].class) {
724 case PDI
: *run
->item
[i
].class = NI
;
727 /* "Only NI, L, R, AN, EN and BN are allowed" */
728 ASSERT(*run
->item
[i
].class <= EN
|| *run
->item
[i
].class == BN
);
731 /* N0: Skipping bracketed pairs for now */
732 pairs
= bidi_compute_bracket_pairs(run
);
734 BracketPair
*p
= pairs
;
736 while (p
->start
>= 0) {
737 UINT8 e
= get_embedding_direction(run
->e
);
738 UINT8 o
= get_embedding_direction(run
->e
+ 1);
742 TRACE("Bracket Pair [%i - %i]\n", p
->start
, p
->end
);
745 for (j
= p
->start
+1; j
< p
->end
; j
++) {
746 if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
747 *run
->item
[p
->start
].class = e
;
748 *run
->item
[p
->end
].class = e
;
751 else if (get_rule_N0_class(*run
->item
[j
].class) == o
)
755 if (j
== p
->end
&& flag_o
) {
756 for (j
= p
->start
; j
>= 0; j
--) {
757 if (get_rule_N0_class(*run
->item
[j
].class) == o
) {
758 *run
->item
[p
->start
].class = o
;
759 *run
->item
[p
->end
].class = o
;
762 else if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
763 *run
->item
[p
->start
].class = e
;
764 *run
->item
[p
->end
].class = e
;
769 *run
->item
[p
->start
].class = run
->sos
;
770 *run
->item
[p
->end
].class = run
->sos
;
781 for (i
= 0; i
< run
->length
; i
++) {
784 if (*run
->item
[i
].class == NI
) {
785 int b
= get_prev_valid_char_from_run(run
, i
);
793 if (*run
->item
[b
].class == R
|| *run
->item
[b
].class == AN
|| *run
->item
[b
].class == EN
)
795 else if (*run
->item
[b
].class == L
)
797 else /* No string type */
800 j
= get_next_valid_char_from_run(run
, i
);
801 while (j
> -1 && *run
->item
[j
].class == NI
) j
= get_next_valid_char_from_run(run
, j
);
806 else if (*run
->item
[j
].class == R
|| *run
->item
[j
].class == AN
|| *run
->item
[j
].class == EN
)
808 else if (*run
->item
[j
].class == L
)
810 else /* No string type */
814 for (b
= i
; b
< j
&& b
< run
->length
; b
++)
815 *run
->item
[b
].class = r
;
821 for (i
= 0; i
< run
->length
; i
++) {
822 if (*run
->item
[i
].class == NI
) {
826 *run
->item
[i
].class = get_embedding_direction(run
->e
);
827 if (b
> -1 && *run
->item
[b
].class == BN
)
828 *run
->item
[b
].class = get_embedding_direction(run
->e
);
829 if (f
< run
->length
&& *run
->item
[f
].class == BN
)
830 *run
->item
[f
].class = get_embedding_direction(run
->e
);
835 /*------------------------------------------------------------------------
836 Function: bidi_resolve_implicit
838 Recursively resolves implicit embedding levels.
839 Implements rules I1 and I2 of the Unicode Bidirectional Algorithm.
841 Input: Array of direction classes
845 In/Out: Array of embedding levels
847 Note: levels may exceed 15 on output.
848 Accepted subset of direction classes
850 ------------------------------------------------------------------------*/
851 static void bidi_resolve_implicit(const UINT8
*classes
, UINT8
*levels
, int sos
, int eos
)
856 for (i
= sos
; i
<= eos
; i
++) {
857 if (classes
[i
] == BN
)
860 ASSERT(classes
[i
] != ON
); /* "No Neutrals allowed to survive here." */
861 ASSERT(classes
[i
] <= EN
); /* "Out of range." */
863 if (odd(levels
[i
]) && (classes
[i
] == L
|| classes
[i
] == EN
|| classes
[i
] == AN
))
865 else if (!odd(levels
[i
]) && classes
[i
] == R
)
867 else if (!odd(levels
[i
]) && (classes
[i
] == EN
|| classes
[i
] == AN
))
872 static inline BOOL
is_rule_L1_reset_class(UINT8
class)
892 static void bidi_resolve_resolved(UINT8 baselevel
, const UINT8
*classes
, UINT8
*levels
, int sos
, int eos
)
897 for (i
= sos
; i
<= eos
; i
++) {
898 if (classes
[i
] == B
|| classes
[i
] == S
) {
900 while (i
> sos
&& j
>= sos
&& is_rule_L1_reset_class(classes
[j
]))
901 levels
[j
--] = baselevel
;
902 levels
[i
] = baselevel
;
904 else if (classes
[i
] == LRE
|| classes
[i
] == RLE
|| classes
[i
] == LRO
|| classes
[i
] == RLO
||
905 classes
[i
] == PDF
|| classes
[i
] == BN
) {
906 levels
[i
] = i
? levels
[i
- 1] : baselevel
;
908 if (i
== eos
&& is_rule_L1_reset_class(classes
[i
])) {
910 while (j
>= sos
&& is_rule_L1_reset_class(classes
[j
]))
911 levels
[j
--] = baselevel
;
916 static HRESULT
bidi_compute_isolating_runs_set(UINT8 baselevel
, UINT8
*classes
, UINT8
*levels
, const WCHAR
*string
, UINT32 count
, struct list
*set
)
918 int run_start
, run_end
, i
;
923 runs
= heap_calloc(count
, sizeof(*runs
));
925 return E_OUTOFMEMORY
;
931 while (run_start
< count
) {
932 run_end
= get_next_valid_char_index(classes
, run_start
, count
);
933 while (run_end
< count
&& levels
[run_end
] == levels
[run_start
])
934 run_end
= get_next_valid_char_index(classes
, run_end
, count
);
936 runs
[run_count
].start
= run_start
;
937 runs
[run_count
].end
= run_end
;
938 runs
[run_count
].e
= levels
[run_start
];
939 run_start
= get_next_valid_char_index(classes
, run_end
, count
);
943 /* Build Isolating Runs */
945 while (i
< run_count
) {
947 if (runs
[k
].start
>= 0) {
948 IsolatedRun
*current_isolated
;
949 int type_fence
, real_end
;
952 current_isolated
= heap_alloc(sizeof(IsolatedRun
) + sizeof(RunChar
)*count
);
953 if (!current_isolated
) {
958 run_start
= runs
[k
].start
;
959 current_isolated
->e
= runs
[k
].e
;
960 current_isolated
->length
= (runs
[k
].end
- runs
[k
].start
)+1;
962 for (j
= 0; j
< current_isolated
->length
; j
++) {
963 current_isolated
->item
[j
].class = &classes
[runs
[k
].start
+j
];
964 current_isolated
->item
[j
].ch
= string
[runs
[k
].start
+j
];
967 run_end
= runs
[k
].end
;
969 TRACE("{ [%i -- %i]",run_start
, run_end
);
971 if (classes
[run_end
] == BN
)
972 run_end
= get_prev_valid_char_index(classes
, run_end
, runs
[k
].start
);
974 while (run_end
< count
&& (classes
[run_end
] == RLI
|| classes
[run_end
] == LRI
|| classes
[run_end
] == FSI
)) {
977 while (j
< run_count
&& classes
[runs
[j
].start
] != PDI
) j
++;
978 if (j
< run_count
&& runs
[i
].e
!= runs
[j
].e
) {
983 if (j
!= run_count
) {
984 int l
= current_isolated
->length
;
987 current_isolated
->length
+= (runs
[j
].end
- runs
[j
].start
)+1;
988 for (m
= 0; l
< current_isolated
->length
; l
++, m
++) {
989 current_isolated
->item
[l
].class = &classes
[runs
[j
].start
+m
];
990 current_isolated
->item
[l
].ch
= string
[runs
[j
].start
+m
];
993 TRACE("[%i -- %i]", runs
[j
].start
, runs
[j
].end
);
995 run_end
= runs
[j
].end
;
996 if (classes
[run_end
] == BN
)
997 run_end
= get_prev_valid_char_index(classes
, run_end
, runs
[i
].start
);
1007 type_fence
= get_prev_valid_char_index(classes
, run_start
, -1);
1009 if (type_fence
== -1)
1010 current_isolated
->sos
= (baselevel
> levels
[run_start
]) ? baselevel
: levels
[run_start
];
1012 current_isolated
->sos
= (levels
[type_fence
] > levels
[run_start
]) ? levels
[type_fence
] : levels
[run_start
];
1014 current_isolated
->sos
= get_embedding_direction(current_isolated
->sos
);
1016 if (run_end
== count
)
1017 current_isolated
->eos
= current_isolated
->sos
;
1019 /* eos could be an BN */
1020 if (classes
[run_end
] == BN
) {
1021 real_end
= get_prev_valid_char_index(classes
, run_end
, run_start
-1);
1022 if (real_end
< run_start
)
1023 real_end
= run_start
;
1028 type_fence
= get_next_valid_char_index(classes
, run_end
, count
);
1029 if (type_fence
== count
)
1030 current_isolated
->eos
= (baselevel
> levels
[real_end
]) ? baselevel
: levels
[real_end
];
1032 current_isolated
->eos
= (levels
[type_fence
] > levels
[real_end
]) ? levels
[type_fence
] : levels
[real_end
];
1034 current_isolated
->eos
= get_embedding_direction(current_isolated
->eos
);
1037 list_add_tail(set
, ¤t_isolated
->entry
);
1038 TRACE(" } level %i {%s <--> %s}\n", current_isolated
->e
, debug_type
[current_isolated
->sos
], debug_type
[current_isolated
->eos
]);
1047 HRESULT
bidi_computelevels(const WCHAR
*string
, UINT32 count
, UINT8 baselevel
, UINT8
*explicit, UINT8
*levels
)
1049 IsolatedRun
*iso_run
, *next
;
1050 struct list IsolatingRuns
;
1054 TRACE("%s, %u\n", debugstr_wn(string
, count
), count
);
1056 chartype
= heap_alloc(count
*sizeof(*chartype
));
1058 return E_OUTOFMEMORY
;
1060 bidi_classify(string
, chartype
, count
);
1061 if (TRACE_ON(bidi
)) bidi_dump_types("start ", chartype
, 0, count
);
1063 bidi_resolve_explicit(baselevel
, chartype
, levels
, count
);
1064 memcpy(explicit, levels
, count
*sizeof(*explicit));
1066 if (TRACE_ON(bidi
)) bidi_dump_types("after explicit", chartype
, 0, count
);
1068 /* X10/BD13: Compute Isolating runs */
1069 hr
= bidi_compute_isolating_runs_set(baselevel
, chartype
, levels
, string
, count
, &IsolatingRuns
);
1073 LIST_FOR_EACH_ENTRY_SAFE(iso_run
, next
, &IsolatingRuns
, IsolatedRun
, entry
)
1075 if (TRACE_ON(bidi
)) iso_dump_types("run", iso_run
);
1077 bidi_resolve_weak(iso_run
);
1078 if (TRACE_ON(bidi
)) iso_dump_types("after weak", iso_run
);
1080 bidi_resolve_neutrals(iso_run
);
1081 if (TRACE_ON(bidi
)) iso_dump_types("after neutrals", iso_run
);
1083 list_remove(&iso_run
->entry
);
1087 if (TRACE_ON(bidi
)) bidi_dump_types("before implicit", chartype
, 0, count
);
1088 bidi_resolve_implicit(chartype
, levels
, 0, count
-1);
1090 bidi_classify(string
, chartype
, count
);
1091 bidi_resolve_resolved(baselevel
, chartype
, levels
, 0, count
-1);
1094 heap_free(chartype
);