~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to normal/charset.c

Tags: upstream-1.98+20100705
ImportĀ upstreamĀ versionĀ 1.98+20100705

Show diffs side-by-side

added added

removed removed

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