add packaging
[platform/upstream/fribidi.git] / 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 <license@farsiweb.info> or write to
22  * Sharif FarsiWeb, Inc., PO Box 13445-389, Tehran, Iran.
23  */
24 /* $Id: fribidi-arabic.c,v 1.3 2007-04-05 16:14:39 behdad Exp $
25  * $Author: behdad $
26  * $Date: 2007-04-05 16:14:39 $
27  * $Revision: 1.3 $
28  * $Source: /home/behdad/src/fdo/fribidi/togit/git/../fribidi/fribidi2/lib/fribidi-arabic.c,v $
29  *
30  * Author(s):
31  *   Behdad Esfahbod, 2005
32  */
33
34 #include "common.h"
35
36 #if HAVE_STDLIB_H+0
37 # include <stdlib.h>
38 #endif
39
40
41 #include <fribidi-arabic.h>
42 #include <fribidi-unicode.h>
43
44
45 typedef struct _PairMap {
46   FriBidiChar pair[2], to;
47 } PairMap;
48
49
50 #define FRIBIDI_ACCESS_SHAPE_TABLE(table,min,max,x,shape) (table), (min), (max)
51 # define FRIBIDI_ACCESS_SHAPE_TABLE_REAL(table,min,max,x,shape) \
52         (((x)<(min)||(x)>(max))?(x):(table)[(x)-(min)][(shape)])
53
54 #include "arabic-shaping.tab.i"
55 #include "arabic-misc.tab.i"
56
57
58 static void
59 fribidi_shape_arabic_joining (
60   /* input */
61   const FriBidiChar table[][4],
62   FriBidiChar min,
63   FriBidiChar max,
64   const FriBidiStrIndex len,
65   const FriBidiArabicProp *ar_props,
66   /* input and output */
67   FriBidiChar *str
68 )
69 {
70   register FriBidiStrIndex i;
71
72   for (i = 0; i < len; i++)
73     if (FRIBIDI_ARAB_SHAPES(ar_props[i]))
74       str[i] = FRIBIDI_ACCESS_SHAPE_TABLE_REAL (table, min, max, str[i], FRIBIDI_JOIN_SHAPE (ar_props[i]));
75 }
76
77
78
79 static int
80 comp_PairMap (const void *pa, const void *pb)
81 {
82   PairMap *a = (PairMap *)pa;
83   PairMap *b = (PairMap *)pb;
84
85   if (a->pair[0] != b->pair[0])
86     return a->pair[0] < b->pair[0] ? -1 : +1;
87   else
88     return a->pair[1] < b->pair[1] ? -1 :
89            a->pair[1] > b->pair[1] ? +1 :
90            0;
91 }
92
93
94 static FriBidiChar
95 find_pair_match (const PairMap *table, int size, FriBidiChar first, FriBidiChar second)
96 {
97   PairMap *match;
98   PairMap x;
99   x.pair[0] = first;
100   x.pair[1] = second;
101   x.to = 0;
102   match = bsearch (&x, table, size, sizeof (table[0]), comp_PairMap);
103   return match ? match->to : 0;
104 }
105
106 #define PAIR_MATCH(table,len,first,second) \
107         ((first)<(table[0].pair[0])||(first)>(table[len-1].pair[0])?0: \
108          find_pair_match(table, len, first, second))
109
110 static void
111 fribidi_shape_arabic_ligature (
112   /* input */
113   const PairMap *table,
114   int size,
115   const FriBidiLevel *embedding_levels,
116   const FriBidiStrIndex len,
117   /* input and output */
118   FriBidiArabicProp *ar_props,
119   FriBidiChar *str
120 )
121 {
122   /* TODO: This doesn't form ligatures for even-level Arabic text.
123    * no big problem though. */
124   register FriBidiStrIndex i;
125
126   for (i = 0; i < len - 1; i++) {
127     register FriBidiChar c;
128     if (FRIBIDI_LEVEL_IS_RTL(embedding_levels[i]) &&
129         embedding_levels[i] == embedding_levels[i+1] &&
130         (c = PAIR_MATCH(table, size, str[i], str[i+1])))
131       {
132         str[i] = FRIBIDI_CHAR_FILL;
133         FRIBIDI_SET_BITS(ar_props[i], FRIBIDI_MASK_LIGATURED);
134         str[i+1] = c;
135       }
136   }
137 }
138
139 #define DO_LIGATURING(table, levels, len, ar_props, str) \
140         fribidi_shape_arabic_ligature ((table), sizeof(table)/sizeof((table)[0]), levels, len, ar_props, str)
141
142 #define DO_SHAPING(tablemacro, len, ar_props, str) \
143         fribidi_shape_arabic_joining (tablemacro(,), len, ar_props, str);
144         
145
146
147
148 FRIBIDI_ENTRY void
149 fribidi_shape_arabic (
150   /* input */
151   FriBidiFlags flags,
152   const FriBidiLevel *embedding_levels,
153   const FriBidiStrIndex len,
154   /* input and output */
155   FriBidiArabicProp *ar_props,
156   FriBidiChar *str
157 )
158 {
159   DBG ("in fribidi_shape_arabic");
160
161   if UNLIKELY
162     (len == 0 || !str) return;
163
164   DBG ("in fribidi_shape");
165
166   fribidi_assert (ar_props);
167
168   if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_PRES))
169     {
170       DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_PRES, len, ar_props, str);
171     }
172
173   if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_LIGA))
174     {
175       DO_LIGATURING (mandatory_liga_table, embedding_levels, len, ar_props, str);
176     }
177
178   if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_CONSOLE))
179     {
180       DO_LIGATURING (console_liga_table, embedding_levels, len, ar_props, str);
181       DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_NSM, len, ar_props, str);
182     }
183 }
184
185 /* Editor directions:
186  * Local Variables:
187  *   mode: c
188  *   c-basic-offset: 2
189  *   indent-tabs-mode: t
190  *   tab-width: 8
191  * End:
192  * vim: textwidth=78: autoindent: cindent: shiftwidth=2: tabstop=8:
193  */