* 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:
parent
c573914389
commit
ebc1da55cd
7 changed files with 417 additions and 107 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue