* grub-core/gfxmenu/theme_loader.c: New global options for the

theme background image handling. desktop-image-scale-method,
       desktop-image-h-align, desktop-image-v-align.
       * grub-core/gfxmenu/view.c: Likewise.
       * include/gfxmenu_view.h: Likewise.
       * include/bitmap_scale.h: Proportional scale functions introduced.
       * grub-core/video/bitmap_scale.c: Likewise. Verification checks are
       put in a separate functions. GRUB_ERR_BUG is set for grub_error in
       cases of unexpected input variables for scale functions.
       * docs/grub.texi: Updated documentation for new options.
This commit is contained in:
Vladimir Testov 2013-10-02 18:17:33 +04:00
parent c573914389
commit ebc1da55cd
7 changed files with 417 additions and 107 deletions

View file

@ -1,3 +1,16 @@
2013-10-02 Vladimir Testov <vladimir.testov@rosalab.ru>
* grub-core/gfxmenu/theme_loader.c: New global options for the
theme background image handling. desktop-image-scale-method,
desktop-image-h-align, desktop-image-v-align.
* grub-core/gfxmenu/view.c: Likewise.
* include/gfxmenu_view.h: Likewise.
* include/bitmap_scale.h: Proportional scale functions introduced.
* grub-core/video/bitmap_scale.c: Likewise. Verification checks are
put in a separate functions. GRUB_ERR_BUG is set for grub_error in
cases of unexpected input variables for scale functions.
* docs/grub.texi: Updated documentation for new options.
2013-10-02 Vladimir Serbinenko <phcoder@gmail.com> 2013-10-02 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/video/readers/png.c: Support narrow (4-/2-/1-bpp) PNG. * grub-core/video/readers/png.c: Support narrow (4-/2-/1-bpp) PNG.

View file

@ -1907,7 +1907,28 @@ In this example, name3 is assigned a color value.
@item message-font @tab Defines the font used for messages, such as when GRUB is unable to automatically boot an entry. @item message-font @tab Defines the font used for messages, such as when GRUB is unable to automatically boot an entry.
@item message-color @tab Defines the color of the message text. @item message-color @tab Defines the color of the message text.
@item message-bg-color @tab Defines the background color of the message text area. @item message-bg-color @tab Defines the background color of the message text area.
@item desktop-image @tab Specifies the image to use as the background. It will be scaled to fit the screen size. @item desktop-image
@tab Specifies the image to use as the background. It will be scaled
to fit the screen size or proportionally scaled depending on the scale
method.
@item desktop-image-scale-method
@tab Specifies the scaling method for the *desktop-image*. Options are
``stretch``, ``crop``, ``padding``, ``fitwidth``, ``fitheight``.
``stretch`` for fitting the screen size. Otherwise it is proportional
scaling of a part of *desktop-image* to the part of the screen.
``crop`` part of the *desktop-image* will be proportionally scaled to
fit the screen sizes. ``padding`` the entire *desktop-image* will be
contained on the screen. ``fitwidth`` for fitting the *desktop-image*'s
width with screen width. ``fitheight`` for fitting the *desktop-image*'s
height with the screen height. Default is ``stretch``.
@item desktop-image-h-align
@tab Specifies the horizontal alignment of the *desktop-image* if
*desktop-image-scale-method* isn't equeal to ``stretch``. Options are
``left``, ``center``, ``right``. Default is ``center``.
@item desktop-image-v-align
@tab Specifies the vertical alignment of the *desktop-image* if
*desktop-image-scale-method* isn't equeal to ``stretch``. Options are
``top``, ``center``, ``bottom``. Default is ``center``.
@item desktop-color @tab Specifies the color for the background if *desktop-image* is not specified. @item desktop-color @tab Specifies the color for the background if *desktop-image* is not specified.
@item terminal-box @tab Specifies the file name pattern for the styled box slices used for the command line terminal window. For example, ``terminal-box: terminal_*.png'' will use the images ``terminal_c.png`` as the center area, ``terminal_n.png`` as the north (top) edge, ``terminal_nw.png`` as the northwest (upper left) corner, and so on. If the image for any slice is not found, it will simply be left empty. @item terminal-box @tab Specifies the file name pattern for the styled box slices used for the command line terminal window. For example, ``terminal-box: terminal_*.png'' will use the images ``terminal_c.png`` as the center area, ``terminal_n.png`` as the north (top) edge, ``terminal_nw.png`` as the northwest (upper left) corner, and so on. If the image for any slice is not found, it will simply be left empty.
@item terminal-border @tab Specifies the border width of the terminal window. @item terminal-border @tab Specifies the border width of the terminal window.

View file

@ -165,7 +165,6 @@ theme_set_string (grub_gfxmenu_view_t view,
else if (! grub_strcmp ("desktop-image", name)) else if (! grub_strcmp ("desktop-image", name))
{ {
struct grub_video_bitmap *raw_bitmap; struct grub_video_bitmap *raw_bitmap;
struct grub_video_bitmap *scaled_bitmap;
char *path; char *path;
path = grub_resolve_relative_path (theme_dir, value); path = grub_resolve_relative_path (theme_dir, value);
if (! path) if (! path)
@ -176,20 +175,56 @@ theme_set_string (grub_gfxmenu_view_t view,
return grub_errno; return grub_errno;
} }
grub_free(path); grub_free(path);
grub_video_bitmap_create_scaled (&scaled_bitmap, grub_video_bitmap_destroy (view->raw_desktop_image);
view->screen.width, view->raw_desktop_image = raw_bitmap;
view->screen.height, }
raw_bitmap, else if (! grub_strcmp ("desktop-image-scale-method", name))
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); {
grub_video_bitmap_destroy (raw_bitmap); if (! value || ! grub_strcmp ("stretch", value))
if (! scaled_bitmap) view->desktop_image_scale_method =
{ GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH;
grub_error_push (); else if (! grub_strcmp ("crop", value))
return grub_error (grub_errno, "error scaling desktop image"); view->desktop_image_scale_method =
} GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP;
else if (! grub_strcmp ("padding", value))
grub_video_bitmap_destroy (view->desktop_image); view->desktop_image_scale_method =
view->desktop_image = scaled_bitmap; GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING;
else if (! grub_strcmp ("fitwidth", value))
view->desktop_image_scale_method =
GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH;
else if (! grub_strcmp ("fitheight", value))
view->desktop_image_scale_method =
GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT;
else
return grub_error (GRUB_ERR_BAD_ARGUMENT,
_("Unsupported scale method: %s"),
grub_strdup (value));
}
else if (! grub_strcmp ("desktop-image-h-align", name))
{
if (! grub_strcmp ("left", value))
view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_LEFT;
else if (! grub_strcmp ("center", value))
view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER;
else if (! grub_strcmp ("right", value))
view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT;
else
return grub_error (GRUB_ERR_BAD_ARGUMENT,
_("Unsupported horizontal align method: %s"),
grub_strdup (value));
}
else if (! grub_strcmp ("desktop-image-v-align", name))
{
if (! grub_strcmp ("top", value))
view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_TOP;
else if (! grub_strcmp ("center", value))
view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER;
else if (! grub_strcmp ("bottom", value))
view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM;
else
return grub_error (GRUB_ERR_BAD_ARGUMENT,
_("Unsupported vertical align method: %s"),
grub_strdup (value));
} }
else if (! grub_strcmp ("desktop-color", name)) else if (! grub_strcmp ("desktop-color", name))
grub_video_parse_color (value, &view->desktop_color); grub_video_parse_color (value, &view->desktop_color);

View file

@ -40,6 +40,8 @@
static void static void
init_terminal (grub_gfxmenu_view_t view); init_terminal (grub_gfxmenu_view_t view);
static void
init_background (grub_gfxmenu_view_t view);
static grub_gfxmenu_view_t term_view; static grub_gfxmenu_view_t term_view;
/* Create a new view object, loading the theme specified by THEME_PATH and /* Create a new view object, loading the theme specified by THEME_PATH and
@ -91,7 +93,11 @@ grub_gfxmenu_view_new (const char *theme_path,
view->title_color = default_fg_color; view->title_color = default_fg_color;
view->message_color = default_bg_color; view->message_color = default_bg_color;
view->message_bg_color = default_fg_color; view->message_bg_color = default_fg_color;
view->desktop_image = 0; view->raw_desktop_image = 0;
view->scaled_desktop_image = 0;
view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH;
view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER;
view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER;
view->desktop_color = default_bg_color; view->desktop_color = default_bg_color;
view->terminal_box = grub_gfxmenu_create_box (0, 0); view->terminal_box = grub_gfxmenu_create_box (0, 0);
view->title_text = grub_strdup (_("GRUB Boot Menu")); view->title_text = grub_strdup (_("GRUB Boot Menu"));
@ -128,7 +134,8 @@ grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view)
grub_gfxmenu_timeout_notifications = grub_gfxmenu_timeout_notifications->next; grub_gfxmenu_timeout_notifications = grub_gfxmenu_timeout_notifications->next;
grub_free (p); grub_free (p);
} }
grub_video_bitmap_destroy (view->desktop_image); grub_video_bitmap_destroy (view->raw_desktop_image);
grub_video_bitmap_destroy (view->scaled_desktop_image);
if (view->terminal_box) if (view->terminal_box)
view->terminal_box->destroy (view->terminal_box); view->terminal_box->destroy (view->terminal_box);
grub_free (view->terminal_font_name); grub_free (view->terminal_font_name);
@ -144,9 +151,9 @@ static void
redraw_background (grub_gfxmenu_view_t view, redraw_background (grub_gfxmenu_view_t view,
const grub_video_rect_t *bounds) const grub_video_rect_t *bounds)
{ {
if (view->desktop_image) if (view->scaled_desktop_image)
{ {
struct grub_video_bitmap *img = view->desktop_image; struct grub_video_bitmap *img = view->scaled_desktop_image;
grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE, grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE,
bounds->x, bounds->y, bounds->x, bounds->y,
bounds->x - view->screen.x, bounds->x - view->screen.x,
@ -328,6 +335,8 @@ grub_gfxmenu_view_draw (grub_gfxmenu_view_t view)
{ {
init_terminal (view); init_terminal (view);
init_background (view);
/* Clear the screen; there may be garbage left over in video memory. */ /* Clear the screen; there may be garbage left over in video memory. */
grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), grub_video_fill_rect (grub_video_map_rgb (0, 0, 0),
view->screen.x, view->screen.y, view->screen.x, view->screen.y,
@ -524,6 +533,35 @@ init_terminal (grub_gfxmenu_view_t view)
grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box; grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box;
} }
static void
init_background (grub_gfxmenu_view_t view)
{
if (view->scaled_desktop_image)
return;
struct grub_video_bitmap *scaled_bitmap;
if (view->desktop_image_scale_method ==
GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH)
grub_video_bitmap_create_scaled (&scaled_bitmap,
view->screen.width,
view->screen.height,
view->raw_desktop_image,
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
else
grub_video_bitmap_scale_proportional (&scaled_bitmap,
view->screen.width,
view->screen.height,
view->raw_desktop_image,
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST,
view->desktop_image_scale_method,
view->desktop_image_v_align,
view->desktop_image_h_align);
if (! scaled_bitmap)
return;
view->scaled_desktop_image = scaled_bitmap;
}
/* FIXME: previously notifications were displayed in special case. /* FIXME: previously notifications were displayed in special case.
Is it necessary? Is it necessary?
*/ */

View file

@ -33,6 +33,46 @@ static grub_err_t scale_nn (struct grub_video_bitmap *dst,
static grub_err_t scale_bilinear (struct grub_video_bitmap *dst, static grub_err_t scale_bilinear (struct grub_video_bitmap *dst,
struct grub_video_bitmap *src); struct grub_video_bitmap *src);
static grub_err_t
verify_source_bitmap (struct grub_video_bitmap *src)
{
/* Verify the simplifying assumptions. */
if (src == 0)
return grub_error (GRUB_ERR_BUG,
"null src bitmap in grub_video_bitmap_create_scaled");
if (src->mode_info.red_field_pos % 8 != 0
|| src->mode_info.green_field_pos % 8 != 0
|| src->mode_info.blue_field_pos % 8 != 0
|| src->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_BUG,
"src format not supported for scale");
if (src->mode_info.width == 0 || src->mode_info.height == 0)
return grub_error (GRUB_ERR_BUG,
"source bitmap has a zero dimension");
if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp)
return grub_error (GRUB_ERR_BUG,
"bitmap to scale has inconsistent Bpp and bpp");
return GRUB_ERR_NONE;
}
static grub_err_t
grub_video_bitmap_scale (struct grub_video_bitmap *dst,
struct grub_video_bitmap *src,
enum grub_video_bitmap_scale_method scale_method)
{
switch (scale_method)
{
case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST:
case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST:
return scale_nn (dst, src);
case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST:
case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR:
return scale_bilinear (dst, src);
default:
return grub_error (GRUB_ERR_BUG, "Invalid scale_method value");
}
}
/* This function creates a new scaled version of the bitmap SRC. The new /* This function creates a new scaled version of the bitmap SRC. The new
bitmap has dimensions DST_WIDTH by DST_HEIGHT. The scaling algorithm bitmap has dimensions DST_WIDTH by DST_HEIGHT. The scaling algorithm
is given by SCALE_METHOD. If an error is encountered, the return code is is given by SCALE_METHOD. If an error is encountered, the return code is
@ -52,25 +92,12 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
{ {
*dst = 0; *dst = 0;
/* Verify the simplifying assumptions. */ grub_err_t err = verify_source_bitmap(src);
if (src == 0) if (err != GRUB_ERR_NONE)
return grub_error (GRUB_ERR_BUG, return err;
"null src bitmap in grub_video_bitmap_create_scaled");
if (src->mode_info.red_field_pos % 8 != 0
|| src->mode_info.green_field_pos % 8 != 0
|| src->mode_info.blue_field_pos % 8 != 0
|| src->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"src format not supported for scale");
if (src->mode_info.width == 0 || src->mode_info.height == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"source bitmap has a zero dimension");
if (dst_width <= 0 || dst_height <= 0) if (dst_width <= 0 || dst_height <= 0)
return grub_error (GRUB_ERR_BUG, return grub_error (GRUB_ERR_BUG,
"requested to scale to a size w/ a zero dimension"); "requested to scale to a size w/ a zero dimension");
if (src->mode_info.bytes_per_pixel * 8 != src->mode_info.bpp)
return grub_error (GRUB_ERR_BUG,
"bitmap to scale has inconsistent Bpp and bpp");
/* Create the new bitmap. */ /* Create the new bitmap. */
grub_err_t ret; grub_err_t ret;
@ -79,20 +106,171 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
if (ret != GRUB_ERR_NONE) if (ret != GRUB_ERR_NONE)
return ret; /* Error. */ return ret; /* Error. */
switch (scale_method) ret = grub_video_bitmap_scale (*dst, src, scale_method);
if (ret == GRUB_ERR_NONE)
{ {
case GRUB_VIDEO_BITMAP_SCALE_METHOD_FASTEST: /* Success: *dst is now a pointer to the scaled bitmap. */
case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST: return GRUB_ERR_NONE;
ret = scale_nn (*dst, src); }
else
{
/* Destroy the bitmap and return the error code. */
grub_video_bitmap_destroy (*dst);
*dst = 0;
return ret;
}
}
static grub_err_t
make_h_align (int *x, int *w, int new_w,
grub_video_bitmap_h_align_t h_align)
{
grub_err_t ret = GRUB_ERR_NONE;
switch (h_align)
{
case GRUB_VIDEO_BITMAP_H_ALIGN_LEFT:
*x = 0;
break; break;
case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST: case GRUB_VIDEO_BITMAP_H_ALIGN_CENTER:
case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR: *x = (*w - new_w) / 2;
ret = scale_bilinear (*dst, src); break;
case GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT:
*x = *w - new_w;
break; break;
default: default:
ret = grub_error (GRUB_ERR_BUG, "Invalid scale_method value"); ret = grub_error (GRUB_ERR_BUG, "Invalid h_align value");
break; break;
} }
*w = new_w;
return ret;
}
static grub_err_t
make_v_align (int *y, int *h, int new_h,
grub_video_bitmap_v_align_t v_align)
{
grub_err_t ret = GRUB_ERR_NONE;
switch (v_align)
{
case GRUB_VIDEO_BITMAP_V_ALIGN_TOP:
*y = 0;
break;
case GRUB_VIDEO_BITMAP_V_ALIGN_CENTER:
*y = (*h - new_h) / 2;
break;
case GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM:
*y = *h - new_h;
break;
default:
ret = grub_error (GRUB_ERR_BUG, "Invalid v_align value");
break;
}
*h = new_h;
return ret;
}
grub_err_t
grub_video_bitmap_scale_proportional (struct grub_video_bitmap **dst,
int dst_width, int dst_height,
struct grub_video_bitmap *src,
enum grub_video_bitmap_scale_method
scale_method,
grub_video_bitmap_selection_method_t
selection_method,
grub_video_bitmap_v_align_t v_align,
grub_video_bitmap_h_align_t h_align)
{
*dst = 0;
grub_err_t ret = verify_source_bitmap(src);
if (ret != GRUB_ERR_NONE)
return ret;
if (dst_width <= 0 || dst_height <= 0)
return grub_error (GRUB_ERR_BUG,
"requested to scale to a size w/ a zero dimension");
ret = grub_video_bitmap_create (dst, dst_width, dst_height,
src->mode_info.blit_format);
if (ret != GRUB_ERR_NONE)
return ret; /* Error. */
int dx0 = 0;
int dy0 = 0;
int dw = dst_width;
int dh = dst_height;
int sx0 = 0;
int sy0 = 0;
int sw = src->mode_info.width;
int sh = src->mode_info.height;
switch (selection_method)
{
case GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP:
/* Comparing sw/sh VS dw/dh. */
if (sw * dh < dw * sh)
ret = make_v_align (&sy0, &sh, sw * dh / dw, v_align);
else
ret = make_h_align (&sx0, &sw, sh * dw / dh, h_align);
break;
case GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING:
if (sw * dh < dw * sh)
ret = make_h_align (&dx0, &dw, sw * dh / sh, h_align);
else
ret = make_v_align (&dy0, &dh, sh * dw / sw, v_align);
break;
case GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH:
if (sw * dh < dw * sh)
ret = make_v_align (&sy0, &sh, sw * dh / dw, v_align);
else
ret = make_v_align (&dy0, &dh, sh * dw / sw, v_align);
break;
case GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT:
if (sw * dh < dw * sh)
ret = make_h_align (&dx0, &dw, sw * dh / sh, h_align);
else
ret = make_h_align (&sx0, &sw, sh * dw / dh, h_align);
break;
default:
ret = grub_error (GRUB_ERR_BUG, "Invalid selection_method value");
break;
}
if (ret == GRUB_ERR_NONE)
{
/* Backup original data. */
int src_width_orig = src->mode_info.width;
int src_height_orig = src->mode_info.height;
grub_uint8_t *src_data_orig = src->data;
int dst_width_orig = (*dst)->mode_info.width;
int dst_height_orig = (*dst)->mode_info.height;
grub_uint8_t *dst_data_orig = (*dst)->data;
int dstride = (*dst)->mode_info.pitch;
int sstride = src->mode_info.pitch;
/* bytes_per_pixel is the same for both src and dst. */
int bytes_per_pixel = src->mode_info.bytes_per_pixel;
/* Crop src and dst. */
src->mode_info.width = sw;
src->mode_info.height = sh;
src->data = (grub_uint8_t *) src->data + sx0 * bytes_per_pixel
+ sy0 * sstride;
(*dst)->mode_info.width = dw;
(*dst)->mode_info.height = dh;
(*dst)->data = (grub_uint8_t *) (*dst)->data + dx0 * bytes_per_pixel
+ dy0 * dstride;
/* Scale our image. */
ret = grub_video_bitmap_scale (*dst, src, scale_method);
/* Restore original data. */
src->mode_info.width = src_width_orig;
src->mode_info.height = src_height_orig;
src->data = src_data_orig;
(*dst)->mode_info.width = dst_width_orig;
(*dst)->mode_info.height = dst_height_orig;
(*dst)->data = dst_data_orig;
}
if (ret == GRUB_ERR_NONE) if (ret == GRUB_ERR_NONE)
{ {
@ -108,6 +286,46 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
} }
} }
static grub_err_t
verify_bitmaps (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
{
/* Verify the simplifying assumptions. */
if (dst == 0 || src == 0)
return grub_error (GRUB_ERR_BUG, "null bitmap in scale function");
if (dst->mode_info.red_field_pos % 8 != 0
|| dst->mode_info.green_field_pos % 8 != 0
|| dst->mode_info.blue_field_pos % 8 != 0
|| dst->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_BUG,
"dst format not supported");
if (src->mode_info.red_field_pos % 8 != 0
|| src->mode_info.green_field_pos % 8 != 0
|| src->mode_info.blue_field_pos % 8 != 0
|| src->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_BUG,
"src format not supported");
if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
|| dst->mode_info.red_mask_size != src->mode_info.red_mask_size
|| dst->mode_info.green_field_pos != src->mode_info.green_field_pos
|| dst->mode_info.green_mask_size != src->mode_info.green_mask_size
|| dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
|| dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
|| dst->mode_info.reserved_field_pos !=
src->mode_info.reserved_field_pos
|| dst->mode_info.reserved_mask_size !=
src->mode_info.reserved_mask_size)
return grub_error (GRUB_ERR_BUG,
"dst and src not compatible");
if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"dst and src not compatible");
if (dst->mode_info.width == 0 || dst->mode_info.height == 0
|| src->mode_info.width == 0 || src->mode_info.height == 0)
return grub_error (GRUB_ERR_BUG, "bitmap has a zero dimension");
return GRUB_ERR_NONE;
}
/* Nearest neighbor bitmap scaling algorithm. /* Nearest neighbor bitmap scaling algorithm.
Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the
@ -121,39 +339,9 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
static grub_err_t static grub_err_t
scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src) scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
{ {
/* Verify the simplifying assumptions. */ grub_err_t err = verify_bitmaps(dst, src);
if (dst == 0 || src == 0) if (err != GRUB_ERR_NONE)
return grub_error (GRUB_ERR_BUG, "null bitmap in scale_nn"); return err;
if (dst->mode_info.red_field_pos % 8 != 0
|| dst->mode_info.green_field_pos % 8 != 0
|| dst->mode_info.blue_field_pos % 8 != 0
|| dst->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"dst format not supported");
if (src->mode_info.red_field_pos % 8 != 0
|| src->mode_info.green_field_pos % 8 != 0
|| src->mode_info.blue_field_pos % 8 != 0
|| src->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"src format not supported");
if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
|| dst->mode_info.red_mask_size != src->mode_info.red_mask_size
|| dst->mode_info.green_field_pos != src->mode_info.green_field_pos
|| dst->mode_info.green_mask_size != src->mode_info.green_mask_size
|| dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
|| dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
|| dst->mode_info.reserved_field_pos !=
src->mode_info.reserved_field_pos
|| dst->mode_info.reserved_mask_size !=
src->mode_info.reserved_mask_size)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"dst and src not compatible");
if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"dst and src not compatible");
if (dst->mode_info.width == 0 || dst->mode_info.height == 0
|| src->mode_info.width == 0 || src->mode_info.height == 0)
return grub_error (GRUB_ERR_BUG, "bitmap has a zero dimension");
grub_uint8_t *ddata = dst->data; grub_uint8_t *ddata = dst->data;
grub_uint8_t *sdata = src->data; grub_uint8_t *sdata = src->data;
@ -208,35 +396,9 @@ scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
static grub_err_t static grub_err_t
scale_bilinear (struct grub_video_bitmap *dst, struct grub_video_bitmap *src) scale_bilinear (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
{ {
/* Verify the simplifying assumptions. */ grub_err_t err = verify_bitmaps(dst, src);
if (dst == 0 || src == 0) if (err != GRUB_ERR_NONE)
return grub_error (GRUB_ERR_BUG, "null bitmap in scale func"); return err;
if (dst->mode_info.red_field_pos % 8 != 0
|| dst->mode_info.green_field_pos % 8 != 0
|| dst->mode_info.blue_field_pos % 8 != 0
|| dst->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "dst format not supported");
if (src->mode_info.red_field_pos % 8 != 0
|| src->mode_info.green_field_pos % 8 != 0
|| src->mode_info.blue_field_pos % 8 != 0
|| src->mode_info.reserved_field_pos % 8 != 0)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "src format not supported");
if (dst->mode_info.red_field_pos != src->mode_info.red_field_pos
|| dst->mode_info.red_mask_size != src->mode_info.red_mask_size
|| dst->mode_info.green_field_pos != src->mode_info.green_field_pos
|| dst->mode_info.green_mask_size != src->mode_info.green_mask_size
|| dst->mode_info.blue_field_pos != src->mode_info.blue_field_pos
|| dst->mode_info.blue_mask_size != src->mode_info.blue_mask_size
|| dst->mode_info.reserved_field_pos !=
src->mode_info.reserved_field_pos
|| dst->mode_info.reserved_mask_size !=
src->mode_info.reserved_mask_size)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "dst and src not compatible");
if (dst->mode_info.bytes_per_pixel != src->mode_info.bytes_per_pixel)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "dst and src not compatible");
if (dst->mode_info.width == 0 || dst->mode_info.height == 0
|| src->mode_info.width == 0 || src->mode_info.height == 0)
return grub_error (GRUB_ERR_BUG, "bitmap has a zero dimension");
grub_uint8_t *ddata = dst->data; grub_uint8_t *ddata = dst->data;
grub_uint8_t *sdata = src->data; grub_uint8_t *sdata = src->data;

View file

@ -38,6 +38,29 @@ enum grub_video_bitmap_scale_method
GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR
}; };
typedef enum grub_video_bitmap_selection_method
{
GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH,
GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP,
GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING,
GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH,
GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT
} grub_video_bitmap_selection_method_t;
typedef enum grub_video_bitmap_v_align
{
GRUB_VIDEO_BITMAP_V_ALIGN_TOP,
GRUB_VIDEO_BITMAP_V_ALIGN_CENTER,
GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM
} grub_video_bitmap_v_align_t;
typedef enum grub_video_bitmap_h_align
{
GRUB_VIDEO_BITMAP_H_ALIGN_LEFT,
GRUB_VIDEO_BITMAP_H_ALIGN_CENTER,
GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT
} grub_video_bitmap_h_align_t;
grub_err_t grub_err_t
EXPORT_FUNC (grub_video_bitmap_create_scaled) (struct grub_video_bitmap **dst, EXPORT_FUNC (grub_video_bitmap_create_scaled) (struct grub_video_bitmap **dst,
int dst_width, int dst_height, int dst_width, int dst_height,
@ -46,4 +69,17 @@ EXPORT_FUNC (grub_video_bitmap_create_scaled) (struct grub_video_bitmap **dst,
grub_video_bitmap_scale_method grub_video_bitmap_scale_method
scale_method); scale_method);
grub_err_t
EXPORT_FUNC (grub_video_bitmap_scale_proportional)
(struct grub_video_bitmap **dst,
int dst_width, int dst_height,
struct grub_video_bitmap *src,
enum grub_video_bitmap_scale_method
scale_method,
grub_video_bitmap_selection_method_t
selection_method,
grub_video_bitmap_v_align_t v_align,
grub_video_bitmap_h_align_t h_align);
#endif /* ! GRUB_BITMAP_SCALE_HEADER */ #endif /* ! GRUB_BITMAP_SCALE_HEADER */

View file

@ -75,6 +75,7 @@ int grub_font_get_string_width (grub_font_t font,
#include <grub/video.h> #include <grub/video.h>
#include <grub/bitmap.h> #include <grub/bitmap.h>
#include <grub/bitmap_scale.h>
#include <grub/gui.h> #include <grub/gui.h>
#include <grub/gfxwidgets.h> #include <grub/gfxwidgets.h>
#include <grub/icon_manager.h> #include <grub/icon_manager.h>
@ -94,7 +95,11 @@ struct grub_gfxmenu_view
grub_video_rgba_color_t title_color; grub_video_rgba_color_t title_color;
grub_video_rgba_color_t message_color; grub_video_rgba_color_t message_color;
grub_video_rgba_color_t message_bg_color; grub_video_rgba_color_t message_bg_color;
struct grub_video_bitmap *desktop_image; struct grub_video_bitmap *raw_desktop_image;
struct grub_video_bitmap *scaled_desktop_image;
grub_video_bitmap_selection_method_t desktop_image_scale_method;
grub_video_bitmap_h_align_t desktop_image_h_align;
grub_video_bitmap_v_align_t desktop_image_v_align;
grub_video_rgba_color_t desktop_color; grub_video_rgba_color_t desktop_color;
grub_gfxmenu_box_t terminal_box; grub_gfxmenu_box_t terminal_box;
char *title_text; char *title_text;