]>
Commit | Line | Data |
---|---|---|
1d3c6f1d VS |
1 | /* |
2 | * GRUB -- GRand Unified Bootloader | |
3 | * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. | |
4 | * | |
5 | * GRUB is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 3 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * GRUB is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
521bf301 VS |
19 | /* |
20 | Current problems with Unicode rendering: | |
21 | - B and BN bidi type characters (ignored) | |
0761327d VS |
22 | - Mc type characters with combining class 0 (poorly combined) |
23 | - Mn type characters with combining class 0 (poorly combined) | |
24 | - Me type characters with combining class 0 (poorly combined) | |
521bf301 VS |
25 | - Cf type characters (ignored) |
26 | - Cc type characters (ignored) | |
27 | - Line-breaking rules (e.g. Zs type characters) | |
28 | - Indic languages | |
0761327d | 29 | - non-Semitic shaping (rarely used) |
521bf301 | 30 | - Zl and Zp characters |
ad109fe0 VS |
31 | - Combining characters of types 7, 8, 9, 21, 35, 36, 84, 91, 103, 107, |
32 | 118, 122, 129, 130, 132, 218, 224, 226, 233, 234 | |
521bf301 | 33 | - Private use characters (not really a problem) |
e83200d8 VS |
34 | - Variations (no font support) |
35 | - Vertical text | |
6d107fb2 | 36 | - Ligatures |
0761327d VS |
37 | Font information ignored: |
38 | - Kerning | |
39 | - Justification data | |
40 | - Glyph posititioning | |
41 | - Baseline data | |
ad109fe0 | 42 | Most underline diacritics aren't displayed in gfxterm |
521bf301 VS |
43 | */ |
44 | ||
1d3c6f1d | 45 | #include <grub/charset.h> |
2e713831 VS |
46 | #include <grub/mm.h> |
47 | #include <grub/misc.h> | |
0a239a82 VS |
48 | #include <grub/unicode.h> |
49 | #include <grub/term.h> | |
50 | #include <grub/normal.h> | |
3f05d693 | 51 | #include <grub/safemath.h> |
1d3c6f1d | 52 | |
6f07c4e4 | 53 | #if HAVE_FONT_SOURCE |
6c363dfd VS |
54 | #include "widthspec.h" |
55 | #endif | |
56 | ||
c5fc563a VS |
57 | /* Returns -2 if not enough space, -1 on invalid character. */ |
58 | grub_ssize_t | |
59 | grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend, | |
60 | grub_uint32_t code) | |
61 | { | |
62 | if (dest >= destend) | |
63 | return -2; | |
64 | if (code <= 0x007F) | |
65 | { | |
66 | *dest++ = code; | |
67 | return 1; | |
68 | } | |
69 | if (code <= 0x07FF) | |
70 | { | |
71 | if (dest + 1 >= destend) | |
72 | return -2; | |
73 | *dest++ = (code >> 6) | 0xC0; | |
74 | *dest++ = (code & 0x3F) | 0x80; | |
75 | return 2; | |
76 | } | |
77 | if ((code >= 0xDC00 && code <= 0xDFFF) | |
78 | || (code >= 0xD800 && code <= 0xDBFF)) | |
79 | { | |
80 | /* No surrogates in UCS-4... */ | |
81 | return -1; | |
82 | } | |
83 | if (code < 0x10000) | |
84 | { | |
85 | if (dest + 2 >= destend) | |
86 | return -2; | |
87 | *dest++ = (code >> 12) | 0xE0; | |
88 | *dest++ = ((code >> 6) & 0x3F) | 0x80; | |
89 | *dest++ = (code & 0x3F) | 0x80; | |
90 | return 3; | |
91 | } | |
92 | { | |
93 | if (dest + 3 >= destend) | |
94 | return -2; | |
95 | *dest++ = (code >> 18) | 0xF0; | |
96 | *dest++ = ((code >> 12) & 0x3F) | 0x80; | |
97 | *dest++ = ((code >> 6) & 0x3F) | 0x80; | |
98 | *dest++ = (code & 0x3F) | 0x80; | |
99 | return 4; | |
100 | } | |
101 | ||
102 | } | |
103 | ||
f10331ed | 104 | /* Convert UCS-4 to UTF-8. */ |
851ffada | 105 | grub_size_t |
cb8f88ea | 106 | grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size, |
f10331ed VS |
107 | grub_uint8_t *dest, grub_size_t destsize) |
108 | { | |
109 | /* Keep last char for \0. */ | |
110 | grub_uint8_t *destend = dest + destsize - 1; | |
851ffada | 111 | grub_uint8_t *dest0 = dest; |
f10331ed VS |
112 | |
113 | while (size-- && dest < destend) | |
114 | { | |
115 | grub_uint32_t code = *src++; | |
c5fc563a | 116 | grub_ssize_t s; |
f3cb4a4e | 117 | s = grub_encode_utf8_character (dest, destend, code); |
c5fc563a VS |
118 | if (s == -2) |
119 | break; | |
120 | if (s == -1) | |
f10331ed | 121 | { |
f10331ed | 122 | *dest++ = '?'; |
c5fc563a | 123 | continue; |
f10331ed | 124 | } |
c5fc563a | 125 | dest += s; |
f10331ed VS |
126 | } |
127 | *dest = 0; | |
851ffada | 128 | return dest - dest0; |
f10331ed VS |
129 | } |
130 | ||
851ffada VS |
131 | /* Returns the number of bytes the string src would occupy is converted |
132 | to UTF-8, excluding trailing \0. */ | |
133 | grub_size_t | |
134 | grub_get_num_of_utf8_bytes (const grub_uint32_t *src, grub_size_t size) | |
f4c623e1 VS |
135 | { |
136 | grub_size_t remaining; | |
cb8f88ea | 137 | const grub_uint32_t *ptr; |
f4c623e1 | 138 | grub_size_t cnt = 0; |
f4c623e1 VS |
139 | |
140 | remaining = size; | |
141 | ptr = src; | |
142 | while (remaining--) | |
143 | { | |
144 | grub_uint32_t code = *ptr++; | |
145 | ||
146 | if (code <= 0x007F) | |
147 | cnt++; | |
148 | else if (code <= 0x07FF) | |
149 | cnt += 2; | |
150 | else if ((code >= 0xDC00 && code <= 0xDFFF) | |
151 | || (code >= 0xD800 && code <= 0xDBFF)) | |
152 | /* No surrogates in UCS-4... */ | |
153 | cnt++; | |
1afcc914 | 154 | else if (code < 0x10000) |
f4c623e1 | 155 | cnt += 3; |
1afcc914 VS |
156 | else |
157 | cnt += 4; | |
f4c623e1 | 158 | } |
851ffada VS |
159 | return cnt; |
160 | } | |
161 | ||
162 | /* Convert UCS-4 to UTF-8. */ | |
163 | char * | |
164 | grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size) | |
165 | { | |
166 | grub_uint8_t *ret; | |
167 | grub_size_t cnt = grub_get_num_of_utf8_bytes (src, size) + 1; | |
f4c623e1 VS |
168 | |
169 | ret = grub_malloc (cnt); | |
170 | if (!ret) | |
171 | return 0; | |
172 | ||
f10331ed | 173 | grub_ucs4_to_utf8 (src, size, ret, cnt); |
f4c623e1 | 174 | |
2e713831 VS |
175 | return (char *) ret; |
176 | } | |
177 | ||
178 | int | |
179 | grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize) | |
180 | { | |
2e713831 | 181 | int count = 0; |
8569f13d | 182 | grub_uint32_t code = 0; |
2e713831 VS |
183 | |
184 | while (srcsize) | |
185 | { | |
2e713831 VS |
186 | if (srcsize != (grub_size_t)-1) |
187 | srcsize--; | |
8569f13d VS |
188 | if (!grub_utf8_process (*src++, &code, &count)) |
189 | return 0; | |
190 | if (count != 0) | |
191 | continue; | |
192 | if (code == 0) | |
193 | return 1; | |
194 | if (code > GRUB_UNICODE_LAST_VALID) | |
195 | return 0; | |
2e713831 VS |
196 | } |
197 | ||
198 | return 1; | |
199 | } | |
200 | ||
8b282ad2 | 201 | grub_ssize_t |
2e713831 | 202 | grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, |
8b282ad2 | 203 | grub_uint32_t **last_position) |
2e713831 VS |
204 | { |
205 | grub_size_t msg_len = grub_strlen (msg); | |
206 | ||
f725fa7c | 207 | *unicode_msg = grub_calloc (msg_len, sizeof (grub_uint32_t)); |
2e713831 VS |
208 | |
209 | if (!*unicode_msg) | |
5303b85d | 210 | return -1; |
2e713831 VS |
211 | |
212 | msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len, | |
213 | (grub_uint8_t *) msg, -1, 0); | |
214 | ||
eaa1f9a6 VS |
215 | if (last_position) |
216 | *last_position = *unicode_msg + msg_len; | |
2e713831 VS |
217 | |
218 | return msg_len; | |
f4c623e1 | 219 | } |
dfed5c6b VS |
220 | |
221 | /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE | |
222 | bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string. | |
223 | Return the number of characters converted. DEST must be able to hold | |
224 | at least DESTSIZE characters. | |
225 | If SRCEND is not NULL, then *SRCEND is set to the next byte after the | |
226 | last byte used in SRC. */ | |
227 | grub_size_t | |
228 | grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, | |
229 | const grub_uint8_t *src, grub_size_t srcsize, | |
230 | const grub_uint8_t **srcend) | |
231 | { | |
232 | grub_uint32_t *p = dest; | |
233 | int count = 0; | |
234 | grub_uint32_t code = 0; | |
235 | ||
236 | if (srcend) | |
237 | *srcend = src; | |
238 | ||
239 | while (srcsize && destsize) | |
240 | { | |
8569f13d | 241 | int was_count = count; |
dfed5c6b VS |
242 | if (srcsize != (grub_size_t)-1) |
243 | srcsize--; | |
8569f13d | 244 | if (!grub_utf8_process (*src++, &code, &count)) |
dfed5c6b | 245 | { |
8569f13d VS |
246 | code = '?'; |
247 | count = 0; | |
248 | /* Character c may be valid, don't eat it. */ | |
249 | if (was_count) | |
250 | src--; | |
dfed5c6b | 251 | } |
8569f13d VS |
252 | if (count != 0) |
253 | continue; | |
254 | if (code == 0) | |
255 | break; | |
256 | *p++ = code; | |
257 | destsize--; | |
dfed5c6b VS |
258 | } |
259 | ||
260 | if (srcend) | |
261 | *srcend = src; | |
262 | return p - dest; | |
263 | } | |
0a239a82 | 264 | |
df3d4cba VS |
265 | static grub_uint8_t *join_types = NULL; |
266 | ||
267 | static void | |
268 | unpack_join (void) | |
269 | { | |
270 | unsigned i; | |
271 | struct grub_unicode_compact_range *cur; | |
272 | ||
273 | join_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); | |
274 | if (!join_types) | |
275 | { | |
276 | grub_errno = GRUB_ERR_NONE; | |
277 | return; | |
278 | } | |
5da8dbc5 VS |
279 | for (cur = grub_unicode_compact; cur->len; cur++) |
280 | for (i = cur->start; i < cur->start + (unsigned) cur->len | |
281 | && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) | |
df3d4cba VS |
282 | join_types[i] = cur->join_type; |
283 | } | |
284 | ||
0a239a82 VS |
285 | static grub_uint8_t *bidi_types = NULL; |
286 | ||
287 | static void | |
288 | unpack_bidi (void) | |
289 | { | |
290 | unsigned i; | |
291 | struct grub_unicode_compact_range *cur; | |
292 | ||
293 | bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); | |
294 | if (!bidi_types) | |
295 | { | |
296 | grub_errno = GRUB_ERR_NONE; | |
297 | return; | |
298 | } | |
5da8dbc5 VS |
299 | for (cur = grub_unicode_compact; cur->len; cur++) |
300 | for (i = cur->start; i < cur->start + (unsigned) cur->len | |
301 | && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) | |
0a239a82 VS |
302 | if (cur->bidi_mirror) |
303 | bidi_types[i] = cur->bidi_type | 0x80; | |
304 | else | |
305 | bidi_types[i] = cur->bidi_type | 0x00; | |
306 | } | |
307 | ||
308 | static inline enum grub_bidi_type | |
309 | get_bidi_type (grub_uint32_t c) | |
310 | { | |
311 | struct grub_unicode_compact_range *cur; | |
312 | ||
313 | if (!bidi_types) | |
314 | unpack_bidi (); | |
315 | ||
316 | if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) | |
317 | return bidi_types[c] & 0x7f; | |
318 | ||
5da8dbc5 VS |
319 | for (cur = grub_unicode_compact; cur->len; cur++) |
320 | if (cur->start <= c && c < cur->start + (unsigned) cur->len) | |
0a239a82 VS |
321 | return cur->bidi_type; |
322 | ||
323 | return GRUB_BIDI_TYPE_L; | |
324 | } | |
325 | ||
df3d4cba VS |
326 | static inline enum grub_join_type |
327 | get_join_type (grub_uint32_t c) | |
328 | { | |
329 | struct grub_unicode_compact_range *cur; | |
330 | ||
331 | if (!join_types) | |
332 | unpack_join (); | |
333 | ||
334 | if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) | |
335 | return join_types[c]; | |
336 | ||
5da8dbc5 VS |
337 | for (cur = grub_unicode_compact; cur->len; cur++) |
338 | if (cur->start <= c && c < cur->start + (unsigned) cur->len) | |
df3d4cba VS |
339 | return cur->join_type; |
340 | ||
341 | return GRUB_JOIN_TYPE_NONJOINING; | |
342 | } | |
343 | ||
0a239a82 VS |
344 | static inline int |
345 | is_mirrored (grub_uint32_t c) | |
346 | { | |
347 | struct grub_unicode_compact_range *cur; | |
348 | ||
349 | if (!bidi_types) | |
350 | unpack_bidi (); | |
351 | ||
352 | if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) | |
353 | return !!(bidi_types[c] & 0x80); | |
354 | ||
5da8dbc5 VS |
355 | for (cur = grub_unicode_compact; cur->len; cur++) |
356 | if (cur->start <= c && c < cur->start + (unsigned) cur->len) | |
0a239a82 VS |
357 | return cur->bidi_mirror; |
358 | ||
359 | return 0; | |
360 | } | |
361 | ||
362 | enum grub_comb_type | |
363 | grub_unicode_get_comb_type (grub_uint32_t c) | |
364 | { | |
365 | static grub_uint8_t *comb_types = NULL; | |
366 | struct grub_unicode_compact_range *cur; | |
367 | ||
368 | if (!comb_types) | |
369 | { | |
370 | unsigned i; | |
371 | comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); | |
372 | if (comb_types) | |
5da8dbc5 VS |
373 | for (cur = grub_unicode_compact; cur->len; cur++) |
374 | for (i = cur->start; i < cur->start + (unsigned) cur->len | |
0a239a82 VS |
375 | && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) |
376 | comb_types[i] = cur->comb_type; | |
377 | else | |
378 | grub_errno = GRUB_ERR_NONE; | |
379 | } | |
380 | ||
381 | if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) | |
382 | return comb_types[c]; | |
383 | ||
5da8dbc5 VS |
384 | for (cur = grub_unicode_compact; cur->len; cur++) |
385 | if (cur->start <= c && c < cur->start + (unsigned) cur->len) | |
0a239a82 VS |
386 | return cur->comb_type; |
387 | ||
388 | return GRUB_UNICODE_COMB_NONE; | |
389 | } | |
390 | ||
6f07c4e4 | 391 | #if HAVE_FONT_SOURCE |
6c363dfd | 392 | |
a2856736 | 393 | grub_size_t |
6c363dfd VS |
394 | grub_unicode_estimate_width (const struct grub_unicode_glyph *c) |
395 | { | |
396 | if (grub_unicode_get_comb_type (c->base)) | |
397 | return 0; | |
398 | if (widthspec[c->base >> 3] & (1 << (c->base & 7))) | |
399 | return 2; | |
400 | else | |
401 | return 1; | |
402 | } | |
403 | ||
404 | #endif | |
405 | ||
ad109fe0 VS |
406 | static inline int |
407 | is_type_after (enum grub_comb_type a, enum grub_comb_type b) | |
408 | { | |
409 | /* Shadda is numerically higher than most of Arabic diacritics but has | |
410 | to be rendered before them. */ | |
411 | if (a == GRUB_UNICODE_COMB_ARABIC_SHADDA | |
412 | && b <= GRUB_UNICODE_COMB_ARABIC_KASRA | |
413 | && b >= GRUB_UNICODE_COMB_ARABIC_FATHATAN) | |
414 | return 0; | |
415 | if (b == GRUB_UNICODE_COMB_ARABIC_SHADDA | |
416 | && a <= GRUB_UNICODE_COMB_ARABIC_KASRA | |
417 | && a >= GRUB_UNICODE_COMB_ARABIC_FATHATAN) | |
418 | return 1; | |
419 | return a > b; | |
420 | } | |
421 | ||
0a239a82 VS |
422 | grub_size_t |
423 | grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, | |
424 | struct grub_unicode_glyph *out) | |
425 | { | |
426 | int haveout = 0; | |
427 | const grub_uint32_t *ptr; | |
428 | unsigned last_comb_pointer = 0; | |
429 | ||
430 | grub_memset (out, 0, sizeof (*out)); | |
431 | ||
e1bd676b VS |
432 | if (inlen && grub_iscntrl (*in)) |
433 | { | |
434 | out->base = *in; | |
435 | out->variant = 0; | |
436 | out->attributes = 0; | |
437 | out->ncomb = 0; | |
438 | out->estimated_width = 1; | |
e1bd676b VS |
439 | return 1; |
440 | } | |
441 | ||
0a239a82 VS |
442 | for (ptr = in; ptr < in + inlen; ptr++) |
443 | { | |
444 | /* Variation selectors >= 17 are outside of BMP and SMP. | |
445 | Handle variation selectors first to avoid potentially costly lookups. | |
446 | */ | |
447 | if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1 | |
448 | && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16) | |
449 | { | |
450 | if (haveout) | |
451 | out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1; | |
452 | continue; | |
0a239a82 VS |
453 | } |
454 | if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17 | |
455 | && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256) | |
456 | { | |
457 | if (haveout) | |
458 | out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17; | |
459 | continue; | |
460 | } | |
461 | ||
462 | enum grub_comb_type comb_type; | |
463 | comb_type = grub_unicode_get_comb_type (*ptr); | |
464 | if (comb_type) | |
465 | { | |
53c648d2 | 466 | struct grub_unicode_combining *n; |
0a239a82 | 467 | unsigned j; |
3f05d693 | 468 | grub_size_t sz; |
0a239a82 VS |
469 | |
470 | if (!haveout) | |
471 | continue; | |
472 | ||
473 | if (comb_type == GRUB_UNICODE_COMB_MC | |
474 | || comb_type == GRUB_UNICODE_COMB_ME | |
475 | || comb_type == GRUB_UNICODE_COMB_MN) | |
476 | last_comb_pointer = out->ncomb; | |
85002bf3 VS |
477 | |
478 | if (out->ncomb + 1 <= (int) ARRAY_SIZE (out->combining_inline)) | |
479 | n = out->combining_inline; | |
480 | else if (out->ncomb > (int) ARRAY_SIZE (out->combining_inline)) | |
0a239a82 | 481 | { |
3f05d693 PJ |
482 | if (grub_add (out->ncomb, 1, &sz) || |
483 | grub_mul (sz, sizeof (n[0]), &sz)) | |
484 | goto fail; | |
485 | ||
486 | n = grub_realloc (out->combining_ptr, sz); | |
85002bf3 VS |
487 | if (!n) |
488 | { | |
3f05d693 | 489 | fail: |
85002bf3 VS |
490 | grub_errno = GRUB_ERR_NONE; |
491 | continue; | |
492 | } | |
493 | out->combining_ptr = n; | |
494 | } | |
495 | else | |
496 | { | |
f725fa7c | 497 | n = grub_calloc (out->ncomb + 1, sizeof (n[0])); |
85002bf3 VS |
498 | if (!n) |
499 | { | |
500 | grub_errno = GRUB_ERR_NONE; | |
501 | continue; | |
502 | } | |
503 | grub_memcpy (n, out->combining_inline, | |
504 | sizeof (out->combining_inline)); | |
505 | out->combining_ptr = n; | |
0a239a82 VS |
506 | } |
507 | ||
508 | for (j = last_comb_pointer; j < out->ncomb; j++) | |
85002bf3 | 509 | if (is_type_after (n[j].type, comb_type)) |
0a239a82 | 510 | break; |
85002bf3 VS |
511 | grub_memmove (n + j + 1, |
512 | n + j, | |
0a239a82 | 513 | (out->ncomb - j) |
85002bf3 VS |
514 | * sizeof (n[0])); |
515 | n[j].code = *ptr; | |
516 | n[j].type = comb_type; | |
0a239a82 VS |
517 | out->ncomb++; |
518 | continue; | |
519 | } | |
520 | if (haveout) | |
521 | return ptr - in; | |
522 | haveout = 1; | |
523 | out->base = *ptr; | |
524 | out->variant = 0; | |
525 | out->attributes = 0; | |
526 | out->ncomb = 0; | |
50186d82 | 527 | out->estimated_width = 1; |
0a239a82 VS |
528 | } |
529 | return ptr - in; | |
530 | } | |
531 | ||
c03995d2 VS |
532 | static void |
533 | revert (struct grub_unicode_glyph *visual, | |
534 | struct grub_term_pos *pos, | |
535 | unsigned start, unsigned end) | |
536 | { | |
537 | struct grub_unicode_glyph t; | |
538 | unsigned i; | |
539 | int a = 0, b = 0; | |
540 | if (pos) | |
541 | { | |
542 | a = pos[visual[start].orig_pos].x; | |
543 | b = pos[visual[end].orig_pos].x; | |
544 | } | |
545 | for (i = 0; i < (end - start) / 2 + 1; i++) | |
546 | { | |
547 | t = visual[start + i]; | |
548 | visual[start + i] = visual[end - i]; | |
549 | visual[end - i] = t; | |
550 | ||
551 | if (pos) | |
552 | { | |
553 | pos[visual[start + i].orig_pos].x = a + b - pos[visual[start + i].orig_pos].x; | |
554 | pos[visual[end - i].orig_pos].x = a + b - pos[visual[end - i].orig_pos].x; | |
555 | } | |
556 | } | |
557 | } | |
558 | ||
559 | ||
eb679523 | 560 | static grub_ssize_t |
f588f1c8 VS |
561 | bidi_line_wrap (struct grub_unicode_glyph *visual_out, |
562 | struct grub_unicode_glyph *visual, | |
85002bf3 | 563 | grub_size_t visual_len, |
a2856736 | 564 | grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg), |
19e29ee1 | 565 | void *getcharwidth_arg, |
34f71cb8 VS |
566 | grub_size_t maxwidth, grub_size_t startwidth, |
567 | grub_uint32_t contchar, | |
568 | struct grub_term_pos *pos, int primitive_wrap, | |
569 | grub_size_t log_end) | |
eb679523 VS |
570 | { |
571 | struct grub_unicode_glyph *outptr = visual_out; | |
572 | unsigned line_start = 0; | |
dafff9ce | 573 | grub_ssize_t line_width; |
cacd173d | 574 | unsigned k; |
8b4ca088 VS |
575 | grub_ssize_t last_space = -1; |
576 | grub_ssize_t last_space_width = 0; | |
34f71cb8 | 577 | int lines = 0; |
eb679523 | 578 | |
eb679523 VS |
579 | if (!visual_len) |
580 | return 0; | |
581 | ||
dafff9ce VS |
582 | if (startwidth >= maxwidth && (grub_ssize_t) maxwidth > 0) |
583 | { | |
584 | if (contchar) | |
585 | { | |
586 | grub_memset (outptr, 0, sizeof (visual[0])); | |
587 | outptr->base = contchar; | |
588 | outptr++; | |
589 | } | |
590 | grub_memset (outptr, 0, sizeof (visual[0])); | |
591 | outptr->base = '\n'; | |
592 | outptr++; | |
593 | startwidth = 0; | |
594 | } | |
595 | ||
596 | line_width = startwidth; | |
597 | ||
eb679523 VS |
598 | for (k = 0; k <= visual_len; k++) |
599 | { | |
600 | grub_ssize_t last_width = 0; | |
34f71cb8 VS |
601 | |
602 | if (pos && k != visual_len) | |
603 | { | |
604 | pos[visual[k].orig_pos].x = line_width; | |
605 | pos[visual[k].orig_pos].y = lines; | |
606 | pos[visual[k].orig_pos].valid = 1; | |
607 | } | |
608 | ||
609 | if (k == visual_len && pos) | |
610 | { | |
611 | pos[log_end].x = line_width; | |
612 | pos[log_end].y = lines; | |
613 | pos[log_end].valid = 1; | |
614 | } | |
615 | ||
eb679523 | 616 | if (getcharwidth && k != visual_len) |
19e29ee1 | 617 | line_width += last_width = getcharwidth (&visual[k], getcharwidth_arg); |
8b4ca088 | 618 | |
e1bd676b | 619 | if (k != visual_len && (visual[k].base == ' ' |
34f71cb8 VS |
620 | || visual[k].base == '\t') |
621 | && !primitive_wrap) | |
8b4ca088 VS |
622 | { |
623 | last_space = k; | |
624 | last_space_width = line_width; | |
625 | } | |
626 | ||
eb679523 VS |
627 | if (((grub_ssize_t) maxwidth > 0 |
628 | && line_width > (grub_ssize_t) maxwidth) || k == visual_len) | |
cacd173d | 629 | { |
f588f1c8 VS |
630 | unsigned min_odd_level = 0xffffffff; |
631 | unsigned max_level = 0; | |
dafff9ce | 632 | unsigned kk = k; |
8b4ca088 | 633 | |
34f71cb8 VS |
634 | lines++; |
635 | ||
3830c087 | 636 | if (k != visual_len && last_space > (signed) line_start) |
dafff9ce VS |
637 | { |
638 | kk = last_space; | |
639 | line_width -= last_space_width; | |
640 | } | |
34f71cb8 | 641 | else if (k != visual_len && line_start == 0 && startwidth != 0 |
dafff9ce VS |
642 | && !primitive_wrap && lines == 1 |
643 | && line_width - startwidth < maxwidth) | |
3830c087 | 644 | { |
dafff9ce VS |
645 | kk = 0; |
646 | line_width -= startwidth; | |
3830c087 | 647 | } |
8b4ca088 | 648 | else |
dafff9ce | 649 | line_width = last_width; |
8b4ca088 | 650 | |
df3d4cba VS |
651 | { |
652 | unsigned i; | |
dafff9ce | 653 | for (i = line_start; i < kk; i++) |
df3d4cba | 654 | { |
85002bf3 VS |
655 | if (visual[i].bidi_level > max_level) |
656 | max_level = visual[i].bidi_level; | |
657 | if (visual[i].bidi_level < min_odd_level && (visual[i].bidi_level & 1)) | |
658 | min_odd_level = visual[i].bidi_level; | |
df3d4cba VS |
659 | } |
660 | } | |
661 | ||
662 | { | |
663 | unsigned j; | |
664 | /* FIXME: can be optimized. */ | |
d46683f9 | 665 | for (j = max_level; j > min_odd_level - 1; j--) |
df3d4cba | 666 | { |
3f8cdd90 | 667 | unsigned in = line_start; |
df3d4cba | 668 | unsigned i; |
dafff9ce | 669 | for (i = line_start; i < kk; i++) |
df3d4cba | 670 | { |
85002bf3 VS |
671 | if (i != line_start && visual[i].bidi_level >= j |
672 | && visual[i-1].bidi_level < j) | |
df3d4cba | 673 | in = i; |
dafff9ce | 674 | if (visual[i].bidi_level >= j && (i + 1 == kk |
85002bf3 | 675 | || visual[i+1].bidi_level < j)) |
c03995d2 | 676 | revert (visual, pos, in, i); |
df3d4cba VS |
677 | } |
678 | } | |
679 | } | |
f588f1c8 | 680 | |
df3d4cba VS |
681 | { |
682 | unsigned i; | |
dafff9ce | 683 | for (i = line_start; i < kk; i++) |
df3d4cba | 684 | { |
85002bf3 | 685 | if (is_mirrored (visual[i].base) && visual[i].bidi_level) |
df3d4cba VS |
686 | visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR; |
687 | if ((visual[i].attributes & GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN) | |
85002bf3 | 688 | && visual[i].bidi_level) |
df3d4cba VS |
689 | { |
690 | int left, right; | |
691 | left = visual[i].attributes | |
692 | & (GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED | |
693 | | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT); | |
694 | right = visual[i].attributes | |
695 | & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED | |
696 | | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT); | |
697 | visual[i].attributes &= ~GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN; | |
698 | left <<= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT; | |
699 | right >>= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT; | |
700 | visual[i].attributes |= (left | right); | |
701 | } | |
702 | } | |
703 | } | |
704 | ||
705 | { | |
706 | int left_join = 0; | |
707 | unsigned i; | |
dafff9ce | 708 | for (i = line_start; i < kk; i++) |
df3d4cba VS |
709 | { |
710 | enum grub_join_type join_type = get_join_type (visual[i].base); | |
711 | if (!(visual[i].attributes | |
712 | & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT) | |
713 | && (join_type == GRUB_JOIN_TYPE_LEFT | |
714 | || join_type == GRUB_JOIN_TYPE_DUAL)) | |
715 | { | |
716 | if (left_join) | |
717 | visual[i].attributes | |
718 | |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; | |
719 | else | |
720 | visual[i].attributes | |
721 | &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; | |
722 | } | |
723 | if (join_type == GRUB_JOIN_TYPE_NONJOINING | |
724 | || join_type == GRUB_JOIN_TYPE_LEFT) | |
725 | left_join = 0; | |
726 | if (join_type == GRUB_JOIN_TYPE_RIGHT | |
727 | || join_type == GRUB_JOIN_TYPE_DUAL | |
728 | || join_type == GRUB_JOIN_TYPE_CAUSING) | |
729 | left_join = 1; | |
730 | } | |
731 | } | |
732 | ||
733 | { | |
734 | int right_join = 0; | |
735 | signed i; | |
dafff9ce | 736 | for (i = kk - 1; i >= 0 && (unsigned) i + 1 > line_start; |
4e27343f | 737 | i--) |
df3d4cba VS |
738 | { |
739 | enum grub_join_type join_type = get_join_type (visual[i].base); | |
740 | if (!(visual[i].attributes | |
741 | & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT) | |
742 | && (join_type == GRUB_JOIN_TYPE_RIGHT | |
743 | || join_type == GRUB_JOIN_TYPE_DUAL)) | |
744 | { | |
745 | if (right_join) | |
746 | visual[i].attributes | |
747 | |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; | |
748 | else | |
749 | visual[i].attributes | |
750 | &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; | |
751 | } | |
752 | if (join_type == GRUB_JOIN_TYPE_NONJOINING | |
753 | || join_type == GRUB_JOIN_TYPE_RIGHT) | |
754 | right_join = 0; | |
755 | if (join_type == GRUB_JOIN_TYPE_LEFT | |
756 | || join_type == GRUB_JOIN_TYPE_DUAL | |
757 | || join_type == GRUB_JOIN_TYPE_CAUSING) | |
758 | right_join = 1; | |
759 | } | |
760 | } | |
eb679523 | 761 | |
3830c087 | 762 | grub_memcpy (outptr, &visual[line_start], |
dafff9ce VS |
763 | (kk - line_start) * sizeof (visual[0])); |
764 | outptr += kk - line_start; | |
765 | if (kk != visual_len) | |
eb679523 | 766 | { |
34f71cb8 VS |
767 | if (contchar) |
768 | { | |
769 | grub_memset (outptr, 0, sizeof (visual[0])); | |
770 | outptr->base = contchar; | |
771 | outptr++; | |
772 | } | |
eb679523 VS |
773 | grub_memset (outptr, 0, sizeof (visual[0])); |
774 | outptr->base = '\n'; | |
775 | outptr++; | |
776 | } | |
8b4ca088 | 777 | |
dafff9ce VS |
778 | if ((signed) kk == last_space) |
779 | kk++; | |
8b4ca088 | 780 | |
dafff9ce VS |
781 | line_start = kk; |
782 | if (pos && kk != visual_len) | |
34f71cb8 | 783 | { |
dafff9ce VS |
784 | pos[visual[kk].orig_pos].x = 0; |
785 | pos[visual[kk].orig_pos].y = lines; | |
34f71cb8 | 786 | } |
eb679523 VS |
787 | } |
788 | } | |
789 | ||
790 | return outptr - visual_out; | |
791 | } | |
792 | ||
793 | ||
0a239a82 VS |
794 | static grub_ssize_t |
795 | grub_bidi_line_logical_to_visual (const grub_uint32_t *logical, | |
796 | grub_size_t logical_len, | |
797 | struct grub_unicode_glyph *visual_out, | |
a2856736 | 798 | grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg), |
19e29ee1 | 799 | void *getcharwidth_arg, |
34f71cb8 VS |
800 | grub_size_t maxwidth, grub_size_t startwidth, |
801 | grub_uint32_t contchar, | |
802 | struct grub_term_pos *pos, | |
803 | int primitive_wrap, | |
804 | grub_size_t log_end) | |
0a239a82 VS |
805 | { |
806 | enum grub_bidi_type type = GRUB_BIDI_TYPE_L; | |
807 | enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L}; | |
0a239a82 VS |
808 | unsigned base_level; |
809 | enum override_status cur_override; | |
810 | unsigned i; | |
811 | unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3]; | |
812 | enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3]; | |
813 | unsigned stack_depth = 0; | |
814 | unsigned invalid_pushes = 0; | |
815 | unsigned visual_len = 0; | |
816 | unsigned run_start, run_end; | |
817 | struct grub_unicode_glyph *visual; | |
818 | unsigned cur_level; | |
a06cec31 | 819 | int bidi_needed = 0; |
0a239a82 | 820 | |
c03995d2 VS |
821 | #define push_stack(new_override, new_level) \ |
822 | { \ | |
823 | if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL) \ | |
824 | { \ | |
825 | invalid_pushes++; \ | |
826 | } \ | |
827 | else \ | |
828 | { \ | |
829 | stack_level[stack_depth] = cur_level; \ | |
830 | stack_override[stack_depth] = cur_override; \ | |
831 | stack_depth++; \ | |
832 | cur_level = new_level; \ | |
833 | cur_override = new_override; \ | |
834 | } \ | |
0a239a82 VS |
835 | } |
836 | ||
c03995d2 VS |
837 | #define pop_stack() \ |
838 | { \ | |
839 | if (invalid_pushes) \ | |
840 | { \ | |
841 | invalid_pushes--; \ | |
842 | } \ | |
843 | else if (stack_depth) \ | |
844 | { \ | |
845 | stack_depth--; \ | |
846 | cur_level = stack_level[stack_depth]; \ | |
847 | cur_override = stack_override[stack_depth]; \ | |
848 | } \ | |
0a239a82 VS |
849 | } |
850 | ||
f725fa7c | 851 | visual = grub_calloc (logical_len, sizeof (visual[0])); |
0a239a82 | 852 | if (!visual) |
85002bf3 | 853 | return -1; |
0a239a82 VS |
854 | |
855 | for (i = 0; i < logical_len; i++) | |
856 | { | |
857 | type = get_bidi_type (logical[i]); | |
858 | if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL | |
859 | || type == GRUB_BIDI_TYPE_R) | |
860 | break; | |
861 | } | |
862 | if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL) | |
863 | base_level = 1; | |
864 | else | |
865 | base_level = 0; | |
866 | ||
867 | cur_level = base_level; | |
868 | cur_override = OVERRIDE_NEUTRAL; | |
869 | { | |
870 | const grub_uint32_t *lptr; | |
df3d4cba VS |
871 | enum {JOIN_DEFAULT, NOJOIN, JOIN_FORCE} join_state = JOIN_DEFAULT; |
872 | int zwj_propagate_to_previous = 0; | |
0a239a82 VS |
873 | for (lptr = logical; lptr < logical + logical_len;) |
874 | { | |
df3d4cba VS |
875 | grub_size_t p; |
876 | ||
877 | if (*lptr == GRUB_UNICODE_ZWJ) | |
878 | { | |
879 | if (zwj_propagate_to_previous) | |
880 | { | |
881 | visual[visual_len - 1].attributes | |
882 | |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT | |
883 | | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; | |
884 | } | |
885 | zwj_propagate_to_previous = 0; | |
886 | join_state = JOIN_FORCE; | |
887 | lptr++; | |
888 | continue; | |
889 | } | |
890 | ||
891 | if (*lptr == GRUB_UNICODE_ZWNJ) | |
892 | { | |
893 | if (zwj_propagate_to_previous) | |
894 | { | |
895 | visual[visual_len - 1].attributes | |
896 | |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT; | |
897 | visual[visual_len - 1].attributes | |
898 | &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; | |
899 | } | |
900 | zwj_propagate_to_previous = 0; | |
901 | join_state = NOJOIN; | |
902 | lptr++; | |
903 | continue; | |
904 | } | |
905 | ||
f3cb4a4e VS |
906 | /* The tags: deprecated, never used. */ |
907 | if (*lptr >= GRUB_UNICODE_TAG_START && *lptr <= GRUB_UNICODE_TAG_END) | |
908 | continue; | |
909 | ||
df3d4cba VS |
910 | p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr, |
911 | &visual[visual_len]); | |
34f71cb8 | 912 | visual[visual_len].orig_pos = lptr - logical; |
0a239a82 VS |
913 | type = get_bidi_type (visual[visual_len].base); |
914 | switch (type) | |
915 | { | |
916 | case GRUB_BIDI_TYPE_RLE: | |
a06cec31 | 917 | bidi_needed = 1; |
0a239a82 VS |
918 | push_stack (cur_override, (cur_level | 1) + 1); |
919 | break; | |
920 | case GRUB_BIDI_TYPE_RLO: | |
a06cec31 | 921 | bidi_needed = 1; |
0a239a82 VS |
922 | push_stack (OVERRIDE_R, (cur_level | 1) + 1); |
923 | break; | |
924 | case GRUB_BIDI_TYPE_LRE: | |
925 | push_stack (cur_override, (cur_level & ~1) + 2); | |
926 | break; | |
927 | case GRUB_BIDI_TYPE_LRO: | |
928 | push_stack (OVERRIDE_L, (cur_level & ~1) + 2); | |
929 | break; | |
930 | case GRUB_BIDI_TYPE_PDF: | |
931 | pop_stack (); | |
932 | break; | |
933 | case GRUB_BIDI_TYPE_BN: | |
934 | break; | |
a06cec31 VS |
935 | case GRUB_BIDI_TYPE_R: |
936 | case GRUB_BIDI_TYPE_AL: | |
937 | bidi_needed = 1; | |
9ee5ae1f | 938 | /* Fallthrough. */ |
0a239a82 VS |
939 | default: |
940 | { | |
df3d4cba VS |
941 | if (join_state == JOIN_FORCE) |
942 | { | |
943 | visual[visual_len].attributes | |
944 | |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT | |
945 | | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; | |
946 | } | |
947 | ||
948 | if (join_state == NOJOIN) | |
949 | { | |
950 | visual[visual_len].attributes | |
951 | |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT; | |
952 | visual[visual_len].attributes | |
953 | &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; | |
954 | } | |
955 | ||
956 | join_state = JOIN_DEFAULT; | |
957 | zwj_propagate_to_previous = 1; | |
958 | ||
85002bf3 | 959 | visual[visual_len].bidi_level = cur_level; |
0a239a82 | 960 | if (cur_override != OVERRIDE_NEUTRAL) |
85002bf3 | 961 | visual[visual_len].bidi_type = |
0a239a82 VS |
962 | (cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L |
963 | : GRUB_BIDI_TYPE_R; | |
964 | else | |
85002bf3 | 965 | visual[visual_len].bidi_type = type; |
0a239a82 VS |
966 | visual_len++; |
967 | } | |
968 | } | |
969 | lptr += p; | |
970 | } | |
971 | } | |
972 | ||
a06cec31 | 973 | if (bidi_needed) |
0a239a82 | 974 | { |
a06cec31 | 975 | for (run_start = 0; run_start < visual_len; run_start = run_end) |
0a239a82 | 976 | { |
a06cec31 VS |
977 | unsigned prev_level, next_level, cur_run_level; |
978 | unsigned last_type, last_strong_type; | |
979 | for (run_end = run_start; run_end < visual_len && | |
85002bf3 | 980 | visual[run_end].bidi_level == visual[run_start].bidi_level; run_end++); |
a06cec31 VS |
981 | if (run_start == 0) |
982 | prev_level = base_level; | |
983 | else | |
85002bf3 | 984 | prev_level = visual[run_start - 1].bidi_level; |
a06cec31 VS |
985 | if (run_end == visual_len) |
986 | next_level = base_level; | |
987 | else | |
85002bf3 VS |
988 | next_level = visual[run_end].bidi_level; |
989 | cur_run_level = visual[run_start].bidi_level; | |
a06cec31 VS |
990 | if (prev_level & 1) |
991 | last_type = GRUB_BIDI_TYPE_R; | |
992 | else | |
993 | last_type = GRUB_BIDI_TYPE_L; | |
994 | last_strong_type = last_type; | |
995 | for (i = run_start; i < run_end; i++) | |
0a239a82 | 996 | { |
85002bf3 | 997 | switch (visual[i].bidi_type) |
a06cec31 VS |
998 | { |
999 | case GRUB_BIDI_TYPE_NSM: | |
85002bf3 | 1000 | visual[i].bidi_type = last_type; |
a06cec31 VS |
1001 | break; |
1002 | case GRUB_BIDI_TYPE_EN: | |
1003 | if (last_strong_type == GRUB_BIDI_TYPE_AL) | |
85002bf3 | 1004 | visual[i].bidi_type = GRUB_BIDI_TYPE_AN; |
a06cec31 VS |
1005 | break; |
1006 | case GRUB_BIDI_TYPE_L: | |
1007 | case GRUB_BIDI_TYPE_R: | |
85002bf3 | 1008 | last_strong_type = visual[i].bidi_type; |
a06cec31 VS |
1009 | break; |
1010 | case GRUB_BIDI_TYPE_ES: | |
1011 | if (last_type == GRUB_BIDI_TYPE_EN | |
1012 | && i + 1 < run_end | |
85002bf3 VS |
1013 | && visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN) |
1014 | visual[i].bidi_type = GRUB_BIDI_TYPE_EN; | |
a06cec31 | 1015 | else |
85002bf3 | 1016 | visual[i].bidi_type = GRUB_BIDI_TYPE_ON; |
a06cec31 VS |
1017 | break; |
1018 | case GRUB_BIDI_TYPE_ET: | |
0a239a82 | 1019 | { |
a06cec31 VS |
1020 | unsigned j; |
1021 | if (last_type == GRUB_BIDI_TYPE_EN) | |
1022 | { | |
85002bf3 | 1023 | visual[i].bidi_type = GRUB_BIDI_TYPE_EN; |
a06cec31 VS |
1024 | break; |
1025 | } | |
1026 | for (j = i; j < run_end | |
85002bf3 VS |
1027 | && visual[j].bidi_type == GRUB_BIDI_TYPE_ET; j++); |
1028 | if (j != run_end && visual[j].bidi_type == GRUB_BIDI_TYPE_EN) | |
a06cec31 VS |
1029 | { |
1030 | for (; i < run_end | |
85002bf3 VS |
1031 | && visual[i].bidi_type == GRUB_BIDI_TYPE_ET; i++) |
1032 | visual[i].bidi_type = GRUB_BIDI_TYPE_EN; | |
a06cec31 VS |
1033 | i--; |
1034 | break; | |
1035 | } | |
0a239a82 | 1036 | for (; i < run_end |
85002bf3 VS |
1037 | && visual[i].bidi_type == GRUB_BIDI_TYPE_ET; i++) |
1038 | visual[i].bidi_type = GRUB_BIDI_TYPE_ON; | |
0a239a82 | 1039 | i--; |
a06cec31 | 1040 | break; |
0a239a82 | 1041 | } |
a06cec31 VS |
1042 | break; |
1043 | case GRUB_BIDI_TYPE_CS: | |
1044 | if (last_type == GRUB_BIDI_TYPE_EN | |
1045 | && i + 1 < run_end | |
85002bf3 | 1046 | && visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN) |
a06cec31 | 1047 | { |
85002bf3 | 1048 | visual[i].bidi_type = GRUB_BIDI_TYPE_EN; |
a06cec31 VS |
1049 | break; |
1050 | } | |
1051 | if (last_type == GRUB_BIDI_TYPE_AN | |
1052 | && i + 1 < run_end | |
85002bf3 VS |
1053 | && (visual[i + 1].bidi_type == GRUB_BIDI_TYPE_AN |
1054 | || (visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN | |
a06cec31 VS |
1055 | && last_strong_type == GRUB_BIDI_TYPE_AL))) |
1056 | { | |
85002bf3 | 1057 | visual[i].bidi_type = GRUB_BIDI_TYPE_EN; |
a06cec31 VS |
1058 | break; |
1059 | } | |
85002bf3 | 1060 | visual[i].bidi_type = GRUB_BIDI_TYPE_ON; |
a06cec31 VS |
1061 | break; |
1062 | case GRUB_BIDI_TYPE_AL: | |
85002bf3 VS |
1063 | last_strong_type = visual[i].bidi_type; |
1064 | visual[i].bidi_type = GRUB_BIDI_TYPE_R; | |
a06cec31 VS |
1065 | break; |
1066 | default: /* Make GCC happy. */ | |
0a239a82 VS |
1067 | break; |
1068 | } | |
85002bf3 VS |
1069 | last_type = visual[i].bidi_type; |
1070 | if (visual[i].bidi_type == GRUB_BIDI_TYPE_EN | |
a06cec31 | 1071 | && last_strong_type == GRUB_BIDI_TYPE_L) |
85002bf3 | 1072 | visual[i].bidi_type = GRUB_BIDI_TYPE_L; |
a06cec31 VS |
1073 | } |
1074 | if (prev_level & 1) | |
1075 | last_type = GRUB_BIDI_TYPE_R; | |
1076 | else | |
1077 | last_type = GRUB_BIDI_TYPE_L; | |
1078 | for (i = run_start; i < run_end; ) | |
1079 | { | |
1080 | unsigned j; | |
1081 | unsigned next_type; | |
1082 | for (j = i; j < run_end && | |
85002bf3 VS |
1083 | (visual[j].bidi_type == GRUB_BIDI_TYPE_B |
1084 | || visual[j].bidi_type == GRUB_BIDI_TYPE_S | |
1085 | || visual[j].bidi_type == GRUB_BIDI_TYPE_WS | |
1086 | || visual[j].bidi_type == GRUB_BIDI_TYPE_ON); j++); | |
a06cec31 | 1087 | if (j == i) |
0a239a82 | 1088 | { |
85002bf3 | 1089 | if (visual[i].bidi_type == GRUB_BIDI_TYPE_L) |
a06cec31 VS |
1090 | last_type = GRUB_BIDI_TYPE_L; |
1091 | else | |
1092 | last_type = GRUB_BIDI_TYPE_R; | |
1093 | i++; | |
1094 | continue; | |
0a239a82 | 1095 | } |
a06cec31 VS |
1096 | if (j == run_end) |
1097 | next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L; | |
1098 | else | |
1099 | { | |
85002bf3 | 1100 | if (visual[j].bidi_type == GRUB_BIDI_TYPE_L) |
a06cec31 VS |
1101 | next_type = GRUB_BIDI_TYPE_L; |
1102 | else | |
1103 | next_type = GRUB_BIDI_TYPE_R; | |
1104 | } | |
1105 | if (next_type == last_type) | |
1106 | for (; i < j; i++) | |
85002bf3 | 1107 | visual[i].bidi_type = last_type; |
a06cec31 VS |
1108 | else |
1109 | for (; i < j; i++) | |
85002bf3 | 1110 | visual[i].bidi_type = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R |
a06cec31 | 1111 | : GRUB_BIDI_TYPE_L; |
0a239a82 | 1112 | } |
0a239a82 | 1113 | } |
a06cec31 VS |
1114 | |
1115 | for (i = 0; i < visual_len; i++) | |
0a239a82 | 1116 | { |
85002bf3 | 1117 | if (!(visual[i].bidi_level & 1) && visual[i].bidi_type == GRUB_BIDI_TYPE_R) |
0a239a82 | 1118 | { |
85002bf3 | 1119 | visual[i].bidi_level++; |
0a239a82 VS |
1120 | continue; |
1121 | } | |
85002bf3 VS |
1122 | if (!(visual[i].bidi_level & 1) && (visual[i].bidi_type == GRUB_BIDI_TYPE_AN |
1123 | || visual[i].bidi_type == GRUB_BIDI_TYPE_EN)) | |
0a239a82 | 1124 | { |
85002bf3 | 1125 | visual[i].bidi_level += 2; |
a06cec31 VS |
1126 | continue; |
1127 | } | |
85002bf3 VS |
1128 | if ((visual[i].bidi_level & 1) && (visual[i].bidi_type == GRUB_BIDI_TYPE_L |
1129 | || visual[i].bidi_type == GRUB_BIDI_TYPE_AN | |
1130 | || visual[i].bidi_type == GRUB_BIDI_TYPE_EN)) | |
a06cec31 | 1131 | { |
85002bf3 | 1132 | visual[i].bidi_level++; |
a06cec31 | 1133 | continue; |
0a239a82 | 1134 | } |
0a239a82 VS |
1135 | } |
1136 | } | |
a06cec31 | 1137 | else |
0a239a82 | 1138 | { |
a06cec31 | 1139 | for (i = 0; i < visual_len; i++) |
85002bf3 | 1140 | visual[i].bidi_level = 0; |
0a239a82 | 1141 | } |
0a239a82 | 1142 | |
0a239a82 | 1143 | { |
eb679523 | 1144 | grub_ssize_t ret; |
85002bf3 | 1145 | ret = bidi_line_wrap (visual_out, visual, visual_len, |
19e29ee1 | 1146 | getcharwidth, getcharwidth_arg, maxwidth, startwidth, contchar, |
34f71cb8 | 1147 | pos, primitive_wrap, log_end); |
0a239a82 | 1148 | grub_free (visual); |
eb679523 | 1149 | return ret; |
0a239a82 VS |
1150 | } |
1151 | } | |
1152 | ||
0fd9fa56 VS |
1153 | static int |
1154 | is_visible (const struct grub_unicode_glyph *gl) | |
1155 | { | |
1156 | if (gl->ncomb) | |
1157 | return 1; | |
1158 | if (gl->base == GRUB_UNICODE_LRM || gl->base == GRUB_UNICODE_RLM) | |
1159 | return 0; | |
1160 | return 1; | |
1161 | } | |
1162 | ||
0a239a82 VS |
1163 | grub_ssize_t |
1164 | grub_bidi_logical_to_visual (const grub_uint32_t *logical, | |
1165 | grub_size_t logical_len, | |
1166 | struct grub_unicode_glyph **visual_out, | |
a2856736 | 1167 | grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg), |
19e29ee1 | 1168 | void *getcharwidth_arg, |
34f71cb8 VS |
1169 | grub_size_t max_length, grub_size_t startwidth, |
1170 | grub_uint32_t contchar, struct grub_term_pos *pos, int primitive_wrap) | |
0a239a82 VS |
1171 | { |
1172 | const grub_uint32_t *line_start = logical, *ptr; | |
1173 | struct grub_unicode_glyph *visual_ptr; | |
f725fa7c PJ |
1174 | *visual_out = visual_ptr = grub_calloc (logical_len + 2, |
1175 | 3 * sizeof (visual_ptr[0])); | |
5303b85d VS |
1176 | if (!visual_ptr) |
1177 | return -1; | |
0a239a82 VS |
1178 | for (ptr = logical; ptr <= logical + logical_len; ptr++) |
1179 | { | |
1180 | if (ptr == logical + logical_len || *ptr == '\n') | |
1181 | { | |
1182 | grub_ssize_t ret; | |
0fd9fa56 | 1183 | grub_ssize_t i, j; |
0a239a82 VS |
1184 | ret = grub_bidi_line_logical_to_visual (line_start, |
1185 | ptr - line_start, | |
1186 | visual_ptr, | |
1187 | getcharwidth, | |
19e29ee1 | 1188 | getcharwidth_arg, |
97b3fbb8 | 1189 | max_length, |
34f71cb8 VS |
1190 | startwidth, |
1191 | contchar, | |
1192 | pos, | |
1193 | primitive_wrap, | |
1194 | logical_len); | |
97b3fbb8 VS |
1195 | startwidth = 0; |
1196 | ||
0a239a82 VS |
1197 | if (ret < 0) |
1198 | { | |
1199 | grub_free (*visual_out); | |
1200 | return ret; | |
1201 | } | |
0fd9fa56 VS |
1202 | for (i = 0, j = 0; i < ret; i++) |
1203 | if (is_visible(&visual_ptr[i])) | |
1204 | visual_ptr[j++] = visual_ptr[i]; | |
1205 | visual_ptr += j; | |
0a239a82 VS |
1206 | line_start = ptr; |
1207 | if (ptr != logical + logical_len) | |
1208 | { | |
1209 | grub_memset (visual_ptr, 0, sizeof (visual_ptr[0])); | |
1210 | visual_ptr->base = '\n'; | |
1211 | visual_ptr++; | |
3830c087 | 1212 | line_start++; |
0a239a82 VS |
1213 | } |
1214 | } | |
1215 | } | |
1216 | return visual_ptr - *visual_out; | |
1217 | } | |
1218 | ||
09f9aa3b VS |
1219 | grub_uint32_t |
1220 | grub_unicode_mirror_code (grub_uint32_t in) | |
6f5568ed VS |
1221 | { |
1222 | int i; | |
1223 | for (i = 0; grub_unicode_bidi_pairs[i].key; i++) | |
1224 | if (grub_unicode_bidi_pairs[i].key == in) | |
1225 | return grub_unicode_bidi_pairs[i].replace; | |
1226 | return in; | |
1227 | } | |
a82890ff VS |
1228 | |
1229 | grub_uint32_t | |
1230 | grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr) | |
1231 | { | |
1232 | int i; | |
1233 | if (!(in >= GRUB_UNICODE_ARABIC_START | |
1234 | && in < GRUB_UNICODE_ARABIC_END)) | |
1235 | return in; | |
1236 | ||
1237 | for (i = 0; grub_unicode_arabic_shapes[i].code; i++) | |
1238 | if (grub_unicode_arabic_shapes[i].code == in) | |
1239 | { | |
1d383404 | 1240 | grub_uint32_t out = 0; |
a82890ff VS |
1241 | switch (attr & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED |
1242 | | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED)) | |
1243 | { | |
1244 | case 0: | |
1245 | out = grub_unicode_arabic_shapes[i].isolated; | |
1246 | break; | |
1247 | case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED: | |
1248 | out = grub_unicode_arabic_shapes[i].right_linked; | |
1249 | break; | |
1250 | case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED: | |
1251 | out = grub_unicode_arabic_shapes[i].left_linked; | |
1252 | break; | |
1253 | case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED | |
1254 | |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED: | |
1255 | out = grub_unicode_arabic_shapes[i].both_linked; | |
1256 | break; | |
1257 | } | |
1258 | if (out) | |
1259 | return out; | |
1260 | } | |
1261 | ||
1262 | return in; | |
1263 | } | |
e1bd676b VS |
1264 | |
1265 | const grub_uint32_t * | |
1266 | grub_unicode_get_comb_start (const grub_uint32_t *str, | |
1267 | const grub_uint32_t *cur) | |
1268 | { | |
1269 | const grub_uint32_t *ptr; | |
1270 | for (ptr = cur; ptr >= str; ptr--) | |
1271 | { | |
1272 | if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1 | |
1273 | && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16) | |
1274 | continue; | |
1275 | ||
1276 | if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17 | |
1277 | && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256) | |
1278 | continue; | |
1279 | ||
1280 | enum grub_comb_type comb_type; | |
1281 | comb_type = grub_unicode_get_comb_type (*ptr); | |
1282 | if (comb_type) | |
1283 | continue; | |
1284 | return ptr; | |
1285 | } | |
1286 | return str; | |
1287 | } | |
1288 | ||
34f71cb8 VS |
1289 | const grub_uint32_t * |
1290 | grub_unicode_get_comb_end (const grub_uint32_t *end, | |
1291 | const grub_uint32_t *cur) | |
1292 | { | |
1293 | const grub_uint32_t *ptr; | |
1294 | for (ptr = cur; ptr < end; ptr++) | |
1295 | { | |
1296 | if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1 | |
1297 | && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16) | |
1298 | continue; | |
1299 | ||
1300 | if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17 | |
1301 | && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256) | |
1302 | continue; | |
1303 | ||
1304 | enum grub_comb_type comb_type; | |
1305 | comb_type = grub_unicode_get_comb_type (*ptr); | |
1306 | if (comb_type) | |
1307 | continue; | |
1308 | return ptr; | |
1309 | } | |
1310 | return end; | |
1311 | } | |
1312 |