# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: address@hidden # target_branch: http://bzr.savannah.gnu.org/r/grub/trunk/grub/ # testament_sha1: 859c9fb07d2ff3ac48712480631b9cc98c1abbee # timestamp: 2010-02-24 19:40:56 +0600 # base_revision_id: address@hidden # # Begin patch === modified file 'font/font.c' --- font/font.c 2010-02-16 12:23:08 +0000 +++ font/font.c 2010-02-24 13:39:50 +0000 @@ -33,7 +33,7 @@ #endif #ifndef FONT_DEBUG -#define FONT_DEBUG 0 +#define FONT_DEBUG 0 #endif struct char_index_entry @@ -740,14 +740,38 @@ return 0; } - len = (width * height + 7) / 8; + enum grub_video_blit_format blit_format; + unsigned int mode_type; + + if ((index_entry->storage_flags & FONT_FORMAT_STORAGE_DEPTH_MASK) == FONT_FORMAT_STORAGE_8BIT_GRAY) + { + len = (width * height); + blit_format = GRUB_VIDEO_BLIT_FORMAT_8BIT_MASK; + mode_type = GRUB_VIDEO_MODE_TYPE_RGB; + } + else if ((index_entry->storage_flags & FONT_FORMAT_STORAGE_DEPTH_MASK) == FONT_FORMAT_STORAGE_1BIT) + { + /* 1 bpp */ + len = (width * height + 7) / 8; + blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK; + mode_type = GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; + } + else + { + remove_font (font); + return 0; + } + glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); if (! glyph) { remove_font (font); return 0; } - + + glyph->blit_format = blit_format; + glyph->mode_type = mode_type; + glyph->font = font; glyph->width = width; glyph->height = height; @@ -1066,17 +1090,9 @@ glyph_bitmap.mode_info.height = glyph->height; glyph_bitmap.mode_info.mode_type = (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) - | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; - glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED; - glyph_bitmap.mode_info.bpp = 1; - - /* Really 1 bit per pixel. */ - glyph_bitmap.mode_info.bytes_per_pixel = 0; - - /* Packed densely as bits. */ - glyph_bitmap.mode_info.pitch = glyph->width; - - glyph_bitmap.mode_info.number_of_colors = 2; + | glyph->mode_type; + glyph_bitmap.mode_info.blit_format = glyph->blit_format; + glyph_bitmap.mode_info.bg_red = 0; glyph_bitmap.mode_info.bg_green = 0; glyph_bitmap.mode_info.bg_blue = 0; === modified file 'include/grub/fbblit.h' --- include/grub/fbblit.h 2009-08-28 13:54:20 +0000 +++ include/grub/fbblit.h 2010-02-24 13:39:50 +0000 @@ -132,51 +132,72 @@ int offset_x, int offset_y); void -grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); - -void -grub_video_fbblit_replace_24bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); - -void -grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); - -void -grub_video_fbblit_replace_8bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); - -void -grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); - -void -grub_video_fbblit_blend_XXX888_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); - -void -grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y); +grub_video_fbblit_replace_32bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_replace_24bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_replace_16bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_replace_8bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_blend_XXXA8888_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_blend_XXX888_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_blend_XXX565_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_blend_XXXA8888_8bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_blend_XXX888_8bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); + +void +grub_video_fbblit_blend_XXX565_8bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y); #endif /* ! GRUB_FBBLIT_HEADER */ === modified file 'include/grub/font.h' --- include/grub/font.h 2010-01-20 07:06:28 +0000 +++ include/grub/font.h 2010-02-24 13:39:50 +0000 @@ -59,6 +59,9 @@ /* Number of pixels to advance to start the next character. */ grub_uint16_t device_width; + + enum grub_video_blit_format blit_format; + unsigned int mode_type; /* Row-major order, packed bits (no padding; rows can break within a byte). The length of the array is (width * height + 7) / 8. Within a === modified file 'include/grub/fontformat.h' --- include/grub/fontformat.h 2010-01-26 20:16:08 +0000 +++ include/grub/fontformat.h 2010-02-24 13:39:50 +0000 @@ -34,5 +34,11 @@ #define FONT_FORMAT_SECTION_NAMES_FAMILY "FAMI" #define FONT_FORMAT_SECTION_NAMES_SLAN "SLAN" +#define FONT_FORMAT_STORAGE_PACK_MASK 0x0F +#define FONT_FORMAT_STORAGE_PACKED 1 +#define FONT_FORMAT_STORAGE_DEPTH_MASK 0xF0 +#define FONT_FORMAT_STORAGE_1BIT 0 +#define FONT_FORMAT_STORAGE_8BIT_GRAY 32 + #endif /* ! GRUB_FONT_FORMAT_HEADER */ === modified file 'include/grub/video.h' --- include/grub/video.h 2010-02-03 00:24:07 +0000 +++ include/grub/video.h 2010-02-24 13:39:50 +0000 @@ -79,8 +79,11 @@ /* When needed, decode color or just use value as is. */ GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR, - /* Two color bitmap; bits packed: rows are not padded to byte boundary. */ - GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED + /* Masks. Uses bg_* and fg_* fields in grub_video_mode_info */ + /* Two levels of alpha mask, 1-bit; bits packed: rows are not padded to byte boundary. */ + GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK, + /* 8-bit alpha mask */ + GRUB_VIDEO_BLIT_FORMAT_8BIT_MASK, }; /* Define blitting operators. */ === modified file 'util/grub-mkfont.c' --- util/grub-mkfont.c 2010-01-26 20:16:08 +0000 +++ util/grub-mkfont.c 2010-02-24 13:39:50 +0000 @@ -60,6 +60,7 @@ #define GRUB_FONT_FLAG_NOBITMAP 2 #define GRUB_FONT_FLAG_NOHINTING 4 #define GRUB_FONT_FLAG_FORCEHINT 8 +#define GRUB_FONT_FLAG_8BIT_AA 4096 struct grub_font_info { @@ -95,6 +96,7 @@ {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"ascii-bitmaps", no_argument, 0, 0x102}, + {"antialiasing", no_argument, 0, 0x103}, {0, 0, 0, 0} }; @@ -110,6 +112,7 @@ Usage: %s [OPTIONS] FONT_FILES\n\ \nOptions:\n\ -o, --output=FILE_NAME set output file name\n\ + --antialiasing use antialiasing when rendering glyphs\n\ --ascii-bitmaps save only the ASCII bitmaps\n\ -i, --index=N set face index\n\ -r, --range=A-B[,C-D] set font range\n\ @@ -155,7 +158,12 @@ grub_uint8_t *data; int mask, i, j, bitmap_size; FT_GlyphSlot glyph; - int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + int flag = FT_LOAD_RENDER; + + if (font_info->flags & GRUB_FONT_FLAG_8BIT_AA) + flag |= FT_LOAD_TARGET_NORMAL; + else + flag |= FT_LOAD_MONOCHROME; if (font_info->flags & GRUB_FONT_FLAG_NOBITMAP) flag |= FT_LOAD_NO_BITMAP; @@ -186,7 +194,11 @@ width = glyph->bitmap.width; height = glyph->bitmap.rows; - bitmap_size = ((width * height + 7) / 8); + if (font_info->flags & GRUB_FONT_FLAG_8BIT_AA) + bitmap_size = width * height; + else + bitmap_size = ((width * height + 7) / 8); + glyph_info = xmalloc (sizeof (struct grub_glyph_info) + bitmap_size); glyph_info->bitmap_size = bitmap_size; @@ -212,13 +224,18 @@ if (glyph_info->y_ofs + height > font_info->max_y) font_info->max_y = glyph_info->y_ofs + height; - mask = 0; - data = &glyph_info->bitmap[0] - 1; - for (j = 0; j < height; j++) - for (i = 0; i < width; i++) - add_pixel (&data, &mask, - glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & - (1 << (7 - (i & 7)))); + if (font_info->flags & GRUB_FONT_FLAG_8BIT_AA) + memcpy (glyph_info->bitmap, glyph->bitmap.buffer, bitmap_size); + else + { + mask = 0; + data = &glyph_info->bitmap[0] - 1; + for (j = 0; j < height; j++) + for (i = 0; i < width; i++) + add_pixel (&data, &mask, + glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & + (1 << (7 - (i & 7)))); + } } void @@ -230,18 +247,17 @@ grub_uint32_t j; for (i = 0; i < font_info->num_range; i++) - for (j = font_info->ranges[i * 2]; j <= font_info->ranges[i * 2 + 1]; - j++) - add_char (font_info, face, j); + for (j = font_info->ranges[i * 2]; j <= font_info->ranges[i * 2 + 1]; j++) + add_char (font_info, face, j); } else { grub_uint32_t char_code, glyph_index; for (char_code = FT_Get_First_Char (face, &glyph_index); - glyph_index; - char_code = FT_Get_Next_Char (face, char_code, &glyph_index)) - add_char (font_info, face, char_code); + glyph_index; + char_code = FT_Get_Next_Char (face, char_code, &glyph_index)) + add_char (font_info, face, char_code); } } @@ -293,56 +309,74 @@ xmax = glyph->x_ofs + glyph->width; if (xmax < glyph->device_width) - xmax = glyph->device_width; + xmax = glyph->device_width; xmin = glyph->x_ofs; if (xmin > 0) - xmin = 0; + xmin = 0; ymax = glyph->y_ofs + glyph->height; if (ymax < font_info->asce) - ymax = font_info->asce; + ymax = font_info->asce; ymin = glyph->y_ofs; if (ymin > - font_info->desc) - ymin = - font_info->desc; + ymin = - font_info->desc; bitmap = glyph->bitmap; mask = 0x80; for (y = ymax - 1; y >= ymin; y--) - { - int line_pos; - - line_pos = 0; - for (x = xmin; x < xmax; x++) { - if ((x >= glyph->x_ofs) && - (x < glyph->x_ofs + glyph->width) && - (y >= glyph->y_ofs) && - (y < glyph->y_ofs + glyph->height)) - { - line[line_pos++] = (*bitmap & mask) ? '#' : '_'; - mask >>= 1; - if (mask == 0) - { - mask = 0x80; - bitmap++; - } - } - else if ((x >= 0) && - (x < glyph->device_width) && - (y >= - font_info->desc) && - (y < font_info->asce)) - { - line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.'; - } - else - line[line_pos++] = '*'; - } - line[line_pos] = 0; - printf ("%s\n", line); - } - } + int line_pos; + + line_pos = 0; + for (x = xmin; x < xmax; x++) + { + if ((x >= glyph->x_ofs) && + (x < glyph->x_ofs + glyph->width) && + (y >= glyph->y_ofs) && + (y < glyph->y_ofs + glyph->height)) + { + if (font_info->flags & GRUB_FONT_FLAG_8BIT_AA) + { + if (*bitmap > 127) + line[line_pos++] = '#'; + else if (*bitmap > 64) + line[line_pos++] = '8'; + else if (*bitmap > 8) + line[line_pos++] = 'o'; + else if (*bitmap > 1) + line[line_pos++] = '-'; + else + line[line_pos++] = '_'; + + bitmap++; + } + else + { + line[line_pos++] = (*bitmap & mask) ? '#' : '_'; + mask >>= 1; + if (mask == 0) + { + mask = 0x80; + bitmap++; + } + } + } + else if ((x >= 0) && + (x < glyph->device_width) && + (y >= - font_info->desc) && + (y < font_info->asce)) + { + line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.'; + } + else + line[line_pos++] = '*'; + } + line[line_pos] = 0; + printf ("%s\n", line); + } + } } void @@ -363,18 +397,18 @@ if (glyph->width != 8 || glyph->height != 16) { /* printf ("Width or height from glyph U+%04x not supported, skipping.\n", glyph->char_code); */ - correct_size = 0; + correct_size = 0; } int row; for (row = 0; row < glyph->height; row++) { - if (correct_size) - fwrite (&glyph->bitmap[row], sizeof(glyph->bitmap[row]), 1, file); - else - fwrite (&correct_size, 1, 1, file); + if (correct_size) + fwrite (&glyph->bitmap[row], sizeof(glyph->bitmap[row]), 1, file); + else + fwrite (&correct_size, 1, 1, file); } } - fclose (file); + fclose (file); } void @@ -441,17 +475,17 @@ if (! font_info->desc) { if (font_info->min_y >= 0) - font_info->desc = 1; + font_info->desc = 1; else - font_info->desc = - font_info->min_y; + font_info->desc = - font_info->min_y; } if (! font_info->asce) { if (font_info->max_y <= 0) - font_info->asce = 1; + font_info->asce = 1; else - font_info->asce = font_info->max_y; + font_info->asce = font_info->max_y; } write_be16_section (FONT_FORMAT_SECTION_NAMES_ASCENT, @@ -498,7 +532,10 @@ { data = grub_cpu_to_be32 (cur->char_code); grub_util_write_image ((char *) &data, 4, file); - data = 0; + if (font_info->flags & GRUB_FONT_FLAG_8BIT_AA) + data = FONT_FORMAT_STORAGE_8BIT_GRAY; + else + data = FONT_FORMAT_STORAGE_1BIT; grub_util_write_image ((char *) &data, 1, file); data = grub_cpu_to_be32 (offset); grub_util_write_image ((char *) &data, 4, file); @@ -644,6 +681,10 @@ case 0x102: file_format = ASCII_BITMAPS; break; + + case 0x103: + font_info.flags |= GRUB_FONT_FLAG_8BIT_AA; + break; default: usage (1); === modified file 'video/fb/fbblit.c' --- video/fb/fbblit.c 2009-08-28 13:54:20 +0000 +++ video/fb/fbblit.c 2010-02-24 13:39:50 +0000 @@ -90,13 +90,13 @@ } } -/* Optimized replacing blitter for 1-bit to 32bit. */ +/* Optimized replacing blitter for 1-bit mask to 32bit. */ void -grub_video_fbblit_replace_32bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y) +grub_video_fbblit_replace_32bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) { int i; int j; @@ -159,14 +159,13 @@ } } - -/* Optimized replacing blitter for 1-bit to 24-bit. */ +/* Optimized replacing blitter for 1-bit mask to 24-bit. */ void -grub_video_fbblit_replace_24bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y) +grub_video_fbblit_replace_24bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) { int i; int j; @@ -248,13 +247,13 @@ } } -/* Optimized replacing blitter for 1-bit to 16-bit. */ +/* Optimized replacing blitter for 1-bit mask to 16-bit. */ void -grub_video_fbblit_replace_16bit_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y) +grub_video_fbblit_replace_16bit_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) { int i; int j; @@ -317,9 +316,9 @@ } } -/* Optimized replacing blitter for 1-bit to 8-bit. */ +/* Optimized replacing blitter for 1-bit mask to 8-bit. */ void -grub_video_fbblit_replace_8bit_1bit (struct grub_video_fbblit_info *dst, +grub_video_fbblit_replace_8bit_1bitm (struct grub_video_fbblit_info *dst, struct grub_video_fbblit_info *src, int x, int y, int width, int height, @@ -1123,13 +1122,13 @@ } } -/* Optimized blending blitter for 1-bit to XXXA8888. */ +/* Optimized blending blitter for 1-bit mask to XXXA8888. */ void -grub_video_fbblit_blend_XXXA8888_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y) +grub_video_fbblit_blend_XXXA8888_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) { int i; int j; @@ -1217,13 +1216,89 @@ } } -/* Optimized blending blitter for 1-bit to XXX888. */ -void -grub_video_fbblit_blend_XXX888_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y) +/* Optimized blending blitter for 8-bit mask to XXXA8888. */ +void +grub_video_fbblit_blend_XXXA8888_8bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) +{ + int i; + int j; + grub_uint8_t *srcptr; + grub_uint8_t *dstptr; + unsigned int dstrowskip; + unsigned int srcrowskip; + grub_uint32_t fgcolor; + int byte_index; + + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ + dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; + srcrowskip = src->mode_info->width - width; + + byte_index = offset_y * src->mode_info->width + offset_x; + srcptr = (grub_uint8_t *) src->data + byte_index; + dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + + fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, + src->mode_info->fg_green, + src->mode_info->fg_blue, + src->mode_info->fg_alpha); + + grub_uint8_t fa, a; + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++) + { + fa = src->mode_info->fg_alpha; + + if (fa == 255 && *srcptr == 255) + a = 255; + else if (fa == 0 || *srcptr == 0) + a = 0; + else + a = (fa * *srcptr) / 255; + + if (a == 255) + *(grub_uint32_t *) dstptr = fgcolor; + else if (a != 0) + { + grub_uint8_t s1 = (fgcolor >> 0) & 0xFF; + grub_uint8_t s2 = (fgcolor >> 8) & 0xFF; + grub_uint8_t s3 = (fgcolor >> 16) & 0xFF; + + grub_uint8_t d1 = (*(grub_uint32_t *) dstptr >> 0) & 0xFF; + grub_uint8_t d2 = (*(grub_uint32_t *) dstptr >> 8) & 0xFF; + grub_uint8_t d3 = (*(grub_uint32_t *) dstptr >> 16) & 0xFF; + grub_uint8_t da = (*(grub_uint32_t *) dstptr >> 24) & 0xFF; + + d1 = (d1 * (255 - a) + s1 * a) / 255; + d2 = (d2 * (255 - a) + s2 * a) / 255; + d3 = (d3 * (255 - a) + s3 * a) / 255; + + *(grub_uint32_t *) dstptr = (da << 24) | (d3 << 16) | (d2 << 8) + | d1; + } + + srcptr++; + dstptr += 4; + } + + srcptr += srcrowskip; + dstptr += dstrowskip; + } +} + +/* Optimized blending blitter for 1-bit mask to XXX888. */ +void +grub_video_fbblit_blend_XXX888_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) { int i; int j; @@ -1316,13 +1391,89 @@ } } -/* Optimized blending blitter for 1-bit to XXX888. */ -void -grub_video_fbblit_blend_XXX565_1bit (struct grub_video_fbblit_info *dst, - struct grub_video_fbblit_info *src, - int x, int y, - int width, int height, - int offset_x, int offset_y) +/* Optimized blending blitter for 8-bit mask to XXX888. */ +void +grub_video_fbblit_blend_XXX888_8bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) +{ + int i; + int j; + grub_uint8_t *srcptr; + grub_uint8_t *dstptr; + unsigned int dstrowskip; + unsigned int srcrowskip; + grub_uint32_t fgcolor; + int byte_index; + + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ + dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; + srcrowskip = src->mode_info->width - width; + + byte_index = offset_y * src->mode_info->width + offset_x; + srcptr = (grub_uint8_t *) src->data + byte_index; + dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + + fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, + src->mode_info->fg_green, + src->mode_info->fg_blue, + src->mode_info->fg_alpha); + + grub_uint8_t fa, a; + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++) + { + fa = src->mode_info->fg_alpha; + + if (fa == 255 && *srcptr == 255) + a = 255; + else if (fa == 0 || *srcptr == 0) + a = 0; + else + a = (fa * *srcptr) / 255; + + if (a == 255) + { + ((grub_uint8_t *) dstptr)[0] = fgcolor & 0xff; + ((grub_uint8_t *) dstptr)[1] = (fgcolor & 0xff00) >> 8; + ((grub_uint8_t *) dstptr)[2] = (fgcolor & 0xff0000) >> 16; + } + else if (a != 0) + { + grub_uint8_t s1 = (fgcolor >> 0) & 0xFF; + grub_uint8_t s2 = (fgcolor >> 8) & 0xFF; + grub_uint8_t s3 = (fgcolor >> 16) & 0xFF; + + grub_uint8_t d1 = (*(grub_uint32_t *) dstptr >> 0) & 0xFF; + grub_uint8_t d2 = (*(grub_uint32_t *) dstptr >> 8) & 0xFF; + grub_uint8_t d3 = (*(grub_uint32_t *) dstptr >> 16) & 0xFF; + + ((grub_uint8_t *) dstptr)[0] = (d1 * (255 - a) + s1 * a) / 255; + ((grub_uint8_t *) dstptr)[1] = (d2 * (255 - a) + s2 * a) / 255; + ((grub_uint8_t *) dstptr)[2] = (d3 * (255 - a) + s3 * a) / 255; + } + + srcptr++; + dstptr += 3; + } + + srcptr += srcrowskip; + dstptr += dstrowskip; + } +} + +/* Optimized blending blitter for 1-bit mask to XXX565. */ +void +grub_video_fbblit_blend_XXX565_1bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) { int i; int j; @@ -1413,3 +1564,78 @@ dstptr += dstrowskip; } } + +/* Optimized blending blitter for 8-bit mask to XXX565. */ +void +grub_video_fbblit_blend_XXX565_8bitm (struct grub_video_fbblit_info *dst, + struct grub_video_fbblit_info *src, + int x, int y, + int width, int height, + int offset_x, int offset_y) +{ + int i; + int j; + grub_uint8_t *srcptr; + grub_uint8_t *dstptr; + unsigned int dstrowskip; + unsigned int srcrowskip; + grub_uint16_t fgcolor; + int byte_index; + + /* Calculate the number of bytes to advance from the end of one line + to the beginning of the next line. */ + dstrowskip = dst->mode_info->pitch - dst->mode_info->bytes_per_pixel * width; + srcrowskip = src->mode_info->width - width; + + byte_index = offset_y * src->mode_info->width + offset_x; + srcptr = (grub_uint8_t *) src->data + byte_index; + dstptr = (grub_uint8_t *) grub_video_fb_get_video_ptr (dst, x, y); + + fgcolor = grub_video_fb_map_rgba (src->mode_info->fg_red, + src->mode_info->fg_green, + src->mode_info->fg_blue, + src->mode_info->fg_alpha); + + grub_uint8_t fa, a; + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++) + { + fa = src->mode_info->fg_alpha; + + if (fa == 255 && *srcptr == 255) + a = 255; + else if (fa == 0 || *srcptr == 0) + a = 0; + else + a = (fa * *srcptr) / 255; + + if (a == 255) + *(grub_uint16_t *) dstptr = fgcolor; + else if (a != 0) + { + grub_uint8_t s1 = (fgcolor >> 0) & 0x1F; + grub_uint8_t s2 = (fgcolor >> 5) & 0x3F; + grub_uint8_t s3 = (fgcolor >> 11) & 0x1F; + + grub_uint8_t d1 = (*(grub_uint16_t *) dstptr >> 0) & 0x1F; + grub_uint8_t d2 = (*(grub_uint16_t *) dstptr >> 5) & 0x3F; + grub_uint8_t d3 = (*(grub_uint16_t *) dstptr >> 11) & 0x1F; + + d1 = (d1 * (255 - a) + s1 * a) / 255; + d2 = (d2 * (255 - a) + s2 * a) / 255; + d3 = (d3 * (255 - a) + s3 * a) / 255; + + *(grub_uint16_t *) dstptr = (d1 & 0x1f) | ((d2 & 0x3f) << 5) + | ((d3 & 0x1f) << 11); + } + + srcptr++; + dstptr += 2; + } + + srcptr += srcrowskip; + dstptr += dstrowskip; + } +} === modified file 'video/fb/fbutil.c' --- video/fb/fbutil.c 2009-08-18 17:26:35 +0000 +++ video/fb/fbutil.c 2010-02-24 13:39:50 +0000 @@ -96,7 +96,7 @@ break; case 1: - if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK) { int bit_index = y * source->mode_info->width + x; grub_uint8_t *ptr = source->data + bit_index / 8; @@ -163,7 +163,7 @@ break; case 1: - if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK) { int bit_index = y * source->mode_info->width + x; grub_uint8_t *ptr = source->data + bit_index / 8; === modified file 'video/fb/video_fb.c' --- video/fb/video_fb.c 2010-02-20 10:15:51 +0000 +++ video/fb/video_fb.c 2010-02-24 13:39:50 +0000 @@ -589,34 +589,34 @@ return; } } - else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK) { if (target->mode_info->bpp == 32) { - grub_video_fbblit_replace_32bit_1bit (target, source, - x, y, width, height, - offset_x, offset_y); + grub_video_fbblit_replace_32bit_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); return; } else if (target->mode_info->bpp == 24) { - grub_video_fbblit_replace_24bit_1bit (target, source, - x, y, width, height, - offset_x, offset_y); + grub_video_fbblit_replace_24bit_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); return; } else if (target->mode_info->bpp == 16) { - grub_video_fbblit_replace_16bit_1bit (target, source, - x, y, width, height, - offset_x, offset_y); + grub_video_fbblit_replace_16bit_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); return; } else if (target->mode_info->bpp == 8) { - grub_video_fbblit_replace_8bit_1bit (target, source, - x, y, width, height, - offset_x, offset_y); + grub_video_fbblit_replace_8bit_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); return; } } @@ -707,41 +707,72 @@ return; } } - else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) - { - if (target->mode_info->blit_format - == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888 - || target->mode_info->blit_format - == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) - { - grub_video_fbblit_blend_XXXA8888_1bit (target, source, - x, y, width, height, - offset_x, offset_y); - return; - } - else if (target->mode_info->blit_format - == GRUB_VIDEO_BLIT_FORMAT_BGR_888 - || target->mode_info->blit_format - == GRUB_VIDEO_BLIT_FORMAT_RGB_888) - { - grub_video_fbblit_blend_XXX888_1bit (target, source, - x, y, width, height, - offset_x, offset_y); - return; - } - else if (target->mode_info->blit_format - == GRUB_VIDEO_BLIT_FORMAT_BGR_565 - || target->mode_info->blit_format - == GRUB_VIDEO_BLIT_FORMAT_RGB_565) - { - grub_video_fbblit_blend_XXX565_1bit (target, source, - x, y, width, height, - offset_x, offset_y); - return; - } - - } - + else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK) + { + if (target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888 + || target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) + { + grub_video_fbblit_blend_XXXA8888_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); + return; + } + else if (target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_BGR_888 + || target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_RGB_888) + { + grub_video_fbblit_blend_XXX888_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); + return; + } + else if (target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_BGR_565 + || target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_RGB_565) + { + grub_video_fbblit_blend_XXX565_1bitm (target, source, + x, y, width, height, + offset_x, offset_y); + return; + } + } + else if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_8BIT_MASK) + { + if (target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_BGRA_8888 + || target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_RGBA_8888) + { + grub_video_fbblit_blend_XXXA8888_8bitm (target, source, + x, y, width, height, + offset_x, offset_y); + return; + } + else if (target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_BGR_888 + || target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_RGB_888) + { + grub_video_fbblit_blend_XXX888_8bitm (target, source, + x, y, width, height, + offset_x, offset_y); + return; + } + else if (target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_BGR_565 + || target->mode_info->blit_format + == GRUB_VIDEO_BLIT_FORMAT_RGB_565) + { + grub_video_fbblit_blend_XXX565_8bitm (target, source, + x, y, width, height, + offset_x, offset_y); + return; + } + } /* No optimized blend operation found, use default (slow) blitter. */ grub_video_fbblit_blend (target, source, x, y, width, height, === modified file 'video/video.c' --- video/video.c 2010-02-03 00:24:07 +0000 +++ video/video.c 2010-02-24 13:39:50 +0000 @@ -190,7 +190,7 @@ } } else if (mode_info->bpp == 1) - return GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED; + return GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED_MASK; /* Backup route. Unknown format. */ # Begin bundle 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