6a21ef346fa7dba8b651a0645f605ba71edbbcde
[framework/uifw/harfbuzz.git] / src / hb-unicode.cc
1 /*
2  * Copyright © 2009  Red Hat, Inc.
3  * Copyright © 2011 Codethink Limited
4  * Copyright © 2010,2011  Google, Inc.
5  *
6  *  This is part of HarfBuzz, a text shaping library.
7  *
8  * Permission is hereby granted, without written agreement and without
9  * license or royalty fees, to use, copy, modify, and distribute this
10  * software and its documentation for any purpose, provided that the
11  * above copyright notice and the following two paragraphs appear in
12  * all copies of this software.
13  *
14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18  * DAMAGE.
19  *
20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25  *
26  * Red Hat Author(s): Behdad Esfahbod
27  * Codethink Author(s): Ryan Lortie
28  * Google Author(s): Behdad Esfahbod
29  */
30
31 #include "hb-private.hh"
32
33 #include "hb-unicode-private.hh"
34
35
36
37 /*
38  * hb_unicode_funcs_t
39  */
40
41 static unsigned int
42 hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
43                                 hb_codepoint_t      unicode   HB_UNUSED,
44                                 void               *user_data HB_UNUSED)
45 {
46   return 0;
47 }
48
49 static unsigned int
50 hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
51                                 hb_codepoint_t      unicode   HB_UNUSED,
52                                 void               *user_data HB_UNUSED)
53 {
54   return 1;
55 }
56
57 static hb_unicode_general_category_t
58 hb_unicode_general_category_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
59                                  hb_codepoint_t      unicode   HB_UNUSED,
60                                  void               *user_data HB_UNUSED)
61 {
62   return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
63 }
64
65 static hb_codepoint_t
66 hb_unicode_mirroring_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
67                           hb_codepoint_t      unicode   HB_UNUSED,
68                           void               *user_data HB_UNUSED)
69 {
70   return unicode;
71 }
72
73 static hb_script_t
74 hb_unicode_script_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
75                        hb_codepoint_t      unicode   HB_UNUSED,
76                        void               *user_data HB_UNUSED)
77 {
78   return HB_SCRIPT_UNKNOWN;
79 }
80
81 static hb_bool_t
82 hb_unicode_compose_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
83                         hb_codepoint_t      a         HB_UNUSED,
84                         hb_codepoint_t      b         HB_UNUSED,
85                         hb_codepoint_t     *ab        HB_UNUSED,
86                         void               *user_data HB_UNUSED)
87 {
88   return false;
89 }
90
91 static hb_bool_t
92 hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
93                           hb_codepoint_t      ab        HB_UNUSED,
94                           hb_codepoint_t     *a         HB_UNUSED,
95                           hb_codepoint_t     *b         HB_UNUSED,
96                           void               *user_data HB_UNUSED)
97 {
98   return false;
99 }
100
101
102
103 hb_unicode_funcs_t *
104 hb_unicode_funcs_get_default (void)
105 {
106   return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default);
107 }
108
109 hb_unicode_funcs_t *
110 hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
111 {
112   hb_unicode_funcs_t *ufuncs;
113
114   if (!(ufuncs = hb_object_create<hb_unicode_funcs_t> ()))
115     return hb_unicode_funcs_get_empty ();
116
117   if (!parent)
118     parent = hb_unicode_funcs_get_empty ();
119
120   hb_unicode_funcs_make_immutable (parent);
121   ufuncs->parent = hb_unicode_funcs_reference (parent);
122
123   ufuncs->func = parent->func;
124
125   /* We can safely copy user_data from parent since we hold a reference
126    * onto it and it's immutable.  We should not copy the destroy notifiers
127    * though. */
128   ufuncs->user_data = parent->user_data;
129
130   return ufuncs;
131 }
132
133
134 //extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
135 const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
136   HB_OBJECT_HEADER_STATIC,
137
138   NULL, /* parent */
139   true, /* immutable */
140   {
141 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil,
142     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
143 #undef HB_UNICODE_FUNC_IMPLEMENT
144   }
145 };
146
147 hb_unicode_funcs_t *
148 hb_unicode_funcs_get_empty (void)
149 {
150   return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
151 }
152
153 hb_unicode_funcs_t *
154 hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
155 {
156   return hb_object_reference (ufuncs);
157 }
158
159 void
160 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
161 {
162   if (!hb_object_destroy (ufuncs)) return;
163
164 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
165   if (ufuncs->destroy.name) ufuncs->destroy.name (ufuncs->user_data.name);
166     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
167 #undef HB_UNICODE_FUNC_IMPLEMENT
168
169   hb_unicode_funcs_destroy (ufuncs->parent);
170
171   free (ufuncs);
172 }
173
174 hb_bool_t
175 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
176                                 hb_user_data_key_t *key,
177                                 void *              data,
178                                 hb_destroy_func_t   destroy,
179                                 hb_bool_t           replace)
180 {
181   return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
182 }
183
184 void *
185 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
186                                 hb_user_data_key_t *key)
187 {
188   return hb_object_get_user_data (ufuncs, key);
189 }
190
191
192 void
193 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
194 {
195   if (hb_object_is_inert (ufuncs))
196     return;
197
198   ufuncs->immutable = true;
199 }
200
201 hb_bool_t
202 hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
203 {
204   return ufuncs->immutable;
205 }
206
207 hb_unicode_funcs_t *
208 hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
209 {
210   return ufuncs->parent ? ufuncs->parent : hb_unicode_funcs_get_empty ();
211 }
212
213
214 #define HB_UNICODE_FUNC_IMPLEMENT(name)                                         \
215                                                                                 \
216 void                                                                            \
217 hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t             *ufuncs,     \
218                                     hb_unicode_##name##_func_t      func,       \
219                                     void                           *user_data,  \
220                                     hb_destroy_func_t               destroy)    \
221 {                                                                               \
222   if (ufuncs->immutable)                                                        \
223     return;                                                                     \
224                                                                                 \
225   if (ufuncs->destroy.name)                                                     \
226     ufuncs->destroy.name (ufuncs->user_data.name);                              \
227                                                                                 \
228   if (func) {                                                                   \
229     ufuncs->func.name = func;                                                   \
230     ufuncs->user_data.name = user_data;                                         \
231     ufuncs->destroy.name = destroy;                                             \
232   } else {                                                                      \
233     ufuncs->func.name = ufuncs->parent->func.name;                              \
234     ufuncs->user_data.name = ufuncs->parent->user_data.name;                    \
235     ufuncs->destroy.name = NULL;                                                \
236   }                                                                             \
237 }
238
239     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
240 #undef HB_UNICODE_FUNC_IMPLEMENT
241
242
243 #define HB_UNICODE_FUNC_IMPLEMENT(return_type, name)                            \
244                                                                                 \
245 return_type                                                                     \
246 hb_unicode_##name (hb_unicode_funcs_t *ufuncs,                                  \
247                    hb_codepoint_t      unicode)                                 \
248 {                                                                               \
249   return ufuncs->func.name (ufuncs, unicode, ufuncs->user_data.name);           \
250 }
251     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
252 #undef HB_UNICODE_FUNC_IMPLEMENT
253
254 hb_bool_t
255 hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
256                     hb_codepoint_t      a,
257                     hb_codepoint_t      b,
258                     hb_codepoint_t     *ab)
259 {
260   *ab = 0;
261   return ufuncs->func.compose (ufuncs, a, b, ab, ufuncs->user_data.compose);
262 }
263
264 hb_bool_t
265 hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
266                       hb_codepoint_t      ab,
267                       hb_codepoint_t     *a,
268                       hb_codepoint_t     *b)
269 {
270   *a = ab; *b = 0;
271   return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose);
272 }
273
274
275
276 unsigned int
277 _hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
278                                       hb_codepoint_t      unicode)
279 {
280   int c = hb_unicode_combining_class (ufuncs, unicode);
281
282   if (unlikely (hb_in_range<int> (c, 27, 33)))
283   {
284     /* Modify the combining-class to suit Arabic better.  See:
285      * http://unicode.org/faq/normalization.html#8
286      * http://unicode.org/faq/normalization.html#9
287      */
288     c = c == 33 ? 27 : c + 1;
289   }
290   else if (unlikely (hb_in_range<int> (c, 10, 25)))
291   {
292     /* The equivalent fix for Hebrew is more complex.
293      *
294      * We permute the "fixed-position" classes 10-25 into the order
295      * described in the SBL Hebrew manual:
296      *
297      * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
298      *
299      * (as recommended by:
300      *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
301      *
302      * More details here:
303      * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
304      */
305     static const int permuted_hebrew_classes[25 - 10 + 1] = {
306       /* 10 sheva */        22,
307       /* 11 hataf segol */  15,
308       /* 12 hataf patah */  16,
309       /* 13 hataf qamats */ 17,
310       /* 14 hiriq */        23,
311       /* 15 tsere */        18,
312       /* 16 segol */        19,
313       /* 17 patah */        20,
314       /* 18 qamats */       21,
315       /* 19 holam */        14,
316       /* 20 qubuts */       24,
317       /* 21 dagesh */       12,
318       /* 22 meteg */        25,
319       /* 23 rafe */         13,
320       /* 24 shin dot */     10,
321       /* 25 sin dot */      11,
322     };
323     c = permuted_hebrew_classes[c - 10];
324   }
325
326   return c;
327 }
328