diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2015-09-28 13:14:43 -0700 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2015-10-27 15:22:24 +0100 |
commit | a11e3ff160370b4d1ac838c7b89dcc0163bfe207 (patch) | |
tree | 8dd3ac701e572ab9081f800c78b94e6b432d9e73 /payloads/libpayload/drivers/video | |
parent | f86515244a94c81484fa72884698acf322a9130f (diff) |
cbgfx: add pivot option to draw_bitmap
This change adds 'pivot' option to draw_bitmap. It controls the point of the
image based on which the image is positioned. For example, if a pivot is set
to the center of the image horizontally and vertically, the image is
positioned using pos_rel as the center of the image.
This feature is necessary, for example, to place a text image in the center
of the screen because each image has a different width depending on the
language.
This change also makes draw_bitmap accept both horizontal and vertical size.
If either of them is zero, the other non-zero value is used to derive the
size to keep the aspect ratio.
Specifying the height is necessary to keep font sizes the same when drawing
text images of different lengths.
draw_bitmap_direct is a variant of draw_bitmap and it draws an image using
a native coordinate and the original size (as opposed to the location and
the size relative to the canvas).
CL:303074 has real use cases.
BUG=none
BRANCH=tot
TEST=Tested on Samus
Change-Id: I5fde69fcb5cc9dc53e827dd9fcf001a0a32748d4
Signed-off-by: Patrick Georgi <pgeorgi@google.com>
Original-Commit-Id: 82a0a8b60808410652552ed3a888937724111584
Original-Change-Id: I0b0d9113ebecf14e8c70de7a3562b215f69f2d4c
Original-Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/302855
Reviewed-on: http://review.coreboot.org/11927
Tested-by: build bot (Jenkins)
Diffstat (limited to 'payloads/libpayload/drivers/video')
-rw-r--r-- | payloads/libpayload/drivers/video/graphics.c | 223 |
1 files changed, 166 insertions, 57 deletions
diff --git a/payloads/libpayload/drivers/video/graphics.c b/payloads/libpayload/drivers/video/graphics.c index da06267aa9..c1dc37486b 100644 --- a/payloads/libpayload/drivers/video/graphics.c +++ b/payloads/libpayload/drivers/video/graphics.c @@ -25,19 +25,14 @@ static struct rect screen; static struct cb_framebuffer *fbinfo; static uint8_t *fbaddr; -static char initialized = 0; #define LOG(x...) printf("CBGFX: " x) - -/* - * This is the range used internally to scale bitmap images. (e.g. 128 = 50%, - * 512 = 200%). We choose 256 so that division and multiplication become bit - * shift operation. - */ -#define BITMAP_SCALE_BASE 256 - +#define PIVOT_H_MASK (PIVOT_H_LEFT|PIVOT_H_CENTER|PIVOT_H_RIGHT) +#define PIVOT_V_MASK (PIVOT_V_TOP|PIVOT_V_CENTER|PIVOT_V_BOTTOM) #define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define ABS(x) ((x) < 0 ? -(x) : (x)) +static char initialized = 0; + static const struct vector vzero = { .x = 0, .y = 0, @@ -66,7 +61,7 @@ static void transform_vector(struct vector *out, /* * Returns 1 if v is exclusively within box, 0 if v is inclusively within box, - * or -1 otherwise. Note that only the left and bottom edges are considered. + * or -1 otherwise. Note that only the right and bottom edges are examined. */ static int within_box(const struct vector *v, const struct rect *bound) { @@ -183,7 +178,7 @@ int draw_box(const struct rect *box, const struct rgb_color *rgb) add_vectors(&t, &top_left, &size); if (within_box(&t, &canvas) < 0) { LOG("Box exceeds canvas boundary\n"); - return CBGFX_ERROR_CANVAS_BOUNDARY; + return CBGFX_ERROR_BOUNDARY; } for (p.y = top_left.y; p.y < t.y; p.y++) @@ -193,7 +188,7 @@ int draw_box(const struct rect *box, const struct rgb_color *rgb) return CBGFX_SUCCESS; } -int clear_canvas(struct rgb_color *rgb) +int clear_canvas(const struct rgb_color *rgb) { const struct rect box = { vzero, @@ -209,7 +204,7 @@ int clear_canvas(struct rgb_color *rgb) return draw_box(&box, rgb); } -int clear_screen(struct rgb_color *rgb) +int clear_screen(const struct rgb_color *rgb) { uint32_t color; struct vector p; @@ -225,12 +220,9 @@ int clear_screen(struct rgb_color *rgb) return CBGFX_SUCCESS; } -/* - * This check guarantees we will not try to read outside pixel data. - */ -static int check_bound(const struct vector *image, - const struct bitmap_header_v3 *header, - const struct scale *scale) +static int check_pixel_boundary(const struct vector *image, + const struct bitmap_header_v3 *header, + const struct scale *scale) { struct vector p = { .x = (image->width - 1) * scale->x.deno / scale->x.nume, @@ -280,7 +272,8 @@ static int draw_bitmap_v3(const struct vector *top_left, return CBGFX_ERROR_SCALE_OUT_OF_RANGE; } - if (check_bound(image, header, scale)) + /* This check guarantees we will not try to read outside pixel data. */ + if (check_pixel_boundary(image, header, scale)) return CBGFX_ERROR_SCALE_OUT_OF_RANGE; const int32_t y_stride = ROUNDUP(header->width * bpp / 8, 4); @@ -431,16 +424,134 @@ static int parse_bitmap_header_v3(const uint8_t *bitmap, return CBGFX_SUCCESS; } -int draw_bitmap(const struct vector *top_left_rel, - size_t scale_rel, const void *bitmap, size_t size) +static int calculate_scale(const struct bitmap_header_v3 *header, + const struct scale *dim_rel, + struct scale *scale) +{ + if (dim_rel->x.nume == 0 && dim_rel->y.nume == 0) + return CBGFX_ERROR_INVALID_PARAMETER; + + if (dim_rel->x.nume > dim_rel->x.deno + || dim_rel->y.nume > dim_rel->y.deno) + return CBGFX_ERROR_INVALID_PARAMETER; + + if (dim_rel->x.nume > 0) { + scale->x.nume = dim_rel->x.nume * canvas.size.width; + scale->x.deno = header->width * dim_rel->x.deno; + } + if (dim_rel->y.nume > 0) { + scale->y.nume = dim_rel->y.nume * canvas.size.height; + scale->y.deno = header->height * dim_rel->y.deno; + } + + if (dim_rel->y.nume == 0) { + scale->y.nume = scale->x.nume; + scale->y.deno = scale->x.deno; + } + if (dim_rel->x.nume == 0) { + scale->x.nume = scale->y.nume; + scale->x.deno = scale->y.deno; + } + + if (scale->x.deno == 0 || scale->y.deno == 0) + return CBGFX_ERROR_INVALID_PARAMETER; + + return CBGFX_SUCCESS; +} + +static void calculate_dimention(const struct bitmap_header_v3 *header, + const struct scale *scale, + struct vector *dim) +{ + dim->width = header->width; + dim->height = ABS(header->height); + transform_vector(dim, dim, scale, &vzero); +} + +static int caclcuate_position(const struct vector *dim, + const struct scale *pos_rel, uint8_t pivot, + struct vector *top_left) +{ + if (pos_rel->x.deno == 0 || pos_rel->y.deno == 0) + return CBGFX_ERROR_INVALID_PARAMETER; + + transform_vector(top_left, &canvas.size, pos_rel, &canvas.offset); + + switch (pivot & PIVOT_H_MASK) { + case PIVOT_H_LEFT: + break; + case PIVOT_H_CENTER: + top_left->x -= dim->width / 2; + break; + case PIVOT_H_RIGHT: + top_left->x -= dim->width; + break; + default: + return CBGFX_ERROR_INVALID_PARAMETER; + } + + switch (pivot & PIVOT_V_MASK) { + case PIVOT_V_TOP: + break; + case PIVOT_V_CENTER: + top_left->y -= dim->height / 2; + break; + case PIVOT_V_BOTTOM: + top_left->y -= dim->height; + break; + default: + return CBGFX_ERROR_INVALID_PARAMETER; + } + + return CBGFX_SUCCESS; +} + +static int setup_image(const struct bitmap_header_v3 *header, + const struct scale *dim_rel, + const struct scale *pos_rel, uint8_t pivot, + /* ^--- IN / OUT ---v */ + struct scale *scale, + struct vector *dim, + struct vector *top_left) +{ + int rv; + + /* Calculate self-scale (scale relative to image size) */ + rv = calculate_scale(header, dim_rel, scale); + if (rv) + return rv; + + /* Calculate height and width of the image */ + calculate_dimention(header, scale, dim); + + /* Calculate coordinate */ + return caclcuate_position(dim, pos_rel, pivot, top_left); +} + +static int check_boundary(const struct vector *top_left, + const struct vector *dim, + const struct rect *bound) +{ + struct vector v; + add_vectors(&v, dim, top_left); + if (top_left->x < bound->offset.x + || top_left->y < bound->offset.y + || within_box(&v, bound) < 0) + return CBGFX_ERROR_BOUNDARY; + return CBGFX_SUCCESS; +} + +static int do_draw_bitmap(const void *bitmap, size_t size, + const struct scale *pos_rel, const uint8_t pivot, + const struct vector *position, + const struct scale *dim_rel) { struct bitmap_file_header file_header; struct bitmap_header_v3 header; const struct bitmap_palette_element_v3 *palette; const uint8_t *pixel_array; - struct vector top_left, image; + struct vector top_left, dim; struct scale scale; - struct vector t; int rv; if (cbgfx_init()) @@ -456,43 +567,41 @@ int draw_bitmap(const struct vector *top_left_rel, if (rv) return rv; - /* - * Calculate absolute coordinate and self-scale (scale relative to image - * size). If relative scale is zero, the image is displayed at the - * original scale and tol_left_rel is treated as absolute coordinate. - */ - if (scale_rel) { - const struct scale s = { - .x = { .nume = top_left_rel->x, .deno = CANVAS_SCALE, }, - .y = { .nume = top_left_rel->y, .deno = CANVAS_SCALE, }, - }; - transform_vector(&top_left, &canvas.size, &s, &canvas.offset); - scale.x.nume = scale_rel * canvas.size.width; - scale.x.deno = header.width * CANVAS_SCALE; - } else { - add_vectors(&top_left, top_left_rel, &vzero); + /* Calculate image scale, dimention, and position */ + if (position) { scale.x.nume = 1; scale.x.deno = 1; + scale.y.nume = 1; + scale.y.deno = 1; + calculate_dimention(&header, &scale, &dim); + add_vectors(&top_left, position, &vzero); + rv = check_boundary(&top_left, &dim, &screen); + } else { + rv = setup_image(&header, dim_rel, pos_rel, pivot, + &scale, &dim, &top_left); + if (rv) + return rv; + rv = check_boundary(&top_left, &dim, &canvas); } - scale.y.nume = scale.x.nume; - scale.y.deno = scale.x.deno; - - /* Calculate height and width of the image on screen */ - image.width = header.width; - image.height = ABS(header.height); - transform_vector(&image, &image, &scale, &vzero); - - /* Check whether the right bottom corner is within screen and canvas */ - add_vectors(&t, &image, &top_left); - if (scale_rel && within_box(&t, &canvas) < 0) { - LOG("Bitmap image exceeds canvas boundary\n"); - return CBGFX_ERROR_CANVAS_BOUNDARY; - } - if (within_box(&t, &screen) < 0) { - LOG("Bitmap image exceeds screen boundary\n"); - return CBGFX_ERROR_SCREEN_BOUNDARY; + if (rv) { + LOG("Bitmap image exceeds screen or canvas boundary\n"); + return rv; } - return draw_bitmap_v3(&top_left, &scale, &image, + return draw_bitmap_v3(&top_left, &scale, &dim, &header, palette, pixel_array); } + +int draw_bitmap(const void *bitmap, size_t size, + const struct scale *pos_rel, uint8_t pivot, + const struct scale *dim_rel) +{ + return do_draw_bitmap(bitmap, size, pos_rel, pivot, NULL, dim_rel); +} + +int draw_bitmap_direct(const void *bitmap, size_t size, + const struct vector *position) +{ + return do_draw_bitmap(bitmap, size, NULL, 0, position, NULL); +} + |