From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1p29fk-00026P-UK for mharc-grub-devel@gnu.org; Mon, 05 Dec 2022 06:30:10 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p29fi-00025z-UQ for grub-devel@gnu.org; Mon, 05 Dec 2022 06:30:06 -0500 Received: from mail-pj1-x1035.google.com ([2607:f8b0:4864:20::1035]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p29fg-00058i-IG for grub-devel@gnu.org; Mon, 05 Dec 2022 06:30:06 -0500 Received: by mail-pj1-x1035.google.com with SMTP id o1-20020a17090a678100b00219cf69e5f0so2553483pjj.2 for ; Mon, 05 Dec 2022 03:30:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=JxoAdNn0880DIrfXHq/1N55WjSYPnsYYsLYbA4EZU+o=; b=Mjbb8BitQq5Ug1jDiZGK2zvYPGOBED56hm9GFWnzPqhBBWncPnPMYVgpZj1Qdq7MCY zfofcjecNeRFczCno3SSSUzcnIZ0wrieuJiUb8K66FMJ7SvZQNay/3EoJKqn1jeRpaA9 cqcHfyjhr96+pOvy9QkB5ELRN/4A/UnEASdzdxB5MbX0rkdEazdbo0hPHhdTdka5dQr0 9H0wv/fVQcTy9pZ1Z5CiUcb1PCDQkC6yzAUR0graPFZ+S5xtOzEZzMZ9TeEtQDYt+WN9 3ShXclw/ydyi3YqCcpJ1HlQzOC9qxoAkLjVx0beZy8vtV6V20Km7/tOnN55s+5/cVqlP 3wrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JxoAdNn0880DIrfXHq/1N55WjSYPnsYYsLYbA4EZU+o=; b=3xsSHEBLWddAiigsyYprPQZdujPW+KrzJz1BOYXmjQ542MAHnIFF0BynUMwks+kr5Z m1edr0cfyEEm0+X14munb6aIquJixp4ooi7SEvI1nTT93VTEXfQOg7FPHiZpSVAeMC5c mRwbNoUhi2sOimzLUSwjMgTfQpbNWY+ervsr+Bsy6bGKEp9pWOfy0+5P6V6TpTMSuGYx WfHJUl79DGEuUAooNZEbc3GutYmwofNVwGyIw5fqxWwMjTC0ZV5hBnSC0gk1N2PlYPOM MIHIsEmOh5zAIqgT174EhlLuZpKSdJ0V+aVaM8zo0Fp4Q97QQdks8ppVKLLYmVzyCsCu ho9g== X-Gm-Message-State: ANoB5pkqe/Bx9orFOUdPzA0Gf72oOCfKAhie+d8ZcVK5kEWzVwqZT3Vf Vzeswh2LulFha38EiMDSGBgGaWXPG/s= X-Google-Smtp-Source: AA0mqf4I/sIrooLGxH/+iRsX7SApLc8XXQ9M2M8gaum3dMOFufIjpiK7T5ZPhMit9GEt0CILAo3gMA== X-Received: by 2002:a17:902:f292:b0:189:91b8:bf92 with SMTP id k18-20020a170902f29200b0018991b8bf92mr34238818plc.19.1670239803214; Mon, 05 Dec 2022 03:30:03 -0800 (PST) Received: from localhost.localdomain (ec2-13-113-80-70.ap-northeast-1.compute.amazonaws.com. [13.113.80.70]) by smtp.gmail.com with ESMTPSA id b7-20020a170902650700b0018869119e37sm10381729plk.142.2022.12.05.03.30.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Dec 2022 03:30:02 -0800 (PST) From: Zhang Boyang To: grub-devel@gnu.org Cc: Zhang Boyang Subject: [PATCH 4/5] font: Add font scaling feature to grub_font_draw_glyph() Date: Mon, 5 Dec 2022 19:29:39 +0800 Message-Id: <20221205112940.246486-5-zhangboyang.id@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221205112940.246486-1-zhangboyang.id@gmail.com> References: <20221205112940.246486-1-zhangboyang.id@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2607:f8b0:4864:20::1035; envelope-from=zhangboyang.id@gmail.com; helo=mail-pj1-x1035.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 05 Dec 2022 11:30:07 -0000 This patch adds an argument 'scale' to grub_font_draw_glyph(). If scale > 1, then the function will create a new scaled bitmap of the drawing glyph, and draws the scaled glyph. The scaled bitmap is cached in the glyph itself, so it can be reused if same glyph is used many times. This patch also adds a new metadata entry named MAXS to font files, limiting the maximum acceptable scale factor at runtime for a specific font. Currently MAXS is set to 8, which is sufficient for 16K monitors. Signed-off-by: Zhang Boyang --- grub-core/commands/videotest.c | 4 +- grub-core/font/font.c | 91 +++++++++++++++++++++++++++++++--- grub-core/gfxmenu/font.c | 2 +- grub-core/term/gfxterm.c | 2 +- include/grub/font.h | 9 +++- 5 files changed, 97 insertions(+), 11 deletions(-) diff --git a/grub-core/commands/videotest.c b/grub-core/commands/videotest.c index ac145afc2..d95ee411d 100644 --- a/grub-core/commands/videotest.c +++ b/grub-core/commands/videotest.c @@ -87,7 +87,7 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), return grub_error (GRUB_ERR_BAD_FONT, "no font loaded"); glyph = grub_font_get_glyph (fixed, '*'); - grub_font_draw_glyph (glyph, color, 200 ,0); + grub_font_draw_glyph (glyph, color, 200, 0, 1); color = grub_video_map_rgb (255, 255, 255); @@ -148,7 +148,7 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), { color = grub_video_map_color (i); palette[i] = color; - grub_font_draw_glyph (glyph, color, 16 + i * 16, 220); + grub_font_draw_glyph (glyph, color, 16 + i * 16, 220, 1); } } diff --git a/grub-core/font/font.c b/grub-core/font/font.c index 24adcb35a..536cbde71 100644 --- a/grub-core/font/font.c +++ b/grub-core/font/font.c @@ -142,6 +142,8 @@ ascii_glyph_lookup (grub_uint32_t code) 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]->scaled_bitmap = NULL; + ascii_font_glyph[current]->scale = 0; ascii_font_glyph[current]->font = &null_font; grub_memcpy (ascii_font_glyph[current]->bitmap, @@ -177,6 +179,8 @@ grub_font_loader_init (void) unknown_glyph->offset_x = 0; unknown_glyph->offset_y = -3; unknown_glyph->device_width = 8; + unknown_glyph->scaled_bitmap = NULL; + unknown_glyph->scale = 0; unknown_glyph->font = &null_font; grub_memcpy (unknown_glyph->bitmap, unknown_glyph_bitmap, sizeof (unknown_glyph_bitmap)); @@ -806,6 +810,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) glyph->offset_x = xoff; glyph->offset_y = yoff; glyph->device_width = dwidth; + glyph->scaled_bitmap = NULL; + glyph->scale = 0; /* Don't try to read empty bitmaps (e.g., space characters). */ if (len != 0) @@ -813,6 +819,7 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) if (grub_file_read (font->file, glyph->bitmap, len) != len) { remove_font (font); + grub_free (glyph->scaled_bitmap); grub_free (glyph); return 0; } @@ -1559,10 +1566,19 @@ grub_font_construct_glyph (grub_font_t hinted_font, if (max_glyph_size < cur_glyph_size) { - grub_free (glyph); + if (glyph) + { + grub_free (glyph->scaled_bitmap); + grub_free (glyph); + } if (grub_mul (cur_glyph_size, 2, &max_glyph_size)) max_glyph_size = 0; glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL; + if (glyph) + { + glyph->scaled_bitmap = NULL; + glyph->scale = 0; + } } if (!glyph) { @@ -1571,9 +1587,12 @@ grub_font_construct_glyph (grub_font_t hinted_font, return main_glyph; } + grub_free (glyph->scaled_bitmap); grub_memset (glyph, 0, cur_glyph_size); glyph->font = main_glyph->font; + glyph->scaled_bitmap = NULL; + glyph->scale = 0; if (bounds.width == 0 || bounds.height == 0 || grub_cast (bounds.width, &glyph->width) || grub_cast (bounds.height, &glyph->height) || @@ -1598,12 +1617,55 @@ grub_font_construct_glyph (grub_font_t hinted_font, return glyph; } +/* + * Scale the glyph bitmap by `scale` times. + * If succeeded, scaled bitmap will be stored at glyph->scaled_bitmap, and + * the corresponding scale factor will be stored at glyph->scale. + * If failed, glyph will not be touched. + */ +static void +try_scale_glyph (struct grub_font_glyph *glyph, int scale) +{ + unsigned i, j, src_bit, dst_bit; + int pixel; + grub_uint16_t new_width, new_height; + grub_size_t bitmap_size; + grub_uint8_t *bitmap; + + if (glyph->scale == scale) + return; + + if (grub_mul (glyph->width, scale, &new_width) || + grub_mul (glyph->height, scale, &new_height)) + return; + + if (grub_video_bitmap_calc_1bpp_bufsz (new_width, new_height, &bitmap_size)) + return; + bitmap = grub_zalloc (bitmap_size); + if (bitmap == NULL) + return; + + for (i = 0; i < new_height; i++) + for (j = 0; j < new_width; j++) + { + src_bit = (i / scale) * glyph->width + (j / scale); + dst_bit = i * new_width + j; + pixel = (glyph->bitmap[src_bit / 8] >> (7 - src_bit % 8)) & 1; + bitmap[dst_bit / 8] |= pixel << (7 - dst_bit % 8); + } + + grub_free (glyph->scaled_bitmap); + glyph->scaled_bitmap = bitmap; + glyph->scale = scale; +} + /* 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) + grub_video_color_t color, int left_x, int baseline_y, + int scale) { struct grub_video_bitmap glyph_bitmap; @@ -1636,11 +1698,28 @@ grub_font_draw_glyph (struct grub_font_glyph * glyph, &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; + if (scale > 1) + try_scale_glyph (glyph, scale); + + if (glyph->scale == scale) + { + glyph_bitmap.mode_info.width = glyph->width * scale; + glyph_bitmap.mode_info.height = glyph->height * scale; + glyph_bitmap.mode_info.pitch = glyph->width * scale; + glyph_bitmap.data = glyph->scaled_bitmap; + } + else + { + /* Scaled bitmap not suitable, fallback to no-scale. */ + scale = 1; + } + + int bitmap_left = left_x + glyph->offset_x * scale; + int bitmap_bottom = baseline_y - glyph->offset_y * scale; + int bitmap_top = bitmap_bottom - glyph->height * scale; return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND, bitmap_left, bitmap_top, - 0, 0, glyph->width, glyph->height); + 0, 0, + glyph->width * scale, glyph->height * scale); } diff --git a/grub-core/gfxmenu/font.c b/grub-core/gfxmenu/font.c index 756c24f20..ed59ca954 100644 --- a/grub-core/gfxmenu/font.c +++ b/grub-core/gfxmenu/font.c @@ -67,7 +67,7 @@ grub_font_draw_string (const char *str, grub_font_t font, err = grub_errno; goto out; } - err = grub_font_draw_glyph (glyph, color, x, baseline_y); + err = grub_font_draw_glyph (glyph, color, x, baseline_y, 1); if (err) goto out; x += glyph->device_width; diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index 3c468f459..4512dee6f 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -656,7 +656,7 @@ paint_char (unsigned cx, unsigned cy) /* Render glyph to text layer. */ grub_video_set_active_render_target (text_layer); grub_video_fill_rect (bgcolor, x, y, width, height); - grub_font_draw_glyph (glyph, color, x, y + ascent); + grub_font_draw_glyph (glyph, color, x, y + ascent, 1); grub_video_set_active_render_target (render_target); /* Mark character to be drawn. */ diff --git a/include/grub/font.h b/include/grub/font.h index 708fa42ac..6417e5b58 100644 --- a/include/grub/font.h +++ b/include/grub/font.h @@ -79,6 +79,12 @@ struct grub_font_glyph /* Number of pixels to advance to start the next character. */ grub_uint16_t device_width; + /* Pointer to cached scaled bitmap. Allocated during a scaling drawing. */ + grub_uint8_t *scaled_bitmap; + + /* The scale factor for cached scaled bitmap. */ + int scale; + /* Row-major order, packed bits (no padding; rows can break within a byte). The length of the array is (width * height + 7) / 8. Within a byte, the most significant bit is the first (leftmost/uppermost) pixel. @@ -141,7 +147,8 @@ struct grub_font_glyph *EXPORT_FUNC (grub_font_get_glyph_with_fallback) (grub_fo grub_err_t EXPORT_FUNC (grub_font_draw_glyph) (struct grub_font_glyph *glyph, grub_video_color_t color, - int left_x, int baseline_y); + int left_x, int baseline_y, + int scale); int EXPORT_FUNC (grub_font_get_constructed_device_width) (grub_font_t hinted_font, -- 2.30.2