bidi works in terminal in grub-emu
This commit is contained in:
parent
dfed5c6bb4
commit
0a239a8211
23 changed files with 1101 additions and 799 deletions
783
lib/charset.c
783
lib/charset.c
|
@ -26,6 +26,9 @@
|
|||
#include <grub/charset.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/unicode.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
grub_ssize_t
|
||||
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
|
||||
|
@ -361,3 +364,783 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
|
|||
*srcend = src;
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
static grub_uint8_t *bidi_types = NULL;
|
||||
|
||||
static void
|
||||
unpack_bidi (void)
|
||||
{
|
||||
unsigned i;
|
||||
struct grub_unicode_compact_range *cur;
|
||||
|
||||
bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
|
||||
if (!bidi_types)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
for (cur = grub_unicode_compact; cur->end; cur++)
|
||||
for (i = cur->start; i <= cur->end
|
||||
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
|
||||
if (cur->bidi_mirror)
|
||||
bidi_types[i] = cur->bidi_type | 0x80;
|
||||
else
|
||||
bidi_types[i] = cur->bidi_type | 0x00;
|
||||
}
|
||||
|
||||
static inline enum grub_bidi_type
|
||||
get_bidi_type (grub_uint32_t c)
|
||||
{
|
||||
struct grub_unicode_compact_range *cur;
|
||||
|
||||
if (!bidi_types)
|
||||
unpack_bidi ();
|
||||
|
||||
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
|
||||
return bidi_types[c] & 0x7f;
|
||||
|
||||
for (cur = grub_unicode_compact; cur->end; cur++)
|
||||
if (cur->start <= c && c <= cur->end)
|
||||
return cur->bidi_type;
|
||||
|
||||
return GRUB_BIDI_TYPE_L;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_mirrored (grub_uint32_t c)
|
||||
{
|
||||
struct grub_unicode_compact_range *cur;
|
||||
|
||||
if (!bidi_types)
|
||||
unpack_bidi ();
|
||||
|
||||
if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
|
||||
return !!(bidi_types[c] & 0x80);
|
||||
|
||||
for (cur = grub_unicode_compact; cur->end; cur++)
|
||||
if (cur->start <= c && c <= cur->end)
|
||||
return cur->bidi_mirror;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum grub_comb_type
|
||||
grub_unicode_get_comb_type (grub_uint32_t c)
|
||||
{
|
||||
static grub_uint8_t *comb_types = NULL;
|
||||
struct grub_unicode_compact_range *cur;
|
||||
|
||||
if (!comb_types)
|
||||
{
|
||||
unsigned i;
|
||||
comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR);
|
||||
if (comb_types)
|
||||
for (cur = grub_unicode_compact; cur->end; cur++)
|
||||
for (i = cur->start; i <= cur->end
|
||||
&& i < GRUB_UNICODE_MAX_CACHED_CHAR; i++)
|
||||
comb_types[i] = cur->comb_type;
|
||||
else
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR)
|
||||
return comb_types[c];
|
||||
|
||||
for (cur = grub_unicode_compact; cur->end; cur++)
|
||||
if (cur->start <= c && c <= cur->end)
|
||||
return cur->comb_type;
|
||||
|
||||
return GRUB_UNICODE_COMB_NONE;
|
||||
}
|
||||
|
||||
grub_size_t
|
||||
grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
|
||||
struct grub_unicode_glyph *out)
|
||||
{
|
||||
int haveout = 0;
|
||||
const grub_uint32_t *ptr;
|
||||
unsigned last_comb_pointer = 0;
|
||||
|
||||
grub_memset (out, 0, sizeof (*out));
|
||||
|
||||
for (ptr = in; ptr < in + inlen; ptr++)
|
||||
{
|
||||
/* Variation selectors >= 17 are outside of BMP and SMP.
|
||||
Handle variation selectors first to avoid potentially costly lookups.
|
||||
*/
|
||||
if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
|
||||
&& *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
|
||||
{
|
||||
if (haveout)
|
||||
out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
|
||||
continue;
|
||||
|
||||
}
|
||||
if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
|
||||
&& *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
|
||||
{
|
||||
if (haveout)
|
||||
out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17;
|
||||
continue;
|
||||
}
|
||||
|
||||
enum grub_comb_type comb_type;
|
||||
comb_type = grub_unicode_get_comb_type (*ptr);
|
||||
if (comb_type)
|
||||
{
|
||||
grub_uint32_t *n;
|
||||
unsigned j;
|
||||
|
||||
if (!haveout)
|
||||
continue;
|
||||
|
||||
if (comb_type == GRUB_UNICODE_COMB_MC
|
||||
|| comb_type == GRUB_UNICODE_COMB_ME
|
||||
|| comb_type == GRUB_UNICODE_COMB_MN)
|
||||
last_comb_pointer = out->ncomb;
|
||||
n = grub_realloc (out->combining,
|
||||
sizeof (grub_uint32_t) * (out->ncomb + 1));
|
||||
if (!n)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = last_comb_pointer; j < out->ncomb; j++)
|
||||
if (grub_unicode_get_comb_type (out->combining[j]) > comb_type)
|
||||
break;
|
||||
grub_memmove (out->combining + j + 1,
|
||||
out->combining + j,
|
||||
(out->ncomb - j)
|
||||
* sizeof (out->combining[0]));
|
||||
out->combining = n;
|
||||
out->combining[j] = *ptr;
|
||||
out->ncomb++;
|
||||
continue;
|
||||
}
|
||||
if (haveout)
|
||||
return ptr - in;
|
||||
haveout = 1;
|
||||
out->base = *ptr;
|
||||
out->variant = 0;
|
||||
out->attributes = 0;
|
||||
out->ncomb = 0;
|
||||
out->combining = NULL;
|
||||
}
|
||||
return ptr - in;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_bidi_line_logical_to_visual (const grub_uint32_t *logical,
|
||||
grub_size_t logical_len,
|
||||
struct grub_unicode_glyph *visual_out,
|
||||
grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
|
||||
grub_size_t maxwidth)
|
||||
{
|
||||
enum grub_bidi_type type = GRUB_BIDI_TYPE_L;
|
||||
enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L};
|
||||
unsigned *levels;
|
||||
enum grub_bidi_type *resolved_types;
|
||||
unsigned base_level;
|
||||
enum override_status cur_override;
|
||||
unsigned i;
|
||||
unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
|
||||
enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3];
|
||||
unsigned stack_depth = 0;
|
||||
unsigned invalid_pushes = 0;
|
||||
unsigned visual_len = 0;
|
||||
unsigned run_start, run_end;
|
||||
struct grub_unicode_glyph *visual;
|
||||
unsigned cur_level;
|
||||
|
||||
auto void push_stack (unsigned new_override, unsigned new_level);
|
||||
void push_stack (unsigned new_override, unsigned new_level)
|
||||
{
|
||||
if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL)
|
||||
{
|
||||
invalid_pushes++;
|
||||
return;
|
||||
}
|
||||
stack_level[stack_depth] = cur_level;
|
||||
stack_override[stack_depth] = cur_override;
|
||||
stack_depth++;
|
||||
cur_level = new_level;
|
||||
cur_override = new_override;
|
||||
}
|
||||
|
||||
auto void pop_stack (void);
|
||||
void pop_stack (void)
|
||||
{
|
||||
if (invalid_pushes)
|
||||
{
|
||||
invalid_pushes--;
|
||||
return;
|
||||
}
|
||||
if (!stack_depth)
|
||||
return;
|
||||
stack_depth--;
|
||||
cur_level = stack_level[stack_depth];
|
||||
cur_override = stack_override[stack_depth];
|
||||
}
|
||||
|
||||
auto void revert (unsigned start, unsigned end);
|
||||
void revert (unsigned start, unsigned end)
|
||||
{
|
||||
struct grub_unicode_glyph t;
|
||||
unsigned k, tl;
|
||||
for (k = 0; k <= (end - start) / 2; k++)
|
||||
{
|
||||
t = visual[start+k];
|
||||
visual[start+k] = visual[end-k];
|
||||
visual[end-k] = t;
|
||||
tl = levels[start+k];
|
||||
levels[start+k] = levels[end-k];
|
||||
levels[end-k] = tl;
|
||||
}
|
||||
}
|
||||
|
||||
levels = grub_malloc (sizeof (levels[0]) * logical_len);
|
||||
if (!levels)
|
||||
return -1;
|
||||
|
||||
resolved_types = grub_malloc (sizeof (resolved_types[0]) * logical_len);
|
||||
if (!resolved_types)
|
||||
{
|
||||
grub_free (levels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
visual = grub_malloc (sizeof (visual[0]) * logical_len);
|
||||
if (!visual)
|
||||
{
|
||||
grub_free (resolved_types);
|
||||
grub_free (levels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < logical_len; i++)
|
||||
{
|
||||
type = get_bidi_type (logical[i]);
|
||||
if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL
|
||||
|| type == GRUB_BIDI_TYPE_R)
|
||||
break;
|
||||
}
|
||||
if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL)
|
||||
base_level = 1;
|
||||
else
|
||||
base_level = 0;
|
||||
|
||||
cur_level = base_level;
|
||||
cur_override = OVERRIDE_NEUTRAL;
|
||||
{
|
||||
const grub_uint32_t *lptr;
|
||||
for (lptr = logical; lptr < logical + logical_len;)
|
||||
{
|
||||
grub_size_t p = grub_unicode_aglomerate_comb (lptr, logical
|
||||
+ logical_len - lptr,
|
||||
&visual[visual_len]);
|
||||
|
||||
type = get_bidi_type (visual[visual_len].base);
|
||||
switch (type)
|
||||
{
|
||||
case GRUB_BIDI_TYPE_RLE:
|
||||
push_stack (cur_override, (cur_level | 1) + 1);
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_RLO:
|
||||
push_stack (OVERRIDE_R, (cur_level | 1) + 1);
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_LRE:
|
||||
push_stack (cur_override, (cur_level & ~1) + 2);
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_LRO:
|
||||
push_stack (OVERRIDE_L, (cur_level & ~1) + 2);
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_PDF:
|
||||
pop_stack ();
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_BN:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
levels[visual_len] = cur_level;
|
||||
if (cur_override != OVERRIDE_NEUTRAL)
|
||||
resolved_types[visual_len] =
|
||||
(cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L
|
||||
: GRUB_BIDI_TYPE_R;
|
||||
else
|
||||
resolved_types[visual_len] = type;
|
||||
visual_len++;
|
||||
}
|
||||
}
|
||||
lptr += p;
|
||||
}
|
||||
}
|
||||
|
||||
for (run_start = 0; run_start < visual_len; run_start = run_end)
|
||||
{
|
||||
unsigned prev_level, next_level, cur_run_level;
|
||||
unsigned last_type, last_strong_type;
|
||||
for (run_end = run_start; run_end < visual_len &&
|
||||
levels[run_end] == levels[run_start]; run_end++);
|
||||
if (run_start == 0)
|
||||
prev_level = base_level;
|
||||
else
|
||||
prev_level = levels[run_start - 1];
|
||||
if (run_end == visual_len)
|
||||
next_level = base_level;
|
||||
else
|
||||
next_level = levels[run_end];
|
||||
cur_run_level = levels[run_start];
|
||||
if (prev_level & 1)
|
||||
last_type = GRUB_BIDI_TYPE_R;
|
||||
else
|
||||
last_type = GRUB_BIDI_TYPE_L;
|
||||
last_strong_type = last_type;
|
||||
for (i = run_start; i < run_end; i++)
|
||||
{
|
||||
switch (resolved_types[i])
|
||||
{
|
||||
case GRUB_BIDI_TYPE_NSM:
|
||||
resolved_types[i] = last_type;
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_EN:
|
||||
if (last_strong_type == GRUB_BIDI_TYPE_AL)
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_AN;
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_L:
|
||||
case GRUB_BIDI_TYPE_R:
|
||||
last_strong_type = resolved_types[i];
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_ES:
|
||||
if (last_type == GRUB_BIDI_TYPE_EN
|
||||
&& i + 1 < run_end
|
||||
&& resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_EN;
|
||||
else
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_ON;
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_ET:
|
||||
{
|
||||
unsigned j;
|
||||
if (last_type == GRUB_BIDI_TYPE_EN)
|
||||
{
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_EN;
|
||||
break;
|
||||
}
|
||||
for (j = i; j < run_end
|
||||
&& resolved_types[j] == GRUB_BIDI_TYPE_ET; j++);
|
||||
if (j != run_end && resolved_types[j] == GRUB_BIDI_TYPE_EN)
|
||||
{
|
||||
for (; i < run_end
|
||||
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_EN;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
for (; i < run_end
|
||||
&& resolved_types[i] == GRUB_BIDI_TYPE_ET; i++)
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_ON;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_CS:
|
||||
if (last_type == GRUB_BIDI_TYPE_EN
|
||||
&& i + 1 < run_end
|
||||
&& resolved_types[i + 1] == GRUB_BIDI_TYPE_EN)
|
||||
{
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_EN;
|
||||
break;
|
||||
}
|
||||
if (last_type == GRUB_BIDI_TYPE_AN
|
||||
&& i + 1 < run_end
|
||||
&& (resolved_types[i + 1] == GRUB_BIDI_TYPE_AN
|
||||
|| (resolved_types[i + 1] == GRUB_BIDI_TYPE_EN
|
||||
&& last_strong_type == GRUB_BIDI_TYPE_AL)))
|
||||
{
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_EN;
|
||||
break;
|
||||
}
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_ON;
|
||||
break;
|
||||
case GRUB_BIDI_TYPE_AL:
|
||||
last_strong_type = resolved_types[i];
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_R;
|
||||
break;
|
||||
default: /* Make GCC happy. */
|
||||
break;
|
||||
}
|
||||
last_type = resolved_types[i];
|
||||
if (resolved_types[i] == GRUB_BIDI_TYPE_EN
|
||||
&& last_strong_type == GRUB_BIDI_TYPE_L)
|
||||
resolved_types[i] = GRUB_BIDI_TYPE_L;
|
||||
}
|
||||
if (prev_level & 1)
|
||||
last_type = GRUB_BIDI_TYPE_R;
|
||||
else
|
||||
last_type = GRUB_BIDI_TYPE_L;
|
||||
for (i = run_start; i < run_end; )
|
||||
{
|
||||
unsigned j;
|
||||
unsigned next_type;
|
||||
for (j = i; j < run_end &&
|
||||
(resolved_types[j] == GRUB_BIDI_TYPE_B
|
||||
|| resolved_types[j] == GRUB_BIDI_TYPE_S
|
||||
|| resolved_types[j] == GRUB_BIDI_TYPE_WS
|
||||
|| resolved_types[j] == GRUB_BIDI_TYPE_ON); j++);
|
||||
if (j == i)
|
||||
{
|
||||
if (resolved_types[i] == GRUB_BIDI_TYPE_L)
|
||||
last_type = GRUB_BIDI_TYPE_L;
|
||||
else
|
||||
last_type = GRUB_BIDI_TYPE_R;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (j == run_end)
|
||||
next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L;
|
||||
else
|
||||
{
|
||||
if (resolved_types[j] == GRUB_BIDI_TYPE_L)
|
||||
next_type = GRUB_BIDI_TYPE_L;
|
||||
else
|
||||
next_type = GRUB_BIDI_TYPE_R;
|
||||
}
|
||||
if (next_type == last_type)
|
||||
for (; i < j; i++)
|
||||
resolved_types[i] = last_type;
|
||||
else
|
||||
for (; i < j; i++)
|
||||
resolved_types[i] = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R
|
||||
: GRUB_BIDI_TYPE_L;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < visual_len; i++)
|
||||
{
|
||||
if (!(levels[i] & 1) && resolved_types[i] == GRUB_BIDI_TYPE_R)
|
||||
{
|
||||
levels[i]++;
|
||||
continue;
|
||||
}
|
||||
if (!(levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_AN
|
||||
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
|
||||
{
|
||||
levels[i] += 2;
|
||||
continue;
|
||||
}
|
||||
if ((levels[i] & 1) && (resolved_types[i] == GRUB_BIDI_TYPE_L
|
||||
|| resolved_types[i] == GRUB_BIDI_TYPE_AN
|
||||
|| resolved_types[i] == GRUB_BIDI_TYPE_EN))
|
||||
{
|
||||
levels[i]++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
grub_free (resolved_types);
|
||||
|
||||
if (!visual_len)
|
||||
{
|
||||
grub_free (levels);
|
||||
grub_free (visual);
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
struct grub_unicode_glyph *outptr = visual_out;
|
||||
unsigned line_start = 0;
|
||||
grub_ssize_t line_width = 0;
|
||||
unsigned k;
|
||||
|
||||
for (k = 0; k <= visual_len; k++)
|
||||
{
|
||||
grub_ssize_t last_width = 0;
|
||||
if (getcharwidth && k != visual_len)
|
||||
line_width += last_width = getcharwidth (&visual[k]);
|
||||
if (((grub_ssize_t) maxwidth > 0
|
||||
&& line_width > (grub_ssize_t) maxwidth) || k == visual_len)
|
||||
{
|
||||
unsigned min_odd_level = 0xffffffff;
|
||||
unsigned max_level = 0;
|
||||
unsigned j;
|
||||
for (i = line_start; i < k; i++)
|
||||
{
|
||||
if (levels[i] > max_level)
|
||||
max_level = levels[i];
|
||||
if (levels[i] < min_odd_level && (levels[i] & 1))
|
||||
min_odd_level = levels[i];
|
||||
}
|
||||
/* FIXME: can be optimized. */
|
||||
for (j = max_level; j >= min_odd_level; j--)
|
||||
{
|
||||
unsigned in = 0;
|
||||
for (i = line_start; i < k; i++)
|
||||
{
|
||||
if (i != line_start && levels[i] >= j && levels[i-1] < j)
|
||||
in = i;
|
||||
if (levels[i] >= j && (i + 1 == k || levels[i+1] < j))
|
||||
revert (in, i);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = line_start; i < k; i++)
|
||||
if (is_mirrored (visual[i].base) && levels[i])
|
||||
visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR;
|
||||
|
||||
grub_memcpy (outptr, &visual[line_start],
|
||||
(k - line_start) * sizeof (visual[0]));
|
||||
outptr += k - line_start;
|
||||
if (k != visual_len)
|
||||
{
|
||||
grub_memset (outptr, 0, sizeof (visual[0]));
|
||||
outptr->base = '\n';
|
||||
outptr++;
|
||||
}
|
||||
|
||||
line_start = k;
|
||||
line_width = last_width;
|
||||
}
|
||||
}
|
||||
grub_free (levels);
|
||||
grub_free (visual);
|
||||
|
||||
return outptr - visual_out;
|
||||
}
|
||||
}
|
||||
|
||||
grub_ssize_t
|
||||
grub_bidi_logical_to_visual (const grub_uint32_t *logical,
|
||||
grub_size_t logical_len,
|
||||
struct grub_unicode_glyph **visual_out,
|
||||
grub_ssize_t (*getcharwidth) (const struct grub_unicode_glyph *visual),
|
||||
grub_size_t max_length)
|
||||
{
|
||||
const grub_uint32_t *line_start = logical, *ptr;
|
||||
struct grub_unicode_glyph *visual_ptr;
|
||||
*visual_out = visual_ptr = grub_malloc (2 * sizeof (visual_ptr[0])
|
||||
* logical_len);
|
||||
for (ptr = logical; ptr <= logical + logical_len; ptr++)
|
||||
{
|
||||
if (ptr == logical + logical_len || *ptr == '\n')
|
||||
{
|
||||
grub_ssize_t ret;
|
||||
ret = grub_bidi_line_logical_to_visual (line_start,
|
||||
ptr - line_start,
|
||||
visual_ptr,
|
||||
getcharwidth,
|
||||
max_length);
|
||||
if (ret < 0)
|
||||
{
|
||||
grub_free (*visual_out);
|
||||
return ret;
|
||||
}
|
||||
visual_ptr += ret;
|
||||
line_start = ptr;
|
||||
if (ptr != logical + logical_len)
|
||||
{
|
||||
grub_memset (visual_ptr, 0, sizeof (visual_ptr[0]));
|
||||
visual_ptr->base = '\n';
|
||||
visual_ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return visual_ptr - *visual_out;
|
||||
}
|
||||
|
||||
struct grub_unicode_glyph *
|
||||
grub_unicode_glyph_dup (const struct grub_unicode_glyph *in)
|
||||
{
|
||||
struct grub_unicode_glyph *out = grub_malloc (sizeof (*out));
|
||||
if (!out)
|
||||
return NULL;
|
||||
grub_memcpy (out, in, sizeof (*in));
|
||||
out->combining = grub_malloc (in->ncomb * sizeof (*in));
|
||||
if (!out->combining)
|
||||
{
|
||||
grub_free (out);
|
||||
return NULL;
|
||||
}
|
||||
grub_memcpy (out->combining, in->combining, in->ncomb * sizeof (*in));
|
||||
return out;
|
||||
}
|
||||
|
||||
struct grub_unicode_glyph *
|
||||
grub_unicode_glyph_from_code (grub_uint32_t code)
|
||||
{
|
||||
struct grub_unicode_glyph *ret;
|
||||
ret = grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
ret->base = code;
|
||||
ret->variant = 0;
|
||||
ret->attributes = 0;
|
||||
ret->ncomb = 0;
|
||||
ret->combining = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static grub_uint32_t
|
||||
map_code (grub_uint32_t in, struct grub_term_output *term)
|
||||
{
|
||||
if (in <= 0x7f)
|
||||
return in;
|
||||
|
||||
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK) == GRUB_TERM_CODE_TYPE_VGA)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case GRUB_TERM_DISP_LEFT:
|
||||
return 0x1b;
|
||||
case GRUB_TERM_DISP_UP:
|
||||
return 0x18;
|
||||
case GRUB_TERM_DISP_RIGHT:
|
||||
return 0x1a;
|
||||
case GRUB_TERM_DISP_DOWN:
|
||||
return 0x19;
|
||||
case GRUB_TERM_DISP_HLINE:
|
||||
return 0xc4;
|
||||
case GRUB_TERM_DISP_VLINE:
|
||||
return 0xb3;
|
||||
case GRUB_TERM_DISP_UL:
|
||||
return 0xda;
|
||||
case GRUB_TERM_DISP_UR:
|
||||
return 0xbf;
|
||||
case GRUB_TERM_DISP_LL:
|
||||
return 0xc0;
|
||||
case GRUB_TERM_DISP_LR:
|
||||
return 0xd9;
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Better than nothing. */
|
||||
switch (in)
|
||||
{
|
||||
case GRUB_TERM_DISP_LEFT:
|
||||
return '<';
|
||||
|
||||
case GRUB_TERM_DISP_UP:
|
||||
return '^';
|
||||
|
||||
case GRUB_TERM_DISP_RIGHT:
|
||||
return '>';
|
||||
|
||||
case GRUB_TERM_DISP_DOWN:
|
||||
return 'v';
|
||||
|
||||
case GRUB_TERM_DISP_HLINE:
|
||||
return '-';
|
||||
|
||||
case GRUB_TERM_DISP_VLINE:
|
||||
return '|';
|
||||
|
||||
case GRUB_TERM_DISP_UL:
|
||||
case GRUB_TERM_DISP_UR:
|
||||
case GRUB_TERM_DISP_LL:
|
||||
case GRUB_TERM_DISP_LR:
|
||||
return '+';
|
||||
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
/* Put a Unicode character. */
|
||||
void
|
||||
grub_putcode (grub_uint32_t code,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
struct grub_unicode_glyph c =
|
||||
{
|
||||
.variant = 0,
|
||||
.attributes = 0,
|
||||
.ncomb = 0,
|
||||
.combining = 0
|
||||
};
|
||||
|
||||
if (grub_unicode_get_comb_type (code) != GRUB_UNICODE_COMB_NONE)
|
||||
return;
|
||||
|
||||
if (code == '\t' && term->getxy)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 8 - ((term->getxy () >> 8) & 7);
|
||||
while (n--)
|
||||
grub_putcode (' ', term);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
c.base = map_code (code, term);
|
||||
|
||||
(term->putchar) (&c);
|
||||
if (code == '\n')
|
||||
grub_putcode ('\r', term);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
grub_print_ucs4 (const grub_uint32_t * str,
|
||||
const grub_uint32_t * last_position,
|
||||
struct grub_term_output *term)
|
||||
{
|
||||
if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)
|
||||
== GRUB_TERM_CODE_TYPE_UCS4_VISUAL)
|
||||
{
|
||||
grub_ssize_t visual_len;
|
||||
struct grub_unicode_glyph *visual;
|
||||
struct grub_unicode_glyph *visual_ptr;
|
||||
visual_len = grub_bidi_logical_to_visual (str,
|
||||
last_position - str,
|
||||
&visual,
|
||||
term->getcharwidth,
|
||||
grub_term_width (term));
|
||||
if (visual_len < 0)
|
||||
{
|
||||
grub_print_error ();
|
||||
return;
|
||||
}
|
||||
for (visual_ptr = visual; visual_ptr < visual + visual_len; visual_ptr++)
|
||||
{
|
||||
struct grub_unicode_glyph glyph_r = {
|
||||
.base = '\r',
|
||||
.variant = 0,
|
||||
.attributes = 0,
|
||||
.ncomb = 0,
|
||||
.combining = 0
|
||||
};
|
||||
term->putchar (visual_ptr);
|
||||
if (visual_ptr->base == '\n')
|
||||
term->putchar (&glyph_r);
|
||||
grub_free (visual_ptr->combining);
|
||||
}
|
||||
grub_free (visual);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: UTF-8 terminals. */
|
||||
{
|
||||
const grub_uint32_t *ptr;
|
||||
for (ptr = str; ptr < last_position; ptr++)
|
||||
grub_putcode (*ptr, term);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_xputs_normal (const char *str)
|
||||
{
|
||||
grub_term_output_t term;
|
||||
|
||||
FOR_ACTIVE_TERM_OUTPUTS(term)
|
||||
{
|
||||
grub_uint32_t *unicode_str, *unicode_last_position;
|
||||
grub_utf8_to_ucs4_alloc (str, &unicode_str,
|
||||
&unicode_last_position);
|
||||
grub_print_ucs4 (unicode_str, unicode_last_position, term);
|
||||
grub_free (unicode_str);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue