(root)/
fribidi-1.0.13/
lib/
fribidi-arabic.c
       1  /* fribidi-arabic.c - Arabic shaping
       2   *
       3   * Copyright (C) 2005  Behdad Esfahbod
       4   *
       5   * This file is part of GNU FriBidi.
       6   * 
       7   * GNU FriBidi is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public License
       9   * as published by the Free Software Foundation; either version 2.1
      10   * of the License, or (at your option) any later version.
      11   * 
      12   * GNU FriBidi is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15   * GNU Lesser General Public License for more details.
      16   * 
      17   * You should have received a copy of the GNU Lesser General Public License
      18   * along with GNU FriBidi; if not, write to the Free Software
      19   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      20   * 
      21   * For licensing issues, contact <fribidi.license@gmail.com> or write to
      22   * Sharif FarsiWeb, Inc., PO Box 13445-389, Tehran, Iran.
      23   *
      24   * Author(s):
      25   *   Behdad Esfahbod, 2005
      26   */
      27  
      28  #include "common.h"
      29  
      30  #ifdef HAVE_CONFIG_H
      31  # include <config.h>
      32  #endif
      33  
      34  #ifdef HAVE_STDLIB_H
      35  # include <stdlib.h>
      36  #endif
      37  
      38  
      39  #include <fribidi-arabic.h>
      40  #include <fribidi-unicode.h>
      41  
      42  
      43  typedef struct _PairMap {
      44    FriBidiChar pair[2], to;
      45  } PairMap;
      46  
      47  
      48  #define FRIBIDI_ACCESS_SHAPE_TABLE(table,min,max,x,shape) (table), (min), (max)
      49  # define FRIBIDI_ACCESS_SHAPE_TABLE_REAL(table,min,max,x,shape) \
      50  	(((x)<(min)||(x)>(max))?(x):(table)[(x)-(min)][(shape)])
      51  
      52  #include "arabic-shaping.tab.i"
      53  #include "arabic-misc.tab.i"
      54  
      55  
      56  static void
      57  fribidi_shape_arabic_joining (
      58    /* input */
      59    const FriBidiChar table[][4],
      60    FriBidiChar min,
      61    FriBidiChar max,
      62    const FriBidiStrIndex len,
      63    const FriBidiArabicProp *ar_props,
      64    /* input and output */
      65    FriBidiChar *str
      66  )
      67  {
      68    register FriBidiStrIndex i;
      69  
      70    for (i = 0; i < len; i++)
      71      if (FRIBIDI_ARAB_SHAPES(ar_props[i]))
      72        str[i] = FRIBIDI_ACCESS_SHAPE_TABLE_REAL (table, min, max, str[i], FRIBIDI_JOIN_SHAPE (ar_props[i]));
      73  }
      74  
      75  
      76  
      77  static int
      78  comp_PairMap (const void *pa, const void *pb)
      79  {
      80    PairMap *a = (PairMap *)pa;
      81    PairMap *b = (PairMap *)pb;
      82  
      83    if (a->pair[0] != b->pair[0])
      84      return a->pair[0] < b->pair[0] ? -1 : +1;
      85    else
      86      return a->pair[1] < b->pair[1] ? -1 :
      87             a->pair[1] > b->pair[1] ? +1 :
      88  	   0;
      89  }
      90  
      91  static void *
      92  fribidi_bsearch (const void *key, const void *base,
      93                   unsigned int nmemb, unsigned int size,
      94                   int (*compar)(const void *_key, const void *_item))
      95  {
      96    int min = 0, max = (int) nmemb - 1;
      97    while (min <= max)
      98    {
      99      int mid = ((unsigned int) min + (unsigned int) max) / 2;
     100      const void *p = (const void *) (((const char *) base) + (mid * size));
     101      int c = compar (key, p);
     102      if (c < 0)
     103        max = mid - 1;
     104      else if (c > 0)
     105        min = mid + 1;
     106      else
     107        return (void *) p;
     108    }
     109    return NULL;
     110  }
     111  
     112  static FriBidiChar
     113  find_pair_match (const PairMap *table, int size, FriBidiChar first, FriBidiChar second)
     114  {
     115    PairMap *match;
     116    PairMap x;
     117    x.pair[0] = first;
     118    x.pair[1] = second;
     119    x.to = 0;
     120    match = fribidi_bsearch (&x, table, size, sizeof (table[0]), comp_PairMap);
     121    return match ? match->to : 0;
     122  }
     123  
     124  #define PAIR_MATCH(table,len,first,second) \
     125  	((first)<(table[0].pair[0])||(first)>(table[len-1].pair[0])?0: \
     126  	 find_pair_match(table, len, first, second))
     127  
     128  static void
     129  fribidi_shape_arabic_ligature (
     130    /* input */
     131    const PairMap *table,
     132    int size,
     133    const FriBidiLevel *embedding_levels,
     134    const FriBidiStrIndex len,
     135    /* input and output */
     136    FriBidiArabicProp *ar_props,
     137    FriBidiChar *str
     138  )
     139  {
     140    /* TODO: This doesn't form ligatures for even-level Arabic text.
     141     * no big problem though. */
     142    register FriBidiStrIndex i;
     143  
     144    for (i = 0; i < len - 1; i++) {
     145      register FriBidiChar c;
     146      if (FRIBIDI_LEVEL_IS_RTL(embedding_levels[i]) &&
     147  	embedding_levels[i] == embedding_levels[i+1] &&
     148  	(c = PAIR_MATCH(table, size, str[i], str[i+1])))
     149        {
     150  	str[i] = FRIBIDI_CHAR_FILL;
     151  	FRIBIDI_SET_BITS(ar_props[i], FRIBIDI_MASK_LIGATURED);
     152  	str[i+1] = c;
     153        }
     154    }
     155  }
     156  
     157  #define DO_LIGATURING(table, levels, len, ar_props, str) \
     158  	fribidi_shape_arabic_ligature ((table), sizeof(table)/sizeof((table)[0]), levels, len, ar_props, str)
     159  
     160  #define DO_SHAPING(tablemacro, len, ar_props, str) \
     161  	fribidi_shape_arabic_joining (tablemacro(,), len, ar_props, str);
     162  	
     163  
     164  
     165  
     166  FRIBIDI_ENTRY void
     167  fribidi_shape_arabic (
     168    /* input */
     169    FriBidiFlags flags,
     170    const FriBidiLevel *embedding_levels,
     171    const FriBidiStrIndex len,
     172    /* input and output */
     173    FriBidiArabicProp *ar_props,
     174    FriBidiChar *str
     175  )
     176  {
     177    DBG ("in fribidi_shape_arabic");
     178  
     179    if UNLIKELY
     180      (len == 0 || !str) return;
     181  
     182    DBG ("in fribidi_shape");
     183  
     184    fribidi_assert (ar_props);
     185  
     186    if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_PRES))
     187      {
     188        DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_PRES, len, ar_props, str);
     189      }
     190  
     191    if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_LIGA))
     192      {
     193        DO_LIGATURING (mandatory_liga_table, embedding_levels, len, ar_props, str);
     194      }
     195  
     196    if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_CONSOLE))
     197      {
     198        DO_LIGATURING (console_liga_table, embedding_levels, len, ar_props, str);
     199        DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_NSM, len, ar_props, str);
     200      }
     201  }
     202  
     203  /* Editor directions:
     204   * Local Variables:
     205   *   mode: c
     206   *   c-basic-offset: 2
     207   *   indent-tabs-mode: t
     208   *   tab-width: 8
     209   * End:
     210   * vim: textwidth=78: autoindent: cindent: shiftwidth=2: tabstop=8:
     211   */