* grub-core/gfxmenu/theme_loader.c: New global options for the
authorVladimir Testov <vladimir.testov@rosalab.ru>
Wed, 2 Oct 2013 14:17:33 +0000 (18:17 +0400)
committerVladimir Testov <vladimir.testov@rosalab.ru>
Wed, 2 Oct 2013 14:17:33 +0000 (18:17 +0400)
       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
docs/grub.texi
grub-core/gfxmenu/theme_loader.c
grub-core/gfxmenu/view.c
grub-core/video/bitmap_scale.c
include/grub/bitmap_scale.h
include/grub/gfxmenu_view.h

index 8b912c8..a3e3742 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
        * grub-core/video/readers/png.c: Support narrow (4-/2-/1-bpp) PNG.
index 2bf0d8b..e605fcb 100644 (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-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.
index c882c19..09fab20 100644 (file)
@@ -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);
index 2dcb962..ed58cdc 100644 (file)
@@ -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?
  */
index 7ad4119..fb08d7a 100644 (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,
                                   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,21 +106,172 @@ 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 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 scale_method value");
+      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)
     {
       /* Success:  *dst is now a pointer to the scaled bitmap. */
@@ -108,33 +286,23 @@ grub_video_bitmap_create_scaled (struct grub_video_bitmap **dst,
     }
 }
 
-/* Nearest neighbor bitmap scaling algorithm.
-
-   Copy the bitmap SRC to the bitmap DST, scaling the bitmap to fit the
-   dimensions of DST.  This function uses the nearest neighbor algorithm to
-   interpolate the pixels.
-
-   Supports only direct color modes which have components separated
-   into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
-   But because of this simplifying assumption, the implementation is
-   greatly simplified.  */
 static grub_err_t
-scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
+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_nn");
+    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_NOT_IMPLEMENTED_YET,
+    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_NOT_IMPLEMENTED_YET,
+    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
@@ -146,7 +314,7 @@ scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
       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,
+    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,
@@ -155,6 +323,26 @@ scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
       || 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
+   dimensions of DST.  This function uses the nearest neighbor algorithm to
+   interpolate the pixels.
+
+   Supports only direct color modes which have components separated
+   into bytes (e.g., RGBA 8:8:8:8 or BGR 8:8:8 true color).
+   But because of this simplifying assumption, the implementation is
+   greatly simplified.  */
+static grub_err_t
+scale_nn (struct grub_video_bitmap *dst, struct grub_video_bitmap *src)
+{
+  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;
   int dw = dst->mode_info.width;
@@ -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;
index dce9fbb..927a7cb 100644 (file)
@@ -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 */
index d3b79a4..4203c8f 100644 (file)
@@ -75,6 +75,7 @@ int grub_font_get_string_width (grub_font_t font,
 
 #include <grub/video.h>
 #include <grub/bitmap.h>
+#include <grub/bitmap_scale.h>
 #include <grub/gui.h>
 #include <grub/gfxwidgets.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 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;