diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font.c new file mode 100644 index 00000000..b12fb6b9 --- /dev/null +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font.c @@ -0,0 +1,1603 @@ +/* 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 +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#if HAVE_FONT_SOURCE +#include "ascii.h" +#endif + +#ifndef FONT_DEBUG +#define FONT_DEBUG 0 +#endif + +struct char_index_entry +{ + grub_uint32_t code; + grub_uint8_t storage_flags; + grub_uint32_t offset; + + /* Glyph if loaded, or NULL otherwise. */ + struct grub_font_glyph *glyph; +}; + +#define FONT_WEIGHT_NORMAL 100 +#define FONT_WEIGHT_BOLD 200 +#define ASCII_BITMAP_SIZE 16 + +/* Definition of font registry. */ +struct grub_font_node *grub_font_list; + +static int register_font (grub_font_t font); +static void font_init (grub_font_t font); +static void free_font (grub_font_t font); +static void remove_font (grub_font_t font); + +struct font_file_section +{ + /* The file this section is in. */ + grub_file_t file; + + /* FOURCC name of the section. */ + char name[4]; + + /* Length of the section contents. */ + grub_uint32_t length; + + /* Set by open_section() on EOF. */ + int eof; +}; + +/* Replace unknown glyphs with a rounded question mark. */ +static grub_uint8_t unknown_glyph_bitmap[] = { + /* 76543210 */ + 0x7C, /* ooooo */ + 0x82, /* o o */ + 0xBA, /* o ooo o */ + 0xAA, /* o o o o */ + 0xAA, /* o o o o */ + 0x8A, /* o o o */ + 0x9A, /* o oo o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x82, /* o o */ + 0x92, /* o o o */ + 0x82, /* o o */ + 0x7C, /* ooooo */ + 0x00 /* */ +}; + +/* The "unknown glyph" glyph, used as a last resort. */ +static struct grub_font_glyph *unknown_glyph; + +/* The font structure used when no other font is loaded. This functions + as a "Null Object" pattern, so that code everywhere does not have to + check for a NULL grub_font_t to avoid dereferencing a null pointer. */ +static struct grub_font null_font; + +/* Flag to ensure module is initialized only once. */ +static grub_uint8_t font_loader_initialized; + +#if HAVE_FONT_SOURCE +static struct grub_font_glyph *ascii_font_glyph[0x80]; +#endif + +static struct grub_font_glyph * +ascii_glyph_lookup (grub_uint32_t code) +{ +#if HAVE_FONT_SOURCE + static int ascii_failback_initialized = 0; + + if (code >= 0x80) + return NULL; + + if (ascii_failback_initialized == 0) + { + int current; + for (current = 0; current < 0x80; current++) + { + ascii_font_glyph[current] = + grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE); + + ascii_font_glyph[current]->width = 8; + ascii_font_glyph[current]->height = 16; + ascii_font_glyph[current]->offset_x = 0; + ascii_font_glyph[current]->offset_y = -2; + ascii_font_glyph[current]->device_width = 8; + ascii_font_glyph[current]->font = NULL; + + grub_memcpy (ascii_font_glyph[current]->bitmap, + &ascii_bitmaps[current * ASCII_BITMAP_SIZE], + ASCII_BITMAP_SIZE); + } + + ascii_failback_initialized = 1; + } + + return ascii_font_glyph[code]; +#else + (void) code; + return NULL; +#endif +} + +void +grub_font_loader_init (void) +{ + /* Only initialize font loader once. */ + if (font_loader_initialized) + return; + + /* Make glyph for unknown glyph. */ + unknown_glyph = grub_malloc (sizeof (struct grub_font_glyph) + + sizeof (unknown_glyph_bitmap)); + if (!unknown_glyph) + return; + + unknown_glyph->width = 8; + unknown_glyph->height = 16; + unknown_glyph->offset_x = 0; + unknown_glyph->offset_y = -3; + unknown_glyph->device_width = 8; + grub_memcpy (unknown_glyph->bitmap, + unknown_glyph_bitmap, sizeof (unknown_glyph_bitmap)); + + /* Initialize the null font. */ + font_init (&null_font); + /* FIXME: Fix this slightly improper cast. */ + null_font.name = (char *) ""; + null_font.ascent = unknown_glyph->height - 3; + null_font.descent = 3; + null_font.max_char_width = unknown_glyph->width; + null_font.max_char_height = unknown_glyph->height; + + font_loader_initialized = 1; +} + +/* Initialize the font object with initial default values. */ +static void +font_init (grub_font_t font) +{ + font->name = 0; + font->file = 0; + font->family = 0; + font->point_size = 0; + font->weight = 0; + + /* Default leading value, not in font file yet. */ + font->leading = 1; + + font->max_char_width = 0; + font->max_char_height = 0; + font->ascent = 0; + font->descent = 0; + font->num_chars = 0; + font->char_index = 0; + font->bmp_idx = 0; +} + +/* Open the next section in the file. + + On success, the section name is stored in section->name and the length in + section->length, and 0 is returned. On failure, 1 is returned and + grub_errno is set appropriately with an error message. + + If 1 is returned due to being at the end of the file, then section->eof is + set to 1; otherwise, section->eof is set to 0. */ +static int +open_section (grub_file_t file, struct font_file_section *section) +{ + grub_ssize_t retval; + grub_uint32_t raw_length; + + section->file = file; + section->eof = 0; + + /* Read the FOURCC section name. */ + retval = grub_file_read (file, section->name, 4); + if (retval >= 0 && retval < 4) + { + /* EOF encountered. */ + section->eof = 1; + return 1; + } + else if (retval < 0) + { + /* Read error. */ + return 1; + } + + /* Read the big-endian 32-bit section length. */ + retval = grub_file_read (file, &raw_length, 4); + if (retval >= 0 && retval < 4) + { + /* EOF encountered. */ + section->eof = 1; + return 1; + } + else if (retval < 0) + { + /* Read error. */ + return 1; + } + + /* Convert byte-order and store in *length. */ + section->length = grub_be_to_cpu32 (raw_length); + + return 0; +} + +/* Size in bytes of each character index (CHIX section) + entry in the font file. */ +#define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4) + +/* Load the character index (CHIX) section contents from the font file. This + presumes that the position of FILE is positioned immediately after the + section length for the CHIX section (i.e., at the start of the section + contents). Returns 0 upon success, nonzero for failure (in which case + grub_errno is set appropriately). */ +static int +load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + grub_font *font) +{ + unsigned i; + grub_uint32_t last_code; + +#if FONT_DEBUG >= 2 + grub_dprintf ("font", "load_font_index(sect_length=%d)\n", sect_length); +#endif + + /* Sanity check: ensure section length is divisible by the entry size. */ + if ((sect_length % FONT_CHAR_INDEX_ENTRY_SIZE) != 0) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error: character index length %d " + "is not a multiple of the entry size %d", + sect_length, FONT_CHAR_INDEX_ENTRY_SIZE); + return 1; + } + + /* Calculate the number of characters. */ + font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE; + + /* Allocate the character index array. */ + font->char_index = grub_malloc (font->num_chars + * sizeof (struct char_index_entry)); + if (!font->char_index) + return 1; + font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); + if (!font->bmp_idx) + return 1; + grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); + + +#if FONT_DEBUG >= 2 + grub_dprintf ("font", "num_chars=%d)\n", font->num_chars); +#endif + + last_code = 0; + + /* Load the character index data from the file. */ + for (i = 0; i < font->num_chars; i++) + { + struct char_index_entry *entry = &font->char_index[i]; + + /* Read code point value; convert to native byte order. */ + if (grub_file_read (file, &entry->code, 4) != 4) + return 1; + entry->code = grub_be_to_cpu32 (entry->code); + + /* Verify that characters are in ascending order. */ + if (i != 0 && entry->code <= last_code) + { + grub_error (GRUB_ERR_BAD_FONT, + "font characters not in ascending order: %u <= %u", + entry->code, last_code); + return 1; + } + + if (entry->code < 0x10000) + font->bmp_idx[entry->code] = i; + + last_code = entry->code; + + /* Read storage flags byte. */ + if (grub_file_read (file, &entry->storage_flags, 1) != 1) + return 1; + + /* Read glyph data offset; convert to native byte order. */ + if (grub_file_read (file, &entry->offset, 4) != 4) + return 1; + entry->offset = grub_be_to_cpu32 (entry->offset); + + /* No glyph loaded. Will be loaded on demand and cached thereafter. */ + entry->glyph = 0; + +#if FONT_DEBUG >= 5 + /* Print the 1st 10 characters. */ + if (i < 10) + grub_dprintf ("font", "c=%d o=%d\n", entry->code, entry->offset); +#endif + } + + return 0; +} + +/* Read the contents of the specified section as a string, which is + allocated on the heap. Returns 0 if there is an error. */ +static char * +read_section_as_string (struct font_file_section *section) +{ + char *str; + grub_ssize_t ret; + + str = grub_malloc (section->length + 1); + if (!str) + return 0; + + ret = grub_file_read (section->file, str, section->length); + if (ret < 0 || ret != (grub_ssize_t) section->length) + { + grub_free (str); + return 0; + } + + str[section->length] = '\0'; + return str; +} + +/* Read the contents of the current section as a 16-bit integer value, + which is stored into *VALUE. + Returns 0 upon success, nonzero upon failure. */ +static int +read_section_as_short (struct font_file_section *section, + grub_int16_t * value) +{ + grub_uint16_t raw_value; + + if (section->length != 2) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error: section %c%c%c%c length " + "is %d but should be 2", + section->name[0], section->name[1], + section->name[2], section->name[3], section->length); + return 1; + } + if (grub_file_read (section->file, &raw_value, 2) != 2) + return 1; + + *value = grub_be_to_cpu16 (raw_value); + return 0; +} + +/* Load a font and add it to the beginning of the global font list. + Returns 0 upon success, nonzero upon failure. */ +grub_font_t +grub_font_load (const char *filename) +{ + grub_file_t file = 0; + struct font_file_section section; + char magic[4]; + grub_font_t font = 0; + +#if FONT_DEBUG >= 1 + grub_dprintf ("font", "add_font(%s)\n", filename); +#endif + + if (filename[0] == '(' || filename[0] == '/' || filename[0] == '+') + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else if (grub_strncmp(filename, "mem:", 4) == 0) + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else + { + const char *prefix = grub_env_get ("prefix"); + char *fullname, *ptr; + if (!prefix) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), + "prefix"); + goto fail; + } + fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1 + + sizeof ("/fonts/") + sizeof (".pf2")); + if (!fullname) + goto fail; + ptr = grub_stpcpy (fullname, prefix); + ptr = grub_stpcpy (ptr, "/fonts/"); + ptr = grub_stpcpy (ptr, filename); + ptr = grub_stpcpy (ptr, ".pf2"); + *ptr = 0; + file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); + grub_free (fullname); + } + if (!file) + goto fail; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "file opened\n"); +#endif + + /* Read the FILE section. It indicates the file format. */ + if (open_section (file, §ion) != 0) + goto fail; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "opened FILE section\n"); +#endif + if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FILE, + sizeof (FONT_FORMAT_SECTION_NAMES_FILE) - 1) != 0) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error: 1st section must be FILE"); + goto fail; + } + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "section name ok\n"); +#endif + if (section.length != 4) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error (file type ID length is %d " + "but should be 4)", section.length); + goto fail; + } + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "section length ok\n"); +#endif + /* Check the file format type code. */ + if (grub_file_read (file, magic, 4) != 4) + goto fail; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "read magic ok\n"); +#endif + + if (grub_memcmp (magic, FONT_FORMAT_PFF2_MAGIC, 4) != 0) + { + grub_error (GRUB_ERR_BAD_FONT, "invalid font magic %x %x %x %x", + magic[0], magic[1], magic[2], magic[3]); + goto fail; + } + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "compare magic ok\n"); +#endif + + /* Allocate the font object. */ + font = (grub_font_t) grub_zalloc (sizeof (struct grub_font)); + if (!font) + goto fail; + + font_init (font); + font->file = file; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "allocate font ok; loading font info\n"); +#endif + + /* Load the font information. */ + while (1) + { + if (open_section (file, §ion) != 0) + { + if (section.eof) + break; /* Done reading the font file. */ + else + goto fail; + } + +#if FONT_DEBUG >= 2 + grub_dprintf ("font", "opened section %c%c%c%c ok\n", + section.name[0], section.name[1], + section.name[2], section.name[3]); +#endif + + if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FONT_NAME, + sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME) - 1) == 0) + { + font->name = read_section_as_string (§ion); + if (!font->name) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_POINT_SIZE, + sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE) - + 1) == 0) + { + if (read_section_as_short (§ion, &font->point_size) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_WEIGHT, + sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT) - 1) + == 0) + { + char *wt; + wt = read_section_as_string (§ion); + if (!wt) + continue; + /* Convert the weight string 'normal' or 'bold' into a number. */ + if (grub_strcmp (wt, "normal") == 0) + font->weight = FONT_WEIGHT_NORMAL; + else if (grub_strcmp (wt, "bold") == 0) + font->weight = FONT_WEIGHT_BOLD; + grub_free (wt); + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH, + sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH) + - 1) == 0) + { + if (read_section_as_short (§ion, &font->max_char_width) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT, + sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT) + - 1) == 0) + { + if (read_section_as_short (§ion, &font->max_char_height) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_ASCENT, + sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT) - 1) + == 0) + { + if (read_section_as_short (§ion, &font->ascent) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DESCENT, + sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT) - 1) + == 0) + { + if (read_section_as_short (§ion, &font->descent) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_CHAR_INDEX, + sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - + 1) == 0) + { + if (load_font_index (file, section.length, font) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DATA, + sizeof (FONT_FORMAT_SECTION_NAMES_DATA) - 1) == 0) + { + /* When the DATA section marker is reached, we stop reading. */ + break; + } + else + { + /* Unhandled section type, simply skip past it. */ +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "Unhandled section type, skipping.\n"); +#endif + grub_off_t section_end = grub_file_tell (file) + section.length; + if ((int) grub_file_seek (file, section_end) == -1) + goto fail; + } + } + + if (!font->name) + { + grub_dprintf ("font", "Font has no name.\n"); + font->name = grub_strdup ("Unknown"); + } + +#if FONT_DEBUG >= 1 + grub_dprintf ("font", "Loaded font `%s'.\n" + "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n", + font->name, + font->ascent, font->descent, + font->max_char_width, font->max_char_height, font->num_chars); +#endif + + if (font->max_char_width == 0 + || font->max_char_height == 0 + || font->num_chars == 0 + || font->char_index == 0 || font->ascent == 0 || font->descent == 0) + { + grub_error (GRUB_ERR_BAD_FONT, + "invalid font file: missing some required data"); + goto fail; + } + + /* Add the font to the global font registry. */ + if (register_font (font) != 0) + goto fail; + + return font; + +fail: + if (file) + grub_file_close (file); + if (font) + font->file = 0; + + free_font (font); + return 0; +} + +/* Read a 16-bit big-endian integer from FILE, convert it to native byte + order, and store it in *VALUE. + Returns 0 on success, 1 on failure. */ +static int +read_be_uint16 (grub_file_t file, grub_uint16_t * value) +{ + if (grub_file_read (file, value, 2) != 2) + return 1; + *value = grub_be_to_cpu16 (*value); + return 0; +} + +static int +read_be_int16 (grub_file_t file, grub_int16_t * value) +{ + /* For the signed integer version, use the same code as for unsigned. */ + return read_be_uint16 (file, (grub_uint16_t *) value); +} + +/* Return a pointer to the character index entry for the glyph corresponding to + the codepoint CODE in the font FONT. If not found, return zero. */ +static inline struct char_index_entry * +find_glyph (const grub_font_t font, grub_uint32_t code) +{ + struct char_index_entry *table; + grub_size_t lo; + grub_size_t hi; + grub_size_t mid; + + table = font->char_index; + + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) + { + if (font->bmp_idx[code] == 0xffff) + return 0; + return &table[font->bmp_idx[code]]; + } + + /* Do a binary search in `char_index', which is ordered by code point. */ + lo = 0; + hi = font->num_chars - 1; + + if (!table) + return 0; + + while (lo <= hi) + { + mid = lo + (hi - lo) / 2; + if (code < table[mid].code) + hi = mid - 1; + else if (code > table[mid].code) + lo = mid + 1; + else + return &table[mid]; + } + + return 0; +} + +/* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded + from the font file if has not been loaded yet. + Returns a pointer to the glyph if found, or 0 if it is not found. */ +static struct grub_font_glyph * +grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) +{ + struct char_index_entry *index_entry; + + index_entry = find_glyph (font, code); + if (index_entry) + { + struct grub_font_glyph *glyph = 0; + grub_uint16_t width; + grub_uint16_t height; + grub_int16_t xoff; + grub_int16_t yoff; + grub_int16_t dwidth; + int len; + + if (index_entry->glyph) + /* Return cached glyph. */ + return index_entry->glyph; + + if (!font->file) + /* No open file, can't load any glyphs. */ + return 0; + + /* Make sure we can find glyphs for error messages. Push active + error message to error stack and reset error message. */ + grub_error_push (); + + grub_file_seek (font->file, index_entry->offset); + + /* Read the glyph width, height, and baseline. */ + if (read_be_uint16 (font->file, &width) != 0 + || read_be_uint16 (font->file, &height) != 0 + || read_be_int16 (font->file, &xoff) != 0 + || read_be_int16 (font->file, &yoff) != 0 + || read_be_int16 (font->file, &dwidth) != 0) + { + remove_font (font); + return 0; + } + + len = (width * height + 7) / 8; + glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); + if (!glyph) + { + remove_font (font); + return 0; + } + + glyph->font = font; + glyph->width = width; + glyph->height = height; + glyph->offset_x = xoff; + glyph->offset_y = yoff; + glyph->device_width = dwidth; + + /* Don't try to read empty bitmaps (e.g., space characters). */ + if (len != 0) + { + if (grub_file_read (font->file, glyph->bitmap, len) != len) + { + remove_font (font); + grub_free (glyph); + return 0; + } + } + + /* Restore old error message. */ + grub_error_pop (); + + /* Cache the glyph. */ + index_entry->glyph = glyph; + + return glyph; + } + + return 0; +} + +/* Free the memory used by FONT. + This should not be called if the font has been made available to + users (once it is added to the global font list), since there would + be the possibility of a dangling pointer. */ +static void +free_font (grub_font_t font) +{ + if (font) + { + if (font->file) + grub_file_close (font->file); + grub_free (font->name); + grub_free (font->family); + grub_free (font->char_index); + grub_free (font->bmp_idx); + grub_free (font); + } +} + +/* Add FONT to the global font registry. + Returns 0 upon success, nonzero on failure + (the font was not registered). */ +static int +register_font (grub_font_t font) +{ + struct grub_font_node *node = 0; + + node = grub_malloc (sizeof (struct grub_font_node)); + if (!node) + return 1; + + node->value = font; + node->next = grub_font_list; + grub_font_list = node; + + return 0; +} + +/* Remove the font from the global font list. We don't actually free the + font's memory since users could be holding references to the font. */ +static void +remove_font (grub_font_t font) +{ + struct grub_font_node **nextp, *cur; + + for (nextp = &grub_font_list, cur = *nextp; + cur; nextp = &cur->next, cur = cur->next) + { + if (cur->value == font) + { + *nextp = cur->next; + + /* Free the node, but not the font itself. */ + grub_free (cur); + + return; + } + } +} + +/* Get a font from the list of loaded fonts. This function will return + another font if the requested font is not available. If no fonts are + loaded, then a special 'null font' is returned, which contains no glyphs, + but is not a null pointer so the caller may omit checks for NULL. */ +grub_font_t +grub_font_get (const char *font_name) +{ + struct grub_font_node *node; + + for (node = grub_font_list; node; node = node->next) + { + grub_font_t font = node->value; + if (grub_strcmp (font->name, font_name) == 0) + return font; + } + + /* If no font by that name is found, return the first font in the list + as a fallback. */ + if (grub_font_list && grub_font_list->value) + return grub_font_list->value; + else + /* The null_font is a last resort. */ + return &null_font; +} + +/* Get the full name of the font. */ +const char * +grub_font_get_name (grub_font_t font) +{ + return font->name; +} + +/* Get the maximum width of any character in the font in pixels. */ +int +grub_font_get_max_char_width (grub_font_t font) +{ + return font->max_char_width; +} + +/* Get the distance in pixels from the baseline to the lowest descenders + (for instance, in a lowercase 'y', 'g', etc.). */ +int +grub_font_get_descent (grub_font_t font) +{ + return font->descent; +} + +/* FIXME: not correct for all fonts. */ +int +grub_font_get_xheight (grub_font_t font) +{ + return font->ascent / 2; +} + +/* Get the *standard leading* of the font in pixel, which is the spacing + between two lines of text. Specifically, it is the space between the + descent of one line and the ascent of the next line. This is included + in the *height* metric. */ +int +grub_font_get_leading (grub_font_t font) +{ + return font->leading; +} + +/* Get the distance in pixels between baselines of adjacent lines of text. */ +int +grub_font_get_height (grub_font_t font) +{ + return font->ascent + font->descent + font->leading; +} + +/* 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. */ +struct grub_font_glyph * +grub_font_get_glyph (grub_font_t font, grub_uint32_t code) +{ + struct grub_font_glyph *glyph = 0; + if (font) + glyph = grub_font_get_glyph_internal (font, code); + if (glyph == 0) + { + glyph = ascii_glyph_lookup (code); + } + return glyph; +} + + +/* Calculate a subject value representing "how similar" two fonts are. + This is used to prioritize the order that fonts are scanned for missing + glyphs. The object is to select glyphs from the most similar font + possible, for the best appearance. + The heuristic is crude, but it helps greatly when fonts of similar + sizes are used so that tiny 8 point glyphs are not mixed into a string + of 24 point text unless there is no other choice. */ +static int +get_font_diversity (grub_font_t a, grub_font_t b) +{ + int d; + + d = 0; + + if (a->ascent && b->ascent) + d += grub_abs (a->ascent - b->ascent) * 8; + else + /* Penalty for missing attributes. */ + d += 50; + + if (a->max_char_height && b->max_char_height) + d += grub_abs (a->max_char_height - b->max_char_height) * 8; + else + /* Penalty for missing attributes. */ + d += 50; + + /* Weight is a minor factor. */ + d += (a->weight != b->weight) ? 5 : 0; + + return d; +} + +/* Get a glyph corresponding to the codepoint CODE. If FONT contains the + specified glyph, then it is returned. Otherwise, all other loaded fonts + are searched until one is found that contains a glyph for CODE. + If no glyph is available for CODE in the loaded fonts, then a glyph + representing an unknown character is returned. + This function never returns NULL. + The returned glyph is owned by the font manager and should not be freed + by the caller. The glyphs are cached. */ +struct grub_font_glyph * +grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) +{ + struct grub_font_glyph *glyph; + struct grub_font_node *node; + /* Keep track of next node, in case there's an I/O error in + grub_font_get_glyph_internal() and the font is removed from the list. */ + struct grub_font_node *next; + /* Information on the best glyph found so far, to help find the glyph in + the best matching to the requested one. */ + int best_diversity; + struct grub_font_glyph *best_glyph; + + if (font) + { + /* First try to get the glyph from the specified font. */ + glyph = grub_font_get_glyph_internal (font, code); + if (glyph) + return glyph; + } + + /* Otherwise, search all loaded fonts for the glyph and use the one from + the font that best matches the requested font. */ + best_diversity = 10000; + best_glyph = 0; + + for (node = grub_font_list; node; node = next) + { + grub_font_t curfont; + + curfont = node->value; + next = node->next; + + glyph = grub_font_get_glyph_internal (curfont, code); + if (glyph && !font) + return glyph; + if (glyph) + { + int d; + + d = get_font_diversity (curfont, font); + if (d < best_diversity) + { + best_diversity = d; + best_glyph = glyph; + } + } + } + + return best_glyph; +} + +#if 0 +static struct grub_font_glyph * +grub_font_dup_glyph (struct grub_font_glyph *glyph) +{ + static struct grub_font_glyph *ret; + ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8); + if (!ret) + return NULL; + grub_memcpy (ret, glyph, sizeof (*ret) + + (glyph->width * glyph->height + 7) / 8); + return ret; +} +#endif + +/* FIXME: suboptimal. */ +static void +grub_font_blit_glyph (struct grub_font_glyph *target, + struct grub_font_glyph *src, unsigned dx, unsigned dy) +{ + unsigned src_bit, tgt_bit, src_byte, tgt_byte; + unsigned i, j; + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i) % 8; + src_byte = (src->width * i) / 8; + tgt_bit = (target->width * (dy + i) + dx) % 8; + tgt_byte = (target->width * (dy + i) + dx) / 8; + for (j = 0; j < src->width; j++) + { + target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit) + & 0x80) >> tgt_bit; + src_bit++; + tgt_bit++; + if (src_bit == 8) + { + src_byte++; + src_bit = 0; + } + if (tgt_bit == 8) + { + tgt_byte++; + tgt_bit = 0; + } + } + } +} + +static void +grub_font_blit_glyph_mirror (struct grub_font_glyph *target, + struct grub_font_glyph *src, + unsigned dx, unsigned dy) +{ + unsigned tgt_bit, src_byte, tgt_byte; + signed src_bit; + unsigned i, j; + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i + src->width - 1) % 8; + src_byte = (src->width * i + src->width - 1) / 8; + tgt_bit = (target->width * (dy + i) + dx) % 8; + tgt_byte = (target->width * (dy + i) + dx) / 8; + for (j = 0; j < src->width; j++) + { + target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit) + & 0x80) >> tgt_bit; + src_bit--; + tgt_bit++; + if (src_bit == -1) + { + src_byte--; + src_bit = 7; + } + if (tgt_bit == 8) + { + tgt_byte++; + tgt_bit = 0; + } + } + } +} + +/* Context for blit_comb. */ +struct blit_comb_ctx +{ + struct grub_font_glyph *glyph; + int *device_width; + struct grub_video_signed_rect bounds; +}; + +/* Helper for blit_comb. */ +static void +do_blit (struct grub_font_glyph *src, signed dx, signed dy, + struct blit_comb_ctx *ctx) +{ + if (ctx->glyph) + grub_font_blit_glyph (ctx->glyph, src, dx - ctx->glyph->offset_x, + (ctx->glyph->height + ctx->glyph->offset_y) + dy); + if (dx < ctx->bounds.x) + { + ctx->bounds.width += ctx->bounds.x - dx; + ctx->bounds.x = dx; + } + if (ctx->bounds.y > -src->height - dy) + { + ctx->bounds.height += ctx->bounds.y - (-src->height - dy); + ctx->bounds.y = (-src->height - dy); + } + if (dx + src->width - ctx->bounds.x >= (signed) ctx->bounds.width) + ctx->bounds.width = dx + src->width - ctx->bounds.x + 1; + if ((signed) ctx->bounds.height < src->height + (-src->height - dy) + - ctx->bounds.y) + ctx->bounds.height = src->height + (-src->height - dy) - ctx->bounds.y; +} + +/* Helper for blit_comb. */ +static inline void +add_device_width (int val, struct blit_comb_ctx *ctx) +{ + if (ctx->glyph) + ctx->glyph->device_width += val; + if (ctx->device_width) + *ctx->device_width += val; +} + +static void +blit_comb (const struct grub_unicode_glyph *glyph_id, + struct grub_font_glyph *glyph, + struct grub_video_signed_rect *bounds_out, + struct grub_font_glyph *main_glyph, + struct grub_font_glyph **combining_glyphs, int *device_width) +{ + struct blit_comb_ctx ctx = { + .glyph = glyph, + .device_width = device_width + }; + unsigned i; + signed above_rightx, above_righty; + signed above_leftx, above_lefty; + signed below_rightx, below_righty; + signed min_devwidth = 0; + const struct grub_unicode_combining *comb; + + if (glyph) + glyph->device_width = main_glyph->device_width; + if (device_width) + *device_width = main_glyph->device_width; + + ctx.bounds.x = main_glyph->offset_x; + ctx.bounds.y = main_glyph->offset_y; + ctx.bounds.width = main_glyph->width; + ctx.bounds.height = main_glyph->height; + + above_rightx = main_glyph->offset_x + main_glyph->width; + above_righty = ctx.bounds.y + ctx.bounds.height; + + above_leftx = main_glyph->offset_x; + above_lefty = ctx.bounds.y + ctx.bounds.height; + + below_rightx = ctx.bounds.x + ctx.bounds.width; + below_righty = ctx.bounds.y; + + comb = grub_unicode_get_comb (glyph_id); + + for (i = 0; i < glyph_id->ncomb; i++) + { + grub_int16_t space = 0; + /* Center by default. */ + grub_int16_t targetx; + + if (!combining_glyphs[i]) + continue; + targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; + /* CGJ is to avoid diacritics reordering. */ + if (comb[i].code + == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) + continue; + switch (comb[i].type) + { + case GRUB_UNICODE_COMB_OVERLAY: + do_blit (combining_glyphs[i], + targetx, + (ctx.bounds.height - combining_glyphs[i]->height) / 2 + - (ctx.bounds.height + ctx.bounds.y), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_ATTACHED_ABOVE_RIGHT: + do_blit (combining_glyphs[i], above_rightx, -above_righty, &ctx); + above_rightx += combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_ABOVE_RIGHT: + do_blit (combining_glyphs[i], above_rightx, + -(above_righty + combining_glyphs[i]->height), &ctx); + above_rightx += combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_ABOVE_LEFT: + above_leftx -= combining_glyphs[i]->width; + do_blit (combining_glyphs[i], above_leftx, + -(above_lefty + combining_glyphs[i]->height), &ctx); + break; + + case GRUB_UNICODE_COMB_BELOW_RIGHT: + do_blit (combining_glyphs[i], below_rightx, below_righty, &ctx); + below_rightx += combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_HEBREW_HOLAM: + if (glyph_id->base != GRUB_UNICODE_HEBREW_WAW) + targetx = + main_glyph->offset_x - combining_glyphs[i]->width - + (combining_glyphs[i]->width + 3) / 4; + goto above_on_main; + + case GRUB_UNICODE_COMB_HEBREW_SIN_DOT: + targetx = main_glyph->offset_x + combining_glyphs[i]->width / 4; + goto above_on_main; + + case GRUB_UNICODE_COMB_HEBREW_SHIN_DOT: + targetx = + main_glyph->width + main_glyph->offset_x - + combining_glyphs[i]->width; + above_on_main: + space = combining_glyphs[i]->offset_y + - grub_font_get_xheight (combining_glyphs[i]->font) - 1; + if (space <= 0) + space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8; + do_blit (combining_glyphs[i], targetx, + -(main_glyph->height + main_glyph->offset_y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + /* TODO: Put dammah, fathah and alif nearer to shadda. */ + case GRUB_UNICODE_COMB_SYRIAC_SUPERSCRIPT_ALAPH: + case GRUB_UNICODE_COMB_ARABIC_DAMMAH: + case GRUB_UNICODE_COMB_ARABIC_DAMMATAN: + case GRUB_UNICODE_COMB_ARABIC_FATHATAN: + case GRUB_UNICODE_COMB_ARABIC_FATHAH: + case GRUB_UNICODE_COMB_ARABIC_SUPERSCRIPT_ALIF: + case GRUB_UNICODE_COMB_ARABIC_SUKUN: + case GRUB_UNICODE_COMB_ARABIC_SHADDA: + case GRUB_UNICODE_COMB_HEBREW_RAFE: + case GRUB_UNICODE_STACK_ABOVE: + stacked_above: + space = combining_glyphs[i]->offset_y + - grub_font_get_xheight (combining_glyphs[i]->font) - 1; + if (space <= 0) + space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8; + /* Fallthrough. */ + case GRUB_UNICODE_STACK_ATTACHED_ABOVE: + do_blit (combining_glyphs[i], targetx, + -(ctx.bounds.height + ctx.bounds.y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_HEBREW_DAGESH: + do_blit (combining_glyphs[i], targetx, + -(ctx.bounds.height / 2 + ctx.bounds.y + + combining_glyphs[i]->height / 2), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_HEBREW_SHEVA: + case GRUB_UNICODE_COMB_HEBREW_HIRIQ: + case GRUB_UNICODE_COMB_HEBREW_QAMATS: + case GRUB_UNICODE_COMB_HEBREW_TSERE: + case GRUB_UNICODE_COMB_HEBREW_SEGOL: + /* TODO: placement in final kaf and under reish. */ + + case GRUB_UNICODE_COMB_HEBREW_HATAF_SEGOL: + case GRUB_UNICODE_COMB_HEBREW_HATAF_PATAH: + case GRUB_UNICODE_COMB_HEBREW_HATAF_QAMATS: + case GRUB_UNICODE_COMB_HEBREW_PATAH: + case GRUB_UNICODE_COMB_HEBREW_QUBUTS: + case GRUB_UNICODE_COMB_HEBREW_METEG: + /* TODO: Put kasra and kasratan under shadda. */ + case GRUB_UNICODE_COMB_ARABIC_KASRA: + case GRUB_UNICODE_COMB_ARABIC_KASRATAN: + /* I don't know how ypogegrammeni differs from subscript. */ + case GRUB_UNICODE_COMB_YPOGEGRAMMENI: + case GRUB_UNICODE_STACK_BELOW: + stacked_below: + space = -(combining_glyphs[i]->offset_y + + combining_glyphs[i]->height); + if (space <= 0) + space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8; + /* Fallthrough. */ + + case GRUB_UNICODE_STACK_ATTACHED_BELOW: + do_blit (combining_glyphs[i], targetx, -(ctx.bounds.y - space), + &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_MN: + switch (comb[i].code) + { + case GRUB_UNICODE_THAANA_ABAFILI: + case GRUB_UNICODE_THAANA_AABAAFILI: + case GRUB_UNICODE_THAANA_UBUFILI: + case GRUB_UNICODE_THAANA_OOBOOFILI: + case GRUB_UNICODE_THAANA_EBEFILI: + case GRUB_UNICODE_THAANA_EYBEYFILI: + case GRUB_UNICODE_THAANA_OBOFILI: + case GRUB_UNICODE_THAANA_OABOAFILI: + case GRUB_UNICODE_THAANA_SUKUN: + goto stacked_above; + case GRUB_UNICODE_THAANA_IBIFILI: + case GRUB_UNICODE_THAANA_EEBEEFILI: + goto stacked_below; + } + /* Fall through. */ + default: + { + /* Default handling. Just draw combining character on top + of base character. + FIXME: support more unicode types correctly. + */ + do_blit (combining_glyphs[i], + main_glyph->device_width + + combining_glyphs[i]->offset_x, + -(combining_glyphs[i]->height + + combining_glyphs[i]->offset_y), &ctx); + add_device_width (combining_glyphs[i]->device_width, &ctx); + } + } + } + add_device_width ((above_rightx > + below_rightx ? above_rightx : below_rightx) - + (main_glyph->offset_x + main_glyph->width), &ctx); + add_device_width (above_leftx - main_glyph->offset_x, &ctx); + if (glyph && glyph->device_width < min_devwidth) + glyph->device_width = min_devwidth; + if (device_width && *device_width < min_devwidth) + *device_width = min_devwidth; + + if (bounds_out) + *bounds_out = ctx.bounds; +} + +static struct grub_font_glyph * +grub_font_construct_dry_run (grub_font_t hinted_font, + const struct grub_unicode_glyph *glyph_id, + struct grub_video_signed_rect *bounds, + struct grub_font_glyph **combining_glyphs, + int *device_width) +{ + struct grub_font_glyph *main_glyph = NULL; + grub_uint32_t desired_attributes = 0; + unsigned i; + grub_uint32_t base = glyph_id->base; + const struct grub_unicode_combining *comb; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED) + desired_attributes |= GRUB_FONT_CODE_RIGHT_JOINED; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED) + desired_attributes |= GRUB_FONT_CODE_LEFT_JOINED; + + comb = grub_unicode_get_comb (glyph_id); + + if (base == 'i' || base == 'j') + { + for (i = 0; i < glyph_id->ncomb; i++) + if (comb[i].type == GRUB_UNICODE_STACK_ABOVE) + break; + if (i < glyph_id->ncomb && base == 'i') + base = GRUB_UNICODE_DOTLESS_LOWERCASE_I; + if (i < glyph_id->ncomb && base == 'j') + base = GRUB_UNICODE_DOTLESS_LOWERCASE_J; + } + + main_glyph = grub_font_get_glyph_with_fallback (hinted_font, base + | desired_attributes); + + if (!main_glyph) + main_glyph = grub_font_get_glyph_with_fallback (hinted_font, + base); + + /* Glyph not available in any font. Use ASCII fallback. */ + if (!main_glyph) + main_glyph = ascii_glyph_lookup (base); + + /* Glyph not available in any font. Return unknown glyph. */ + if (!main_glyph) + return NULL; + + if (device_width) + *device_width = main_glyph->device_width; + + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + + if (glyph_id->ncomb && !combining_glyphs) + { + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + + for (i = 0; i < glyph_id->ncomb; i++) + combining_glyphs[i] + = grub_font_get_glyph_with_fallback (main_glyph->font, + comb[i].code); + + blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs, + device_width); + + return main_glyph; +} + +static struct grub_font_glyph **render_combining_glyphs = 0; +static grub_size_t render_max_comb_glyphs = 0; + +static void +ensure_comb_space (const struct grub_unicode_glyph *glyph_id) +{ + if (glyph_id->ncomb <= render_max_comb_glyphs) + return; + + render_max_comb_glyphs = 2 * glyph_id->ncomb; + if (render_max_comb_glyphs < 8) + render_max_comb_glyphs = 8; + grub_free (render_combining_glyphs); + render_combining_glyphs = grub_malloc (render_max_comb_glyphs + * sizeof (render_combining_glyphs[0])); + if (!render_combining_glyphs) + grub_errno = 0; +} + +int +grub_font_get_constructed_device_width (grub_font_t hinted_font, + const struct grub_unicode_glyph + *glyph_id) +{ + int ret; + struct grub_font_glyph *main_glyph; + + ensure_comb_space (glyph_id); + + main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, NULL, + render_combining_glyphs, &ret); + if (!main_glyph) + return unknown_glyph->device_width; + return ret; +} + +struct grub_font_glyph * +grub_font_construct_glyph (grub_font_t hinted_font, + const struct grub_unicode_glyph *glyph_id) +{ + struct grub_font_glyph *main_glyph; + struct grub_video_signed_rect bounds; + static struct grub_font_glyph *glyph = 0; + static grub_size_t max_glyph_size = 0; + + ensure_comb_space (glyph_id); + + main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, + &bounds, render_combining_glyphs, + NULL); + + if (!main_glyph) + return unknown_glyph; + + if (!render_combining_glyphs && glyph_id->ncomb) + return main_glyph; + + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + + if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) + { + grub_free (glyph); + max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2; + if (max_glyph_size < 8) + max_glyph_size = 8; + glyph = grub_malloc (max_glyph_size); + } + if (!glyph) + { + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + + grub_memset (glyph, 0, sizeof (*glyph) + + (bounds.width * bounds.height + + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT); + + glyph->font = main_glyph->font; + glyph->width = bounds.width; + glyph->height = bounds.height; + glyph->offset_x = bounds.x; + glyph->offset_y = bounds.y; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR) + grub_font_blit_glyph_mirror (glyph, main_glyph, + main_glyph->offset_x - glyph->offset_x, + (glyph->height + glyph->offset_y) + - (main_glyph->height + + main_glyph->offset_y)); + else + grub_font_blit_glyph (glyph, main_glyph, + main_glyph->offset_x - glyph->offset_x, + (glyph->height + glyph->offset_y) + - (main_glyph->height + main_glyph->offset_y)); + + blit_comb (glyph_id, glyph, NULL, main_glyph, render_combining_glyphs, NULL); + + return glyph; +} + +/* Draw the specified glyph at (x, y). The y coordinate designates the + baseline of the character, while the x coordinate designates the left + side location of the character. */ +grub_err_t +grub_font_draw_glyph (struct grub_font_glyph * glyph, + grub_video_color_t color, int left_x, int baseline_y) +{ + struct grub_video_bitmap glyph_bitmap; + + /* Don't try to draw empty glyphs (U+0020, etc.). */ + if (glyph->width == 0 || glyph->height == 0) + return GRUB_ERR_NONE; + + glyph_bitmap.mode_info.width = glyph->width; + glyph_bitmap.mode_info.height = glyph->height; + glyph_bitmap.mode_info.mode_type + = (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; + glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED; + glyph_bitmap.mode_info.bpp = 1; + + /* Really 1 bit per pixel. */ + glyph_bitmap.mode_info.bytes_per_pixel = 0; + + /* Packed densely as bits. */ + glyph_bitmap.mode_info.pitch = glyph->width; + + glyph_bitmap.mode_info.number_of_colors = 2; + glyph_bitmap.mode_info.bg_red = 0; + glyph_bitmap.mode_info.bg_green = 0; + glyph_bitmap.mode_info.bg_blue = 0; + glyph_bitmap.mode_info.bg_alpha = 0; + grub_video_unmap_color (color, + &glyph_bitmap.mode_info.fg_red, + &glyph_bitmap.mode_info.fg_green, + &glyph_bitmap.mode_info.fg_blue, + &glyph_bitmap.mode_info.fg_alpha); + glyph_bitmap.data = glyph->bitmap; + + int bitmap_left = left_x + glyph->offset_x; + int bitmap_bottom = baseline_y - glyph->offset_y; + int bitmap_top = bitmap_bottom - glyph->height; + + return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND, + bitmap_left, bitmap_top, + 0, 0, glyph->width, glyph->height); +} diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c index 5e448d27..63d8c7be 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c @@ -59,11 +59,15 @@ struct grub_gui_label grub_font_t font; grub_video_rgba_color_t color; int value; + int vtoytip; enum align_mode align; }; typedef struct grub_gui_label *grub_gui_label_t; +extern const char * g_ventoy_tip_msg1; +extern const char * g_ventoy_tip_msg2; + static void label_destroy (void *vself) { @@ -90,6 +94,7 @@ label_is_instance (void *vself __attribute__((unused)), const char *type) static void label_paint (void *vself, const grub_video_rect_t *region) { + const char *text; grub_gui_label_t self = vself; if (! self->visible) @@ -98,16 +103,24 @@ label_paint (void *vself, const grub_video_rect_t *region) if (!grub_video_have_common_points (region, &self->bounds)) return; + if (self->vtoytip == 1) { + text = g_ventoy_tip_msg1 ? g_ventoy_tip_msg1 : ""; + } else if (self->vtoytip == 2) { + text = g_ventoy_tip_msg2 ? g_ventoy_tip_msg2 : ""; + } else { + text = self->text; + } + /* Calculate the starting x coordinate. */ int left_x; if (self->align == align_left) left_x = 0; else if (self->align == align_center) left_x = (self->bounds.width - - grub_font_get_string_width (self->font, self->text)) / 2; + - grub_font_get_string_width (self->font, text)) / 2; else if (self->align == align_right) left_x = (self->bounds.width - - grub_font_get_string_width (self->font, self->text)); + - grub_font_get_string_width (self->font, text)); else return; /* Invalid alignment. */ @@ -116,7 +129,7 @@ label_paint (void *vself, const grub_video_rect_t *region) grub_video_rect_t vpsave; grub_gui_set_viewport (&self->bounds, &vpsave); - grub_font_draw_string (self->text, + grub_font_draw_string (text, self->font, grub_video_map_rgba_color (self->color), left_x, @@ -156,8 +169,8 @@ static void label_get_minimal_size (void *vself, unsigned *width, unsigned *height) { grub_gui_label_t self = vself; - *width = grub_font_get_string_width (self->font, self->text); - *height = (grub_font_get_ascent (self->font) + *width = grub_font_get_string_width (self->font, self->text); + *height = (grub_font_get_ascent (self->font) + grub_font_get_descent (self->font)); } @@ -255,8 +268,14 @@ label_set_property (void *vself, const char *name, const char *value) { grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); grub_free (self->id); - if (value) + if (value) { self->id = grub_strdup (value); + if (grub_strcmp(value, "VTOY_MENU_TIP_1") == 0) { + self->vtoytip = 1; + } else if (grub_strcmp(value, "VTOY_MENU_TIP_2") == 0) { + self->vtoytip = 2; + } + } else self->id = 0; if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID) diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c index cc905ced..5fea1cb2 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c @@ -733,6 +733,8 @@ done: return grub_errno; } +extern int g_menu_update_mode; + /* Set properties on the view based on settings from the specified theme file. */ grub_err_t @@ -752,7 +754,7 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) } p.len = grub_file_size (file); - p.buf = grub_malloc (p.len + 4096); + p.buf = grub_malloc (p.len + 8192); p.pos = 0; p.line_num = 1; p.col_num = 1; @@ -781,6 +783,33 @@ grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) } } +{ + const char *tip = grub_env_get("VTOY_MENU_TIP_ENABLE"); + if (tip && tip[0] == '1') + { + char tmpmsg[512]; + + grub_memset(tmpmsg, 'w', 500); + tmpmsg[500] = 0; + + g_menu_update_mode = 1; + p.len += grub_snprintf(p.buf + p.len, 4096, + "\n+ vbox{\n left = %s\n top = %s\n" + "+ label { id=\"VTOY_MENU_TIP_1\" text = \"%s\" color = \"%s\" align = \"%s\"}\n" + "+ label { id=\"VTOY_MENU_TIP_2\" text = \"%s\" color = \"%s\" align = \"%s\"}\n" + "}\n", + grub_env_get("VTOY_TIP_LEFT"), + grub_env_get("VTOY_TIP_TOP"), + tmpmsg, + grub_env_get("VTOY_TIP_COLOR"), + grub_env_get("VTOY_TIP_ALIGN"), + tmpmsg, + grub_env_get("VTOY_TIP_COLOR"), + grub_env_get("VTOY_TIP_ALIGN") + ); + } +} + if (view->canvas) view->canvas->component.ops->destroy (view->canvas); diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c index bfac3756..0bd7515e 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c @@ -386,21 +386,37 @@ redraw_menu_visit (grub_gui_component_t component, } } +extern int g_menu_update_mode; + +static void grub_gfxmenu_update_all(grub_gfxmenu_view_t view) +{ + grub_video_set_area_status(GRUB_VIDEO_AREA_DISABLED); + grub_gfxmenu_view_redraw(view, &view->screen); +} + void grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view) { update_menu_components (view); - grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, - redraw_menu_visit, view); + if (g_menu_update_mode) + grub_gfxmenu_update_all(view); + else + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + grub_video_swap_buffers (); if (view->double_repaint) { - grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, - redraw_menu_visit, view); + if (g_menu_update_mode) + grub_gfxmenu_update_all(view); + else + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); } } + void grub_gfxmenu_set_chosen_entry (int entry, void *data) { @@ -408,6 +424,8 @@ grub_gfxmenu_set_chosen_entry (int entry, void *data) view->selected = entry; grub_gfxmenu_redraw_menu (view); + + } static void diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c index 14e3dac5..0a86a743 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include "ventoy/ventoy_def.h" int g_ventoy_menu_refresh = 0; int g_ventoy_memdisk_mode = 0; @@ -381,10 +384,28 @@ grub_menu_execute_with_fallback (grub_menu_t menu, static struct grub_menu_viewer *viewers; +int g_menu_update_mode = 0; +int g_ventoy_tip_label_enable = 0; +const char * g_ventoy_tip_msg1 = NULL; +const char * g_ventoy_tip_msg2 = NULL; + static void -menu_set_chosen_entry (int entry) +menu_set_chosen_entry (grub_menu_t menu, int entry) { struct grub_menu_viewer *cur; + img_info *img; + grub_menu_entry_t e = grub_menu_get_entry (menu, entry); + + g_ventoy_tip_msg1 = g_ventoy_tip_msg2 = NULL; + if (e && e->id && grub_strncmp(e->id, "VID_", 4) == 0) { + img = (img_info *)(void *)grub_strtoul(e->id + 4, NULL, 16); + if (img) + { + g_ventoy_tip_msg1 = img->tip1; + g_ventoy_tip_msg2 = img->tip2; + } + } + for (cur = viewers; cur; cur = cur->next) cur->set_chosen_entry (entry, cur->data); } @@ -732,13 +753,13 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) case GRUB_TERM_KEY_HOME: case GRUB_TERM_CTRL | 'a': current_entry = 0; - menu_set_chosen_entry (current_entry); + menu_set_chosen_entry (menu, current_entry); break; case GRUB_TERM_KEY_END: case GRUB_TERM_CTRL | 'e': current_entry = menu->size - 1; - menu_set_chosen_entry (current_entry); + menu_set_chosen_entry (menu, current_entry); break; case GRUB_TERM_KEY_UP: @@ -746,7 +767,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) case '^': if (current_entry > 0) current_entry--; - menu_set_chosen_entry (current_entry); + menu_set_chosen_entry (menu, current_entry); break; case GRUB_TERM_CTRL | 'n': @@ -754,7 +775,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) case 'v': if (current_entry < menu->size - 1) current_entry++; - menu_set_chosen_entry (current_entry); + menu_set_chosen_entry (menu, current_entry); break; case GRUB_TERM_CTRL | 'g': @@ -763,7 +784,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) current_entry = 0; else current_entry -= GRUB_MENU_PAGE_SIZE; - menu_set_chosen_entry (current_entry); + menu_set_chosen_entry (menu, current_entry); break; case GRUB_TERM_CTRL | 'c': @@ -772,7 +793,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) current_entry += GRUB_MENU_PAGE_SIZE; else current_entry = menu->size - 1; - menu_set_chosen_entry (current_entry); + menu_set_chosen_entry (menu, current_entry); break; case '\n': diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c index 502f260a..b7e7ce0a 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c @@ -1562,6 +1562,7 @@ static int ventoy_collect_img_files(const char *filename, const struct grub_dirh grub_size_t len; img_info *img; img_info *tail; + const menu_tip *tip; img_iterator_node *tmp; img_iterator_node *new_node; img_iterator_node *node = (img_iterator_node *)data; @@ -1779,6 +1780,14 @@ static int ventoy_collect_img_files(const char *filename, const struct grub_dirh g_ventoy_img_count++; img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path); + + tip = ventoy_plugin_get_menu_tip(img->path); + if (tip) + { + img->tip1 = tip->tip1; + img->tip2 = tip->tip2; + } + img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name, img->path); if (!img->class) { @@ -2073,23 +2082,23 @@ static int ventoy_dynamic_tree_menu(img_iterator_node *node) if (g_tree_view_menu_style == 0) { vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, - "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%d\" {\n" + "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n" " %s_%s \n" "}\n", grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), img->unsupport ? "[***********] " : "", - img->alias ? img->alias : img->name, img->class, img->id, + img->alias ? img->alias : img->name, img->class, img, img->menu_prefix, img->unsupport ? "unsupport_menuentry" : "common_menuentry"); } else { vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, - "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n" + "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n" " %s_%s \n" "}\n", img->unsupport ? "[***********] " : "", - img->alias ? img->alias : img->name, img->class, img->id, + img->alias ? img->alias : img->name, img->class, img, img->menu_prefix, img->unsupport ? "unsupport_menuentry" : "common_menuentry"); } @@ -2136,7 +2145,7 @@ static int ventoy_set_default_menu(void) if (0 == g_default_menu_mode) { - vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%d'\n", default_node->id); + vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node); } else { @@ -2169,7 +2178,7 @@ static int ventoy_set_default_menu(void) pos = end + 1; } - vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%d'\n", default_node->id); + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node); grub_free(def); } } @@ -2266,7 +2275,7 @@ static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image"); } - grub_snprintf(id, sizeof(id), "VID_%d", cur->id); + grub_snprintf(id, sizeof(id), "VID_%p", cur); grub_env_set("chosen", id); grub_env_export("chosen"); @@ -2275,11 +2284,10 @@ static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args) { - int img_id = 0; char value[32]; char *pos = NULL; const char *id = NULL; - img_info *cur = g_ventoy_img_list; + img_info *cur = NULL; (void)ctxt; @@ -2293,20 +2301,11 @@ static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int arg pos = grub_strstr(id, "VID_"); if (pos) { - img_id = (int)grub_strtoul(pos + 4, NULL, 10); + cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16); } else { - img_id = (int)grub_strtoul(id, NULL, 10); - } - - while (cur) - { - if (img_id == cur->id) - { - break; - } - cur = cur->next; + cur = g_ventoy_img_list; } if (!cur) @@ -2335,12 +2334,14 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char grub_device_t dev = NULL; img_info *cur = NULL; img_info *tail = NULL; + img_info *min = NULL; + img_info *head = NULL; const char *strdata = NULL; char *device_name = NULL; char buf[32]; img_iterator_node *node = NULL; img_iterator_node *tmp = NULL; - + (void)ctxt; if (argc != 2) @@ -2470,17 +2471,49 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char } /* sort image list by image name */ - for (cur = g_ventoy_img_list; cur; cur = cur->next) + while (g_ventoy_img_list) { - for (tail = cur->next; tail; tail = tail->next) + min = g_ventoy_img_list; + for (cur = g_ventoy_img_list->next; cur; cur = cur->next) { - if (ventoy_cmp_img(cur, tail) > 0) + if (ventoy_cmp_img(min, cur) > 0) { - ventoy_swap_img(cur, tail); + min = cur; } } + + if (min->prev) + { + min->prev->next = min->next; + } + + if (min->next) + { + min->next->prev = min->prev; + } + + if (min == g_ventoy_img_list) + { + g_ventoy_img_list = min->next; + } + + if (head == NULL) + { + head = tail = min; + min->prev = NULL; + min->next = NULL; + } + else + { + tail->next = min; + min->prev = tail; + min->next = NULL; + tail = min; + } } + g_ventoy_img_list = head; + if (g_default_menu_mode == 1) { vtoy_ssprintf(g_list_script_buf, g_list_script_pos, @@ -2492,11 +2525,11 @@ static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char for (cur = g_ventoy_img_list; cur; cur = cur->next) { vtoy_ssprintf(g_list_script_buf, g_list_script_pos, - "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%d\" {\n" + "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n" " %s_%s \n" "}\n", cur->unsupport ? "[***********] " : "", - cur->alias ? cur->alias : cur->name, cur->class, cur->id, + cur->alias ? cur->alias : cur->name, cur->class, cur, cur->menu_prefix, cur->unsupport ? "unsupport_menuentry" : "common_menuentry"); } @@ -4851,6 +4884,27 @@ static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, cha } + +/* : Deleted by longpanda, 20210916 PN:XX LABEL:XX */ +#if 0 +void ventoy_tip_set_menu_label(const char *vid) +{ + img_info *node; + + g_ventoy_tip_msg1 = g_ventoy_tip_msg2 = NULL; + if (vid) + { + node = (img_info *)(void *)grub_strtoul(vid + 4, NULL, 16); + if (node) + { + g_ventoy_tip_msg1 = node->tip1; + g_ventoy_tip_msg2 = node->tip2; + } + } +} +#endif /* #if 0 */ +/* : Deleted by longpanda, 20210916 PN:XX LABEL:XX */ + int ventoy_env_init(void) { char buf[64]; diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h index 8e503b1e..44fdc800 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h @@ -215,6 +215,8 @@ typedef struct img_info char name[256]; const char *alias; + const char *tip1; + const char *tip2; const char *class; const char *menu_prefix; @@ -865,6 +867,17 @@ typedef struct menu_alias struct menu_alias *next; }menu_alias; +typedef struct menu_tip +{ + int pathlen; + char isopath[256]; + char tip1[1024]; + char tip2[1024]; + + struct menu_tip *next; +}menu_tip; + + #define vtoy_class_image_file 0 #define vtoy_class_directory 1 @@ -1017,6 +1030,7 @@ int ventoy_fill_windows_rtdata(void *buf, char *isopath); int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list); const char * ventoy_plugin_get_injection(const char *isopath); const char * ventoy_plugin_get_menu_alias(int type, const char *isopath); +const menu_tip * ventoy_plugin_get_menu_tip(const char *isopath); const char * ventoy_plugin_get_menu_class(int type, const char *name, const char *path); int ventoy_plugin_check_memdisk(const char *isopath); int ventoy_plugin_get_image_list_index(int type, const char *name); diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c index c41d9649..591ed265 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c @@ -48,6 +48,7 @@ static install_template *g_install_template_head = NULL; static dud *g_dud_head = NULL; static menu_password *g_pwd_head = NULL; static persistence_config *g_persistence_head = NULL; +static menu_tip *g_menu_tip_head = NULL; static menu_alias *g_menu_alias_head = NULL; static menu_class *g_menu_class_head = NULL; static custom_boot *g_custom_boot_head = NULL; @@ -1417,6 +1418,176 @@ static int ventoy_plugin_menualias_entry(VTOY_JSON *json, const char *isodisk) return 0; } +static int ventoy_plugin_menutip_check(VTOY_JSON *json, const char *isodisk) +{ + const char *path = NULL; + const char *tip = NULL; + VTOY_JSON *pNode = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("Not object %d\n", json->enDataType); + return 1; + } + + tip = vtoy_json_get_string_ex(json->pstChild, "left"); + if (tip) + { + grub_printf("left: <%s>\n", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "top"); + if (tip) + { + grub_printf("top: <%s>\n", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "color"); + if (tip) + { + grub_printf("color: <%s>\n", tip); + } + + pNode = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "tips"); + for (pNode = pNode->pstChild; pNode; pNode = pNode->pstNext) + { + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (path && path[0] == '/') + { + if (grub_strchr(path, '*')) + { + grub_printf("image: <%s> [ * ]\n", path); + } + else if (ventoy_check_file_exist("%s%s", isodisk, path)) + { + grub_printf("image: <%s> [ OK ]\n", path); + } + else + { + grub_printf("image: <%s> [ NOT EXIST ]\n", path); + } + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip"); + if (tip) + { + grub_printf("tip: <%s>\n", tip); + } + else + { + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip1"); + if (tip) + grub_printf("tip1: <%s>\n", tip); + else + grub_printf("tip1: \n"); + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip2"); + if (tip) + grub_printf("tip2: <%s>\n", tip); + else + grub_printf("tip2: \n"); + } + } + else + { + grub_printf("image: <%s> [ INVALID ]\n", path); + } + } + + return 0; +} + +static int ventoy_plugin_menutip_entry(VTOY_JSON *json, const char *isodisk) +{ + const char *path = NULL; + const char *tip = NULL; + VTOY_JSON *pNode = NULL; + menu_tip *node = NULL; + menu_tip *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_OBJECT) + { + debug("Not object %d\n", json->enDataType); + return 0; + } + + pNode = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "tips"); + if (pNode == NULL) + { + debug("Not tips found\n"); + return 0; + } + + if (g_menu_tip_head) + { + for (node = g_menu_tip_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_menu_tip_head = NULL; + } + + tip = vtoy_json_get_string_ex(json->pstChild, "left"); + if (tip) + { + grub_env_set("VTOY_TIP_LEFT", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "top"); + if (tip) + { + grub_env_set("VTOY_TIP_TOP", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "color"); + if (tip) + { + grub_env_set("VTOY_TIP_COLOR", tip); + } + + for (pNode = pNode->pstChild; pNode; pNode = pNode->pstNext) + { + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (path && path[0] == '/') + { + node = grub_zalloc(sizeof(menu_tip)); + if (node) + { + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path); + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip"); + if (tip) + { + grub_snprintf(node->tip1, 1000, "%s", tip); + } + else + { + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip1"); + if (tip) + grub_snprintf(node->tip1, 1000, "%s", tip); + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip2"); + if (tip) + grub_snprintf(node->tip2, 1000, "%s", tip); + } + + if (g_menu_tip_head) + { + node->next = g_menu_tip_head; + } + + g_menu_tip_head = node; + } + } + } + + return 0; +} static int ventoy_plugin_injection_check(VTOY_JSON *json, const char *isodisk) { @@ -2101,6 +2272,7 @@ static plugin_entry g_plugin_entries[] = { "auto_install", ventoy_plugin_auto_install_entry, ventoy_plugin_auto_install_check }, { "persistence", ventoy_plugin_persistence_entry, ventoy_plugin_persistence_check }, { "menu_alias", ventoy_plugin_menualias_entry, ventoy_plugin_menualias_check }, + { "menu_tip", ventoy_plugin_menutip_entry, ventoy_plugin_menutip_check }, { "menu_class", ventoy_plugin_menuclass_entry, ventoy_plugin_menuclass_check }, { "injection", ventoy_plugin_injection_entry, ventoy_plugin_injection_check }, { "auto_memdisk", ventoy_plugin_auto_memdisk_entry, ventoy_plugin_auto_memdisk_check }, @@ -2149,6 +2321,11 @@ grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **a (void)ctxt; (void)argc; + grub_env_set("VTOY_TIP_LEFT", "10%"); + grub_env_set("VTOY_TIP_TOP", "80%+5"); + grub_env_set("VTOY_TIP_COLOR", "blue"); + grub_env_set("VTOY_TIP_ALIGN", "left"); + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy.json", args[0]); if (!file) { @@ -2205,6 +2382,15 @@ grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **a } } + if (g_menu_tip_head) + { + grub_env_set("VTOY_MENU_TIP_ENABLE", "1"); + } + else + { + grub_env_unset("VTOY_MENU_TIP_ENABLE"); + } + VENTOY_CMD_RETURN(GRUB_ERR_NONE); } @@ -2465,6 +2651,28 @@ const char * ventoy_plugin_get_menu_alias(int type, const char *isopath) return NULL; } +const menu_tip * ventoy_plugin_get_menu_tip(const char *isopath) +{ + int len; + menu_tip *node = NULL; + + if (!g_menu_tip_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + for (node = g_menu_tip_head; node; node = node->next) + { + if (node->pathlen == len && ventoy_strcmp(node->isopath, isopath) == 0) + { + return node; + } + } + + return NULL; +} + const char * ventoy_plugin_get_menu_class(int type, const char *name, const char *path) { int namelen; diff --git a/IMG/cpio/ventoy/init_chain b/IMG/cpio/ventoy/init_chain index 18dba2c5..6f87a5d2 100644 --- a/IMG/cpio/ventoy/init_chain +++ b/IMG/cpio/ventoy/init_chain @@ -185,7 +185,7 @@ ventoy_unpack_injection() { if [ -e $VTOY_PATH/ventoy_injection ]; then echo "### decompress injection ... ###" >>$VTLOG - ventoy_unpack_injection > $VTOY_PATH/injection.log 2>&1 + ventoy_unpack_injection > $VTOY_PATH/injection.log 2>&1 fi diff --git a/IMG/cpio/ventoy/ventoy_chain.sh b/IMG/cpio/ventoy/ventoy_chain.sh index 7b10a96b..7bed6d75 100644 --- a/IMG/cpio/ventoy/ventoy_chain.sh +++ b/IMG/cpio/ventoy/ventoy_chain.sh @@ -350,7 +350,17 @@ fi #################################################################### # # -# Step 3 : Check for debug break # +# Step 3 : Run LiveInjection Hook # +# # +#################################################################### +if [ -f "/live_injection_7ed136ec_7a61_4b54_adc3_ae494d5106ea/hook.sh" ]; then + $BUSYBOX_PATH/sh "/live_injection_7ed136ec_7a61_4b54_adc3_ae494d5106ea/hook.sh" $VTOS +fi + + +#################################################################### +# # +# Step 4 : Check for debug break # # # #################################################################### if [ "$VTOY_BREAK_LEVEL" = "03" ] || [ "$VTOY_BREAK_LEVEL" = "13" ]; then @@ -367,7 +377,7 @@ fi #################################################################### # # -# Step 4 : Hand over to real init # +# Step 5 : Hand over to real init # # # #################################################################### $BUSYBOX_PATH/umount /proc diff --git a/INSTALL/VentoyGUI.aarch64 b/INSTALL/VentoyGUI.aarch64 index d2a2f260..6b1f5dcd 100644 Binary files a/INSTALL/VentoyGUI.aarch64 and b/INSTALL/VentoyGUI.aarch64 differ diff --git a/INSTALL/VentoyGUI.i386 b/INSTALL/VentoyGUI.i386 index 467df8d5..0824dd49 100644 Binary files a/INSTALL/VentoyGUI.i386 and b/INSTALL/VentoyGUI.i386 differ diff --git a/INSTALL/VentoyGUI.mips64el b/INSTALL/VentoyGUI.mips64el index 2e3424e7..46e88287 100644 Binary files a/INSTALL/VentoyGUI.mips64el and b/INSTALL/VentoyGUI.mips64el differ diff --git a/INSTALL/VentoyGUI.x86_64 b/INSTALL/VentoyGUI.x86_64 index 45e47f83..71b6b4bd 100644 Binary files a/INSTALL/VentoyGUI.x86_64 and b/INSTALL/VentoyGUI.x86_64 differ diff --git a/INSTALL/grub/debug.cfg b/INSTALL/grub/debug.cfg index aa833ffa..38e42b50 100644 --- a/INSTALL/grub/debug.cfg +++ b/INSTALL/grub/debug.cfg @@ -112,6 +112,15 @@ submenu 'Check plugin json configuration (ventoy.json)' --class=debug_json --cla unset pager } + menuentry 'Check menu tip plugin configuration' --class=debug_menutip --class=debug_json --class=F5tool { + set pager=1 + vt_check_plugin_json $vt_plugin_path menu_tip $vtoy_iso_part + + echo -e "\npress ENTER to exit ..." + read vtInputKey + unset pager + } + menuentry 'Check menu class plugin configuration' --class=debug_menuclass --class=debug_json --class=F5tool { set pager=1 vt_check_plugin_json $vt_plugin_path menu_class $vtoy_iso_part diff --git a/INSTALL/grub/grub.cfg b/INSTALL/grub/grub.cfg index 4d596b98..cb538c9a 100644 --- a/INSTALL/grub/grub.cfg +++ b/INSTALL/grub/grub.cfg @@ -1075,7 +1075,7 @@ function legacy_linux_menu_func { ventoy_gui_console else ventoy_acpi_param ${vtoy_chain_mem_addr} 2048 - linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size} + linux16 $vtoy_path/ipxe.krn ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size} boot fi else @@ -1963,7 +1963,7 @@ function img_unsupport_menuentry { ############################################################# ############################################################# -set VENTOY_VERSION="1.0.52" +set VENTOY_VERSION="1.0.53" #ACPI not compatible with Window7/8, so disable by default set VTOY_PARAM_NO_ACPI=1 @@ -2032,7 +2032,10 @@ else set vtoydev=$vtoy_dev set vtoy_iso_part=($vtoy_dev,1) set vtoy_efi_part=($vtoy_dev,2) - loadfont unicode + + vt_load_file_to_mem "auto" $prefix/fonts/unicode.pf2 vtoy_font_mem + loadfont mem:${vtoy_font_mem_addr}:size:${vtoy_font_mem_size} + set vt_plugin_path=$vtoy_iso_part fi diff --git a/INSTALL/grub/i386-pc/core.img b/INSTALL/grub/i386-pc/core.img index 727246ff..f6fbc395 100644 Binary files a/INSTALL/grub/i386-pc/core.img and b/INSTALL/grub/i386-pc/core.img differ diff --git a/INSTALL/grub/themes/ventoy/theme.txt b/INSTALL/grub/themes/ventoy/theme.txt index f8815065..75c5f3ab 100644 --- a/INSTALL/grub/themes/ventoy/theme.txt +++ b/INSTALL/grub/themes/ventoy/theme.txt @@ -30,13 +30,15 @@ terminal-box: "terminal_box_*.png" scrollbar_thumb = "slider_*.png" } + + + progress_bar { id = "__timeout__" text = "@TIMEOUT_NOTIFICATION_SHORT@" - left = 20% - width = 60% - top = 85% + left = 90% + width = 10% + top = 90% text_color = "red" bar_style = "*" @@ -93,4 +95,3 @@ terminal-box: "terminal_box_*.png" height = 25 + label {text = "@VTOY_ISO_UEFI_DRV@" color = "red" align = "left"} } - diff --git a/INSTALL/tool/aarch64/V2DServer b/INSTALL/tool/aarch64/V2DServer index 59140e8a..26b4cbb3 100644 Binary files a/INSTALL/tool/aarch64/V2DServer and b/INSTALL/tool/aarch64/V2DServer differ diff --git a/INSTALL/tool/aarch64/Ventoy2Disk.gtk3 b/INSTALL/tool/aarch64/Ventoy2Disk.gtk3 index eba4b62f..9ab248e4 100644 Binary files a/INSTALL/tool/aarch64/Ventoy2Disk.gtk3 and b/INSTALL/tool/aarch64/Ventoy2Disk.gtk3 differ diff --git a/INSTALL/tool/aarch64/Ventoy2Disk.qt5 b/INSTALL/tool/aarch64/Ventoy2Disk.qt5 index f416c31f..eb26488a 100644 Binary files a/INSTALL/tool/aarch64/Ventoy2Disk.qt5 and b/INSTALL/tool/aarch64/Ventoy2Disk.qt5 differ diff --git a/INSTALL/tool/i386/V2DServer b/INSTALL/tool/i386/V2DServer index d5111c62..9e1322e0 100644 Binary files a/INSTALL/tool/i386/V2DServer and b/INSTALL/tool/i386/V2DServer differ diff --git a/INSTALL/tool/i386/Ventoy2Disk.gtk2 b/INSTALL/tool/i386/Ventoy2Disk.gtk2 index 643d797b..32f4e9d8 100644 Binary files a/INSTALL/tool/i386/Ventoy2Disk.gtk2 and b/INSTALL/tool/i386/Ventoy2Disk.gtk2 differ diff --git a/INSTALL/tool/i386/Ventoy2Disk.gtk3 b/INSTALL/tool/i386/Ventoy2Disk.gtk3 index f3ced7bf..1a1ba58e 100644 Binary files a/INSTALL/tool/i386/Ventoy2Disk.gtk3 and b/INSTALL/tool/i386/Ventoy2Disk.gtk3 differ diff --git a/INSTALL/tool/i386/Ventoy2Disk.qt5 b/INSTALL/tool/i386/Ventoy2Disk.qt5 index 1390b35d..0b64ecc7 100644 Binary files a/INSTALL/tool/i386/Ventoy2Disk.qt5 and b/INSTALL/tool/i386/Ventoy2Disk.qt5 differ diff --git a/INSTALL/tool/mips64el/Ventoy2Disk.gtk3 b/INSTALL/tool/mips64el/Ventoy2Disk.gtk3 index 325d9ca9..c4109a45 100644 Binary files a/INSTALL/tool/mips64el/Ventoy2Disk.gtk3 and b/INSTALL/tool/mips64el/Ventoy2Disk.gtk3 differ diff --git a/INSTALL/tool/mips64el/Ventoy2Disk.qt5 b/INSTALL/tool/mips64el/Ventoy2Disk.qt5 index 5a8c24a8..5e7c6a58 100644 Binary files a/INSTALL/tool/mips64el/Ventoy2Disk.qt5 and b/INSTALL/tool/mips64el/Ventoy2Disk.qt5 differ diff --git a/INSTALL/tool/x86_64/V2DServer b/INSTALL/tool/x86_64/V2DServer index 43696c00..19010a41 100644 Binary files a/INSTALL/tool/x86_64/V2DServer and b/INSTALL/tool/x86_64/V2DServer differ diff --git a/INSTALL/tool/x86_64/Ventoy2Disk.gtk2 b/INSTALL/tool/x86_64/Ventoy2Disk.gtk2 index 85a0cea0..ff9cc6b0 100644 Binary files a/INSTALL/tool/x86_64/Ventoy2Disk.gtk2 and b/INSTALL/tool/x86_64/Ventoy2Disk.gtk2 differ diff --git a/INSTALL/tool/x86_64/Ventoy2Disk.gtk3 b/INSTALL/tool/x86_64/Ventoy2Disk.gtk3 index 5f1b9cd2..38ca766b 100644 Binary files a/INSTALL/tool/x86_64/Ventoy2Disk.gtk3 and b/INSTALL/tool/x86_64/Ventoy2Disk.gtk3 differ diff --git a/INSTALL/tool/x86_64/Ventoy2Disk.qt5 b/INSTALL/tool/x86_64/Ventoy2Disk.qt5 index b9536a62..8bd405b4 100644 Binary files a/INSTALL/tool/x86_64/Ventoy2Disk.qt5 and b/INSTALL/tool/x86_64/Ventoy2Disk.qt5 differ