diff --git a/conf/common.rmk b/conf/common.rmk index 2d9f2c763..84f9c9fe4 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -496,7 +496,8 @@ gfxmenu_mod_SOURCES = \ gfxmenu/gui_progress_bar.c \ gfxmenu/gui_util.c \ gfxmenu/gui_string_util.c \ - gfxmenu/named_colors.c + gfxmenu/named_colors.c \ + gfxmenu/font.c gfxmenu_mod_CFLAGS = $(COMMON_CFLAGS) gfxmenu_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/font/font.c b/font/font.c index a94fe8ed1..6209b60d2 100644 --- a/font/font.c +++ b/font/font.c @@ -924,30 +924,6 @@ grub_font_get_height (grub_font_t font) return font->ascent + font->descent + font->leading; } -/* Get the width in pixels of the specified UTF-8 string, when rendered in - in the specified font (but falling back on other fonts for glyphs that - are missing). */ -int -grub_font_get_string_width (grub_font_t font, const char *str) -{ - int width; - struct grub_font_glyph *glyph; - grub_uint32_t code; - const grub_uint8_t *ptr; - - for (ptr = (const grub_uint8_t *) str, width = 0; - grub_utf8_to_ucs4 (&code, 1, ptr, -1, &ptr) > 0; ) - { - glyph = grub_font_get_glyph_with_fallback (font, code); - if (glyph) - width += glyph->device_width; - else - width += unknown_glyph->device_width; - } - - return width; -} - /* Get the glyph for FONT corresponding to the Unicode code point CODE. Returns the ASCII glyph for the code if no other fonts are available. The glyphs are cached once loaded. */ @@ -1202,7 +1178,6 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, for (i = 0; i < glyph_id->ncomb; i++) { - enum grub_comb_type combtype; grub_int16_t space = 0; grub_int16_t centerx = (bounds.width - combining_glyphs[i]->width) / 2 + bounds.x; @@ -1210,10 +1185,9 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, if (!combining_glyphs[i]) continue; /* CGJ is to avoid diacritics reordering. */ - if (glyph_id->combining[i] == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) + if (glyph_id->combining[i].code == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) continue; - combtype = grub_unicode_get_comb_type (glyph_id->combining[i]); - switch (combtype) + switch (glyph_id->combining[i].type) { case GRUB_UNICODE_COMB_OVERLAY: do_blit (combining_glyphs[i], @@ -1324,7 +1298,7 @@ grub_font_construct_dry_run (grub_font_t hinted_font, for (i = 0; i < glyph_id->ncomb; i++) combining_glyphs[i] = grub_font_get_glyph_with_fallback (main_glyph->font, - glyph_id->combining[i]); + glyph_id->combining[i].code); } blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs, device_width); @@ -1446,46 +1420,3 @@ grub_font_draw_glyph (struct grub_font_glyph *glyph, glyph->width, glyph->height); } -/* Draw a UTF-8 string of text on the current video render target. - The x coordinate specifies the starting x position for the first character, - while the y coordinate specifies the baseline position. - If the string contains a character that FONT does not contain, then - a glyph from another loaded font may be used instead. */ -grub_err_t -grub_font_draw_string (const char *str, grub_font_t font, - grub_video_color_t color, - int left_x, int baseline_y) -{ - int x; - struct grub_font_glyph *glyph; - grub_uint32_t *logical; - grub_ssize_t logical_len, visual_len; - struct grub_unicode_glyph *visual, *ptr; - - logical_len = grub_utf8_to_ucs4_alloc (str, &logical, 0); - if (logical_len < 0) - return grub_errno; - - visual_len = grub_bidi_logical_to_visual (logical, logical_len, &visual, 0, 0); - grub_free (logical); - if (visual_len < 0) - return grub_errno; - - for (ptr = visual, x = left_x; ptr < visual + visual_len; ptr++) - { - grub_err_t err; - glyph = grub_font_construct_glyph (font, ptr); - if (!glyph) - return grub_errno; - err = grub_font_draw_glyph (glyph, color, x, baseline_y); - grub_free (glyph); - if (err) - return err; - x += glyph->device_width; - } - - grub_free (visual); - - return GRUB_ERR_NONE; -} - diff --git a/gfxmenu/font.c b/gfxmenu/font.c new file mode 100644 index 000000000..9209cbaa5 --- /dev/null +++ b/gfxmenu/font.c @@ -0,0 +1,107 @@ +/* font.c - Font API and font file loader. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Draw a UTF-8 string of text on the current video render target. + The x coordinate specifies the starting x position for the first character, + while the y coordinate specifies the baseline position. + If the string contains a character that FONT does not contain, then + a glyph from another loaded font may be used instead. */ +grub_err_t +grub_font_draw_string (const char *str, grub_font_t font, + grub_video_color_t color, + int left_x, int baseline_y) +{ + int x; + struct grub_font_glyph *glyph; + grub_uint32_t *logical; + grub_ssize_t logical_len, visual_len; + struct grub_unicode_glyph *visual, *ptr; + + logical_len = grub_utf8_to_ucs4_alloc (str, &logical, 0); + if (logical_len < 0) + return grub_errno; + + visual_len = grub_bidi_logical_to_visual (logical, logical_len, &visual, 0, 0); + grub_free (logical); + if (visual_len < 0) + return grub_errno; + + for (ptr = visual, x = left_x; ptr < visual + visual_len; ptr++) + { + grub_err_t err; + glyph = grub_font_construct_glyph (font, ptr); + if (!glyph) + return grub_errno; + err = grub_font_draw_glyph (glyph, color, x, baseline_y); + grub_free (glyph); + if (err) + return err; + x += glyph->device_width; + } + + grub_free (visual); + + return GRUB_ERR_NONE; +} + +/* Get the width in pixels of the specified UTF-8 string, when rendered in + in the specified font (but falling back on other fonts for glyphs that + are missing). */ +int +grub_font_get_string_width (grub_font_t font, const char *str) +{ + int width = 0; + grub_uint32_t *ptr; + grub_ssize_t logical_len; + grub_uint32_t *logical; + + logical_len = grub_utf8_to_ucs4_alloc (str, &logical, 0); + if (logical_len < 0) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + + for (ptr = logical; ptr < logical + logical_len;) + { + struct grub_unicode_glyph glyph; + + ptr += grub_unicode_aglomerate_comb (ptr, + logical_len - (ptr - logical), + &glyph); + width += grub_font_get_constructed_device_width (font, &glyph); + + grub_free (glyph.combining); + } + + return width; +} diff --git a/include/grub/unicode.h b/include/grub/unicode.h index 1f6c4df38..733bb0279 100644 --- a/include/grub/unicode.h +++ b/include/grub/unicode.h @@ -20,6 +20,8 @@ #define GRUB_BIDI_HEADER 1 #include +#include +#include struct grub_unicode_compact_range { @@ -78,7 +80,10 @@ struct grub_unicode_glyph grub_uint16_t variant:9; grub_uint8_t attributes:1; grub_size_t ncomb; - grub_uint32_t *combining; + struct grub_unicode_combining { + grub_uint32_t code; + enum grub_comb_type type; + } *combining; }; #define GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR 0x1 @@ -106,9 +111,39 @@ grub_unicode_get_comb_type (grub_uint32_t c); grub_size_t grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, struct grub_unicode_glyph *out); -struct grub_unicode_glyph * -grub_unicode_glyph_from_code (grub_uint32_t code); -struct grub_unicode_glyph * -grub_unicode_glyph_dup (const struct grub_unicode_glyph *in); + +static inline 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; +} + +static inline 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; +} #endif diff --git a/lib/charset.c b/lib/charset.c index c71de7b5a..db72a9026 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -488,7 +488,7 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, comb_type = grub_unicode_get_comb_type (*ptr); if (comb_type) { - grub_uint32_t *n; + struct grub_unicode_combining *n; unsigned j; if (!haveout) @@ -499,7 +499,7 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, || comb_type == GRUB_UNICODE_COMB_MN) last_comb_pointer = out->ncomb; n = grub_realloc (out->combining, - sizeof (grub_uint32_t) * (out->ncomb + 1)); + sizeof (n[0]) * (out->ncomb + 1)); if (!n) { grub_errno = GRUB_ERR_NONE; @@ -507,14 +507,15 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, } for (j = last_comb_pointer; j < out->ncomb; j++) - if (grub_unicode_get_comb_type (out->combining[j]) > comb_type) + if (out->combining[j].type > 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->combining[j].code = *ptr; + out->combining[j].type = comb_type; out->ncomb++; continue; } @@ -946,40 +947,6 @@ grub_bidi_logical_to_visual (const grub_uint32_t *logical, 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) { diff --git a/normal/menu_text.c b/normal/menu_text.c index 1504a8e60..5b75f29fd 100644 --- a/normal/menu_text.c +++ b/normal/menu_text.c @@ -267,6 +267,7 @@ print_entry (int y, int highlight, grub_menu_entry_t entry, len - i, &glyph); width = grub_term_getcharwidth (term, &glyph); + grub_free (glyph.combining); if (x + width <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)