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

« back to all changes in this revision

Viewing changes to grub-core/normal/charset.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

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