2 * fribidi-bidi.c - bidirectional algorithm
4 * $Id: fribidi-bidi.c,v 1.21 2007-03-15 18:09:25 behdad Exp $
6 * $Date: 2007-03-15 18:09:25 $
8 * $Source: /home/behdad/src/fdo/fribidi/togit/git/../fribidi/fribidi2/lib/fribidi-bidi.c,v $
11 * Behdad Esfahbod, 2001, 2002, 2004
12 * Dov Grobgeld, 1999, 2000
14 * Copyright (C) 2004 Sharif FarsiWeb, Inc
15 * Copyright (C) 2001,2002 Behdad Esfahbod
16 * Copyright (C) 1999,2000 Dov Grobgeld
18 * This library is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU Lesser General Public
20 * License as published by the Free Software Foundation; either
21 * version 2.1 of the License, or (at your option) any later version.
23 * This library is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * Lesser General Public License for more details.
28 * You should have received a copy of the GNU Lesser General Public License
29 * along with this library, in a file named COPYING; if not, write to the
30 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
31 * Boston, MA 02110-1301, USA
33 * For licensing issues, contact <license@farsiweb.info>.
38 #include <fribidi-bidi.h>
39 #include <fribidi-mirroring.h>
40 #include <fribidi-unicode.h>
43 #include "bidi-types.h"
47 * This file implements most of Unicode Standard Annex #9, Tracking Number 13.
51 # define MAX(a,b) ((a) > (b) ? (a) : (b))
54 /* Some convenience macros */
55 #define RL_TYPE(list) ((list)->type)
56 #define RL_LEN(list) ((list)->len)
57 #define RL_POS(list) ((list)->pos)
58 #define RL_LEVEL(list) ((list)->level)
67 fribidi_assert (second);
68 fribidi_assert (second->next);
70 fribidi_assert (first);
72 first->next = second->next;
73 first->next->prev = first;
74 RL_LEN (first) += RL_LEN (second);
84 fribidi_assert (list);
87 for_run_list (list, list)
88 if (RL_TYPE (list->prev) == RL_TYPE (list)
89 && RL_LEVEL (list->prev) == RL_LEVEL (list))
90 list = merge_with_prev (list);
98 fribidi_assert (list);
102 for_run_list (list, list)
104 if (RL_LEVEL (list->prev) == RL_LEVEL (list)
107 (list->prev) == RL_TYPE (list)
108 || (FRIBIDI_IS_NEUTRAL (RL_TYPE (list->prev))
109 && FRIBIDI_IS_NEUTRAL (RL_TYPE (list))))))
110 list = merge_with_prev (list);
116 /*======================================================================
117 * For debugging, define some functions for printing the types and the
119 *----------------------------------------------------------------------*/
121 static char char_from_level_array[] = {
122 '$', /* -1 == FRIBIDI_SENTINEL, indicating
123 * start or end of string. */
124 /* 0-61 == 0-9,a-z,A-Z are the the only valid levels before resolving
125 * implicits. after that the level @ may be appear too. */
126 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
127 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
128 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
129 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
130 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
131 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
134 '@', /* 62 == only must appear after resolving
137 '!', /* 63 == FRIBIDI_LEVEL_INVALID, internal error,
138 * this level shouldn't be seen. */
140 '*', '*', '*', '*', '*' /* >= 64 == overflows, this levels and higher
141 * levels show a real bug!. */
144 #define fribidi_char_from_level(level) char_from_level_array[(level) + 1]
153 MSG (" Run types : ");
154 for_run_list (pp, pp)
156 MSG5 ("%d:%d(%s)[%d] ",
157 pp->pos, pp->len, fribidi_get_bidi_type_name (pp->type), pp->level);
163 print_resolved_levels (
169 MSG (" Res. levels: ");
170 for_run_list (pp, pp)
172 register FriBidiStrIndex i;
173 for (i = RL_LEN (pp); i; i--)
174 MSG2 ("%c", fribidi_char_from_level (RL_LEVEL (pp)));
180 print_resolved_types (
186 MSG (" Res. types : ");
187 for_run_list (pp, pp)
190 for (i = RL_LEN (pp); i; i--)
191 MSG2 ("%c", fribidi_char_from_bidi_type (pp->type));
199 const FriBidiCharType *bidi_types,
200 const FriBidiStrIndex len
203 register FriBidiStrIndex i;
205 fribidi_assert (bidi_types);
207 MSG (" Org. types : ");
208 for (i = 0; i < len; i++)
209 MSG2 ("%c", fribidi_char_from_bidi_type (bidi_types[i]));
215 /*=========================================================================
216 * define macros for push and pop the status in to / out of the stack
217 *-------------------------------------------------------------------------*/
219 /* There are a few little points in pushing into and poping from the status
221 1. when the embedding level is not valid (more than
222 FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL=61), you must reject it, and not to push
223 into the stack, but when you see a PDF, you must find the matching code,
224 and if it was pushed in the stack, pop it, it means you must pop if and
225 only if you have pushed the matching code, the over_pushed var counts the
226 number of rejected codes so far.
227 2. there's a more confusing point too, when the embedding level is exactly
228 FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL-1=60, an LRO or LRE is rejected
229 because the new level would be FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL+1=62, that
230 is invalid; but an RLO or RLE is accepted because the new level is
231 FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL=61, that is valid, so the rejected codes
232 may be not continuous in the logical order, in fact there are at most two
233 continuous intervals of codes, with an RLO or RLE between them. To support
234 this case, the first_interval var counts the number of rejected codes in
235 the first interval, when it is 0, means that there is only one interval.
238 /* a. If this new level would be valid, then this embedding code is valid.
239 Remember (push) the current embedding level and override status.
240 Reset current level to this new level, and reset the override status to
242 b. If the new level would not be valid, then this code is invalid. Don't
243 change the current level or override status.
245 #define PUSH_STATUS \
247 if LIKELY(new_level <= FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL) \
249 if UNLIKELY(level == FRIBIDI_BIDI_MAX_EXPLICIT_LEVEL - 1) \
250 first_interval = over_pushed; \
251 status_stack[stack_size].level = level; \
252 status_stack[stack_size].override = override; \
255 override = new_override; \
260 /* If there was a valid matching code, restore (pop) the last remembered
261 (pushed) embedding level and directional override.
267 if UNLIKELY(over_pushed > first_interval) \
271 if LIKELY(over_pushed == first_interval) \
272 first_interval = 0; \
274 level = status_stack[stack_size].level; \
275 override = status_stack[stack_size].override; \
281 /* Return the type of previous run or the SOR, if already at the start of
283 #define PREV_TYPE_OR_SOR(pp) \
285 RL_LEVEL(pp->prev) == RL_LEVEL(pp) ? \
286 RL_TYPE(pp->prev) : \
287 FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(pp->prev), RL_LEVEL(pp))) \
290 /* Return the type of next run or the EOR, if already at the end of
292 #define NEXT_TYPE_OR_EOR(pp) \
294 RL_LEVEL(pp->next) == RL_LEVEL(pp) ? \
295 RL_TYPE(pp->next) : \
296 FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(pp->next), RL_LEVEL(pp))) \
300 /* Return the embedding direction of a link. */
301 #define FRIBIDI_EMBEDDING_DIRECTION(link) \
302 FRIBIDI_LEVEL_TO_DIR(RL_LEVEL(link))
305 FRIBIDI_ENTRY FriBidiParType
306 fribidi_get_par_direction (
308 const FriBidiCharType *bidi_types,
309 const FriBidiStrIndex len
312 register FriBidiStrIndex i;
314 fribidi_assert (bidi_types);
316 for (i = 0; i < len; i++)
317 if (FRIBIDI_IS_LETTER (bidi_types[i]))
318 return FRIBIDI_IS_RTL (bidi_types[i]) ? FRIBIDI_PAR_RTL :
321 return FRIBIDI_PAR_ON;
324 FRIBIDI_ENTRY FriBidiLevel
325 fribidi_get_par_embedding_levels (
327 const FriBidiCharType *bidi_types,
328 const FriBidiStrIndex len,
329 /* input and output */
330 FriBidiParType *pbase_dir,
332 FriBidiLevel *embedding_levels
335 FriBidiLevel base_level, max_level = 0;
336 FriBidiParType base_dir;
337 FriBidiRun *main_run_list = NULL, *explicits_list = NULL, *pp;
338 fribidi_boolean status = false;
347 DBG ("in fribidi_get_par_embedding_levels");
349 fribidi_assert (bidi_types);
350 fribidi_assert (pbase_dir);
351 fribidi_assert (embedding_levels);
353 /* Determinate character types */
355 /* Get run-length encoded character types */
356 main_run_list = run_list_encode_bidi_types (bidi_types, len);
358 (!main_run_list) goto out;
361 /* Find base level */
362 /* If no strong base_dir was found, resort to the weak direction
363 that was passed on input. */
364 base_level = FRIBIDI_DIR_TO_LEVEL (*pbase_dir);
365 if (!FRIBIDI_IS_STRONG (*pbase_dir))
366 /* P2. P3. Search for first strong character and use its direction as
369 for_run_list (pp, main_run_list) if (FRIBIDI_IS_LETTER (RL_TYPE (pp)))
371 base_level = FRIBIDI_DIR_TO_LEVEL (RL_TYPE (pp));
372 *pbase_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
376 base_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
377 DBG2 (" base level : %c", fribidi_char_from_level (base_level));
378 DBG2 (" base dir : %c", fribidi_char_from_bidi_type (base_dir));
382 (fribidi_debug_status ())
384 print_types_re (main_run_list);
388 /* Explicit Levels and Directions */
389 DBG ("explicit levels and directions");
391 FriBidiLevel level, new_level;
392 FriBidiCharType override, new_override;
394 int stack_size, over_pushed, first_interval;
397 FriBidiCharType override; /* only LTR, RTL and ON are valid */
400 FriBidiRun temp_link;
402 /* explicits_list is a list like main_run_list, that holds the explicit
403 codes that are removed from main_run_list, to reinsert them later by
404 calling the shadow_run_list.
406 explicits_list = new_run_list ();
408 (!explicits_list) goto out;
410 /* X1. Begin by setting the current embedding level to the paragraph
411 embedding level. Set the directional override status to neutral.
412 Process each character iteratively, applying rules X2 through X9.
413 Only embedding levels from 0 to 61 are valid in this phase. */
416 override = FRIBIDI_TYPE_ON;
421 status_stack = fribidi_malloc (sizeof (status_stack[0]) *
422 FRIBIDI_BIDI_MAX_RESOLVED_LEVELS);
424 for_run_list (pp, main_run_list)
426 FriBidiCharType this_type = RL_TYPE (pp);
427 if (FRIBIDI_IS_EXPLICIT_OR_BN (this_type))
429 if (FRIBIDI_IS_STRONG (this_type))
430 { /* LRE, RLE, LRO, RLO */
431 /* 1. Explicit Embeddings */
432 /* X2. With each RLE, compute the least greater odd
434 /* X3. With each LRE, compute the least greater even
436 /* 2. Explicit Overrides */
437 /* X4. With each RLO, compute the least greater odd
439 /* X5. With each LRO, compute the least greater even
441 new_override = FRIBIDI_EXPLICIT_TO_OVERRIDE_DIR (this_type);
442 for (i = RL_LEN (pp); i; i--)
445 ((level + FRIBIDI_DIR_TO_LEVEL (this_type) + 2) & ~1) -
446 FRIBIDI_DIR_TO_LEVEL (this_type);
450 else if (this_type == FRIBIDI_TYPE_PDF)
452 /* 3. Terminating Embeddings and overrides */
453 /* X7. With each PDF, determine the matching embedding or
455 for (i = RL_LEN (pp); i; i--)
459 /* X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes. */
460 /* Remove element and add it to explicits_list */
461 RL_LEVEL (pp) = FRIBIDI_SENTINEL;
462 temp_link.next = pp->next;
463 move_node_before (pp, explicits_list);
468 /* X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
469 a. Set the level of the current character to the current
471 b. Whenever the directional override status is not neutral,
472 reset the current character type to the directional override
474 RL_LEVEL (pp) = level;
475 if (!FRIBIDI_IS_NEUTRAL (override))
476 RL_TYPE (pp) = override;
478 /* X8. All explicit directional embeddings and overrides are
479 completely terminated at the end of each paragraph. Paragraph
480 separators are not included in the embedding. */
481 /* This function is running on a single paragraph, so we can do
482 X8 after all the input is processed. */
485 /* Implementing X8. It has no effect on a single paragraph! */
487 override = FRIBIDI_TYPE_ON;
491 fribidi_free (status_stack);
493 /* X10. The remaining rules are applied to each run of characters at the
494 same level. For each run, determine the start-of-level-run (sor) and
495 end-of-level-run (eor) type, either L or R. This depends on the
496 higher of the two levels on either side of the boundary (at the start
497 or end of the paragraph, the level of the 'other' run is the base
498 embedding level). If the higher level is odd, the type is R, otherwise
500 /* Resolving Implicit Levels can be done out of X10 loop, so only change
501 of Resolving Weak Types and Resolving Neutral Types is needed. */
503 compact_list (main_run_list);
507 (fribidi_debug_status ())
509 print_types_re (main_run_list);
510 print_bidi_string (bidi_types, len);
511 print_resolved_levels (main_run_list);
512 print_resolved_types (main_run_list);
516 /* 4. Resolving weak types */
517 DBG ("resolving weak types");
519 FriBidiCharType last_strong, prev_type_orig;
522 last_strong = base_dir;
524 for_run_list (pp, main_run_list)
526 register FriBidiCharType prev_type, this_type, next_type;
528 prev_type = PREV_TYPE_OR_SOR (pp);
529 this_type = RL_TYPE (pp);
530 next_type = NEXT_TYPE_OR_EOR (pp);
532 if (FRIBIDI_IS_STRONG (prev_type))
533 last_strong = prev_type;
536 Examine each non-spacing mark (NSM) in the level run, and change the
537 type of the NSM to the type of the previous character. If the NSM
538 is at the start of the level run, it will get the type of sor. */
539 /* Implementation note: it is important that if the previous character
540 is not sor, then we should merge this run with the previous,
541 because of rules like W5, that we assume all of a sequence of
542 adjacent ETs are in one FriBidiRun. */
543 if (this_type == FRIBIDI_TYPE_NSM)
545 if (RL_LEVEL (pp->prev) == RL_LEVEL (pp))
546 pp = merge_with_prev (pp);
548 RL_TYPE (pp) = prev_type;
549 continue; /* As we know the next condition cannot be true. */
552 /* W2: European numbers. */
553 if (this_type == FRIBIDI_TYPE_EN && last_strong == FRIBIDI_TYPE_AL)
555 RL_TYPE (pp) = FRIBIDI_TYPE_AN;
557 /* Resolving dependency of loops for rules W1 and W2, so we
558 can merge them in one loop. */
559 if (next_type == FRIBIDI_TYPE_NSM)
560 RL_TYPE (pp->next) = FRIBIDI_TYPE_AN;
565 last_strong = base_dir;
566 /* Resolving dependency of loops for rules W4 and W5, W5 may
567 want to prevent W4 to take effect in the next turn, do this
570 /* Resolving dependency of loops for rules W4 and W5 with W7,
571 W7 may change an EN to L but it sets the prev_type_orig if needed,
572 so W4 and W5 in next turn can still do their works. */
573 prev_type_orig = FRIBIDI_TYPE_ON;
575 for_run_list (pp, main_run_list)
577 register FriBidiCharType prev_type, this_type, next_type;
579 prev_type = PREV_TYPE_OR_SOR (pp);
580 this_type = RL_TYPE (pp);
581 next_type = NEXT_TYPE_OR_EOR (pp);
583 if (FRIBIDI_IS_STRONG (prev_type))
584 last_strong = prev_type;
586 /* W3: Change ALs to R. */
587 if (this_type == FRIBIDI_TYPE_AL)
589 RL_TYPE (pp) = FRIBIDI_TYPE_RTL;
591 prev_type_orig = FRIBIDI_TYPE_ON;
595 /* W4. A single european separator changes to a european number.
596 A single common separator between two numbers of the same type
597 changes to that type. */
599 && RL_LEN (pp) == 1 && FRIBIDI_IS_ES_OR_CS (this_type)
600 && FRIBIDI_IS_NUMBER (prev_type_orig)
601 && prev_type_orig == next_type
602 && (prev_type_orig == FRIBIDI_TYPE_EN
603 || this_type == FRIBIDI_TYPE_CS))
605 RL_TYPE (pp) = prev_type;
606 this_type = RL_TYPE (pp);
610 /* W5. A sequence of European terminators adjacent to European
611 numbers changes to All European numbers. */
612 if (this_type == FRIBIDI_TYPE_ET
613 && (prev_type_orig == FRIBIDI_TYPE_EN
614 || next_type == FRIBIDI_TYPE_EN))
616 RL_TYPE (pp) = FRIBIDI_TYPE_EN;
618 this_type = RL_TYPE (pp);
621 /* W6. Otherwise change separators and terminators to other neutral. */
622 if (FRIBIDI_IS_NUMBER_SEPARATOR_OR_TERMINATOR (this_type))
623 RL_TYPE (pp) = FRIBIDI_TYPE_ON;
625 /* W7. Change european numbers to L. */
626 if (this_type == FRIBIDI_TYPE_EN && last_strong == FRIBIDI_TYPE_LTR)
628 RL_TYPE (pp) = FRIBIDI_TYPE_LTR;
629 prev_type_orig = (RL_LEVEL (pp) == RL_LEVEL (pp->next) ?
630 FRIBIDI_TYPE_EN : FRIBIDI_TYPE_ON);
633 prev_type_orig = PREV_TYPE_OR_SOR (pp->next);
637 compact_neutrals (main_run_list);
641 (fribidi_debug_status ())
643 print_resolved_levels (main_run_list);
644 print_resolved_types (main_run_list);
648 /* 5. Resolving Neutral Types */
649 DBG ("resolving neutral types");
652 For each neutral, resolve it. */
653 for_run_list (pp, main_run_list)
655 FriBidiCharType prev_type, this_type, next_type;
657 /* "European and Arabic numbers are treated as though they were R"
658 FRIBIDI_CHANGE_NUMBER_TO_RTL does this. */
659 this_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE (pp));
660 prev_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (PREV_TYPE_OR_SOR (pp));
661 next_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (NEXT_TYPE_OR_EOR (pp));
663 if (FRIBIDI_IS_NEUTRAL (this_type))
664 RL_TYPE (pp) = (prev_type == next_type) ?
665 /* N1. */ prev_type :
666 /* N2. */ FRIBIDI_EMBEDDING_DIRECTION (pp);
670 compact_list (main_run_list);
674 (fribidi_debug_status ())
676 print_resolved_levels (main_run_list);
677 print_resolved_types (main_run_list);
681 /* 6. Resolving implicit levels */
682 DBG ("resolving implicit levels");
684 max_level = base_level;
686 for_run_list (pp, main_run_list)
688 FriBidiCharType this_type;
691 this_type = RL_TYPE (pp);
692 level = RL_LEVEL (pp);
696 if (FRIBIDI_IS_NUMBER (this_type))
697 RL_LEVEL (pp) = (level + 2) & ~1;
701 (FRIBIDI_LEVEL_IS_RTL (level) ^ FRIBIDI_DIR_TO_LEVEL (this_type));
703 if (RL_LEVEL (pp) > max_level)
704 max_level = RL_LEVEL (pp);
708 compact_list (main_run_list);
712 (fribidi_debug_status ())
714 print_bidi_string (bidi_types, len);
715 print_resolved_levels (main_run_list);
716 print_resolved_types (main_run_list);
720 /* Reinsert the explicit codes & BN's that are already removed, from the
721 explicits_list to main_run_list. */
722 DBG ("reinserting explicit codes");
724 (explicits_list->next != explicits_list)
726 register FriBidiRun *p;
727 register fribidi_boolean stat =
728 shadow_run_list (main_run_list, explicits_list, true);
729 explicits_list = NULL;
733 /* Set level of inserted explicit chars to that of their previous
734 * char, such that they do not affect reordering. */
735 p = main_run_list->next;
736 if (p != main_run_list && p->level == FRIBIDI_SENTINEL)
737 p->level = base_level;
738 for_run_list (p, main_run_list) if (p->level == FRIBIDI_SENTINEL)
739 p->level = p->prev->level;
744 (fribidi_debug_status ())
746 print_types_re (main_run_list);
747 print_resolved_levels (main_run_list);
748 print_resolved_types (main_run_list);
752 DBG ("reset the embedding levels, 1, 2, 3.");
754 register int j, state, pos;
755 register FriBidiCharType char_type;
756 register FriBidiRun *p, *q, *list;
758 /* L1. Reset the embedding levels of some chars:
759 1. segment separators,
760 2. paragraph separators,
761 3. any sequence of whitespace characters preceding a segment
762 separator or paragraph separator, and
763 ... (to be continued in fribidi_reorder_line()). */
764 list = new_run_list ();
770 for (j = len - 1; j >= -1; j--)
772 /* close up the open link at the end */
774 char_type = bidi_types[j];
776 char_type = FRIBIDI_TYPE_ON;
777 if (!state && FRIBIDI_IS_SEPARATOR (char_type))
782 else if (state && !FRIBIDI_IS_EXPLICIT_OR_SEPARATOR_OR_BN_OR_WS
790 free_run_list (list);
796 p->level = base_level;
797 move_node_before (p, q);
802 (!shadow_run_list (main_run_list, list, false)) goto out;
807 (fribidi_debug_status ())
809 print_types_re (main_run_list);
810 print_resolved_levels (main_run_list);
811 print_resolved_types (main_run_list);
816 FriBidiStrIndex pos = 0;
817 for_run_list (pp, main_run_list)
819 register FriBidiStrIndex l;
820 register FriBidiLevel level = pp->level;
821 for (l = pp->len; l; l--)
822 embedding_levels[pos++] = level;
829 DBG ("leaving fribidi_get_par_embedding_levels");
832 free_run_list (main_run_list);
834 (explicits_list) free_run_list (explicits_list);
836 return status ? max_level + 1 : 0;
841 bidi_string_reverse (
843 const FriBidiStrIndex len
848 fribidi_assert (str);
850 for (i = 0; i < len / 2; i++)
852 FriBidiChar tmp = str[i];
853 str[i] = str[len - 1 - i];
854 str[len - 1 - i] = tmp;
859 index_array_reverse (
860 FriBidiStrIndex *arr,
861 const FriBidiStrIndex len
866 fribidi_assert (arr);
868 for (i = 0; i < len / 2; i++)
870 FriBidiStrIndex tmp = arr[i];
871 arr[i] = arr[len - 1 - i];
872 arr[len - 1 - i] = tmp;
877 FRIBIDI_ENTRY FriBidiLevel
878 fribidi_reorder_line (
880 FriBidiFlags flags, /* reorder flags */
881 const FriBidiCharType *bidi_types,
882 const FriBidiStrIndex len,
883 const FriBidiStrIndex off,
884 const FriBidiParType base_dir,
885 /* input and output */
886 FriBidiLevel *embedding_levels,
887 FriBidiChar *visual_str,
892 fribidi_boolean status = false;
893 FriBidiLevel max_level = 0;
902 DBG ("in fribidi_reorder_line");
904 fribidi_assert (bidi_types);
905 fribidi_assert (embedding_levels);
907 DBG ("reset the embedding levels, 4. whitespace at the end of line");
909 register FriBidiStrIndex i;
911 /* L1. Reset the embedding levels of some chars:
912 4. any sequence of white space characters at the end of the line. */
913 for (i = off + len - 1; i >= off &&
914 FRIBIDI_IS_EXPLICIT_OR_BN_OR_WS (bidi_types[i]); i--)
915 embedding_levels[i] = FRIBIDI_DIR_TO_LEVEL (base_dir);
918 /* 7. Reordering resolved levels */
920 register FriBidiLevel level;
921 register FriBidiStrIndex i;
923 /* Reorder both the outstring and the order array */
925 if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_REORDER_NSM))
927 /* L3. Reorder NSMs. */
928 for (i = off + len - 1; i >= off; i--)
929 if (FRIBIDI_LEVEL_IS_RTL (embedding_levels[i])
930 && bidi_types[i] == FRIBIDI_TYPE_NSM)
932 register FriBidiStrIndex seq_end = i;
933 level = embedding_levels[i];
935 for (i--; i >= off &&
936 FRIBIDI_IS_EXPLICIT_OR_BN_OR_NSM (bidi_types[i])
937 && embedding_levels[i] == level; i--)
940 if (i < off || embedding_levels[i] != level)
943 DBG ("warning: NSM(s) at the beggining of level run");
948 bidi_string_reverse (visual_str + i, seq_end - i + 1);
952 index_array_reverse (map + i, seq_end - i + 1);
957 /* Find max_level of the line. We don't reuse the paragraph
958 * max_level, both for a cleaner API, and that the line max_level
959 * may be far less than paragraph max_level. */
960 for (i = off + len - 1; i >= off; i--)
961 if (embedding_levels[i] > max_level)
962 max_level = embedding_levels[i];
965 for (level = max_level; level > 0; level--)
966 for (i = off + len - 1; i >= off; i--)
967 if (embedding_levels[i] >= level)
969 /* Find all stretches that are >= level_idx */
970 register FriBidiStrIndex seq_end = i;
971 for (i--; i >= off && embedding_levels[i] >= level; i--)
975 bidi_string_reverse (visual_str + i + 1, seq_end - i);
977 index_array_reverse (map + i + 1, seq_end - i);
987 return status ? max_level + 1 : 0;
990 /* Editor directions:
991 * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent