Imported Upstream version 1.0.10
[platform/upstream/fribidi.git] / lib / fribidi.c
1 /* FriBidi
2  * fribidi.c - Unicode bidirectional and Arabic joining/shaping algorithms
3  *
4  * Authors:
5  *   Behdad Esfahbod, 2001, 2002, 2004
6  *   Dov Grobgeld, 1999, 2000
7  *
8  * Copyright (C) 2004 Sharif FarsiWeb, Inc
9  * Copyright (C) 2001,2002 Behdad Esfahbod
10  * Copyright (C) 1999,2000 Dov Grobgeld
11  * 
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  * 
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  * 
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this library, in a file named COPYING; if not, write to the
24  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA
26  * 
27  * For licensing issues, contact <fribidi.license@gmail.com>.
28  */
29
30 #include "common.h"
31
32 #include <fribidi.h>
33
34 #ifdef DEBUG
35 static int flag_debug = false;
36 #endif
37
38 FRIBIDI_ENTRY fribidi_boolean
39 fribidi_debug_status (
40   void
41 )
42 {
43 #ifdef DEBUG
44   return flag_debug;
45 #else
46   return false;
47 #endif
48 }
49
50 FRIBIDI_ENTRY fribidi_boolean
51 fribidi_set_debug (
52   /* input */
53   fribidi_boolean state
54 )
55 {
56 #ifdef DEBUG
57   return flag_debug = state;
58 #else
59   return false;
60 #endif
61 }
62
63 FRIBIDI_ENTRY FriBidiStrIndex
64 fribidi_remove_bidi_marks (
65   FriBidiChar *str,
66   const FriBidiStrIndex len,
67   FriBidiStrIndex *positions_to_this,
68   FriBidiStrIndex *position_from_this_list,
69   FriBidiLevel *embedding_levels
70 )
71 {
72   register FriBidiStrIndex i, j = 0;
73   fribidi_boolean private_from_this = false;
74   fribidi_boolean status = false;
75
76   if UNLIKELY
77     (len == 0)
78     {
79       status = true;
80       goto out;
81     }
82
83   DBG ("in fribidi_remove_bidi_marks");
84
85   fribidi_assert (str);
86
87   /* If to_this is not NULL, we must have from_this as well. If it is
88      not given by the caller, we have to make a private instance of it. */
89   if (positions_to_this && !position_from_this_list)
90     {
91       position_from_this_list = fribidi_malloc (sizeof
92                                                 (position_from_this_list[0]) *
93                                                 len);
94       if UNLIKELY
95         (!position_from_this_list) goto out;
96       private_from_this = true;
97       for (i = 0; i < len; i++)
98         position_from_this_list[positions_to_this[i]] = i;
99     }
100
101   for (i = 0; i < len; i++)
102     if (!FRIBIDI_IS_EXPLICIT_OR_BN (fribidi_get_bidi_type (str[i]))
103         && !FRIBIDI_IS_ISOLATE (fribidi_get_bidi_type (str[i]))
104         && str[i] != FRIBIDI_CHAR_LRM && str[i] != FRIBIDI_CHAR_RLM)
105       {
106         str[j] = str[i];
107         if (embedding_levels)
108           embedding_levels[j] = embedding_levels[i];
109         if (position_from_this_list)
110           position_from_this_list[j] = position_from_this_list[i];
111         j++;
112       }
113
114   /* Convert the from_this list to to_this */
115   if (positions_to_this)
116     {
117       for (i = 0; i < len; i++)
118         positions_to_this[i] = -1;
119       for (i = 0; i < len; i++)
120         positions_to_this[position_from_this_list[i]] = i;
121     }
122
123   status = true;
124
125 out:
126
127   if (private_from_this)
128     fribidi_free (position_from_this_list);
129
130   return status ? j : -1;
131 }
132
133 /* Local array size, used for stack-based local arrays */
134 #define LOCAL_LIST_SIZE 128
135 static FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
136
137
138 FRIBIDI_ENTRY FriBidiLevel
139 fribidi_log2vis (
140   /* input */
141   const FriBidiChar *str,
142   const FriBidiStrIndex len,
143   /* input and output */
144   FriBidiParType *pbase_dir,
145   /* output */
146   FriBidiChar *visual_str,
147   FriBidiStrIndex *positions_L_to_V,
148   FriBidiStrIndex *positions_V_to_L,
149   FriBidiLevel *embedding_levels
150 )
151 {
152   register FriBidiStrIndex i;
153   FriBidiLevel max_level = 0;
154   fribidi_boolean private_V_to_L = false;
155   fribidi_boolean private_embedding_levels = false;
156   fribidi_boolean status = false;
157   FriBidiArabicProp local_ar_props[LOCAL_LIST_SIZE];
158   FriBidiArabicProp *ar_props = NULL;
159   FriBidiLevel local_embedding_levels[LOCAL_LIST_SIZE];
160   FriBidiCharType local_bidi_types[LOCAL_LIST_SIZE];
161   FriBidiCharType *bidi_types = NULL;
162   FriBidiBracketType local_bracket_types[LOCAL_LIST_SIZE];
163   FriBidiBracketType *bracket_types = NULL;
164   FriBidiStrIndex local_positions_V_to_L[LOCAL_LIST_SIZE];
165
166   if UNLIKELY
167     (len == 0)
168     {
169       status = true;
170       goto out;
171     }
172
173   DBG ("in fribidi_log2vis");
174
175   fribidi_assert (str);
176   fribidi_assert (pbase_dir);
177
178   if (len < LOCAL_LIST_SIZE)
179     bidi_types = local_bidi_types;
180   else
181     bidi_types = fribidi_malloc (len * sizeof bidi_types[0]);
182   if (!bidi_types)
183     goto out;
184
185   fribidi_get_bidi_types (str, len, bidi_types);
186
187   if (len < LOCAL_LIST_SIZE)
188     bracket_types = local_bracket_types;
189   else
190     bracket_types = fribidi_malloc (len * sizeof bracket_types[0]);
191     
192   if (!bracket_types)
193     goto out;
194
195   fribidi_get_bracket_types (str, len, bidi_types,
196                              /* output */
197                              bracket_types);
198   if (!embedding_levels)
199     {
200       if (len < LOCAL_LIST_SIZE)
201         embedding_levels = local_embedding_levels;
202       else
203         embedding_levels = fribidi_malloc (len * sizeof embedding_levels[0]);
204       if (!embedding_levels)
205         goto out;
206       private_embedding_levels = true;
207     }
208
209   max_level = fribidi_get_par_embedding_levels_ex (bidi_types,
210                                                    bracket_types,
211                                                    len,
212                                                    pbase_dir,
213                                                    embedding_levels) - 1;
214   if UNLIKELY
215     (max_level < 0) goto out;
216
217   /* If l2v is to be calculated we must have v2l as well. If it is not
218      given by the caller, we have to make a private instance of it. */
219   if (positions_L_to_V && !positions_V_to_L)
220     {
221       if (len < LOCAL_LIST_SIZE)
222         positions_V_to_L = local_positions_V_to_L;
223       else
224         positions_V_to_L =
225         (FriBidiStrIndex *) fribidi_malloc (sizeof (FriBidiStrIndex) * len);
226       if (!positions_V_to_L)
227         goto out;
228       private_V_to_L = true;
229     }
230
231   /* Set up the ordering array to identity order */
232   if (positions_V_to_L)
233     {
234       for (i = 0; i < len; i++)
235         positions_V_to_L[i] = i;
236     }
237
238
239   if (visual_str)
240     {
241       /* Using memcpy instead
242       for (i = len - 1; i >= 0; i--)
243         visual_str[i] = str[i];
244       */
245       memcpy (visual_str, str, len * sizeof (*visual_str));
246
247       /* Arabic joining */
248       if (len < LOCAL_LIST_SIZE)
249         ar_props = local_ar_props;
250       else
251         ar_props = fribidi_malloc (len * sizeof ar_props[0]);
252       fribidi_get_joining_types (str, len, ar_props);
253       fribidi_join_arabic (bidi_types, len, embedding_levels, ar_props);
254
255       fribidi_shape (flags, embedding_levels, len, ar_props, visual_str);
256     }
257
258   /* line breaking goes here, but we assume one line in this function */
259
260   /* and this should be called once per line, but again, we assume one
261    * line in this deprecated function */
262   status =
263     fribidi_reorder_line (flags, bidi_types, len, 0, *pbase_dir,
264                           embedding_levels, visual_str,
265                           positions_V_to_L);
266
267   /* Convert the v2l list to l2v */
268   if (positions_L_to_V)
269     {
270       for (i = 0; i < len; i++)
271         positions_L_to_V[i] = -1;
272       for (i = 0; i < len; i++)
273         positions_L_to_V[positions_V_to_L[i]] = i;
274     }
275
276 out:
277
278   if (private_V_to_L && positions_V_to_L != local_positions_V_to_L)
279     fribidi_free (positions_V_to_L);
280
281   if (private_embedding_levels && embedding_levels != local_embedding_levels)
282     fribidi_free (embedding_levels);
283
284   if (ar_props && ar_props != local_ar_props)
285     fribidi_free (ar_props);
286
287   if (bidi_types && bidi_types != local_bidi_types)
288     fribidi_free (bidi_types);
289
290   if (bracket_types && bracket_types != local_bracket_types)
291     fribidi_free (bracket_types);
292
293   return status ? max_level + 1 : 0;
294 }
295
296 const char *fribidi_unicode_version = FRIBIDI_UNICODE_VERSION;
297
298 const char *fribidi_version_info =
299   "(" FRIBIDI_NAME ") " FRIBIDI_VERSION "\n"
300   "interface version " FRIBIDI_INTERFACE_VERSION_STRING ",\n"
301   "Unicode Character Database version " FRIBIDI_UNICODE_VERSION ",\n"
302   "Configure options"
303 #ifdef DEBUG
304   " --enable-debug"
305 #endif /* DEBUG */
306   ".\n\n"
307   "Copyright (C) 2004  Sharif FarsiWeb, Inc.\n"
308   "Copyright (C) 2001, 2002, 2004, 2005  Behdad Esfahbod\n"
309   "Copyright (C) 1999, 2000, 2017, 2018, 2019  Dov Grobgeld\n"
310   FRIBIDI_NAME " comes with NO WARRANTY, to the extent permitted by law.\n"
311   "You may redistribute copies of " FRIBIDI_NAME " under\n"
312   "the terms of the GNU Lesser General Public License.\n"
313   "For more information about these matters, see the file named COPYING.\n\n"
314   "Written by Behdad Esfahbod and Dov Grobgeld.\n";
315
316 /* Editor directions:
317  * vim:textwidth=78:tabstop=8:shiftwidth=2:autoindent:cindent
318  */