From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1p29fu-00029A-CE for mharc-grub-devel@gnu.org; Mon, 05 Dec 2022 06:30:19 -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 1p29fm-00026j-WA for grub-devel@gnu.org; Mon, 05 Dec 2022 06:30:12 -0500 Received: from mail-pj1-x102f.google.com ([2607:f8b0:4864:20::102f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1p29fk-0005KT-5V for grub-devel@gnu.org; Mon, 05 Dec 2022 06:30:10 -0500 Received: by mail-pj1-x102f.google.com with SMTP id u5so1540637pjy.5 for ; Mon, 05 Dec 2022 03:30:07 -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=fbkv/iOmJzVT0498+KWF6mul2KjJiJPDISgOCowyoxs=; b=Gcpmra6kek3Znssye20zYKbLhE1nqL0bJ05kf+FseDyFy8YF6rOydUDmYYg9ixqlXc zdz0ZWq/tIUt0kDzrBF06J1Qjr7FEOVB2lOTXPAKAhgdXJO3Nyijrk43iS9TIF0p1gCk q9U0yF9ak5Gomg60/o1pm2ft7FtB0UY+xiefJ+YTEYkJDpjZHN1cojkSzeTOPFKExHtP uE5H+cc31/j1wzwxDJy+7+EAneIKfYHvqs78eXrQMeBF31GdSF4iJYT0K9Ay/HJcwXVT ifsMi89FAICyAcw02MKPVNsWjWc+oS2C+b4j6sxHCAuMb6OuYzfF7L2B7Rl6V17bTnYl engg== 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=fbkv/iOmJzVT0498+KWF6mul2KjJiJPDISgOCowyoxs=; b=vrijhTcUb/XpssesPRF1Q2JbdYBmV/YgD5QkMC5vZQQfonKuKdyu2WdvMgdLM8gGl+ F8O34+A77ZiztYkSd/dHyO5LCLk9+EIUYGbc1b4OLsRg8OUCkOcAdfYRW5Aupv8M8ZKQ 3gl8GTuGAA3TEKKLS+W6Wnf1TjDV3WLAUeeK5PGu7P6CJtFdEPJRXB6V5D2tZQiLpJEC dHFYON+0W+QgJtpkgaVuH+YsC/nmT78KKIsOYoSxPf6Z/Ol5GkEdfU9XiQi+4ZQgVhfM OCQ5wE64pd4xZJoatOVZdVWUx+HLwONmw0T4LQmm7FnQJjV6vL1ariMZwbz9/CNj2mfv 5HFA== X-Gm-Message-State: ANoB5pl+NbI5LzC3tjw90ZXO6D0M7HNgU6zOPr4mq21S9nhBuXeKDC0v 5cEIvVU0fBLNfL1vSA/efHDw8wzQm2o= X-Google-Smtp-Source: AA0mqf75HINRxoawaZkRtBXp34PoKcMjqEhsqwbbcPcL5PYtlQcqqSDIhAr0QIvjuqOL+sBNNNH3kQ== X-Received: by 2002:a17:902:b094:b0:189:cae0:ea27 with SMTP id p20-20020a170902b09400b00189cae0ea27mr8919329plr.90.1670239805474; Mon, 05 Dec 2022 03:30:05 -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.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Dec 2022 03:30:05 -0800 (PST) From: Zhang Boyang To: grub-devel@gnu.org Cc: Zhang Boyang Subject: [PATCH 5/5] term/gfxterm: Preliminary HiDPI support Date: Mon, 5 Dec 2022 19:29:40 +0800 Message-Id: <20221205112940.246486-6-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::102f; envelope-from=zhangboyang.id@gmail.com; helo=mail-pj1-x102f.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:12 -0000 Currently GRUB's default font is too small to see on a HiDPI monitor. This patch adds preliminary HiDPI support to gfxterm. It introduces a new environment variable 'gfxterm_scale'. If set to 0, and a high resolution monitor is detected, it will scale the font size automatically. If set to other number, that number will be the scale factor, overriding automatic scale factor calculation. Signed-off-by: Zhang Boyang --- docs/grub.texi | 11 ++++ grub-core/gfxmenu/view.c | 1 + grub-core/term/gfxterm.c | 120 ++++++++++++++++++++++++++++++++------- include/grub/gfxterm.h | 8 ++- 4 files changed, 117 insertions(+), 23 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index 50c811a88..b754a465b 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3309,6 +3309,7 @@ These variables have special meaning to GRUB. * gfxmode:: * gfxpayload:: * gfxterm_font:: +* gfxterm_scale:: * grub_cpu:: * grub_platform:: * icondir:: @@ -3588,6 +3589,16 @@ If this variable is set, it names a font to use for text on the available font. +@node gfxterm_scale +@subsection gfxterm_scale + +If this variable is not set, or set to @samp{0}, the @samp{gfxterm} +graphical terminal will scale the font automatically when a high resolution +monitor is detected. If set to other number, the font scale factor will be +forced to that number. Set this to @samp{1} if user don't want +@samp{gfxterm} to scale the font on screen. + + @node grub_cpu @subsection grub_cpu diff --git a/grub-core/gfxmenu/view.c b/grub-core/gfxmenu/view.c index 6358004b2..94b9ef4db 100644 --- a/grub-core/gfxmenu/view.c +++ b/grub-core/gfxmenu/view.c @@ -546,6 +546,7 @@ init_terminal (grub_gfxmenu_view_t view) view->terminal_rect.height, view->double_repaint, terminal_font, + 1, view->terminal_border); grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box; } diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index 4512dee6f..d16410f5e 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -37,6 +37,13 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define DEFAULT_STANDARD_COLOR 0x07 +/* Arbitrarily pick half of 80x24 as minimum number of rows and columns. */ +#define MIN_COL 40 +#define MIN_ROW 12 + +/* For 8x16 fonts, 8x is sufficient on a 16K monitor. */ +#define MAX_SCALE 8 + struct grub_dirty_region { int top_left_x; @@ -65,6 +72,9 @@ struct grub_virtual_screen unsigned int offset_x; unsigned int offset_y; + /* Scale factor. */ + int scale; + /* TTY Character sizes in pixes. */ unsigned int normal_char_width; unsigned int normal_char_height; @@ -201,10 +211,51 @@ grub_virtual_screen_free (void) text_layer = 0; } +/* + * Adjust scale factor, `scale` can be any untrusted value. + * If `scale` is 0, determine scale factor heuristically. + * Returns the adjusted value, which is always in [1, MAX_SCALE]. + */ +int +grub_gfxterm_adjust_scale_factor (grub_font_t font, int scale, + int width, int height, + int border_width) +{ + int i; + int max_scale; + int normal_char_width, normal_char_height; + int columns, rows; + + normal_char_width = calculate_normal_character_width (font); + normal_char_height = grub_font_get_max_char_height (font); + + max_scale = 1; + for (i = 2; i <= MAX_SCALE; i++) + { + columns = (width - 2 * border_width * i) / (normal_char_width * i); + rows = (height - 2 * border_width * i) / (normal_char_height * i); + if (columns < MIN_COL || rows < MIN_ROW) + break; + max_scale = i; + } + + if (scale == 0) + { + scale = 1; + for (i = 2; i <= MAX_SCALE; i *= 2) + if (width > 1920 * (i / 2) && height > 1080 * (i / 2)) + scale = i; + } + + scale = grub_max (scale, 1); + scale = grub_min (scale, max_scale); + return scale; +} + static grub_err_t grub_virtual_screen_setup (unsigned int x, unsigned int y, unsigned int width, unsigned int height, - grub_font_t font) + grub_font_t font, int scale) { unsigned int i; @@ -213,16 +264,17 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, /* Initialize with default data. */ virtual_screen.font = font; + virtual_screen.scale = scale; virtual_screen.width = width; virtual_screen.height = height; virtual_screen.offset_x = x; virtual_screen.offset_y = y; virtual_screen.normal_char_width = - calculate_normal_character_width (virtual_screen.font); + calculate_normal_character_width (virtual_screen.font) * virtual_screen.scale; virtual_screen.normal_char_height = - grub_font_get_max_char_height (virtual_screen.font); + grub_font_get_max_char_height (virtual_screen.font) * virtual_screen.scale; if (virtual_screen.normal_char_height == 0) - virtual_screen.normal_char_height = 16; + virtual_screen.normal_char_height = 16 * virtual_screen.scale; virtual_screen.cursor_x = 0; virtual_screen.cursor_y = 0; virtual_screen.cursor_state = 1; @@ -234,10 +286,10 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, /* * There must be a minimum number of rows and columns for the screen to - * make sense. Arbitrarily pick half of 80x24. If either dimensions is 0 - * we would allocate 0 bytes for the text_buffer. + * make sense. If either dimensions is 0 we would allocate 0 bytes for + * the text_buffer. */ - if (virtual_screen.columns < 40 || virtual_screen.rows < 12) + if (virtual_screen.columns < MIN_COL || virtual_screen.rows < MIN_ROW) return grub_error (GRUB_ERR_BAD_FONT, "font: glyphs too large to fit on screen"); @@ -297,7 +349,8 @@ grub_err_t grub_gfxterm_set_window (struct grub_video_render_target *target, int x, int y, int width, int height, int double_repaint, - grub_font_t font, int border_width) + grub_font_t font, int scale, + int border_width) { /* Clean up any prior instance. */ destroy_window (); @@ -306,10 +359,10 @@ grub_gfxterm_set_window (struct grub_video_render_target *target, render_target = target; /* Create virtual screen. */ - if (grub_virtual_screen_setup (border_width, border_width, - width - 2 * border_width, - height - 2 * border_width, - font) + if (grub_virtual_screen_setup (border_width * scale, border_width * scale, + width - 2 * border_width * scale, + height - 2 * border_width * scale, + font, scale) != GRUB_ERR_NONE) { return grub_errno; @@ -337,6 +390,8 @@ grub_gfxterm_fullscreen (void) grub_err_t err; int double_redraw; grub_font_t font; + int scale; + const char *scale_str; err = grub_video_get_info (&mode_info); /* Figure out what mode we ended up. */ @@ -366,12 +421,32 @@ grub_gfxterm_fullscreen (void) if (!font) return grub_error (GRUB_ERR_BAD_FONT, "no font loaded"); + /* Decide scale factor. */ + scale = 0; + + scale_str = grub_env_get ("gfxterm_scale"); + if (scale_str) + { + const char *scale_str_end; + unsigned long scale_ull; + grub_error_push (); + scale_ull = grub_strtoull (scale_str, &scale_str_end, 10); + if (*scale_str == '\0' || *scale_str_end != '\0' || grub_errno != GRUB_ERR_NONE + || grub_cast (scale_ull, &scale)) + scale = 0; + grub_error_pop (); + } + + scale = grub_gfxterm_adjust_scale_factor (font, scale, + mode_info.width, mode_info.height, + DEFAULT_BORDER_WIDTH); + grub_gfxterm_decorator_hook = NULL; return grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, 0, 0, mode_info.width, mode_info.height, double_redraw, - font, DEFAULT_BORDER_WIDTH); + font, scale, DEFAULT_BORDER_WIDTH); } static grub_err_t @@ -642,7 +717,7 @@ paint_char (unsigned cx, unsigned cy) grub_errno = GRUB_ERR_NONE; return; } - ascent = grub_font_get_ascent (virtual_screen.font); + ascent = grub_font_get_ascent (virtual_screen.font) * virtual_screen.scale; width = virtual_screen.normal_char_width * calculate_character_width(glyph); height = virtual_screen.normal_char_height; @@ -656,7 +731,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, 1); + grub_font_draw_glyph (glyph, color, x, y + ascent, virtual_screen.scale); grub_video_set_active_render_target (render_target); /* Mark character to be drawn. */ @@ -690,9 +765,9 @@ draw_cursor (int show) return; /* Ensure that cursor doesn't go outside of character box. */ - ascent = grub_font_get_ascent(virtual_screen.font); - if (ascent > virtual_screen.normal_char_height - 2) - ascent = virtual_screen.normal_char_height - 2; + ascent = grub_font_get_ascent(virtual_screen.font) * virtual_screen.scale; + if (ascent > virtual_screen.normal_char_height - 2 * virtual_screen.scale) + ascent = virtual_screen.normal_char_height - 2 * virtual_screen.scale; /* Determine cursor properties and position on text layer. */ x = virtual_screen.cursor_x * virtual_screen.normal_char_width; @@ -701,7 +776,7 @@ draw_cursor (int show) y = ((virtual_screen.cursor_y + virtual_screen.total_scroll) * virtual_screen.normal_char_height + ascent); - height = 2; + height = 2 * virtual_screen.scale; /* Render cursor to text layer. */ grub_video_set_active_render_target (text_layer); @@ -968,7 +1043,7 @@ calculate_character_width (struct grub_font_glyph *glyph) if (! glyph || glyph->device_width == 0) return 1; - return (glyph->device_width + return (glyph->device_width * virtual_screen.scale + (virtual_screen.normal_char_width - 1)) / virtual_screen.normal_char_width; } @@ -983,8 +1058,9 @@ grub_gfxterm_getcharwidth (struct grub_term_output *term __attribute__ ((unused) if (dev_width == 0) return 1; - return (dev_width + (virtual_screen.normal_char_width - 1)) - / virtual_screen.normal_char_width; + return (dev_width * virtual_screen.scale + + (virtual_screen.normal_char_width - 1)) + / virtual_screen.normal_char_width; } static struct grub_term_coordinate diff --git a/include/grub/gfxterm.h b/include/grub/gfxterm.h index 7e1ff6dfc..6cd99dd54 100644 --- a/include/grub/gfxterm.h +++ b/include/grub/gfxterm.h @@ -25,11 +25,17 @@ #include #include +int +EXPORT_FUNC (grub_gfxterm_adjust_scale_factor) (grub_font_t font, int scale, + int width, int height, + int border_width); + grub_err_t EXPORT_FUNC (grub_gfxterm_set_window) (struct grub_video_render_target *target, int x, int y, int width, int height, int double_repaint, - grub_font_t font, int border_width); + grub_font_t font, int scale, + int border_width); void EXPORT_FUNC (grub_gfxterm_schedule_repaint) (void); -- 2.30.2