(root)/
fribidi-1.0.13/
lib/
fribidi-run.c
       1  /* FriBidi
       2   * fribidi-run.c - text run data type
       3   *
       4   * Authors:
       5   *   Behdad Esfahbod, 2001, 2002, 2004
       6   *   Dov Grobgeld, 1999, 2000, 2017
       7   *
       8   * Copyright (C) 2004 Sharif FarsiWeb, Inc
       9   * Copyright (C) 2001,2002 Behdad Esfahbod
      10   * Copyright (C) 1999,2000,2017 Dov Grobgeld
      11   * 
      12   * This library is free software; you can redistribute it and/or
      13   * modify it under the terms of the GNU Lesser General Public
      14   * License as published by the Free Software Foundation; either
      15   * version 2.1 of the License, or (at your option) any later version.
      16   * 
      17   * This library is distributed in the hope that it will be useful,
      18   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20   * Lesser General Public License for more details.
      21   * 
      22   * You should have received a copy of the GNU Lesser General Public License
      23   * along with this library, in a file named COPYING; if not, write to the
      24   * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      25   * Boston, MA 02110-1301, USA
      26   * 
      27   * For licensing issues, contact <fribidi.license@gmail.com>.
      28   */
      29  
      30  #include "common.h"
      31  
      32  #include <fribidi-bidi-types.h>
      33  
      34  #include "run.h"
      35  #include "bidi-types.h"
      36  
      37  FriBidiRun *
      38  new_run (
      39    void
      40  )
      41  {
      42    register FriBidiRun *run;
      43  
      44    run = fribidi_malloc (sizeof (FriBidiRun));
      45  
      46    if LIKELY
      47      (run)
      48      {
      49        run->len = run->pos = run->level = run->isolate_level = 0;
      50        run->next = run->prev = run->prev_isolate = run->next_isolate = NULL;
      51      }
      52    return run;
      53  }
      54  
      55  FriBidiRun *
      56  new_run_list (
      57    void
      58  )
      59  {
      60    register FriBidiRun *run;
      61  
      62    run = new_run ();
      63  
      64    if LIKELY
      65      (run)
      66      {
      67        run->type = FRIBIDI_TYPE_SENTINEL;
      68        run->level = FRIBIDI_SENTINEL;
      69        run->pos = FRIBIDI_SENTINEL;
      70        run->len = FRIBIDI_SENTINEL;
      71        run->next = run->prev = run;
      72      }
      73  
      74    return run;
      75  }
      76  
      77  void
      78  free_run_list (
      79    FriBidiRun *run_list
      80  )
      81  {
      82    if (!run_list)
      83      return;
      84  
      85    fribidi_validate_run_list (run_list);
      86  
      87    {
      88      register FriBidiRun *pp;
      89  
      90      pp = run_list;
      91      pp->prev->next = NULL;
      92      while LIKELY
      93        (pp)
      94        {
      95  	register FriBidiRun *p;
      96  
      97  	p = pp;
      98  	pp = pp->next;
      99  	fribidi_free (p);
     100        };
     101    }
     102  }
     103  
     104  
     105  FriBidiRun *
     106  run_list_encode_bidi_types (
     107    /* input */
     108    const FriBidiCharType *bidi_types,
     109    const FriBidiBracketType *bracket_types,
     110    const FriBidiStrIndex len
     111  )
     112  {
     113    FriBidiRun *list, *last;
     114    register FriBidiRun *run = NULL;
     115    FriBidiStrIndex i;
     116  
     117    fribidi_assert (bidi_types);
     118  
     119    /* Create the list sentinel */
     120    list = new_run_list ();
     121    if UNLIKELY
     122      (!list) return NULL;
     123    last = list;
     124  
     125    /* Scan over the character types */
     126    for (i = 0; i < len; i++)
     127      {
     128        register FriBidiCharType char_type = bidi_types[i];
     129        register FriBidiBracketType bracket_type = FRIBIDI_NO_BRACKET;
     130        if (bracket_types)
     131          bracket_type = bracket_types[i];
     132        
     133        if (char_type != last->type
     134            || bracket_type != FRIBIDI_NO_BRACKET /* Always separate bracket into single char runs! */
     135            || last->bracket_type != FRIBIDI_NO_BRACKET
     136            || FRIBIDI_IS_ISOLATE(char_type)
     137            )
     138  	{
     139  	  run = new_run ();
     140  	  if UNLIKELY
     141  	    (!run) break;
     142  	  run->type = char_type;
     143  	  run->pos = i;
     144  	  last->len = run->pos - last->pos;
     145  	  last->next = run;
     146  	  run->prev = last;
     147            run->bracket_type = bracket_type;
     148  	  last = run;
     149  	}
     150      }
     151  
     152    /* Close the circle */
     153    last->len = len - last->pos;
     154    last->next = list;
     155    list->prev = last;
     156  
     157    if UNLIKELY
     158      (!run)
     159      {
     160        /* Memory allocation failed */
     161        free_run_list (list);
     162        return NULL;
     163      }
     164  
     165    fribidi_validate_run_list (list);
     166  
     167    return list;
     168  }
     169  
     170  /* override the run list 'base', with the runs in the list 'over', to
     171     reinsert the previously-removed explicit codes (at X9) from
     172     'explicits_list' back into 'type_rl_list' for example. This is used at the
     173     end of I2 to restore the explicit marks, and also to reset the character
     174     types of characters at L1.
     175  
     176     it is assumed that the 'pos' of the first element in 'base' list is not
     177     more than the 'pos' of the first element of the 'over' list, and the
     178     'pos' of the last element of the 'base' list is not less than the 'pos'
     179     of the last element of the 'over' list. these two conditions are always
     180     satisfied for the two usages mentioned above.
     181  
     182     Note:
     183       frees the over list.
     184  
     185     Todo:
     186       use some explanatory names instead of p, q, ...
     187       rewrite comment above to remove references to special usage.
     188  */
     189  fribidi_boolean
     190  shadow_run_list (
     191    /* input */
     192    FriBidiRun *base,
     193    FriBidiRun *over,
     194    fribidi_boolean preserve_length
     195  )
     196  {
     197    register FriBidiRun *p = base, *q, *r, *s, *t;
     198    register FriBidiStrIndex pos = 0, pos2;
     199    fribidi_boolean status = false;
     200  
     201    fribidi_validate_run_list (base);
     202    fribidi_validate_run_list (over);
     203  
     204    for_run_list (q, over)
     205    {
     206      if UNLIKELY
     207        (!q->len || q->pos < pos) continue;
     208      pos = q->pos;
     209      while (p->next->type != FRIBIDI_TYPE_SENTINEL && p->next->pos <= pos)
     210        p = p->next;
     211      /* now p is the element that q must be inserted 'in'. */
     212      pos2 = pos + q->len;
     213      r = p;
     214      while (r->next->type != FRIBIDI_TYPE_SENTINEL && r->next->pos < pos2)
     215        r = r->next;
     216      if (preserve_length)
     217        r->len += q->len;
     218      /* now r is the last element that q affects. */
     219      if LIKELY
     220        (p == r)
     221        {
     222  	/* split p into at most 3 intervals, and insert q in the place of
     223  	   the second interval, set r to be the third part. */
     224  	/* third part needed? */
     225  	if (p->pos + p->len > pos2)
     226  	  {
     227  	    r = new_run ();
     228  	    if UNLIKELY
     229  	      (!r) goto out;
     230  	    p->next->prev = r;
     231  	    r->next = p->next;
     232  	    r->level = p->level;
     233  	    r->isolate_level = p->isolate_level;
     234  	    r->type = p->type;
     235  	    r->len = p->pos + p->len - pos2;
     236  	    r->pos = pos2;
     237  	  }
     238  	else
     239  	  r = r->next;
     240  
     241  	if LIKELY
     242  	  (p->pos + p->len >= pos)
     243  	  {
     244  	    /* first part needed? */
     245  	    if (p->pos < pos)
     246  	      /* cut the end of p. */
     247  	      p->len = pos - p->pos;
     248  	    else
     249  	      {
     250  		t = p;
     251  		p = p->prev;
     252  		fribidi_free (t);
     253  	      }
     254  	  }
     255        }
     256      else
     257        {
     258  	if LIKELY
     259  	  (p->pos + p->len >= pos)
     260  	  {
     261  	    /* p needed? */
     262  	    if (p->pos < pos)
     263  	      /* cut the end of p. */
     264  	      p->len = pos - p->pos;
     265  	    else
     266  	      p = p->prev;
     267  	  }
     268  
     269  	/* r needed? */
     270  	if (r->pos + r->len > pos2)
     271  	  {
     272  	    /* cut the beginning of r. */
     273  	    r->len = r->pos + r->len - pos2;
     274  	    r->pos = pos2;
     275  	  }
     276  	else
     277  	  r = r->next;
     278  
     279  	/* remove the elements between p and r. */
     280  	for (s = p->next; s != r;)
     281  	  {
     282  	    t = s;
     283  	    s = s->next;
     284  	    fribidi_free (t);
     285  	  }
     286        }
     287      /* before updating the next and prev runs to point to the inserted q,
     288         we must remember the next element of q in the 'over' list.
     289       */
     290      t = q;
     291      q = q->prev;
     292      delete_node (t);
     293      p->next = t;
     294      t->prev = p;
     295      t->next = r;
     296      r->prev = t;
     297    }
     298    status = true;
     299  
     300    fribidi_validate_run_list (base);
     301  
     302  out:
     303    free_run_list (over);
     304  
     305    return status;
     306  }
     307  
     308  #ifdef DEBUG
     309  
     310  void
     311  fribidi_validate_run_list (
     312    FriBidiRun *run_list		/* input run list */
     313  )
     314  {
     315    register FriBidiRun *q;
     316  
     317    fribidi_assert (run_list);
     318    fribidi_assert (run_list->next);
     319    fribidi_assert (run_list->next->prev == run_list);
     320    fribidi_assert (run_list->type == FRIBIDI_TYPE_SENTINEL);
     321    for_run_list (q, run_list)
     322    {
     323      fribidi_assert (q->next);
     324      fribidi_assert (q->next->prev == q);
     325    }
     326    fribidi_assert (q == run_list);
     327  }
     328  
     329  #endif /* !DEBUG */
     330  
     331  /* Editor directions:
     332   * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
     333   */