/src/fribidi/lib/fribidi-arabic.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #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 | 0 | (((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 | 0 | { |
68 | 0 | register FriBidiStrIndex i; |
69 | |
|
70 | 0 | for (i = 0; i < len; i++) |
71 | 0 | if (FRIBIDI_ARAB_SHAPES(ar_props[i])) |
72 | 0 | str[i] = FRIBIDI_ACCESS_SHAPE_TABLE_REAL (table, min, max, str[i], FRIBIDI_JOIN_SHAPE (ar_props[i])); |
73 | 0 | } |
74 | | |
75 | | |
76 | | |
77 | | static int |
78 | | comp_PairMap (const void *pa, const void *pb) |
79 | 0 | { |
80 | 0 | PairMap *a = (PairMap *)pa; |
81 | 0 | PairMap *b = (PairMap *)pb; |
82 | |
|
83 | 0 | if (a->pair[0] != b->pair[0]) |
84 | 0 | return a->pair[0] < b->pair[0] ? -1 : +1; |
85 | 0 | else |
86 | 0 | return a->pair[1] < b->pair[1] ? -1 : |
87 | 0 | a->pair[1] > b->pair[1] ? +1 : |
88 | 0 | 0; |
89 | 0 | } |
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 | 0 | { |
96 | 0 | int min = 0, max = (int) nmemb - 1; |
97 | 0 | while (min <= max) |
98 | 0 | { |
99 | 0 | int mid = ((unsigned int) min + (unsigned int) max) / 2; |
100 | 0 | const void *p = (const void *) (((const char *) base) + (mid * size)); |
101 | 0 | int c = compar (key, p); |
102 | 0 | if (c < 0) |
103 | 0 | max = mid - 1; |
104 | 0 | else if (c > 0) |
105 | 0 | min = mid + 1; |
106 | 0 | else |
107 | 0 | return (void *) p; |
108 | 0 | } |
109 | 0 | return NULL; |
110 | 0 | } |
111 | | |
112 | | static FriBidiChar |
113 | | find_pair_match (const PairMap *table, int size, FriBidiChar first, FriBidiChar second) |
114 | 0 | { |
115 | 0 | PairMap *match; |
116 | 0 | PairMap x; |
117 | 0 | x.pair[0] = first; |
118 | 0 | x.pair[1] = second; |
119 | 0 | x.to = 0; |
120 | 0 | match = fribidi_bsearch (&x, table, size, sizeof (table[0]), comp_PairMap); |
121 | 0 | return match ? match->to : 0; |
122 | 0 | } |
123 | | |
124 | | #define PAIR_MATCH(table,len,first,second) \ |
125 | 0 | ((first)<(table[0].pair[0])||(first)>(table[len-1].pair[0])?0: \ |
126 | 0 | 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 | 0 | { |
140 | | /* TODO: This doesn't form ligatures for even-level Arabic text. |
141 | | * no big problem though. */ |
142 | 0 | register FriBidiStrIndex i; |
143 | |
|
144 | 0 | for (i = 0; i < len - 1; i++) { |
145 | 0 | register FriBidiChar c; |
146 | 0 | if (FRIBIDI_LEVEL_IS_RTL(embedding_levels[i]) && |
147 | 0 | embedding_levels[i] == embedding_levels[i+1] && |
148 | 0 | (c = PAIR_MATCH(table, size, str[i], str[i+1]))) |
149 | 0 | { |
150 | 0 | str[i] = FRIBIDI_CHAR_FILL; |
151 | 0 | FRIBIDI_SET_BITS(ar_props[i], FRIBIDI_MASK_LIGATURED); |
152 | 0 | str[i+1] = c; |
153 | 0 | } |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | | #define DO_LIGATURING(table, levels, len, ar_props, str) \ |
158 | 0 | 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 | 0 | 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 | 0 | { |
177 | 0 | DBG ("in fribidi_shape_arabic"); |
178 | |
|
179 | 0 | if UNLIKELY |
180 | 0 | (len == 0 || !str) return; |
181 | | |
182 | 0 | DBG ("in fribidi_shape"); |
183 | |
|
184 | 0 | fribidi_assert (ar_props); |
185 | |
|
186 | 0 | if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_PRES)) |
187 | 0 | { |
188 | 0 | DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_PRES, len, ar_props, str); |
189 | 0 | } |
190 | |
|
191 | 0 | if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_LIGA)) |
192 | 0 | { |
193 | 0 | DO_LIGATURING (mandatory_liga_table, embedding_levels, len, ar_props, str); |
194 | 0 | } |
195 | |
|
196 | 0 | if (FRIBIDI_TEST_BITS (flags, FRIBIDI_FLAG_SHAPE_ARAB_CONSOLE)) |
197 | 0 | { |
198 | 0 | DO_LIGATURING (console_liga_table, embedding_levels, len, ar_props, str); |
199 | 0 | DO_SHAPING (FRIBIDI_GET_ARABIC_SHAPE_NSM, len, ar_props, str); |
200 | 0 | } |
201 | 0 | } |
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 | | */ |