(root)/
fribidi-1.0.13/
lib/
fribidi-joining.c
       1  /* FriBidi
       2   * fribidi-joining.h - Arabic joining algorithm
       3   *
       4   * Authors:
       5   *   Behdad Esfahbod, 2004
       6   *
       7   * Copyright (C) 2004 Sharif FarsiWeb, Inc
       8   * Copyright (C) 2004 Behdad Esfahbod
       9   * 
      10   * This library is free software; you can redistribute it and/or
      11   * modify it under the terms of the GNU Lesser General Public
      12   * License as published by the Free Software Foundation; either
      13   * version 2.1 of the License, or (at your option) any later version.
      14   * 
      15   * This library is distributed in the hope that it will be useful,
      16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18   * Lesser General Public License for more details.
      19   * 
      20   * You should have received a copy of the GNU Lesser General Public License
      21   * along with this library, in a file named COPYING; if not, write to the
      22   * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      23   * Boston, MA 02110-1301, USA
      24   * 
      25   * For licensing issues, contact <fribidi.license@gmail.com>.
      26   */
      27  
      28  #include "common.h"
      29  
      30  #include <fribidi-joining.h>
      31  
      32  #include "bidi-types.h"
      33  #include "joining-types.h"
      34  
      35  #ifdef DEBUG
      36  /*======================================================================
      37   *  For debugging, define some functions for printing joining types and
      38   *  properties.
      39   *----------------------------------------------------------------------*/
      40  
      41  static void
      42  print_joining_types (
      43    /* input */
      44    const FriBidiLevel *embedding_levels,
      45    const FriBidiStrIndex len,
      46    const FriBidiJoiningType *jtypes
      47  )
      48  {
      49    register FriBidiStrIndex i;
      50  
      51    fribidi_assert (jtypes);
      52  
      53    MSG ("  Join. types: ");
      54    for (i = 0; i < len; i++)
      55      MSG2 ("%c", fribidi_char_from_joining_type (jtypes[i],
      56  						!FRIBIDI_LEVEL_IS_RTL
      57  						(embedding_levels[i])));
      58    MSG ("\n");
      59  }
      60  #endif /* DEBUG */
      61  
      62  #define FRIBIDI_CONSISTENT_LEVEL(i)	\
      63  	(FRIBIDI_IS_EXPLICIT_OR_BN (bidi_types[(i)])	\
      64  	 ? FRIBIDI_SENTINEL	\
      65  	 : embedding_levels[(i)])
      66  
      67  #define FRIBIDI_LEVELS_MATCH(i, j)	\
      68  	((i) == (j) || (i) == FRIBIDI_SENTINEL || (j) == FRIBIDI_SENTINEL)
      69  
      70  FRIBIDI_ENTRY void
      71  fribidi_join_arabic (
      72    /* input */
      73    const FriBidiCharType *bidi_types,
      74    const FriBidiStrIndex len,
      75    const FriBidiLevel *embedding_levels,
      76    /* input and output */
      77    FriBidiArabicProp *ar_props
      78  )
      79  {
      80    if UNLIKELY
      81      (len == 0) return;
      82  
      83    DBG ("in fribidi_join_arabic");
      84  
      85    fribidi_assert (bidi_types);
      86    fribidi_assert (embedding_levels);
      87    fribidi_assert (ar_props);
      88  
      89  # if DEBUG
      90    if UNLIKELY
      91      (fribidi_debug_status ())
      92      {
      93        print_joining_types (embedding_levels, len, ar_props);
      94      }
      95  # endif	/* DEBUG */
      96  
      97    /* The joining algorithm turned out very very dirty :(.  That's what happens
      98     * when you follow the standard which has never been implemented closely
      99     * before.
     100     */
     101  
     102    /* 8.2 Arabic - Cursive Joining */
     103    DBG ("Arabic cursive joining");
     104    {
     105      /* The following do not need to be initialized as long as joins is
     106       * initialized to false.  We just do to turn off compiler warnings. */
     107      register FriBidiStrIndex saved = 0;
     108      register FriBidiLevel saved_level = FRIBIDI_SENTINEL;
     109      register fribidi_boolean saved_shapes = false;
     110      register FriBidiArabicProp saved_joins_following_mask = 0;
     111  
     112      register fribidi_boolean joins = false;
     113      register FriBidiStrIndex i;
     114  
     115      for (i = 0; i < len; i++)
     116        if (!FRIBIDI_IS_JOINING_TYPE_G (ar_props[i]))
     117  	{
     118  	  register fribidi_boolean disjoin = false;
     119  	  register fribidi_boolean shapes = FRIBIDI_ARAB_SHAPES (ar_props[i]);
     120  	  register FriBidiLevel level = FRIBIDI_CONSISTENT_LEVEL (i);
     121  
     122  	  if (joins && !FRIBIDI_LEVELS_MATCH (saved_level, level))
     123  	    {
     124  	      disjoin = true;
     125  	      joins = false;
     126  	    }
     127  
     128  	  if (!FRIBIDI_IS_JOIN_SKIPPED (ar_props[i]))
     129  	    {
     130  	      register const FriBidiArabicProp joins_preceding_mask =
     131  		FRIBIDI_JOINS_PRECEDING_MASK (level);
     132  
     133  	      if (!joins)
     134  		{
     135  		  if (shapes)
     136  		    FRIBIDI_UNSET_BITS (ar_props[i], joins_preceding_mask);
     137  		}
     138  	      else if (!FRIBIDI_TEST_BITS (ar_props[i], joins_preceding_mask))
     139  	        {
     140  		  disjoin = true;
     141  		}
     142  	      else
     143  	        {
     144  		  register FriBidiStrIndex j;
     145  		  /* This is a FriBidi extension:  we set joining properties
     146  		   * for skipped characters in between, so we can put NSMs on tatweel
     147  		   * later if we want.  Useful on console for example.
     148  		   */
     149  		  for (j = saved + 1; j < i; j++)
     150  		    FRIBIDI_SET_BITS (ar_props[j], joins_preceding_mask | saved_joins_following_mask);
     151  		}
     152  	    }
     153  
     154  	  if (disjoin && saved_shapes)
     155  	    FRIBIDI_UNSET_BITS (ar_props[saved], saved_joins_following_mask);
     156  
     157  	  if (!FRIBIDI_IS_JOIN_SKIPPED (ar_props[i]))
     158  	    {
     159  	      saved = i;
     160  	      saved_level = level;
     161  	      saved_shapes = shapes;
     162  	      saved_joins_following_mask =
     163  		FRIBIDI_JOINS_FOLLOWING_MASK (level);
     164  	      joins =
     165  		FRIBIDI_TEST_BITS (ar_props[i], saved_joins_following_mask);
     166  	    }
     167  	}
     168      if ((joins) && saved_shapes)
     169        FRIBIDI_UNSET_BITS (ar_props[saved], saved_joins_following_mask);
     170  
     171    }
     172  
     173  # if DEBUG
     174    if UNLIKELY
     175      (fribidi_debug_status ())
     176      {
     177        print_joining_types (embedding_levels, len, ar_props);
     178      }
     179  # endif	/* DEBUG */
     180  
     181    DBG ("leaving fribidi_join_arabic");
     182  }
     183  
     184  /* Editor directions:
     185   * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
     186   */