Remove memcpy of png_transform_background

Replaced by a structure copy which is safer since it doesn't depend on knowing
the first member to be copied, also the copies are improved to copy the
transform args too; not required at present but it may prevent a bug being
introduced in the future.

Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
John Bowler 2015-09-16 21:33:43 -07:00
parent 601ae5387e
commit fea86b1c29

View File

@ -4049,19 +4049,22 @@ png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
typedef struct typedef struct
{ {
png_transform tr; png_transform tr;
png_color_16 background; /* MUST COME FIRST */ struct
unsigned int need_expand :1; /* Background matches format of this PNG */ {
unsigned int rgb_to_gray :1; /* RGB-to-gray transform found */ png_color_16 background;
unsigned int compose_background :1; /* png_set_background */ unsigned int need_expand :1; /* Background matches format of PNG */
unsigned int associate_alpha :1; unsigned int rgb_to_gray :1; /* RGB-to-gray transform found */
unsigned int encode_alpha :1; unsigned int compose_background :1; /* png_set_background */
unsigned int optimize_alpha :1; unsigned int associate_alpha :1;
unsigned int background_is_gray :1; /* Background color is gray */ unsigned int encode_alpha :1;
unsigned int background_bit_depth :5; /* bit depth, 1..16 */ unsigned int optimize_alpha :1;
unsigned int ntrans :3; /* 1..6 bytes */ unsigned int background_is_gray :1; /* Background color is gray */
png_byte transparent_pixel[6]; unsigned int background_bit_depth :5; /* bit depth, 1..16 */
png_byte background_pixel[6]; unsigned int ntrans :3; /* 1..6 bytes */
png_fixed_point background_gamma; png_byte transparent_pixel[6];
png_byte background_pixel[6];
png_fixed_point background_gamma;
} st; /* to allow the whole state to be copied reliably */
} png_transform_background; } png_transform_background;
static void static void
@ -4074,9 +4077,9 @@ resolve_background_color(png_transform_background *tr,
* special case is when need_expand is set and the PNG has palette format, * special case is when need_expand is set and the PNG has palette format,
* then (and only then) the background value is a palette index. * then (and only then) the background value is a palette index.
*/ */
if (tr->need_expand && tc->palette) if (tr->st.need_expand && tc->palette)
{ {
unsigned int i = tr->background.index; unsigned int i = tr->st.background.index;
png_byte r, g, b; png_byte r, g, b;
if (i >= png_ptr->num_palette) if (i >= png_ptr->num_palette)
@ -4086,24 +4089,24 @@ resolve_background_color(png_transform_background *tr,
return; return;
} }
tr->background_bit_depth = 8U; tr->st.background_bit_depth = 8U;
r = png_ptr->palette[i].red; r = png_ptr->palette[i].red;
g = png_ptr->palette[i].green; g = png_ptr->palette[i].green;
b = png_ptr->palette[i].blue; b = png_ptr->palette[i].blue;
if (r == g && g == b) if (r == g && g == b)
{ {
tr->background_is_gray = 1U; tr->st.background_is_gray = 1U;
tr->background.gray = g; tr->st.background.gray = g;
UNTESTED UNTESTED
} }
else else
{ {
tr->background_is_gray = 0U; tr->st.background_is_gray = 0U;
tr->background.red = r; tr->st.background.red = r;
tr->background.green = g; tr->st.background.green = g;
tr->background.blue = b; tr->st.background.blue = b;
UNTESTED UNTESTED
} }
} }
@ -4116,10 +4119,10 @@ resolve_background_color(png_transform_background *tr,
/* First work out the bit depth and whether or not to use the RGB /* First work out the bit depth and whether or not to use the RGB
* fields of the background. * fields of the background.
*/ */
if (tr->need_expand) if (tr->st.need_expand)
{ {
affirm(!(tc->format & PNG_FORMAT_FLAG_COLORMAP)); affirm(!(tc->format & PNG_FORMAT_FLAG_COLORMAP));
tr->background_bit_depth = tr->st.background_bit_depth =
png_check_bits(png_ptr, png_ptr->bit_depth, 5U); png_check_bits(png_ptr, png_ptr->bit_depth, 5U);
use_rgb = (png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0; use_rgb = (png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0;
} }
@ -4131,10 +4134,10 @@ resolve_background_color(png_transform_background *tr,
* COLORMAP PNG and png_set_quantize. * COLORMAP PNG and png_set_quantize.
*/ */
if ((png_ptr->row_format & PNG_FORMAT_FLAG_COLORMAP) != 0) if ((png_ptr->row_format & PNG_FORMAT_FLAG_COLORMAP) != 0)
tr->background_bit_depth = 8U; tr->st.background_bit_depth = 8U;
else else
tr->background_bit_depth = tr->st.background_bit_depth =
png_check_bits(png_ptr, png_ptr->row_bit_depth, 5U); png_check_bits(png_ptr, png_ptr->row_bit_depth, 5U);
use_rgb = (png_ptr->row_format & PNG_FORMAT_FLAG_COLOR) != 0; use_rgb = (png_ptr->row_format & PNG_FORMAT_FLAG_COLOR) != 0;
@ -4144,35 +4147,35 @@ resolve_background_color(png_transform_background *tr,
* the high bits here (at present no warning is produced if they are * the high bits here (at present no warning is produced if they are
* set.) * set.)
*/ */
mask = png_check_u16(png_ptr, (1U << tr->background_bit_depth)-1U); mask = png_check_u16(png_ptr, (1U << tr->st.background_bit_depth)-1U);
if (use_rgb) if (use_rgb)
{ {
png_uint_16 r, g, b; png_uint_16 r, g, b;
r = tr->background.red & mask; r = tr->st.background.red & mask;
g = tr->background.green & mask; g = tr->st.background.green & mask;
b = tr->background.blue & mask; b = tr->st.background.blue & mask;
if (r == g && g == b) if (r == g && g == b)
{ {
tr->background_is_gray = 1U; tr->st.background_is_gray = 1U;
tr->background.gray = g; tr->st.background.gray = g;
} }
else else
{ {
tr->background_is_gray = 0U; tr->st.background_is_gray = 0U;
tr->background.red = r; tr->st.background.red = r;
tr->background.green = g; tr->st.background.green = g;
tr->background.blue = b; tr->st.background.blue = b;
} }
} }
else /* gray */ else /* gray */
{ {
tr->background_is_gray = 1U; tr->st.background_is_gray = 1U;
tr->background.gray = tr->background.gray & mask; tr->st.background.gray = tr->st.background.gray & mask;
} }
} }
} }
@ -4213,7 +4216,7 @@ gamma_correct_background(png_transform_background *tr,
{ {
# define png_ptr (tc->png_ptr) # define png_ptr (tc->png_ptr)
png_fixed_point correction = tc->gamma; png_fixed_point correction = tc->gamma;
const unsigned int bdback = tr->background_bit_depth; const unsigned int bdback = tr->st.background_bit_depth;
const unsigned int bdrow = tc->bit_depth; const unsigned int bdrow = tc->bit_depth;
/* This is harmless if it fails but it will damage the output pixels - they /* This is harmless if it fails but it will damage the output pixels - they
@ -4221,7 +4224,7 @@ gamma_correct_background(png_transform_background *tr,
* used. * used.
*/ */
debug(bdback <= bdrow); debug(bdback <= bdrow);
debug(tr->background_is_gray || (bdrow >= 8U && bdback >= 8U)); debug(tr->st.background_is_gray || (bdrow >= 8U && bdback >= 8U));
/* The background is assumed to be full precision; there is no sBIT /* The background is assumed to be full precision; there is no sBIT
* information for it. The convertion converts from the current depth and * information for it. The convertion converts from the current depth and
@ -4229,28 +4232,28 @@ gamma_correct_background(png_transform_background *tr,
* full 16-bit precision when considering the gamma values even though this * full 16-bit precision when considering the gamma values even though this
* is probably spurious. * is probably spurious.
*/ */
if (correction != 0 && (tr->background_gamma == 0 || if (correction != 0 && (tr->st.background_gamma == 0 ||
png_gamma_equal(png_ptr, tr->background_gamma, correction, &correction, png_gamma_equal(png_ptr, tr->st.background_gamma, correction,
16U))) &correction, 16U)))
correction = 0; /* no correction! */ correction = 0; /* no correction! */
if (tr->background_is_gray) if (tr->st.background_is_gray)
gamma_correct_background_component(png_ptr, &tr->background.gray, bdback, gamma_correct_background_component(png_ptr, &tr->st.background.gray,
correction, bdrow); bdback, correction, bdrow);
else else
{ {
gamma_correct_background_component(png_ptr, &tr->background.red, bdback, gamma_correct_background_component(png_ptr, &tr->st.background.red,
correction, bdrow); bdback, correction, bdrow);
gamma_correct_background_component(png_ptr, &tr->background.green, bdback, gamma_correct_background_component(png_ptr, &tr->st.background.green,
correction, bdrow); bdback, correction, bdrow);
gamma_correct_background_component(png_ptr, &tr->background.blue, bdback, gamma_correct_background_component(png_ptr, &tr->st.background.blue,
correction, bdrow); bdback, correction, bdrow);
} }
/* Regardless of whether there was a correction set the background gamma: */ /* Regardless of whether there was a correction set the background gamma: */
tr->background_gamma = tc->gamma; tr->st.background_gamma = tc->gamma;
tr->background_bit_depth = png_check_bits(png_ptr, bdrow, 5U); tr->st.background_bit_depth = png_check_bits(png_ptr, bdrow, 5U);
# undef png_ptr # undef png_ptr
} }
@ -4269,9 +4272,9 @@ fill_background_pixel(png_transform_background *tr, png_transform_controlp tc)
*/ */
gamma_correct_background(tr, tc); gamma_correct_background(tr, tc);
if (tr->background_is_gray) if (tr->st.background_is_gray)
{ {
unsigned int g = tr->background.gray; unsigned int g = tr->st.background.gray;
/* 'g' now has enough bits for the destination, note that in the case of /* 'g' now has enough bits for the destination, note that in the case of
* low bit depth gray this causes the pixel to be replicated through the * low bit depth gray this causes the pixel to be replicated through the
@ -4284,40 +4287,40 @@ fill_background_pixel(png_transform_background *tr, png_transform_controlp tc)
bdtc <<= 1; bdtc <<= 1;
} }
memset(tr->background_pixel, PNG_BYTE(g), 6U); memset(tr->st.background_pixel, PNG_BYTE(g), 6U);
if (bdtc == 16U) if (bdtc == 16U)
tr->background_pixel[0] = tr->background_pixel[2] = tr->st.background_pixel[0] = tr->st.background_pixel[2] =
tr->background_pixel[4] = PNG_BYTE(g >> 8); tr->st.background_pixel[4] = PNG_BYTE(g >> 8);
/* Must not include the alpha channel here: */ /* Must not include the alpha channel here: */
tr->ntrans = png_check_bits(png_ptr, tr->st.ntrans = png_check_bits(png_ptr,
((tc->format & PNG_FORMAT_FLAG_COLOR)+1U) << (bdtc == 16U), 3U); ((tc->format & PNG_FORMAT_FLAG_COLOR)+1U) << (bdtc == 16U), 3U);
} }
else else
{ {
unsigned int r = tr->background.red; unsigned int r = tr->st.background.red;
unsigned int g = tr->background.green; unsigned int g = tr->st.background.green;
unsigned int b = tr->background.blue; unsigned int b = tr->st.background.blue;
debug((tc->format & PNG_FORMAT_FLAG_COLOR) != 0); debug((tc->format & PNG_FORMAT_FLAG_COLOR) != 0);
switch (bdtc) switch (bdtc)
{ {
case 8U: case 8U:
tr->background_pixel[0] = PNG_BYTE(r); tr->st.background_pixel[0] = PNG_BYTE(r);
tr->background_pixel[1] = PNG_BYTE(g); tr->st.background_pixel[1] = PNG_BYTE(g);
tr->background_pixel[2] = PNG_BYTE(b); tr->st.background_pixel[2] = PNG_BYTE(b);
tr->ntrans = 3U; tr->st.ntrans = 3U;
break; break;
case 16U: case 16U:
tr->background_pixel[0] = PNG_BYTE(r>>8); tr->st.background_pixel[0] = PNG_BYTE(r>>8);
tr->background_pixel[1] = PNG_BYTE(r); tr->st.background_pixel[1] = PNG_BYTE(r);
tr->background_pixel[2] = PNG_BYTE(g>>8); tr->st.background_pixel[2] = PNG_BYTE(g>>8);
tr->background_pixel[3] = PNG_BYTE(g); tr->st.background_pixel[3] = PNG_BYTE(g);
tr->background_pixel[4] = PNG_BYTE(b>>8); tr->st.background_pixel[4] = PNG_BYTE(b>>8);
tr->background_pixel[5] = PNG_BYTE(b); tr->st.background_pixel[5] = PNG_BYTE(b);
tr->ntrans = 6U; tr->st.ntrans = 6U;
break; break;
default: default:
@ -4337,7 +4340,7 @@ png_do_replace_tRNS_multi(png_transformp *transform, png_transform_controlp tc)
png_transform_background *tr = png_transform_background *tr =
png_transform_cast(png_transform_background, *transform); png_transform_cast(png_transform_background, *transform);
png_bytep dp = png_voidcast(png_bytep, tc->dp); png_bytep dp = png_voidcast(png_bytep, tc->dp);
const unsigned int cbytes = tr->ntrans; const unsigned int cbytes = tr->st.ntrans;
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - cbytes/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - cbytes/*safety*/;
const int copy = dp != sp; const int copy = dp != sp;
@ -4361,7 +4364,7 @@ png_do_replace_tRNS_multi(png_transformp *transform, png_transform_controlp tc)
/* Find a transparent pixel, or the end: */ /* Find a transparent pixel, or the end: */
do do
{ {
if (memcmp(sp, tr->transparent_pixel, cbytes) == 0) /* transparent */ if (memcmp(sp, tr->st.transparent_pixel, cbytes) == 0) /*transparent*/
break; break;
sp += cbytes; sp += cbytes;
} }
@ -4383,11 +4386,11 @@ png_do_replace_tRNS_multi(png_transformp *transform, png_transform_controlp tc)
*/ */
if (sp <= ep) do if (sp <= ep) do
{ {
memcpy(dp, tr->background_pixel, cbytes); memcpy(dp, tr->st.background_pixel, cbytes);
sp += cbytes; sp += cbytes;
dp += cbytes; dp += cbytes;
} }
while (sp <= ep && memcmp(sp, tr->transparent_pixel, cbytes) == 0); while (sp <= ep && memcmp(sp, tr->st.transparent_pixel, cbytes) == 0);
} while (sp <= ep); } while (sp <= ep);
debug(sp == ep+cbytes); debug(sp == ep+cbytes);
@ -4405,14 +4408,14 @@ png_do_replace_tRNS_8(png_transformp *transform, png_transform_controlp tc)
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
png_alloc_size_t row_bytes = tc->width; png_alloc_size_t row_bytes = tc->width;
const int copy = dp != sp; const int copy = dp != sp;
const int transparent_pixel = tr->transparent_pixel[0]; const int transparent_pixel = tr->st.transparent_pixel[0];
const int background_pixel = tr->background_pixel[0]; const int background_pixel = tr->st.background_pixel[0];
/* We expect opaque and transparent pixels to be interleaved but with long /* We expect opaque and transparent pixels to be interleaved but with long
* sequences of each. * sequences of each.
*/ */
debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) && debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) &&
PNG_TC_PIXEL_DEPTH(*tc) == 8 && tr->ntrans == 1); PNG_TC_PIXEL_DEPTH(*tc) == 8 && tr->st.ntrans == 1);
tc->invalid_info |= PNG_INFO_tRNS; tc->invalid_info |= PNG_INFO_tRNS;
tc->sp = dp; tc->sp = dp;
@ -4486,14 +4489,14 @@ png_do_replace_tRNS_lbd(png_transformp *transform, png_transform_controlp tc)
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
const unsigned int copy = sp != dp; const unsigned int copy = sp != dp;
const png_byte transparent_pixel = tr->transparent_pixel[0]; const png_byte transparent_pixel = tr->st.transparent_pixel[0];
const png_byte background_pixel = tr->background_pixel[0]; const png_byte background_pixel = tr->st.background_pixel[0];
/* We expect opaque and transparent pixels to be interleaved but with long /* We expect opaque and transparent pixels to be interleaved but with long
* sequences of each. * sequences of each.
*/ */
debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) && debug(!(tc->format & PNG_FORMAT_FLAG_ALPHA) &&
PNG_TC_PIXEL_DEPTH(*tc) < 8 && tr->ntrans == 1); PNG_TC_PIXEL_DEPTH(*tc) < 8 && tr->st.ntrans == 1);
tc->sp = dp; tc->sp = dp;
/* Now search for a byte that contains the transparent pixel /* Now search for a byte that contains the transparent pixel
@ -4593,13 +4596,13 @@ png_do_background_with_transparent_GA8(png_transformp *transform,
png_bytep dp = png_voidcast(png_bytep, tc->dp); png_bytep dp = png_voidcast(png_bytep, tc->dp);
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 1U/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 1U/*safety*/;
const png_byte background_pixel = tr->background_pixel[0]; const png_byte background_pixel = tr->st.background_pixel[0];
/* Because this is an alpha format and we are removing the alpha channel we /* Because this is an alpha format and we are removing the alpha channel we
* can copy up. * can copy up.
*/ */
debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_GA && debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_GA &&
tr->ntrans == 1U); tr->st.ntrans == 1U);
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
tc->sp = dp; tc->sp = dp;
@ -4628,14 +4631,14 @@ png_do_background_with_transparent_GA16(png_transformp *transform,
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/;
debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA && debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA &&
tr->ntrans == 2U); tr->st.ntrans == 2U);
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
tc->sp = dp; tc->sp = dp;
do do
{ {
if (sp[2] == 0U && sp[3] == 0U) /* transparent */ if (sp[2] == 0U && sp[3] == 0U) /* transparent */
dp[0] = tr->background_pixel[0], dp[1] = tr->background_pixel[1]; dp[0] = tr->st.background_pixel[0], dp[1] = tr->st.background_pixel[1];
else else
dp[0] = sp[0], dp[1] = sp[1]; dp[0] = sp[0], dp[1] = sp[1];
@ -4663,10 +4666,10 @@ png_do_background_with_transparent_GAlbd(png_transformp *transform,
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc); const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
const unsigned int bit_depth = tc->bit_depth; const unsigned int bit_depth = tc->bit_depth;
const unsigned int mask = (1U << bit_depth) - 1U; const unsigned int mask = (1U << bit_depth) - 1U;
const unsigned int back = tr->background_pixel[0] & mask; const unsigned int back = tr->st.background_pixel[0] & mask;
unsigned int opos, ob, inb; unsigned int opos, ob, inb;
debug(bit_depth < 8U && tc->format == PNG_FORMAT_GA && tr->ntrans == 1U); debug(bit_depth < 8U && tc->format == PNG_FORMAT_GA && tr->st.ntrans == 1U);
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
tc->sp = dp; tc->sp = dp;
@ -4730,14 +4733,14 @@ png_do_background_with_transparent_RGBA8(png_transformp *transform,
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/;
debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_RGBA && debug(tc->bit_depth == 8U && tc->format == PNG_FORMAT_RGBA &&
tr->ntrans == 3U); tr->st.ntrans == 3U);
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
tc->sp = dp; tc->sp = dp;
do do
{ {
if (sp[3] == 0U) /* transparent */ if (sp[3] == 0U) /* transparent */
memcpy(dp, tr->background_pixel, 3U); memcpy(dp, tr->st.background_pixel, 3U);
else else
memmove(dp, sp, 3U); memmove(dp, sp, 3U);
@ -4762,14 +4765,14 @@ png_do_background_with_transparent_RGBA16(png_transformp *transform,
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/;
debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA && debug(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA &&
tr->ntrans == 6U); tr->st.ntrans == 6U);
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
tc->sp = dp; tc->sp = dp;
do do
{ {
if (sp[6] == 0U && sp[7] == 0U) /* transparent */ if (sp[6] == 0U && sp[7] == 0U) /* transparent */
memcpy(dp, tr->background_pixel, 6U); memcpy(dp, tr->st.background_pixel, 6U);
else else
memmove(dp, sp, 6U); memmove(dp, sp, 6U);
@ -4859,13 +4862,14 @@ png_do_background_alpha_GA(png_transformp *transform, png_transform_controlp tc)
png_bytep dp = png_voidcast(png_bytep, tc->dp); png_bytep dp = png_voidcast(png_bytep, tc->dp);
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 3U/*safety*/;
const unsigned int background = tr->background.gray; const unsigned int background = tr->st.background.gray;
const int copy = (sp != dp); const int copy = (sp != dp);
const int compose = tr->compose_background; const int compose = tr->st.compose_background;
affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA && affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_GA &&
tr->background_bit_depth == 16U && tr->st.background_bit_depth == 16U &&
(tr->background_gamma == tc->gamma || tr->background_gamma == 0)); (tr->st.background_gamma == tc->gamma ||
tr->st.background_gamma == 0));
tc->sp = tc->dp; /* nothing else changes */ tc->sp = tc->dp; /* nothing else changes */
@ -4928,15 +4932,16 @@ png_do_background_alpha_RGBA(png_transformp *transform,
png_bytep dp = png_voidcast(png_bytep, tc->dp); png_bytep dp = png_voidcast(png_bytep, tc->dp);
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp); png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/; const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc) - 7U/*safety*/;
const unsigned int bred = tr->background.red; const unsigned int bred = tr->st.background.red;
const unsigned int bgreen = tr->background.green; const unsigned int bgreen = tr->st.background.green;
const unsigned int bblue = tr->background.blue; const unsigned int bblue = tr->st.background.blue;
const int copy = (sp != dp); const int copy = (sp != dp);
const int compose = tr->compose_background; const int compose = tr->st.compose_background;
affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA && affirm(tc->bit_depth == 16U && tc->format == PNG_FORMAT_RGBA &&
tr->background_bit_depth == 16U && tr->st.background_bit_depth == 16U &&
(tr->background_gamma == tc->gamma || tr->background_gamma == 0)); (tr->st.background_gamma == tc->gamma ||
tr->st.background_gamma == 0));
tc->sp = tc->dp; /* nothing else changes */ tc->sp = tc->dp; /* nothing else changes */
@ -5013,11 +5018,11 @@ png_init_background_alpha_end(png_transformp *transform,
debug(tc->gamma == 0 || debug(tc->gamma == 0 ||
!png_gamma_significant(png_ptr, tc->gamma, tc_sBIT(tc))); !png_gamma_significant(png_ptr, tc->gamma, tc_sBIT(tc)));
/* tr->background_is_gray was filled in by resolve_background_color and /* tr->st.background_is_gray was filled in by resolve_background_color and
* records if either the background was a gray value or it was a color * records if either the background was a gray value or it was a color
* value with all the channels equal. * value with all the channels equal.
*/ */
if (!tr->background_is_gray && !(tc->format & PNG_FORMAT_FLAG_COLOR)) if (!tr->st.background_is_gray && !(tc->format & PNG_FORMAT_FLAG_COLOR))
{ {
# ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED # ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
/* Color background with gray data: this happens when there is a /* Color background with gray data: this happens when there is a
@ -5041,7 +5046,7 @@ png_init_background_alpha_end(png_transformp *transform,
* This only happens with background composition, otherwise the * This only happens with background composition, otherwise the
* transparent pixels are already 0 and nothing needs to be done. * transparent pixels are already 0 and nothing needs to be done.
*/ */
if (tr->compose_background) if (tr->st.compose_background)
{ {
/* The transparent pixel handling happens *after* the data has been /* The transparent pixel handling happens *after* the data has been
* re-encoded to the output gamma: * re-encoded to the output gamma:
@ -5052,11 +5057,11 @@ png_init_background_alpha_end(png_transformp *transform,
png_init_background_transparent, PNG_TR_GAMMA_ENCODE+0xF0U)); png_init_background_transparent, PNG_TR_GAMMA_ENCODE+0xF0U));
/* Copy the current state into the new png_transform_background: */ /* Copy the current state into the new png_transform_background: */
memcpy(&tr_alpha->background, &tr->background, tr_alpha->st = tr->st;
(sizeof *tr) - offsetof(png_transform_background, background)); tr_alpha->tr.args = tr->tr.args;
} }
/* Now it is possible to overwrite tr->background with the linear version. /* Now it is possible to overwrite tr->st.background with the linear version.
*/ */
gamma_correct_background(tr, tc); gamma_correct_background(tr, tc);
@ -5075,14 +5080,14 @@ png_init_background_alpha_end(png_transformp *transform,
* gray to RGB transform missing and we need it to happen before * gray to RGB transform missing and we need it to happen before
* this point! * this point!
*/ */
affirm(tr->background_is_gray); affirm(tr->st.background_is_gray);
tr->tr.fn = png_do_background_alpha_GA; tr->tr.fn = png_do_background_alpha_GA;
break; break;
case PNG_FORMAT_RGBA: case PNG_FORMAT_RGBA:
if (tr->background_is_gray) if (tr->st.background_is_gray)
tr->background.blue = tr->background.green = tr->background.red = tr->st.background.blue = tr->st.background.green =
tr->background.gray; tr->st.background.red = tr->st.background.gray;
tr->tr.fn = png_do_background_alpha_RGBA; tr->tr.fn = png_do_background_alpha_RGBA;
break; break;
@ -5127,8 +5132,8 @@ png_init_background_alpha(png_transformp *transform, png_transform_controlp tc)
* be set here. Notice that in C++ terms we are very friendly with * be set here. Notice that in C++ terms we are very friendly with
* png_transform_gamma. * png_transform_gamma.
*/ */
tr_end->encode_alpha = tr->encode_alpha; tr_end->encode_alpha = tr->st.encode_alpha;
tr_end->optimize_alpha = tr->optimize_alpha; tr_end->optimize_alpha = tr->st.optimize_alpha;
} }
{ {
@ -5181,10 +5186,11 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
/* Background composition removes the alpha channel, so the other /* Background composition removes the alpha channel, so the other
* operations become irrelevant: * operations become irrelevant:
*/ */
if (tr->compose_background) if (tr->st.compose_background)
tr->associate_alpha = tr->encode_alpha = tr->optimize_alpha = 0U; tr->st.associate_alpha = tr->st.encode_alpha = tr->st.optimize_alpha =
0U;
else if (!tr->associate_alpha) else if (!tr->st.associate_alpha)
{ {
/* There is nothing to do, delete the whole transform. */ /* There is nothing to do, delete the whole transform. */
tr->tr.fn = NULL; tr->tr.fn = NULL;
@ -5200,13 +5206,13 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
* inserted between this one and an rgb-to-gray transform, so we can find * inserted between this one and an rgb-to-gray transform, so we can find
* out if rgb-to-gray has been requested: * out if rgb-to-gray has been requested:
*/ */
tr->rgb_to_gray = tr->tr.next != NULL && tr->st.rgb_to_gray = tr->tr.next != NULL &&
tr->tr.next->order == PNG_TR_RGB_TO_GRAY; tr->tr.next->order == PNG_TR_RGB_TO_GRAY;
if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0) if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0)
{ {
/* Associated alpha does not strip the alpha channel! */ /* Associated alpha does not strip the alpha channel! */
if (tr->compose_background) if (tr->st.compose_background)
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA); tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
} }
@ -5215,7 +5221,7 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
{ {
/* tRNS will be expanded, or handled */ /* tRNS will be expanded, or handled */
tc->invalid_info |= PNG_INFO_tRNS; tc->invalid_info |= PNG_INFO_tRNS;
if (!tr->compose_background) if (!tr->st.compose_background)
{ {
tc->format |= PNG_FORMAT_FLAG_ALPHA; tc->format |= PNG_FORMAT_FLAG_ALPHA;
/* And in this case, only, because we are adding an alpha channel we /* And in this case, only, because we are adding an alpha channel we
@ -5244,18 +5250,18 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
* was in the PNG and no gamma information has been provided by * was in the PNG and no gamma information has been provided by
* png_set_gamma or png_set_alpha_mode. * png_set_gamma or png_set_alpha_mode.
*/ */
switch (tr->background_gamma) switch (tr->st.background_gamma)
{ {
case PNG_BACKGROUND_GAMMA_FILE: case PNG_BACKGROUND_GAMMA_FILE:
/* png_init_transform_control has already found the file gamma, /* png_init_transform_control has already found the file gamma,
* and because this is the first arithmetic transformation * and because this is the first arithmetic transformation
* nothing has changed it. * nothing has changed it.
*/ */
tr->background_gamma = tc->gamma; tr->st.background_gamma = tc->gamma;
break; break;
case PNG_BACKGROUND_GAMMA_SCREEN: case PNG_BACKGROUND_GAMMA_SCREEN:
tr->background_gamma = png_ptr->row_gamma; tr->st.background_gamma = png_ptr->row_gamma;
break; break;
default: default:
@ -5279,11 +5285,11 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
* following gray-to-RGB transform and the now gray image must be * following gray-to-RGB transform and the now gray image must be
* composited on a color background. * composited on a color background.
*/ */
if (tr->compose_background /* alpha channel stripped */ && if (tr->st.compose_background /* alpha channel stripped */ &&
(tr->background_is_gray || (tr->st.background_is_gray ||
((tc->format & PNG_FORMAT_FLAG_COLOR) != 0 && !tr->rgb_to_gray)) ((tc->format & PNG_FORMAT_FLAG_COLOR) != 0 && !tr->st.rgb_to_gray))
/* color compatible */ && /* color compatible */ &&
tc->bit_depth >= tr->background_bit_depth tc->bit_depth >= tr->st.background_bit_depth
/* bit depth compatible */ && /* bit depth compatible */ &&
(tc->transparent_alpha || (tc->transparent_alpha ||
(!tc->palette && png_ptr->num_trans == 1 && (!tc->palette && png_ptr->num_trans == 1 &&
@ -5321,8 +5327,8 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
debug(PNG_PIXEL_DEPTH(*png_ptr) == PNG_TC_PIXEL_DEPTH(*tc)); debug(PNG_PIXEL_DEPTH(*png_ptr) == PNG_TC_PIXEL_DEPTH(*tc));
/* The transparent_pixel value needs to be filled in. */ /* The transparent_pixel value needs to be filled in. */
affirm(tr->ntrans == affirm(tr->st.ntrans ==
fill_transparent_pixel(png_ptr, tr->transparent_pixel)); fill_transparent_pixel(png_ptr, tr->st.transparent_pixel));
/* The whole operation is a no-op if the transparent pixel and the /* The whole operation is a no-op if the transparent pixel and the
* background pixel match, even in the associated alpha case where * background pixel match, even in the associated alpha case where
@ -5335,12 +5341,12 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
* 'background_pixel' have been expanded to fill a byte, so this * 'background_pixel' have been expanded to fill a byte, so this
* works. * works.
*/ */
if (memcmp(tr->transparent_pixel, tr->background_pixel, tr->ntrans) if (memcmp(tr->st.transparent_pixel, tr->st.background_pixel,
== 0) tr->st.ntrans) == 0)
tr->tr.fn = NULL; tr->tr.fn = NULL;
/* Then the processing function depends on the pixel size: */ /* Then the processing function depends on the pixel size: */
else if (tr->ntrans > 1U) else if (tr->st.ntrans > 1U)
tr->tr.fn = png_do_replace_tRNS_multi; tr->tr.fn = png_do_replace_tRNS_multi;
else if (tc->bit_depth == 8U) else if (tc->bit_depth == 8U)
@ -5353,7 +5359,7 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
* bits are replaced by '1' or all the '1' bits are replaced by * bits are replaced by '1' or all the '1' bits are replaced by
* '0': * '0':
*/ */
png_uint_32 args = tr->background_pixel[0]; png_uint_32 args = tr->st.background_pixel[0];
args <<= 24; args <<= 24;
args |= PNG_INFO_tRNS | PNG_INFO_sRGB; args |= PNG_INFO_tRNS | PNG_INFO_sRGB;
@ -5388,8 +5394,8 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
png_init_background_alpha, PNG_TR_COMPOSE_ALPHA)); png_init_background_alpha, PNG_TR_COMPOSE_ALPHA));
/* Copy the current state into the new png_transform_background: */ /* Copy the current state into the new png_transform_background: */
memcpy(&tr_alpha->background, &tr->background, tr_alpha->st = tr->st;
(sizeof *tr) - offsetof(png_transform_background, background)); tr_alpha->tr.args = tr->tr.args;
/* The rest of the init occurs later; this transform is no longer /* The rest of the init occurs later; this transform is no longer
* needed. * needed.
@ -5401,7 +5407,7 @@ png_init_background(png_transformp *transform, png_transform_controlp tc)
* invalidate tRNS. * invalidate tRNS.
*/ */
tc->expand_tRNS = 1U; tc->expand_tRNS = 1U;
if (tr->compose_background) if (tr->st.compose_background)
tc->strip_alpha = 0U; tc->strip_alpha = 0U;
/* And push the expand: */ /* And push the expand: */
@ -5433,20 +5439,20 @@ png_set_background_fixed(png_structrp png_ptr,
/* This silently overwrites the information if png_set_background is /* This silently overwrites the information if png_set_background is
* called more than once. * called more than once.
*/ */
tr->background = *background_color; tr->st.background = *background_color;
tr->need_expand = need_expand != 0; tr->st.need_expand = need_expand != 0;
tr->compose_background = 1U; /* png_set_background called */ tr->st.compose_background = 1U; /* png_set_background called */
switch (background_gamma_code) switch (background_gamma_code)
{ {
case PNG_BACKGROUND_GAMMA_SCREEN: case PNG_BACKGROUND_GAMMA_SCREEN:
case PNG_BACKGROUND_GAMMA_FILE: case PNG_BACKGROUND_GAMMA_FILE:
tr->background_gamma = background_gamma_code; tr->st.background_gamma = background_gamma_code;
break; break;
case PNG_BACKGROUND_GAMMA_UNIQUE: case PNG_BACKGROUND_GAMMA_UNIQUE:
if (background_gamma >= 16 && background_gamma <= 625000000) if (background_gamma >= 16 && background_gamma <= 625000000)
{ {
tr->background_gamma = background_gamma; tr->st.background_gamma = background_gamma;
break; break;
} }
@ -5454,7 +5460,7 @@ png_set_background_fixed(png_structrp png_ptr,
/* FALL THROUGH */ /* FALL THROUGH */
default: default:
png_app_error(png_ptr, "invalid gamma information"); png_app_error(png_ptr, "invalid gamma information");
tr->background_gamma = (need_expand ? tr->st.background_gamma = (need_expand ?
PNG_BACKGROUND_GAMMA_FILE : PNG_BACKGROUND_GAMMA_SCREEN); PNG_BACKGROUND_GAMMA_FILE : PNG_BACKGROUND_GAMMA_SCREEN);
break; break;
} }
@ -5547,32 +5553,32 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
* is the only mode that doesn't interfere with what * is the only mode that doesn't interfere with what
* png_set_background does. * png_set_background does.
*/ */
tr->associate_alpha = 0U; tr->st.associate_alpha = 0U;
tr_gamma->encode_alpha = tr->encode_alpha = 0U; tr_gamma->encode_alpha = tr->st.encode_alpha = 0U;
tr_gamma->optimize_alpha = tr->optimize_alpha = 0U; tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U;
break; break;
case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
tr->associate_alpha = 1U; tr->st.associate_alpha = 1U;
tr_gamma->encode_alpha = tr->encode_alpha = 0U; tr_gamma->encode_alpha = tr->st.encode_alpha = 0U;
tr_gamma->optimize_alpha = tr->optimize_alpha = 0U; tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U;
break; break;
case PNG_ALPHA_OPTIMIZED: case PNG_ALPHA_OPTIMIZED:
/* associated with opaque pixels having the given gamma and /* associated with opaque pixels having the given gamma and
* non-opaque pixels being linear. * non-opaque pixels being linear.
*/ */
tr->associate_alpha = 1U; tr->st.associate_alpha = 1U;
tr_gamma->encode_alpha = tr->encode_alpha = 0U; tr_gamma->encode_alpha = tr->st.encode_alpha = 0U;
tr_gamma->optimize_alpha = tr->optimize_alpha = 1U; tr_gamma->optimize_alpha = tr->st.optimize_alpha = 1U;
/* output_gamma records the encoding of opaque pixels! */ /* output_gamma records the encoding of opaque pixels! */
break; break;
case PNG_ALPHA_BROKEN: case PNG_ALPHA_BROKEN:
/* associated+non-linear+alpha encoded */ /* associated+non-linear+alpha encoded */
tr->associate_alpha = 1U; tr->st.associate_alpha = 1U;
tr_gamma->encode_alpha = tr->encode_alpha = 1U; tr_gamma->encode_alpha = tr->st.encode_alpha = 1U;
tr_gamma->optimize_alpha = tr->optimize_alpha = 0U; tr_gamma->optimize_alpha = tr->st.optimize_alpha = 0U;
break; break;
default: default: