1 /* FriBidi - Library of BiDi algorithm
2 * Copyright (C) 1999,2000 Dov Grobgeld, and
3 * Copyright (C) 2001,2002 Behdad Esfahbod.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library, in a file named COPYING; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA
20 * For licensing issues, contact <dov@imagic.weizmann.ac.il> and
30 /* Redefine FRIBIDI_CHUNK_SIZE in config.h to override this. */
31 #ifndef FRIBIDI_CHUNK_SIZE
33 #define FRIBIDI_CHUNK_SIZE 16
35 #define FRIBIDI_CHUNK_SIZE 128
42 /*======================================================================
43 * Typedef for the run-length list.
44 *----------------------------------------------------------------------*/
45 typedef struct _TypeLink TypeLink;
53 FriBidiStrIndex pos, len;
57 #define FRIBIDI_LEVEL_START -1
58 #define FRIBIDI_LEVEL_END -1
59 #define FRIBIDI_LEVEL_REMOVED -2
63 FriBidiCharType override; /* only L, R and N are valid */
73 link = g_slice_new0 (TypeLink);
79 free_type_link (TypeLink *link)
81 g_slice_free (TypeLink, link);
84 #define FRIBIDI_ADD_TYPE_LINK(p,q) \
86 (p)->len = (q)->pos - (p)->pos; \
93 run_length_encode_types_utf8 (const char *s,
96 FriBidiCharType *pored_types,
97 FriBidiCharType *panded_strongs)
99 TypeLink *list, *last, *link;
100 FriBidiCharType char_type;
101 FriBidiCharType ored_types = 0;
102 FriBidiCharType anded_strongs = FRIBIDI_TYPE_RLE;
106 /* Add the starting link */
107 list = new_type_link ();
108 list->type = FRIBIDI_TYPE_SOT;
109 list->level = FRIBIDI_LEVEL_START;
112 /* Sweep over the string s */
114 for (p = s; p < s + bytelen; p = g_utf8_next_char(p)) {
115 char_type = fribidi_get_type (g_utf8_get_char (p));
116 ored_types |= char_type;
117 if (FRIBIDI_IS_STRONG (char_type))
118 anded_strongs &= char_type;
119 if (char_type != last->type)
121 link = new_type_link ();
122 link->type = char_type;
124 FRIBIDI_ADD_TYPE_LINK (last, link);
129 /* Add the ending link */
130 link = new_type_link ();
131 link->type = FRIBIDI_TYPE_EOT;
132 link->level = FRIBIDI_LEVEL_END;
134 FRIBIDI_ADD_TYPE_LINK (last, link);
140 *pored_types = ored_types;
142 *panded_strongs = anded_strongs;
147 /* explicits_list is a list like type_rl_list, that holds the explicit
148 codes that are removed from rl_list, to reinsert them later by calling
152 init_list (TypeLink **start,
158 /* Add the starting link */
159 list = new_type_link ();
160 list->type = FRIBIDI_TYPE_SOT;
161 list->level = FRIBIDI_LEVEL_START;
165 /* Add the ending link */
166 link = new_type_link ();
167 link->type = FRIBIDI_TYPE_EOT;
168 link->level = FRIBIDI_LEVEL_END;
178 /* move an element before another element in a list, the list must have a
179 previous element, used to update explicits_list.
180 assuming that p have both prev and next or none of them, also update
181 the list that p is currently in, if any.
184 move_element_before (TypeLink *p,
189 p->prev->next = p->next;
190 p->next->prev = p->prev;
192 p->prev = list->prev;
193 list->prev->next = p;
198 /* override the rl_list 'base', with the elements in the list 'over', to
199 reinsert the previously-removed explicit codes (at X9) from
200 'explicits_list' back into 'type_rl_list'. This is used at the end of I2
201 to restore the explicit marks, and also to reset the character types of
204 it is assumed that the 'pos' of the first element in 'base' list is not
205 more than the 'pos' of the first element of the 'over' list, and the
206 'pos' of the last element of the 'base' list is not less than the 'pos'
207 of the last element of the 'over' list. these two conditions are always
208 satisfied for the two usages mentioned above.
210 TBD: use some explanatory names instead of p, q, ...
213 override_list (TypeLink *base,
216 TypeLink *p = base, *q, *r, *s, *t;
217 FriBidiStrIndex pos = 0, pos2;
224 if (!q->len || q->pos < pos)
232 while (p->next && p->next->pos <= pos)
234 /* now p is the element that q must be inserted 'in'. */
237 while (r->next && r->next->pos < pos2)
239 /* now r is the last element that q affects. */
242 /* split p into at most 3 interval, and insert q in the place of
243 the second interval, set r to be the third part. */
244 /* third part needed? */
245 if (p->next && p->next->pos == pos2)
249 r = new_type_link ();
254 r->len = r->next->pos - pos2;
257 r->len -= pos - p->pos;
260 /* first part needed? */
261 if (p->prev && p->pos == pos)
268 p->len = pos - p->pos;
272 /* cut the end of p. */
273 p->len = pos - p->pos;
274 /* if all of p is cut, remove it. */
275 if (!p->len && p->prev)
278 /* cut the begining of r. */
281 r->len = r->next->pos - pos2;
282 /* if all of r is cut, remove it. */
283 if (!r->len && r->next)
286 /* remove the elements between p and r. */
287 for (s = p->next; s != r;)
294 /* before updating the next and prev links to point to the inserted q,
295 we must remember the next element of q in the 'over' list.
306 /* Some convenience macros */
307 #define RL_TYPE(list) ((list)->type)
308 #define RL_LEN(list) ((list)->len)
309 #define RL_POS(list) ((list)->pos)
310 #define RL_LEVEL(list) ((list)->level)
313 merge_with_prev (TypeLink *second)
315 TypeLink *first = second->prev;
316 first->next = second->next;
317 first->next->prev = first;
318 RL_LEN (first) += RL_LEN (second);
319 free_type_link (second);
324 compact_list (TypeLink *list)
327 for (list = list->next; list; list = list->next)
328 if (RL_TYPE (list->prev) == RL_TYPE (list)
329 && RL_LEVEL (list->prev) == RL_LEVEL (list))
330 list = merge_with_prev (list);
334 compact_neutrals (TypeLink *list)
338 for (list = list->next; list; list = list->next)
340 if (RL_LEVEL (list->prev) == RL_LEVEL (list)
343 (list->prev) == RL_TYPE (list)
344 || (FRIBIDI_IS_NEUTRAL (RL_TYPE (list->prev))
345 && FRIBIDI_IS_NEUTRAL (RL_TYPE (list))))))
346 list = merge_with_prev (list);
351 /*======================================================================
352 * Frees up the rl_list, must be called after each call to
353 * fribidi_analyse_string(), after the list is not needed anymore.
354 *----------------------------------------------------------------------*/
356 free_rl_list (TypeLink *type_rl_list)
358 DBG ("Entering free_rl_list()\n");
362 DBG ("Leaving free_rl_list()\n");
366 g_slice_free_chain (TypeLink, type_rl_list, next);
368 DBG ("Leaving free_rl_list()\n");
372 /*=========================================================================
373 * define macros for push and pop the status in to / out of the stack
374 *-------------------------------------------------------------------------*/
376 /* There's some little points in pushing and poping into the status stack:
377 1. when the embedding level is not valid (more than UNI_MAX_BIDI_LEVEL=61),
378 you must reject it, and not to push into the stack, but when you see a
379 PDF, you must find the matching code, and if it was pushed in the stack,
380 pop it, it means you must pop if and only if you have pushed the
381 matching code, the over_pushed var counts the number of rejected codes yet.
382 2. there's a more confusing point too, when the embedding level is exactly
383 UNI_MAX_BIDI_LEVEL-1=60, an LRO or LRE must be rejected because the new
384 level would be UNI_MAX_BIDI_LEVEL+1=62, that is invalid, but an RLO or RLE
385 must be accepted because the new level is UNI_MAX_BIDI_LEVEL=61, that is
386 valid, so the rejected codes may be not continuous in the logical order,
387 in fact there is at most two continuous intervals of codes, with a RLO or
388 RLE between them. To support this case, the first_interval var counts the
389 number of rejected codes in the first interval, when it is 0, means that
390 there is only one interval yet.
393 /* a. If this new level would be valid, then this embedding code is valid.
394 Remember (push) the current embedding level and override status.
395 Reset current level to this new level, and reset the override status to
397 b. If the new level would not be valid, then this code is invalid. Don't
398 change the current level or override status.
400 #define PUSH_STATUS \
402 if (new_level <= UNI_MAX_BIDI_LEVEL) \
404 if (level == UNI_MAX_BIDI_LEVEL - 1) \
405 first_interval = over_pushed; \
406 status_stack[stack_size].level = level; \
407 status_stack[stack_size].override = override; \
410 override = new_override; \
415 /* If there was a valid matching code, restore (pop) the last remembered
416 (pushed) embedding level and directional override.
420 if (over_pushed || stack_size) \
422 if (over_pushed > first_interval) \
426 if (over_pushed == first_interval) \
427 first_interval = 0; \
429 level = status_stack[stack_size].level; \
430 override = status_stack[stack_size].override; \
435 /*==========================================================================
436 * There was no support for sor and eor in the absence of Explicit Embedding
437 * Levels, so define macros, to support them, with as less change as needed.
438 *--------------------------------------------------------------------------*/
440 /* Return the type of previous char or the sor, if already at the start of
442 #define PREV_TYPE_OR_SOR(pp) \
444 RL_LEVEL(pp->prev) == RL_LEVEL(pp) ? \
445 RL_TYPE(pp->prev) : \
446 FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(pp->prev), RL_LEVEL(pp))) \
449 /* Return the type of next char or the eor, if already at the end of
451 #define NEXT_TYPE_OR_EOR(pp) \
454 FRIBIDI_LEVEL_TO_DIR(RL_LEVEL(pp)) : \
455 (RL_LEVEL(pp->next) == RL_LEVEL(pp) ? \
456 RL_TYPE(pp->next) : \
457 FRIBIDI_LEVEL_TO_DIR(MAX(RL_LEVEL(pp->next), RL_LEVEL(pp))) \
462 /* Return the embedding direction of a link. */
463 #define FRIBIDI_EMBEDDING_DIRECTION(list) \
464 FRIBIDI_LEVEL_TO_DIR(RL_LEVEL(list))
467 /*======================================================================
468 * This function should follow the Unicode specification closely!
469 *----------------------------------------------------------------------*/
470 static fribidi_boolean
471 fribidi_analyse_string_utf8 ( /* input */
474 FriBidiCharType *pbase_dir,
476 FriBidiStrIndex *len,
477 TypeLink **ptype_rl_list,
478 FriBidiLevel *pmax_level)
480 FriBidiLevel base_level, max_level;
481 FriBidiCharType base_dir;
482 TypeLink *type_rl_list, *explicits_list, *explicits_list_end, *pp;
484 DBG ("Entering fribidi_analyse_string()\n");
486 /* Determinate character types */
487 DBG (" Determine character types\n");
489 FriBidiCharType ored_types;
490 FriBidiCharType anded_strongs;
492 /* Run length encode the character types */
493 type_rl_list = run_length_encode_types_utf8 (str, bytelen, len,
494 &ored_types, &anded_strongs);
496 /* The case that all resolved levels will be ltr.
497 * First, all strongs should be ltr, and one of the following:
499 * o *pbase_dir doesn't have an rtl taste.
500 * o there are letters, and *pbase_dir is weak.
502 if (!FRIBIDI_IS_RTL (ored_types) &&
503 (!FRIBIDI_IS_RTL (*pbase_dir) ||
504 (FRIBIDI_IS_WEAK (*pbase_dir) && FRIBIDI_IS_LETTER (ored_types))
508 free_rl_list (type_rl_list);
510 *ptype_rl_list = NULL;
512 *pbase_dir = FRIBIDI_TYPE_LTR;
516 /* The case that all resolved levels will be rtl is much more complex.
517 * First, there should be no numbers, all strongs be rtl, and one of
520 * o *pbase_dir has an rtl taste (may be weak).
521 * o there are letters, and *pbase_dir is weak.
523 else if (!FRIBIDI_IS_NUMBER (ored_types) && FRIBIDI_IS_RTL (anded_strongs) &&
524 (FRIBIDI_IS_RTL (*pbase_dir) ||
525 (FRIBIDI_IS_WEAK (*pbase_dir) && FRIBIDI_IS_LETTER (ored_types))
528 free_rl_list (type_rl_list);
530 *ptype_rl_list = NULL;
532 *pbase_dir = FRIBIDI_TYPE_RTL;
537 DBG (" Determine character types, Done\n");
539 init_list (&explicits_list, &explicits_list_end);
541 /* Find base level */
542 DBG (" Finding the base level\n");
543 if (FRIBIDI_IS_STRONG (*pbase_dir))
544 base_level = FRIBIDI_DIR_TO_LEVEL (*pbase_dir);
545 /* P2. P3. Search for first strong character and use its direction as
549 /* If no strong base_dir was found, resort to the weak direction
550 that was passed on input. */
551 base_level = FRIBIDI_DIR_TO_LEVEL (*pbase_dir);
552 base_dir = FRIBIDI_TYPE_ON;
553 for (pp = type_rl_list; pp; pp = pp->next)
554 if (FRIBIDI_IS_LETTER (RL_TYPE (pp)))
556 base_level = FRIBIDI_DIR_TO_LEVEL (RL_TYPE (pp));
557 base_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
561 base_dir = FRIBIDI_LEVEL_TO_DIR (base_level);
562 DBG2 (" Base level : %c\n", fribidi_char_from_level (base_level));
563 DBG2 (" Base dir : %c\n", fribidi_char_from_type (base_dir));
564 DBG (" Finding the base level, Done\n");
566 /* Explicit Levels and Directions */
567 DBG ("Explicit Levels and Directions\n");
569 /* X1. Begin by setting the current embedding level to the paragraph
570 embedding level. Set the directional override status to neutral.
571 Process each character iteratively, applying rules X2 through X9.
572 Only embedding levels from 0 to 61 are valid in this phase. */
573 FriBidiLevel level, new_level;
574 FriBidiCharType override, new_override;
576 int stack_size, over_pushed, first_interval;
577 LevelInfo *status_stack;
581 override = FRIBIDI_TYPE_ON;
587 (LevelInfo *) malloc (sizeof (LevelInfo) * (UNI_MAX_BIDI_LEVEL + 2));
589 for (pp = type_rl_list->next; pp->next; pp = pp->next)
591 FriBidiCharType this_type = RL_TYPE (pp);
592 if (FRIBIDI_IS_EXPLICIT_OR_BN (this_type))
594 if (FRIBIDI_IS_STRONG (this_type))
595 { /* LRE, RLE, LRO, RLO */
596 /* 1. Explicit Embeddings */
597 /* X2. With each RLE, compute the least greater odd embedding level. */
598 /* X3. With each LRE, compute the least greater even embedding level. */
599 /* 2. Explicit Overrides */
600 /* X4. With each RLO, compute the least greater odd embedding level. */
601 /* X5. With each LRO, compute the least greater even embedding level. */
602 new_override = FRIBIDI_EXPLICIT_TO_OVERRIDE_DIR (this_type);
603 for (i = 0; i < RL_LEN (pp); i++)
606 ((level + FRIBIDI_DIR_TO_LEVEL (this_type) + 2) & ~1) -
607 FRIBIDI_DIR_TO_LEVEL (this_type);
611 else if (this_type == FRIBIDI_TYPE_PDF)
613 /* 3. Terminating Embeddings and overrides */
614 /* X7. With each PDF, determine the matching embedding or
616 for (i = 0; i < RL_LEN (pp); i++)
619 /* X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes. */
620 /* Remove element and add it to explicits_list */
621 temp_link.next = pp->next;
622 pp->level = FRIBIDI_LEVEL_REMOVED;
623 move_element_before (pp, explicits_list_end);
628 /* X6. For all typed besides RLE, LRE, RLO, LRO, and PDF:
629 a. Set the level of the current character to the current
631 b. Whenever the directional override status is not neutral,
632 reset the current character type to the directional override
634 RL_LEVEL (pp) = level;
635 if (!FRIBIDI_IS_NEUTRAL (override))
636 RL_TYPE (pp) = override;
638 /* X8. All explicit directional embeddings and overrides are
639 completely terminated at the end of each paragraph. Paragraph
640 separators are not included in the embedding. */
641 /* This function is running on a single paragraph, so we can do
642 X8 after all the input is processed. */
645 /* Implementing X8. It has no effect on a single paragraph! */
647 override = FRIBIDI_TYPE_ON;
653 /* X10. The remaining rules are applied to each run of characters at the
654 same level. For each run, determine the start-of-level-run (sor) and
655 end-of-level-run (eor) type, either L or R. This depends on the
656 higher of the two levels on either side of the boundary (at the start
657 or end of the paragraph, the level of the 'other' run is the base
658 embedding level). If the higher level is odd, the type is R, otherwise
660 /* Resolving Implicit Levels can be done out of X10 loop, so only change
661 of Resolving Weak Types and Resolving Neutral Types is needed. */
663 compact_list (type_rl_list);
665 /* 4. Resolving weak types */
666 DBG ("Resolving weak types\n");
668 FriBidiCharType last_strong, prev_type_org;
671 last_strong = base_dir;
673 for (pp = type_rl_list->next; pp->next; pp = pp->next)
675 FriBidiCharType prev_type, this_type, next_type;
677 prev_type = PREV_TYPE_OR_SOR (pp);
678 this_type = RL_TYPE (pp);
679 next_type = NEXT_TYPE_OR_EOR (pp);
681 if (FRIBIDI_IS_STRONG (prev_type))
682 last_strong = prev_type;
685 Examine each non-spacing mark (NSM) in the level run, and change the
686 type of the NSM to the type of the previous character. If the NSM
687 is at the start of the level run, it will get the type of sor. */
688 /* Implementation note: it is important that if the previous character
689 is not sor, then we should merge this run with the previous,
690 because of rules like W5, that we assume all of a sequence of
691 adjacent ETs are in one TypeLink. */
692 if (this_type == FRIBIDI_TYPE_NSM)
694 if (RL_LEVEL (pp->prev) == RL_LEVEL (pp))
695 pp = merge_with_prev (pp);
697 RL_TYPE (pp) = prev_type;
698 continue; /* As we know the next condition cannot be true. */
701 /* W2: European numbers. */
702 if (this_type == FRIBIDI_TYPE_EN && last_strong == FRIBIDI_TYPE_AL)
704 RL_TYPE (pp) = FRIBIDI_TYPE_AN;
706 /* Resolving dependency of loops for rules W1 and W2, so we
707 can merge them in one loop. */
708 if (next_type == FRIBIDI_TYPE_NSM)
709 RL_TYPE (pp->next) = FRIBIDI_TYPE_AN;
714 last_strong = base_dir;
715 /* Resolving dependency of loops for rules W4 and W5, W5 may
716 want to prevent W4 to take effect in the next turn, do this
719 /* Resolving dependency of loops for rules W4 and W5 with W7,
720 W7 may change an EN to L but it sets the prev_type_org if needed,
721 so W4 and W5 in next turn can still do their works. */
722 prev_type_org = FRIBIDI_TYPE_ON;
724 for (pp = type_rl_list->next; pp->next; pp = pp->next)
726 FriBidiCharType prev_type, this_type, next_type;
728 prev_type = PREV_TYPE_OR_SOR (pp);
729 this_type = RL_TYPE (pp);
730 next_type = NEXT_TYPE_OR_EOR (pp);
732 if (FRIBIDI_IS_STRONG (prev_type))
733 last_strong = prev_type;
735 /* W3: Change ALs to R. */
736 if (this_type == FRIBIDI_TYPE_AL)
738 RL_TYPE (pp) = FRIBIDI_TYPE_RTL;
740 prev_type_org = FRIBIDI_TYPE_ON;
744 /* W4. A single european separator changes to a european number.
745 A single common separator between two numbers of the same type
746 changes to that type. */
748 && RL_LEN (pp) == 1 && FRIBIDI_IS_ES_OR_CS (this_type)
749 && FRIBIDI_IS_NUMBER (prev_type_org) && prev_type_org == next_type
750 && (prev_type_org == FRIBIDI_TYPE_EN
751 || this_type == FRIBIDI_TYPE_CS))
753 RL_TYPE (pp) = prev_type;
754 this_type = RL_TYPE (pp);
758 /* W5. A sequence of European terminators adjacent to European
759 numbers changes to All European numbers. */
760 if (this_type == FRIBIDI_TYPE_ET
761 && (prev_type_org == FRIBIDI_TYPE_EN
762 || next_type == FRIBIDI_TYPE_EN))
764 RL_TYPE (pp) = FRIBIDI_TYPE_EN;
766 this_type = RL_TYPE (pp);
769 /* W6. Otherwise change separators and terminators to other neutral. */
770 if (FRIBIDI_IS_NUMBER_SEPARATOR_OR_TERMINATOR (this_type))
771 RL_TYPE (pp) = FRIBIDI_TYPE_ON;
773 /* W7. Change european numbers to L. */
774 if (this_type == FRIBIDI_TYPE_EN && last_strong == FRIBIDI_TYPE_LTR)
776 RL_TYPE (pp) = FRIBIDI_TYPE_LTR;
777 prev_type_org = (RL_LEVEL (pp) == RL_LEVEL (pp->next) ?
778 FRIBIDI_TYPE_EN : FRIBIDI_TYPE_ON);
781 prev_type_org = PREV_TYPE_OR_SOR (pp->next);
785 compact_neutrals (type_rl_list);
787 /* 5. Resolving Neutral Types */
788 DBG ("Resolving neutral types\n");
791 For each neutral, resolve it. */
792 for (pp = type_rl_list->next; pp->next; pp = pp->next)
794 FriBidiCharType prev_type, this_type, next_type;
796 /* "European and arabic numbers are treated as though they were R"
797 FRIBIDI_CHANGE_NUMBER_TO_RTL does this. */
798 this_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (RL_TYPE (pp));
799 prev_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (PREV_TYPE_OR_SOR (pp));
800 next_type = FRIBIDI_CHANGE_NUMBER_TO_RTL (NEXT_TYPE_OR_EOR (pp));
802 if (FRIBIDI_IS_NEUTRAL (this_type))
803 RL_TYPE (pp) = (prev_type == next_type) ?
804 /* N1. */ prev_type :
805 /* N2. */ FRIBIDI_EMBEDDING_DIRECTION (pp);
809 compact_list (type_rl_list);
811 /* 6. Resolving implicit levels */
812 DBG ("Resolving implicit levels\n");
814 max_level = base_level;
816 for (pp = type_rl_list->next; pp->next; pp = pp->next)
818 FriBidiCharType this_type;
821 this_type = RL_TYPE (pp);
822 level = RL_LEVEL (pp);
826 if (FRIBIDI_IS_NUMBER (this_type))
827 RL_LEVEL (pp) = (level + 2) & ~1;
829 RL_LEVEL (pp) = (level ^ FRIBIDI_DIR_TO_LEVEL (this_type)) +
832 if (RL_LEVEL (pp) > max_level)
833 max_level = RL_LEVEL (pp);
837 compact_list (type_rl_list);
839 /* Reinsert the explicit codes & bn's that already removed, from the
840 explicits_list to type_rl_list. */
841 DBG ("Reinserting explicit codes\n");
845 override_list (type_rl_list, explicits_list);
846 p = type_rl_list->next;
848 p->level = base_level;
849 for (; p->next; p = p->next)
851 p->level = p->prev->level;
854 DBG ("Reset the embedding levels\n");
856 int j, k, state, pos;
857 TypeLink *p, *q, *list, *list_end;
859 const char *strp = str + bytelen;
861 /* L1. Reset the embedding levels of some chars. */
862 init_list (&list, &list_end);
866 for (j = *len - 1; j >= -1; j--)
868 /* if state is on at the very first of string, do this too. */
870 k = fribidi_get_type (g_utf8_get_char (strp = g_utf8_prev_char (strp)));
873 if (!state && FRIBIDI_IS_SEPARATOR (k))
878 else if (state && !FRIBIDI_IS_EXPLICIT_OR_SEPARATOR_OR_BN_OR_WS (k))
881 p = new_type_link ();
882 p->prev = p->next = NULL;
886 p->level = base_level;
887 move_element_before (p, q);
891 override_list (type_rl_list, list);
894 *ptype_rl_list = type_rl_list;
895 *pmax_level = max_level;
896 *pbase_dir = base_dir;
898 DBG ("Leaving fribidi_analyse_string()\n");
902 /*======================================================================
903 * fribidi_log2vis_get_embedding_levels() is used in order to just get
904 * the embedding levels.
905 *----------------------------------------------------------------------*/
906 FRIBIDI_API FriBidiLevel *
907 fribidi_log2vis_get_embedding_levels_new_utf8 ( /* input */
910 FriBidiCharType *pbase_dir)
912 TypeLink *type_rl_list, *pp;
913 FriBidiLevel max_level, *embedding_level_list;
916 DBG ("Entering fribidi_log2vis_get_embedding_levels()\n");
920 DBG ("Leaving fribidi_log2vis_get_embedding_levels()\n");
924 if (!fribidi_analyse_string_utf8 (str, bytelen, pbase_dir,
926 &len, &type_rl_list, &max_level))
928 /* unidirectional. return all-zero or all-one embedding levels */
932 embedding_level_list = g_new (FriBidiLevel, len);
933 /* assumes sizeof(FriBidiLevel) == 1, which is true! */
934 memset (embedding_level_list, max_level, len);
935 return embedding_level_list;
939 return g_new0 (FriBidiLevel, len);
943 embedding_level_list = g_new (FriBidiLevel, len);
944 for (pp = type_rl_list->next; pp->next; pp = pp->next)
946 FriBidiStrIndex i, pos = RL_POS (pp), len = RL_LEN (pp);
947 FriBidiLevel level = RL_LEVEL (pp);
948 for (i = 0; i < len; i++)
949 embedding_level_list[pos + i] = level;
952 free_rl_list (type_rl_list);
954 DBG ("Leaving fribidi_log2vis_get_embedding_levels()\n");
955 return embedding_level_list;