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