assembling: Fix copying only partial tile on overhang

If the tile in question was hanging over the left edge we would not be
copying the full available width. Fix this and change the test to catch
the error condition (by forcing a too small image and overlap both
ways).

Simplify the code by only selecting the starting point inside the
image/frame and then just checking the both image and frame boundary in
the loop. Not quite as efficient, but it really shouldn't matter too
much here.
This commit is contained in:
Benjamin Berg 2021-06-23 17:42:59 +02:00
parent 1ed2b23902
commit 51cab75b1e
2 changed files with 20 additions and 53 deletions

View file

@ -210,69 +210,36 @@ aes_blit_stripe (struct fpi_frame_asmbl_ctx *ctx,
struct fpi_frame *stripe, struct fpi_frame *stripe,
int x, int y) int x, int y)
{ {
unsigned int ix, iy; unsigned int ix1, iy1;
unsigned int fx, fy; unsigned int fx1, fy1;
unsigned int width, height; unsigned int fx, fy, ix, iy;
/* Find intersection */ /* Select starting point inside image and frame */
if (x < 0) if (x < 0)
{ {
width = ctx->frame_width + x; ix1 = 0;
ix = 0; fx1 = -x;
fx = -x;
} }
else else
{ {
ix = x; ix1 = x;
fx = 0; fx1 = 0;
width = ctx->frame_width;
} }
if ((ix + width) > img->width)
width = img->width - ix;
if (y < 0) if (y < 0)
{ {
iy = 0; iy1 = 0;
fy = -y; fy1 = -y;
height = ctx->frame_height + y;
} }
else else
{ {
iy = y; iy1 = y;
fy = 0; fy1 = 0;
height = ctx->frame_height;
} }
if (fx > ctx->frame_width) for (fy = fy1, iy = iy1; fy < ctx->frame_height && iy < img->height; fy++, iy++)
return; for (fx = fx1, ix = ix1; fx < ctx->frame_width && ix < img->width; fx++, ix++)
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
if (fy > ctx->frame_height)
return;
if (ix > img->width)
return;
if (iy > img->height)
return;
if ((iy + height) > img->height)
height = img->height - iy;
for (; fy < height; fy++, iy++)
{
if (x < 0)
{
ix = 0;
fx = -x;
}
else
{
ix = x;
fx = 0;
}
for (; fx < width; fx++, ix++)
img->data[ix + (iy * img->width)] = ctx->get_pixel (ctx, stripe, fx, fy);
}
} }
/** /**
@ -298,7 +265,6 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
//FIXME g_return_if_fail //FIXME g_return_if_fail
g_return_val_if_fail (stripes != NULL, NULL); g_return_val_if_fail (stripes != NULL, NULL);
BUG_ON (ctx->image_width < ctx->frame_width);
/* No offset for 1st image */ /* No offset for 1st image */
fpi_frame = stripes->data; fpi_frame = stripes->data;
@ -331,7 +297,7 @@ fpi_assemble_frames (struct fpi_frame_asmbl_ctx *ctx,
/* Assemble stripes */ /* Assemble stripes */
y = reverse ? (height - ctx->frame_height) : 0; y = reverse ? (height - ctx->frame_height) : 0;
x = (ctx->image_width - ctx->frame_width) / 2; x = ((int) ctx->image_width - (int) ctx->frame_width) / 2;
for (l = stripes; l != NULL; l = l->next) for (l = stripes; l != NULL; l = l->next)
{ {

View file

@ -62,6 +62,7 @@ test_frame_assembling (void)
int test_height; int test_height;
guchar *data; guchar *data;
struct fpi_frame_asmbl_ctx ctx = { 0, }; struct fpi_frame_asmbl_ctx ctx = { 0, };
gint xborder = 5;
g_autoptr(FpImage) fp_img = NULL; g_autoptr(FpImage) fp_img = NULL;
GSList *frames = NULL; GSList *frames = NULL;
@ -79,7 +80,7 @@ test_frame_assembling (void)
ctx.get_pixel = cairo_get_pixel; ctx.get_pixel = cairo_get_pixel;
ctx.frame_width = width; ctx.frame_width = width;
ctx.frame_height = 20; ctx.frame_height = 20;
ctx.image_width = width; ctx.image_width = width - 2 * xborder;
g_assert (height > ctx.frame_height); g_assert (height > ctx.frame_height);
@ -118,8 +119,8 @@ test_frame_assembling (void)
/* The FpImage and cairo surface need to be identical in the test area */ /* The FpImage and cairo surface need to be identical in the test area */
for (int y = 0; y < test_height; y++) for (int y = 0; y < test_height; y++)
for (int x = 0; x < width; x++) for (int x = 0; x < ctx.image_width; x++)
g_assert_cmpint (data[x * 4 + y * stride + 1], ==, fp_img->data[x + y * width]); g_assert_cmpint (data[(x + xborder) * 4 + y * stride + 1], ==, fp_img->data[x + y * ctx.image_width]);
g_slist_free_full (frames, g_free); g_slist_free_full (frames, g_free);
cairo_surface_destroy (img); cairo_surface_destroy (img);