• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdint.h>
2 #include <stdlib.h>
3 
4 #include <harfbuzz-external.h>
5 #include <harfbuzz-impl.h>
6 #include <harfbuzz-shaper.h>
7 #include "harfbuzz-unicode.h"
8 
9 #include "tables/grapheme-break-properties.h"
10 #include "tables/mirroring-properties.h"
11 #include "tables/script-properties.h"
12 
13 uint32_t
utf16_to_code_point(const uint16_t * chars,size_t len,ssize_t * iter)14 utf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter) {
15   const uint16_t v = chars[(*iter)++];
16   if (HB_IsHighSurrogate(v)) {
17     // surrogate pair
18     if (*iter >= len) {
19       // the surrogate is incomplete.
20       return HB_InvalidCodePoint;
21     }
22     const uint16_t v2 = chars[(*iter)++];
23     if (!HB_IsLowSurrogate(v2)) {
24       // invalidate surrogate pair.
25       return HB_InvalidCodePoint;
26     }
27 
28     return HB_SurrogateToUcs4(v, v2);
29   }
30 
31   if (HB_IsLowSurrogate(v)) {
32     // this isn't a valid code point
33     return HB_InvalidCodePoint;
34   }
35 
36   return v;
37 }
38 
39 uint32_t
utf16_to_code_point_prev(const uint16_t * chars,size_t len,ssize_t * iter)40 utf16_to_code_point_prev(const uint16_t *chars, size_t len, ssize_t *iter) {
41   const uint16_t v = chars[(*iter)--];
42   if (HB_IsLowSurrogate(v)) {
43     // surrogate pair
44     if (*iter < 0) {
45       // the surrogate is incomplete.
46       return HB_InvalidCodePoint;
47     }
48     const uint16_t v2 = chars[(*iter)--];
49     if (!HB_IsHighSurrogate(v2)) {
50       // invalidate surrogate pair.
51       return HB_InvalidCodePoint;
52     }
53 
54     return HB_SurrogateToUcs4(v2, v);
55   }
56 
57   if (HB_IsHighSurrogate(v)) {
58     // this isn't a valid code point
59     return HB_InvalidCodePoint;
60   }
61 
62   return v;
63 }
64 
65 static int
script_property_cmp(const void * vkey,const void * vcandidate)66 script_property_cmp(const void *vkey, const void *vcandidate) {
67   const uint32_t key = (uint32_t) (intptr_t) vkey;
68   const struct script_property *candidate = vcandidate;
69 
70   if (key < candidate->range_start) {
71     return -1;
72   } else if (key > candidate->range_end) {
73     return 1;
74   } else {
75     return 0;
76   }
77 }
78 
79 HB_Script
code_point_to_script(uint32_t cp)80 code_point_to_script(uint32_t cp) {
81   if (cp == 0) {
82     // bsearch can throw an assertion on null pointer, so skip if zero
83     return HB_Script_Common;
84   }
85   const void *vprop = bsearch((void *) (intptr_t) cp, script_properties,
86                               script_properties_count,
87                               sizeof(struct script_property),
88                               script_property_cmp);
89   if (!vprop)
90     return HB_Script_Common;
91 
92   return ((const struct script_property *) vprop)->script;
93 }
94 
95 char
hb_utf16_script_run_next(unsigned * num_code_points,HB_ScriptItem * output,const uint16_t * chars,size_t len,ssize_t * iter)96 hb_utf16_script_run_next(unsigned *num_code_points, HB_ScriptItem *output,
97                          const uint16_t *chars, size_t len, ssize_t *iter) {
98   if (*iter == len)
99     return 0;
100 
101   output->pos = *iter;
102   const uint32_t init_cp = utf16_to_code_point(chars, len, iter);
103   unsigned cps = 1;
104   if (init_cp == HB_InvalidCodePoint)
105     return 0;
106   const HB_Script init_script = code_point_to_script(init_cp);
107   HB_Script current_script = init_script;
108   output->script = init_script;
109 
110   for (;;) {
111     if (*iter == len)
112       break;
113     const ssize_t prev_iter = *iter;
114     const uint32_t cp = utf16_to_code_point(chars, len, iter);
115     if (cp == HB_InvalidCodePoint)
116       return 0;
117     cps++;
118     const HB_Script script = code_point_to_script(cp);
119 
120     if (script != current_script) {
121         /* BEGIN android-changed
122            The condition was not correct by doing "a == b == constant"
123            END android-changed */
124       if (current_script == HB_Script_Inherited && init_script == HB_Script_Inherited) {
125         // If we started off as inherited, we take whatever we can find.
126         output->script = script;
127         current_script = script;
128         continue;
129       } else if (script == HB_Script_Inherited) {
130         continue;
131       } else {
132         *iter = prev_iter;
133         cps--;
134         break;
135       }
136     }
137   }
138 
139   if (output->script == HB_Script_Inherited)
140     output->script = HB_Script_Common;
141 
142   output->length = *iter - output->pos;
143   if (num_code_points)
144     *num_code_points = cps;
145   return 1;
146 }
147 
148 char
hb_utf16_script_run_prev(unsigned * num_code_points,HB_ScriptItem * output,const uint16_t * chars,size_t len,ssize_t * iter)149 hb_utf16_script_run_prev(unsigned *num_code_points, HB_ScriptItem *output,
150                          const uint16_t *chars, size_t len, ssize_t *iter) {
151   if (*iter == (size_t) -1)
152     return 0;
153 
154   const size_t ending_index = *iter;
155   const uint32_t init_cp = utf16_to_code_point_prev(chars, len, iter);
156   unsigned cps = 1;
157   if (init_cp == HB_InvalidCodePoint)
158     return 0;
159   const HB_Script init_script = code_point_to_script(init_cp);
160   HB_Script current_script = init_script;
161   output->script = init_script;
162 
163   for (;;) {
164     if (*iter < 0)
165       break;
166     const ssize_t prev_iter = *iter;
167     const uint32_t cp = utf16_to_code_point_prev(chars, len, iter);
168     if (cp == HB_InvalidCodePoint)
169       return 0;
170     cps++;
171     const HB_Script script = code_point_to_script(cp);
172 
173     if (script != current_script) {
174       if (current_script == HB_Script_Inherited && init_script == HB_Script_Inherited) {
175         // If we started off as inherited, we take whatever we can find.
176         output->script = script;
177         current_script = script;
178         continue;
179       } else if (script == HB_Script_Inherited) {
180         /* BEGIN android-changed
181            We apply the same fix for Chrome to Android.
182            Chrome team will talk with upsteam about it.
183            Just assume that whatever follows this combining character is within
184            the same script.  This is incorrect if you had language1 + combining
185            char + language 2, but that is rare and this code is suspicious
186            anyway.
187            END android-changed */
188         continue;
189       } else {
190         *iter = prev_iter;
191         cps--;
192         break;
193       }
194     }
195   }
196 
197   if (output->script == HB_Script_Inherited)
198     output->script = HB_Script_Common;
199 
200   output->pos = *iter + 1;
201   output->length = ending_index - *iter;
202   if (num_code_points)
203     *num_code_points = cps;
204   return 1;
205 }
206 
207 static int
grapheme_break_property_cmp(const void * vkey,const void * vcandidate)208 grapheme_break_property_cmp(const void *vkey, const void *vcandidate) {
209   const uint32_t key = (uint32_t) (intptr_t) vkey;
210   const struct grapheme_break_property *candidate = vcandidate;
211 
212   if (key < candidate->range_start) {
213     return -1;
214   } else if (key > candidate->range_end) {
215     return 1;
216   } else {
217     return 0;
218   }
219 }
220 
221 HB_GraphemeClass
HB_GetGraphemeClass(HB_UChar32 ch)222 HB_GetGraphemeClass(HB_UChar32 ch) {
223   const void *vprop = bsearch((void *) (intptr_t) ch, grapheme_break_properties,
224                               grapheme_break_properties_count,
225                               sizeof(struct grapheme_break_property),
226                               grapheme_break_property_cmp);
227   if (!vprop)
228     return HB_Grapheme_Other;
229 
230   return ((const struct grapheme_break_property *) vprop)->klass;
231 }
232 
233 HB_WordClass
HB_GetWordClass(HB_UChar32 ch)234 HB_GetWordClass(HB_UChar32 ch) {
235   abort();
236   return 0;
237 }
238 
239 HB_SentenceClass
HB_GetSentenceClass(HB_UChar32 ch)240 HB_GetSentenceClass(HB_UChar32 ch) {
241   abort();
242   return 0;
243 }
244 
245 void
HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch,HB_GraphemeClass * gclass,HB_LineBreakClass * breakclass)246 HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *gclass, HB_LineBreakClass *breakclass) {
247   *gclass = HB_GetGraphemeClass(ch);
248   *breakclass = HB_GetLineBreakClass(ch);
249 }
250 
251 static int
mirroring_property_cmp(const void * vkey,const void * vcandidate)252 mirroring_property_cmp(const void *vkey, const void *vcandidate) {
253   const uint32_t key = (uint32_t) (intptr_t) vkey;
254   const struct mirroring_property *candidate = vcandidate;
255 
256   if (key < candidate->a) {
257     return -1;
258   } else if (key > candidate->a) {
259     return 1;
260   } else {
261     return 0;
262   }
263 }
264 
265 HB_UChar16
HB_GetMirroredChar(HB_UChar16 ch)266 HB_GetMirroredChar(HB_UChar16 ch) {
267   const void *mprop = bsearch((void *) (intptr_t) ch, mirroring_properties,
268                               mirroring_properties_count,
269                               sizeof(struct mirroring_property),
270                               mirroring_property_cmp);
271   if (!mprop)
272     return ch;
273 
274   return ((const struct mirroring_property *) mprop)->b;
275 }
276 
277 void *
HB_Library_Resolve(const char * library,int version,const char * symbol)278 HB_Library_Resolve(const char *library, int version, const char *symbol) {
279   abort();
280   return NULL;
281 }
282