From ebc1da55cd75dc65109f941d340c05174fc0366e Mon Sep 17 00:00:00 2001 From: Vladimir Testov Date: Wed, 2 Oct 2013 18:17:33 +0400 Subject: [PATCH] * 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. --- ChangeLog | 13 ++ docs/grub.texi | 23 ++- grub-core/gfxmenu/theme_loader.c | 65 ++++-- grub-core/gfxmenu/view.c | 46 ++++- grub-core/video/bitmap_scale.c | 334 +++++++++++++++++++++++-------- include/grub/bitmap_scale.h | 36 ++++ include/grub/gfxmenu_view.h | 7 +- 7 files changed, 417 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8b912c8ff..a3e374203 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2013-10-02 Vladimir Testov + + * 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 * grub-core/video/readers/png.c: Support narrow (4-/2-/1-bpp) PNG. diff --git a/docs/grub.texi b/docs/grub.texi index 2bf0d8b05..e605fcba4 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -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-color @tab Defines the color of the message text. @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 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. diff --git a/grub-core/gfxmenu/theme_loader.c b/grub-core/gfxmenu/theme_loader.c index c882c1958..09fab2040 100644 --- a/grub-core/gfxmenu/theme_loader.c +++ b/grub-core/gfxmenu/theme_loader.c @@ -165,7 +165,6 @@ theme_set_string (grub_gfxmenu_view_t view, else if (! grub_strcmp ("desktop-image", name)) { struct grub_video_bitmap *raw_bitmap; - struct grub_video_bitmap *scaled_bitmap; char *path; path = grub_resolve_relative_path (theme_dir, value); if (! path) @@ -176,20 +175,56 @@ theme_set_string (grub_gfxmenu_view_t view, return grub_errno; } grub_free(path); - grub_video_bitmap_create_scaled (&scaled_bitmap, - view->screen.width, - view->screen.height, - raw_bitmap, - GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); - grub_video_bitmap_destroy (raw_bitmap); - if (! scaled_bitmap) - { - grub_error_push (); - return grub_error (grub_errno, "error scaling desktop image"); - } - - grub_video_bitmap_destroy (view->desktop_image); - view->desktop_image = scaled_bitmap; + grub_video_bitmap_destroy (view->raw_desktop_image); + view->raw_desktop_image = raw_bitmap; + } + else if (! grub_strcmp ("desktop-image-scale-method", name)) + { + if (! value || ! grub_strcmp ("stretch", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH; + else if (! grub_strcmp ("crop", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP; + else if (! grub_strcmp ("padding", value)) + view->desktop_image_scale_method = + 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)) grub_video_parse_color (value, &view->desktop_color); diff --git a/grub-core/gfxmenu/view.c b/grub-core/gfxmenu/view.c index 2dcb962dd..ed58cdc6d 100644 --- a/grub-core/gfxmenu/view.c +++ b/grub-core/gfxmenu/view.c @@ -40,6 +40,8 @@ static void init_terminal (grub_gfxmenu_view_t view); +static void +init_background (grub_gfxmenu_view_t view); static grub_gfxmenu_view_t term_view; /* 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->message_color = default_bg_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->terminal_box = grub_gfxmenu_create_box (0, 0); 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_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) view->terminal_box->destroy (view->terminal_box); grub_free (view->terminal_font_name); @@ -144,9 +151,9 @@ static void redraw_background (grub_gfxmenu_view_t view, 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, bounds->x, bounds->y, bounds->x - view->screen.x, @@ -328,6 +335,8 @@ grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) { init_terminal (view); + init_background (view); + /* Clear the screen; there may be garbage left over in video memory. */ grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), 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; } +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. Is it necessary? */ diff --git a/grub-core/video/bitmap_scale.c b/grub-core/video/bitmap_scale.c index 7ad411909..fb08d7a2d 100644 --- a/grub-core/video/bitmap_scale.c +++ b/grub-core/video/bitmap_scale.c @@ -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, 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 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 @@ -52,25 +92,12 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst, { *dst = 0; - /* 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_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"); + grub_err_t err = verify_source_bitmap(src); + if (err != GRUB_ERR_NONE) + return err; if (dst_width <= 0 || dst_height <= 0) return grub_error (GRUB_ERR_BUG, "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. */ grub_err_t ret; @@ -79,20 +106,171 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst, if (ret != GRUB_ERR_NONE) 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: - case GRUB_VIDEO_BITMAP_SCALE_METHOD_NEAREST: - ret = scale_nn (*dst, src); + /* Success: *dst is now a pointer to the scaled bitmap. */ + return GRUB_ERR_NONE; + } + 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; - case GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST: - case GRUB_VIDEO_BITMAP_SCALE_METHOD_BILINEAR: - ret = scale_bilinear (*dst, src); + case GRUB_VIDEO_BITMAP_H_ALIGN_CENTER: + *x = (*w - new_w) / 2; + break; + case GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT: + *x = *w - new_w; break; default: - ret = grub_error (GRUB_ERR_BUG, "Invalid scale_method value"); + ret = grub_error (GRUB_ERR_BUG, "Invalid h_align value"); 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) { @@ -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. 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 scale_nn (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_nn"); - 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_err_t err = verify_bitmaps(dst, src); + if (err != GRUB_ERR_NONE) + return err; grub_uint8_t *ddata = dst->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 scale_bilinear (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 func"); - 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_err_t err = verify_bitmaps(dst, src); + if (err != GRUB_ERR_NONE) + return err; grub_uint8_t *ddata = dst->data; grub_uint8_t *sdata = src->data; diff --git a/include/grub/bitmap_scale.h b/include/grub/bitmap_scale.h index dce9fbbf2..927a7cba5 100644 --- a/include/grub/bitmap_scale.h +++ b/include/grub/bitmap_scale.h @@ -38,6 +38,29 @@ enum grub_video_bitmap_scale_method 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 EXPORT_FUNC (grub_video_bitmap_create_scaled) (struct grub_video_bitmap **dst, 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 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 */ diff --git a/include/grub/gfxmenu_view.h b/include/grub/gfxmenu_view.h index d3b79a4ee..4203c8fb9 100644 --- a/include/grub/gfxmenu_view.h +++ b/include/grub/gfxmenu_view.h @@ -75,6 +75,7 @@ int grub_font_get_string_width (grub_font_t font, #include #include +#include #include #include #include @@ -94,7 +95,11 @@ struct grub_gfxmenu_view grub_video_rgba_color_t title_color; grub_video_rgba_color_t message_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_gfxmenu_box_t terminal_box; char *title_text;