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"
49 #include "wine/list.h"
51 #include "dwrite_private.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(bidi
);
55 extern const unsigned short bidi_bracket_table
[];
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 numberic 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
)
155 static const enum directions dir_map
[16] =
157 L
, /* unassigned defaults to L */
172 PDF
/* also LRE, LRO, RLE, RLO */
177 for (i
= 0; i
< count
; ++i
) {
178 chartype
[i
] = dir_map
[get_char_typeW(string
[i
]) >> 12];
180 switch (chartype
[i
]) {
185 case 0x202a: chartype
[i
] = LRE
; break;
186 case 0x202b: chartype
[i
] = RLE
; break;
187 case 0x202c: chartype
[i
] = PDF
; break;
188 case 0x202d: chartype
[i
] = LRO
; break;
189 case 0x202e: chartype
[i
] = RLO
; break;
190 case 0x2066: chartype
[i
] = LRI
; break;
191 case 0x2067: chartype
[i
] = RLI
; break;
192 case 0x2068: chartype
[i
] = FSI
; break;
193 case 0x2069: chartype
[i
] = PDI
; break;
200 WCHAR
bidi_get_mirrored_char(WCHAR ch
)
202 extern const WCHAR wine_mirror_map
[];
203 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
206 /* RESOLVE EXPLICIT */
208 static inline UINT8
get_greater_even_level(UINT8 level
)
210 return odd(level
) ? level
+ 1 : level
+ 2;
213 static inline UINT8
get_greater_odd_level(UINT8 level
)
215 return odd(level
) ? level
+ 2 : level
+ 1;
218 static inline UINT8
get_embedding_direction(UINT8 level
)
220 return odd(level
) ? R
: L
;
223 /*------------------------------------------------------------------------
224 Function: bidi_resolve_explicit
226 Recursively resolves explicit embedding levels and overrides.
227 Implements rules X1-X9, of the Unicode Bidirectional Algorithm.
229 Input: Base embedding level and direction
232 Output: Array of embedding levels
234 In/Out: Array of direction classes
237 Note: The function uses two simple counters to keep track of
238 matching explicit codes and PDF. Use the default argument for
239 the outermost call. The nesting counter counts the recursion
240 depth and not the embedding level.
241 ------------------------------------------------------------------------*/
242 typedef struct tagStackItem
249 #define push_stack(l,o,i) \
251 stack[stack_top].level = l; \
252 stack[stack_top].override = o; \
253 stack[stack_top].isolate = i;} while(0)
255 #define pop_stack() do { stack_top++; } while(0)
257 #define valid_level(x) (x <= MAX_DEPTH && overflow_isolate_count == 0 && overflow_embedding_count == 0)
259 static void bidi_resolve_explicit(UINT8 baselevel
, UINT8
*classes
, UINT8
*levels
, UINT32 count
)
262 int overflow_isolate_count
= 0;
263 int overflow_embedding_count
= 0;
264 int valid_isolate_count
= 0;
267 StackItem stack
[MAX_DEPTH
+2];
268 int stack_top
= MAX_DEPTH
+1;
270 stack
[stack_top
].level
= baselevel
;
271 stack
[stack_top
].override
= NI
;
272 stack
[stack_top
].isolate
= FALSE
;
274 for (i
= 0; i
< count
; i
++) {
275 UINT8 least_odd
, least_even
;
277 switch (classes
[i
]) {
281 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
282 levels
[i
] = stack
[stack_top
].level
;
283 if (valid_level(least_odd
))
284 push_stack(least_odd
, NI
, FALSE
);
285 else if (overflow_isolate_count
== 0)
286 overflow_embedding_count
++;
291 least_even
= get_greater_even_level(stack
[stack_top
].level
);
292 levels
[i
] = stack
[stack_top
].level
;
293 if (valid_level(least_even
))
294 push_stack(least_even
, NI
, FALSE
);
295 else if (overflow_isolate_count
== 0)
296 overflow_embedding_count
++;
301 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
302 levels
[i
] = stack
[stack_top
].level
;
303 if (valid_level(least_odd
))
304 push_stack(least_odd
, R
, FALSE
);
305 else if (overflow_isolate_count
== 0)
306 overflow_embedding_count
++;
311 least_even
= get_greater_even_level(stack
[stack_top
].level
);
312 levels
[i
] = stack
[stack_top
].level
;
313 if (valid_level(least_even
))
314 push_stack(least_even
, L
, FALSE
);
315 else if (overflow_isolate_count
== 0)
316 overflow_embedding_count
++;
321 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
322 levels
[i
] = stack
[stack_top
].level
;
323 if (valid_level(least_odd
))
325 valid_isolate_count
++;
326 push_stack(least_odd
, NI
, TRUE
);
329 overflow_isolate_count
++;
334 least_even
= get_greater_even_level(stack
[stack_top
].level
);
335 levels
[i
] = stack
[stack_top
].level
;
336 if (valid_level(least_even
))
338 valid_isolate_count
++;
339 push_stack(least_even
, NI
, TRUE
);
342 overflow_isolate_count
++;
352 levels
[i
] = stack
[stack_top
].level
;
353 for (j
= i
+1; j
< count
; j
++)
355 if (classes
[j
] == LRI
|| classes
[j
] == RLI
|| classes
[j
] == FSI
)
360 else if (classes
[j
] == PDI
)
369 if (skipping
) continue;
376 else if (classes
[j
] == R
|| classes
[j
] == AL
)
384 least_odd
= get_greater_odd_level(stack
[stack_top
].level
);
385 if (valid_level(least_odd
))
387 valid_isolate_count
++;
388 push_stack(least_odd
, NI
, TRUE
);
391 overflow_isolate_count
++;
395 least_even
= get_greater_even_level(stack
[stack_top
].level
);
396 if (valid_level(least_even
))
398 valid_isolate_count
++;
399 push_stack(least_even
, NI
, TRUE
);
402 overflow_isolate_count
++;
420 levels
[i
] = stack
[stack_top
].level
;
421 if (stack
[stack_top
].override
!= NI
)
422 classes
[i
] = stack
[stack_top
].override
;
427 if (overflow_isolate_count
) overflow_isolate_count
--;
428 else if (!valid_isolate_count
) {/* do nothing */}
431 overflow_embedding_count
= 0;
432 while (!stack
[stack_top
].isolate
) pop_stack();
434 valid_isolate_count
--;
436 levels
[i
] = stack
[stack_top
].level
;
441 levels
[i
] = stack
[stack_top
].level
;
442 if (overflow_isolate_count
) {/* do nothing */}
443 else if (overflow_embedding_count
) overflow_embedding_count
--;
444 else if (!stack
[stack_top
].isolate
&& stack_top
< (MAX_DEPTH
+1))
453 /* X9: Based on 5.2 Retaining Explicit Formatting Characters */
454 for (i
= 0; i
< count
; i
++)
455 if (classes
[i
] == RLE
|| classes
[i
] == LRE
|| classes
[i
] == RLO
|| classes
[i
] == LRO
|| classes
[i
] == PDF
)
459 static inline int get_prev_valid_char_index(const UINT8
*classes
, int index
, int back_fence
)
461 if (index
== -1 || index
== back_fence
) return index
;
463 while (index
> back_fence
&& classes
[index
] == BN
) index
--;
467 static inline int get_next_valid_char_index(const UINT8
*classes
, int index
, int front_fence
)
469 if (index
== front_fence
) return index
;
471 while (index
< front_fence
&& classes
[index
] == BN
) index
++;
475 typedef struct tagRun
482 typedef struct tagRunChar
488 typedef struct tagIsolatedRun
499 static inline int get_next_valid_char_from_run(IsolatedRun
*run
, int index
)
501 if (index
>= (run
->length
-1)) return -1;
503 while (index
< run
->length
&& *run
->item
[index
].class == BN
) index
++;
504 if (index
== run
->length
) return -1;
508 static inline int get_prev_valid_char_from_run(IsolatedRun
*run
, int index
)
510 if (index
<= 0) return -1;
512 while (index
> -1 && *run
->item
[index
].class == BN
) index
--;
516 static inline void iso_dump_types(const char* header
, IsolatedRun
*run
)
521 for (i
= 0; i
< run
->length
&& len
< 200; i
++) {
522 TRACE(" %s", debug_type
[*run
->item
[i
].class]);
523 len
+= strlen(debug_type
[*run
->item
[i
].class])+1;
525 if (i
!= run
->length
)
530 /*------------------------------------------------------------------------
531 Function: bidi_resolve_weak
533 Resolves the directionality of numeric and other weak character types
535 Implements rules X10 and W1-W6 of the Unicode Bidirectional Algorithm.
537 Input: Array of embedding levels
540 In/Out: Array of directional classes
542 Note: On input only these directional classes are expected
543 AL, HL, R, L, ON, BN, NSM, AN, EN, ES, ET, CS,
544 ------------------------------------------------------------------------*/
545 static void bidi_resolve_weak(IsolatedRun
*iso_run
)
550 for (i
=0; i
< iso_run
->length
; i
++) {
551 if (*iso_run
->item
[i
].class == NSM
) {
552 int j
= get_prev_valid_char_from_run(iso_run
, i
);
554 *iso_run
->item
[i
].class = iso_run
->sos
;
555 else if (*iso_run
->item
[j
].class >= LRI
)
556 *iso_run
->item
[i
].class = ON
;
558 *iso_run
->item
[i
].class = *iso_run
->item
[j
].class;
563 for (i
= 0; i
< iso_run
->length
; i
++) {
564 if (*iso_run
->item
[i
].class == EN
) {
565 int j
= get_prev_valid_char_from_run(iso_run
, i
);
567 if (*iso_run
->item
[j
].class == R
|| *iso_run
->item
[j
].class == L
|| *iso_run
->item
[j
].class == AL
) {
568 if (*iso_run
->item
[j
].class == AL
)
569 *iso_run
->item
[i
].class = AN
;
572 j
= get_prev_valid_char_from_run(iso_run
, j
);
578 for (i
= 0; i
< iso_run
->length
; i
++) {
579 if (*iso_run
->item
[i
].class == AL
)
580 *iso_run
->item
[i
].class = R
;
584 for (i
= 0; i
< iso_run
->length
; i
++) {
585 if (*iso_run
->item
[i
].class == ES
) {
586 int b
= get_prev_valid_char_from_run(iso_run
, i
);
587 int f
= get_next_valid_char_from_run(iso_run
, i
);
589 if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == EN
&& *iso_run
->item
[f
].class == EN
)
590 *iso_run
->item
[i
].class = EN
;
592 else if (*iso_run
->item
[i
].class == CS
) {
593 int b
= get_prev_valid_char_from_run(iso_run
, i
);
594 int f
= get_next_valid_char_from_run(iso_run
, i
);
596 if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == EN
&& *iso_run
->item
[f
].class == EN
)
597 *iso_run
->item
[i
].class = EN
;
598 else if (b
> -1 && f
> -1 && *iso_run
->item
[b
].class == AN
&& *iso_run
->item
[f
].class == AN
)
599 *iso_run
->item
[i
].class = AN
;
604 for (i
= 0; i
< iso_run
->length
; i
++) {
605 if (*iso_run
->item
[i
].class == ET
) {
607 for (j
= i
-1 ; j
> -1; j
--) {
608 if (*iso_run
->item
[j
].class == BN
) continue;
609 if (*iso_run
->item
[j
].class == ET
) continue;
610 else if (*iso_run
->item
[j
].class == EN
) *iso_run
->item
[i
].class = EN
;
613 if (*iso_run
->item
[i
].class == ET
) {
614 for (j
= i
+1; j
< iso_run
->length
; j
++) {
615 if (*iso_run
->item
[j
].class == BN
) continue;
616 if (*iso_run
->item
[j
].class == ET
) continue;
617 else if (*iso_run
->item
[j
].class == EN
) *iso_run
->item
[i
].class = EN
;
625 for (i
= 0; i
< iso_run
->length
; i
++) {
626 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
)
630 if (b
> -1 && *iso_run
->item
[b
].class == BN
)
631 *iso_run
->item
[b
].class = ON
;
632 if (f
< iso_run
->length
&& *iso_run
->item
[f
].class == BN
)
633 *iso_run
->item
[f
].class = ON
;
635 *iso_run
->item
[i
].class = ON
;
640 for (i
= 0; i
< iso_run
->length
; i
++) {
641 if (*iso_run
->item
[i
].class == EN
) {
643 for (j
= get_prev_valid_char_from_run(iso_run
, i
); j
> -1; j
= get_prev_valid_char_from_run(iso_run
, j
))
644 if (*iso_run
->item
[j
].class == R
|| *iso_run
->item
[j
].class == L
) {
645 if (*iso_run
->item
[j
].class == L
)
646 *iso_run
->item
[i
].class = L
;
649 if (iso_run
->sos
== L
&& j
== -1)
650 *iso_run
->item
[i
].class = L
;
655 typedef struct tagBracketPair
661 static int bracketpair_compr(const void *a
, const void* b
)
663 return ((BracketPair
*)a
)->start
- ((BracketPair
*)b
)->start
;
666 static BracketPair
*bidi_compute_bracket_pairs(IsolatedRun
*iso_run
)
670 int stack_top
= iso_run
->length
;
671 BracketPair
*out
= NULL
;
675 open_stack
= heap_alloc(sizeof(WCHAR
) * iso_run
->length
);
676 stack_index
= heap_alloc(sizeof(int) * iso_run
->length
);
678 for (i
= 0; i
< iso_run
->length
; i
++) {
679 unsigned short ubv
= get_table_entry(bidi_bracket_table
, iso_run
->item
[i
].ch
);
682 out
= heap_alloc(sizeof(BracketPair
));
686 if ((ubv
>> 8) == 0) {
688 open_stack
[stack_top
] = iso_run
->item
[i
].ch
+ (signed char)(ubv
& 0xff);
689 /* deal with canonical equivalent U+2329/232A and U+3008/3009 */
690 if (open_stack
[stack_top
] == 0x232A)
691 open_stack
[stack_top
] = 0x3009;
692 stack_index
[stack_top
] = i
;
694 else if ((ubv
>> 8) == 1) {
697 if (stack_top
== iso_run
->length
) continue;
698 for (j
= stack_top
; j
< iso_run
->length
; j
++) {
699 WCHAR c
= iso_run
->item
[i
].ch
;
700 if (c
== 0x232A) c
= 0x3009;
701 if (c
== open_stack
[j
]) {
702 out
[pair_count
].start
= stack_index
[j
];
703 out
[pair_count
].end
= i
;
705 out
= heap_realloc(out
, sizeof(BracketPair
) * (pair_count
+1));
706 out
[pair_count
].start
= -1;
714 if (pair_count
== 0) {
718 else if (pair_count
> 1)
719 qsort(out
, pair_count
, sizeof(BracketPair
), bracketpair_compr
);
721 heap_free(open_stack
);
722 heap_free(stack_index
);
726 static inline UINT8
get_rule_N0_class(UINT8
class)
728 return (class == AN
|| class == EN
) ? R
: class;
731 /*------------------------------------------------------------------------
732 Function: bidi_resolve_neutrals
734 Resolves the directionality of neutral character types.
736 Implements rules N1 and N2 of the Unicode Bidi Algorithm.
738 Input: Array of embedding levels
742 In/Out: Array of directional classes
744 Note: On input only these directional classes are expected
745 R, L, NI, AN, EN and BN
747 W8 resolves a number of ENs to L
748 ------------------------------------------------------------------------*/
749 static void bidi_resolve_neutrals(IsolatedRun
*run
)
754 /* Translate isolates into NI */
755 for (i
= 0; i
< run
->length
; i
++) {
756 if (*run
->item
[i
].class >= LRI
)
757 *run
->item
[i
].class = NI
;
759 switch (*run
->item
[i
].class) {
762 case WS
: *run
->item
[i
].class = NI
;
765 ASSERT(*run
->item
[i
].class < 5 || *run
->item
[i
].class == BN
); /* "Only NI, L, R, AN, EN and BN are allowed" */
768 /* N0: Skipping bracketed pairs for now */
769 pairs
= bidi_compute_bracket_pairs(run
);
771 BracketPair
*p
= pairs
;
773 while (p
->start
>= 0) {
774 UINT8 e
= get_embedding_direction(run
->e
);
775 UINT8 o
= get_embedding_direction(run
->e
+ 1);
779 TRACE("Bracket Pair [%i - %i]\n", p
->start
, p
->end
);
782 for (j
= p
->start
+1; j
< p
->end
; j
++) {
783 if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
784 *run
->item
[p
->start
].class = e
;
785 *run
->item
[p
->end
].class = e
;
788 else if (get_rule_N0_class(*run
->item
[j
].class) == o
)
792 if (j
== p
->end
&& flag_o
) {
793 for (j
= p
->start
; j
>= 0; j
--) {
794 if (get_rule_N0_class(*run
->item
[j
].class) == o
) {
795 *run
->item
[p
->start
].class = o
;
796 *run
->item
[p
->end
].class = o
;
799 else if (get_rule_N0_class(*run
->item
[j
].class) == e
) {
800 *run
->item
[p
->start
].class = e
;
801 *run
->item
[p
->end
].class = e
;
806 *run
->item
[p
->start
].class = run
->sos
;
807 *run
->item
[p
->end
].class = run
->sos
;
818 for (i
= 0; i
< run
->length
; i
++) {
821 if (*run
->item
[i
].class == NI
) {
822 int b
= get_prev_valid_char_from_run(run
, i
);
830 if (*run
->item
[b
].class == R
|| *run
->item
[b
].class == AN
|| *run
->item
[b
].class == EN
)
832 else if (*run
->item
[b
].class == L
)
834 else /* No string type */
837 j
= get_next_valid_char_from_run(run
, i
);
838 while (j
> -1 && *run
->item
[j
].class == NI
) j
= get_next_valid_char_from_run(run
, j
);
843 else if (*run
->item
[j
].class == R
|| *run
->item
[j
].class == AN
|| *run
->item
[j
].class == EN
)
845 else if (*run
->item
[j
].class == L
)
847 else /* No string type */
851 for (b
= i
; b
< j
&& b
< run
->length
; b
++)
852 *run
->item
[b
].class = r
;
858 for (i
= 0; i
< run
->length
; i
++) {
859 if (*run
->item
[i
].class == NI
) {
863 *run
->item
[i
].class = get_embedding_direction(run
->e
);
864 if (b
> -1 && *run
->item
[b
].class == BN
)
865 *run
->item
[b
].class = get_embedding_direction(run
->e
);
866 if (f
< run
->length
&& *run
->item
[f
].class == BN
)
867 *run
->item
[f
].class = get_embedding_direction(run
->e
);
872 /*------------------------------------------------------------------------
873 Function: bidi_resolve_implicit
875 Recursively resolves implicit embedding levels.
876 Implements rules I1 and I2 of the Unicode Bidirectional Algorithm.
878 Input: Array of direction classes
882 In/Out: Array of embedding levels
884 Note: levels may exceed 15 on output.
885 Accepted subset of direction classes
887 ------------------------------------------------------------------------*/
888 static void bidi_resolve_implicit(const UINT8
*classes
, UINT8
*levels
, int sos
, int eos
)
893 for (i
= sos
; i
<= eos
; i
++) {
894 if (classes
[i
] == BN
)
897 ASSERT(classes
[i
] > 0); /* "No Neutrals allowed to survive here." */
898 ASSERT(classes
[i
] < 5); /* "Out of range." */
900 if (odd(levels
[i
]) && (classes
[i
] == L
|| classes
[i
] == EN
|| classes
[i
] == AN
))
902 else if (!odd(levels
[i
]) && classes
[i
] == R
)
904 else if (!odd(levels
[i
]) && (classes
[i
] == EN
|| classes
[i
] == AN
))
909 static inline BOOL
is_rule_L1_reset_class(UINT8
class)
929 static void bidi_resolve_resolved(UINT8 baselevel
, const UINT8
*classes
, UINT8
*levels
, int sos
, int eos
)
934 for (i
= sos
; i
<= eos
; i
++) {
935 if (classes
[i
] == B
|| classes
[i
] == S
) {
937 while (i
> sos
&& j
>= sos
&& is_rule_L1_reset_class(classes
[j
]))
938 levels
[j
--] = baselevel
;
939 levels
[i
] = baselevel
;
941 if (i
== eos
&& is_rule_L1_reset_class(classes
[i
])) {
943 while (j
>= sos
&& is_rule_L1_reset_class(classes
[j
]))
944 levels
[j
--] = baselevel
;
949 static HRESULT
bidi_compute_isolating_runs_set(UINT8 baselevel
, UINT8
*classes
, UINT8
*levels
, const WCHAR
*string
, UINT32 count
, struct list
*set
)
951 int run_start
, run_end
, i
;
956 runs
= heap_alloc(count
* sizeof(Run
));
958 return E_OUTOFMEMORY
;
964 while (run_start
< count
) {
965 run_end
= get_next_valid_char_index(classes
, run_start
, count
);
966 while (run_end
< count
&& levels
[run_end
] == levels
[run_start
])
967 run_end
= get_next_valid_char_index(classes
, run_end
, count
);
969 runs
[run_count
].start
= run_start
;
970 runs
[run_count
].end
= run_end
;
971 runs
[run_count
].e
= levels
[run_start
];
972 run_start
= get_next_valid_char_index(classes
, run_end
, count
);
976 /* Build Isolating Runs */
978 while (i
< run_count
) {
980 if (runs
[k
].start
>= 0) {
981 IsolatedRun
*current_isolated
;
982 int type_fence
, real_end
;
985 current_isolated
= heap_alloc(sizeof(IsolatedRun
) + sizeof(RunChar
)*count
);
986 if (!current_isolated
) {
991 run_start
= runs
[k
].start
;
992 current_isolated
->e
= runs
[k
].e
;
993 current_isolated
->length
= (runs
[k
].end
- runs
[k
].start
)+1;
995 for (j
= 0; j
< current_isolated
->length
; j
++) {
996 current_isolated
->item
[j
].class = &classes
[runs
[k
].start
+j
];
997 current_isolated
->item
[j
].ch
= string
[runs
[k
].start
+j
];
1000 run_end
= runs
[k
].end
;
1002 TRACE("{ [%i -- %i]",run_start
, run_end
);
1004 if (classes
[run_end
] == BN
)
1005 run_end
= get_prev_valid_char_index(classes
, run_end
, runs
[k
].start
);
1007 while (run_end
< count
&& (classes
[run_end
] == RLI
|| classes
[run_end
] == LRI
|| classes
[run_end
] == FSI
)) {
1010 while (j
< run_count
&& classes
[runs
[j
].start
] != PDI
) j
++;
1011 if (j
< run_count
&& runs
[i
].e
!= runs
[j
].e
) {
1016 if (j
!= run_count
) {
1017 int l
= current_isolated
->length
;
1020 current_isolated
->length
+= (runs
[j
].end
- runs
[j
].start
)+1;
1021 for (m
= 0; l
< current_isolated
->length
; l
++, m
++) {
1022 current_isolated
->item
[l
].class = &classes
[runs
[j
].start
+m
];
1023 current_isolated
->item
[l
].ch
= string
[runs
[j
].start
+m
];
1026 TRACE("[%i -- %i]", runs
[j
].start
, runs
[j
].end
);
1028 run_end
= runs
[j
].end
;
1029 if (classes
[run_end
] == BN
)
1030 run_end
= get_prev_valid_char_index(classes
, run_end
, runs
[i
].start
);
1040 type_fence
= get_prev_valid_char_index(classes
, run_start
, -1);
1042 if (type_fence
== -1)
1043 current_isolated
->sos
= (baselevel
> levels
[run_start
]) ? baselevel
: levels
[run_start
];
1045 current_isolated
->sos
= (levels
[type_fence
] > levels
[run_start
]) ? levels
[type_fence
] : levels
[run_start
];
1047 current_isolated
->sos
= get_embedding_direction(current_isolated
->sos
);
1049 if (run_end
== count
)
1050 current_isolated
->eos
= current_isolated
->sos
;
1052 /* eos could be an BN */
1053 if (classes
[run_end
] == BN
) {
1054 real_end
= get_prev_valid_char_index(classes
, run_end
, run_start
-1);
1055 if (real_end
< run_start
)
1056 real_end
= run_start
;
1061 type_fence
= get_next_valid_char_index(classes
, run_end
, count
);
1062 if (type_fence
== count
)
1063 current_isolated
->eos
= (baselevel
> levels
[real_end
]) ? baselevel
: levels
[real_end
];
1065 current_isolated
->eos
= (levels
[type_fence
] > levels
[real_end
]) ? levels
[type_fence
] : levels
[real_end
];
1067 current_isolated
->eos
= get_embedding_direction(current_isolated
->eos
);
1070 list_add_tail(set
, ¤t_isolated
->entry
);
1071 TRACE(" } level %i {%s <--> %s}\n", current_isolated
->e
, debug_type
[current_isolated
->sos
], debug_type
[current_isolated
->eos
]);
1080 HRESULT
bidi_computelevels(const WCHAR
*string
, UINT32 count
, UINT8 baselevel
, UINT8
*explicit, UINT8
*levels
)
1082 IsolatedRun
*iso_run
, *next
;
1083 struct list IsolatingRuns
;
1087 TRACE("%s, %u\n", debugstr_wn(string
, count
), count
);
1089 chartype
= heap_alloc(count
*sizeof(*chartype
));
1091 return E_OUTOFMEMORY
;
1093 bidi_classify(string
, chartype
, count
);
1094 if (TRACE_ON(bidi
)) bidi_dump_types("start ", chartype
, 0, count
);
1096 bidi_resolve_explicit(baselevel
, chartype
, levels
, count
);
1097 memcpy(explicit, levels
, count
*sizeof(*explicit));
1099 if (TRACE_ON(bidi
)) bidi_dump_types("after explicit", chartype
, 0, count
);
1101 /* X10/BD13: Compute Isolating runs */
1102 hr
= bidi_compute_isolating_runs_set(baselevel
, chartype
, levels
, string
, count
, &IsolatingRuns
);
1106 LIST_FOR_EACH_ENTRY_SAFE(iso_run
, next
, &IsolatingRuns
, IsolatedRun
, entry
)
1108 if (TRACE_ON(bidi
)) iso_dump_types("run", iso_run
);
1110 bidi_resolve_weak(iso_run
);
1111 if (TRACE_ON(bidi
)) iso_dump_types("after weak", iso_run
);
1113 bidi_resolve_neutrals(iso_run
);
1114 if (TRACE_ON(bidi
)) iso_dump_types("after neutrals", iso_run
);
1116 list_remove(&iso_run
->entry
);
1120 if (TRACE_ON(bidi
)) bidi_dump_types("before implicit", chartype
, 0, count
);
1121 bidi_resolve_implicit(chartype
, levels
, 0, count
-1);
1123 bidi_classify(string
, chartype
, count
);
1124 bidi_resolve_resolved(baselevel
, chartype
, levels
, 0, count
-1);
1127 heap_free(chartype
);