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
43typedef 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
56static void
57fribidi_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
77static int
78comp_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
91static void *
92fribidi_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
112static FriBidiChar
113find_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 (key: &x, base: table, nmemb: size, size: sizeof (table[0]), compar: 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
128static void
129fribidi_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
166FRIBIDI_ENTRY void
167fribidi_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 */
212

source code of gtk/subprojects/fribidi/lib/fribidi-arabic.c