From 86499967c316a78726be7196c0baf8b038dc27f6 Mon Sep 17 00:00:00 2001 From: John Bowler Date: Thu, 3 Dec 2015 13:25:11 -0800 Subject: [PATCH] Checkpoint for 'methodical' filter selection This checkpoint is to allow the massive merge with the recent mainline libpng17 changes. Signed-off-by: John Bowler --- pngpriv.h | 36 +++++++---- pngstruct.h | 8 ++- pngwrite.c | 100 +++++++++++++---------------- pngwutil.c | 180 +++++++++++++++++++++++++++++++--------------------- 4 files changed, 181 insertions(+), 143 deletions(-) diff --git a/pngpriv.h b/pngpriv.h index 294853dc3..10b4bb9c4 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -959,12 +959,6 @@ PNG_INTERNAL_FUNCTION(void, png_zstream_error,(z_stream *zstream, int ret), * set before they return. */ -#ifdef PNG_WRITE_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, - png_compression_bufferp *list),PNG_EMPTY); - /* Free the buffer list used by the compressed write code. */ -#endif - #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ @@ -1206,14 +1200,30 @@ PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, * * This may be called multiple times per row, but calls must be in 'x' order; * first a call with x 0 to mark the start of the row and, at the end, one with - * 'end_of_row' set (this can be done in the same function call if the whole row - * is passed.) + * PNG_ROW_END set (this can be done in the same function call if the whole row + * is passed.) The following flags are used internally to control pass + * filtering and deflate: */ -PNG_INTERNAL_FUNCTION(unsigned int, png_write_filter_row, - (png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, - png_uint_32 x, unsigned int width/*pixels*/, int first_row_in_pass, - int last_pass_row, unsigned int filters_to_try/*from previous call*/, - int end_of_image), +enum +{ + png_row_end =0x1U, /* This is the last block in the row */ + png_pass_first_row =0x2U, /* This is the first row in a pass */ + png_pass_last_row =0x4U, /* This is the last row in a pass */ + png_pass_last =0x8U /* This is the last pass in the image */ + + /* A useful macro; return true if this is the last block of the last row in + * the image. + */ +# define PNG_IDAT_END(f) (((f) & ~png_pass_first_row) == \ + (png_row_end+png_pass_last_row+png_pass_last)) +}; +PNG_INTERNAL_FUNCTION(void, png_write_filter_row, (png_structrp png_ptr, + png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, + unsigned int width/*pixels*/, unsigned int row_info_flags), + PNG_EMPTY); + +/* Release memory used by the deflate mechanism */ +PNG_INTERNAL_FUNCTION(void, png_deflate_destroy, (png_structrp png_ptr), PNG_EMPTY); #ifdef PNG_TRANSFORM_MECH_SUPPORTED diff --git a/pngstruct.h b/pngstruct.h index 09d47a40a..009a16eca 100644 --- a/pngstruct.h +++ b/pngstruct.h @@ -67,6 +67,11 @@ typedef struct png_compression_buffer *png_compression_bufferp; #endif +#ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED +/* Type of the data cache used when selecting filters methodicially */ +typedef struct png_filter_select *png_filter_selectp; +#endif + /* Colorspace support; structures used in png_struct, png_info and in internal * functions to hold and communicate information about the color space. * @@ -751,8 +756,9 @@ struct png_struct_def png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */ png_uint_32 zbuffer_len; /* Length of data in list */ unsigned int zbuffer_start; /* Bytes written from start */ + unsigned int zbuffer_filters;/*Filters for this row */ # ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - png_voidp zbuffer_select; + png_filter_selectp zbuffer_select; # endif /* SELECT_FILTER_METHODICALLY */ # endif /* WRITE */ # ifdef PNG_READ_SUPPORTED diff --git a/pngwrite.c b/pngwrite.c index 6da955902..b736f60d4 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -629,8 +629,8 @@ png_write_image(png_structrp png_ptr, png_bytepp image) #if defined(PNG_WRITE_INTERLACING_SUPPORTED) ||\ defined(PNG_WRITE_TRANSFORMS_SUPPORTED) static void -write_row_buffered(png_structrp png_ptr, png_const_bytep row, - int first_row_in_pass, int last_pass_row, int end_of_image, +write_row_buffered(png_structrp png_ptr, + png_const_bytep row, unsigned int row_info_flags, void (*copy_fn)(png_const_structrp png_ptr, png_bytep row_buffer, png_const_bytep row, png_uint_32 x, unsigned int count, unsigned int p), unsigned int copy_parameter) @@ -640,15 +640,12 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row, const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ? png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass); png_uint_32 x; - unsigned int filters; png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */ memset(prev_pixels, 0U, sizeof prev_pixels); - for (x = 0U, filters = 0U; x < width; x += max_pixels) + for (x = 0U; x < width; x += max_pixels) { - int finish = 0; - union { PNG_ROW_BUFFER_ALIGN_TYPE force_buffer_alignment; @@ -658,8 +655,9 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row, if (max_pixels > width - x) max_pixels = (unsigned int)/*SAFE*/(width - x); - if (end_of_image && x + max_pixels >= width) - finish = 1; + debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */ + if (x + max_pixels >= width) + row_info_flags |= png_row_end; /* Copy a block of input pixels into the buffer, effecting the interlace * on the way if required. The argument is the number of pixels in the @@ -707,11 +705,10 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row, # endif /* WRITE_TRANSFORMS */ /* Call png_write_filter_row to write this block of data, the test on - * maxpixels says if this is the final block in the row, 'filters' is - * initialized when 0 is 0 then preserved here for later blocks: + * maxpixels says if this is the final block in the row. */ - filters = png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer, - x, max_pixels, first_row_in_pass, last_pass_row, filters, finish); + png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer, x, + max_pixels, row_info_flags); } } #endif /* WRITE { INTERLACING || TRANSFORMS } */ @@ -825,7 +822,7 @@ interlace_row_byte(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp, static void write_row_unbuffered(png_structrp png_ptr, png_const_bytep row, - int first_row_in_pass, int last_pass_row, int end_of_image) + unsigned int row_info_flags) { /* Split the row into blocks of the appropriate size: */ const unsigned int input_depth = png_ptr->row_input_pixel_depth; @@ -835,7 +832,6 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row, const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ? png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass); png_uint_32 x; - unsigned int filters; png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */ /* max_pixels is at most 16 bits, input_depth is at most 64, so the product @@ -847,10 +843,8 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row, memset(prev_pixels, 0U, sizeof prev_pixels); - for (x = 0U, filters = 0U; x < width; x += max_pixels, row += max_bytes) + for (x = 0U; x < width; x += max_pixels, row += max_bytes) { - int finish = 0; - if (max_pixels > width - x) { max_bytes = width - x; @@ -858,22 +852,23 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row, max_bytes = (max_bytes * input_depth + 7U) >> 3; } - if (end_of_image && x + max_pixels >= width) - finish = 1; + debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */ + if (x + max_pixels >= width) + row_info_flags |= png_row_end; - filters = png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels, - first_row_in_pass, last_pass_row, filters, finish); + png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels, + row_info_flags); } } static void write_row_core(png_structrp png_ptr, png_const_bytep row, - int first_row_in_pass, int last_pass_row, int end_of_image) + unsigned int row_info_flags) { # ifdef PNG_WRITE_TRANSFORMS_SUPPORTED if (png_ptr->transform_list != NULL) - write_row_buffered(png_ptr, row, first_row_in_pass, last_pass_row, - end_of_image, copy_row, png_ptr->row_input_pixel_depth); + write_row_buffered(png_ptr, row, row_info_flags, + copy_row, png_ptr->row_input_pixel_depth); else # endif /* WRITE_TRANSFORMS */ @@ -881,8 +876,7 @@ write_row_core(png_structrp png_ptr, png_const_bytep row, /* If control reaches this point the intermediate buffer is not required and * the input data can be used unmodified. */ - write_row_unbuffered(png_ptr, row, first_row_in_pass, last_pass_row, - end_of_image); + write_row_unbuffered(png_ptr, row, row_info_flags); } /* Write a single non-interlaced row. */ @@ -892,8 +886,11 @@ write_row_non_interlaced(png_structrp png_ptr, png_const_bytep row) const png_uint_32 row_number = png_ptr->row_number+1U; const int last_pass_row = row_number == png_ptr->height; - write_row_core(png_ptr, row, row_number == 1U, last_pass_row, - last_pass_row); + /* There is only one pass, so this is the last pass: */ + write_row_core(png_ptr, row, + (row_number == 1U ? png_pass_first_row : 0U) | + (last_pass_row ? png_pass_last_row : 0U) | + png_pass_last); if (!last_pass_row) png_ptr->row_number = row_number; @@ -910,14 +907,17 @@ static void write_row_interlaced(png_structrp png_ptr, png_const_bytep row) { /* row_number is the row in the pass. The app must only call png_write_row - * the correct number of times. 'pass' is set to 7U at the end. + * the correct number of times. 'pass' is set to 7U after the end. */ const png_uint_32 row_number = png_ptr->row_number+1U; unsigned int pass = png_ptr->pass; const int last_pass_row = row_number == PNG_PASS_ROWS(png_ptr->height, pass); - write_row_core(png_ptr, row, row_number == 1U, last_pass_row, - last_pass_row && pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height)); + write_row_core(png_ptr, row, + (row_number == 1U ? png_pass_first_row : 0U) | + (last_pass_row ? png_pass_last_row : 0U) | + (pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ? + png_pass_last : 0U)); if (!last_pass_row) png_ptr->row_number = row_number; @@ -950,8 +950,13 @@ interlace_row(png_structrp png_ptr, png_const_bytep row) if (write_row) { - const int last_pass_row = - PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height); + const unsigned int row_info_flags = + (row_number == PNG_PASS_START_ROW(pass) ? + png_pass_first_row : 0U) | + (PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height) ? + png_pass_last_row : 0U) | + (pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ? + png_pass_last : 0U); if (pass < 6) { @@ -963,8 +968,6 @@ interlace_row(png_structrp png_ptr, png_const_bytep row) */ const unsigned int input_depth = png_ptr->row_input_pixel_depth; unsigned int B = 0; /* log2(input_depth) */ - const int end_of_image = last_pass_row && - pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height); switch (input_depth) { @@ -975,22 +978,19 @@ interlace_row(png_structrp png_ptr, png_const_bytep row) ++B; /*FALL THROUGH*/ case 1U: /* B will be 0 */ - write_row_buffered(png_ptr, row, - row_number == PNG_PASS_START_ROW(pass), last_pass_row, - end_of_image, interlace_row_lbd, B); + write_row_buffered(png_ptr, row, row_info_flags, + interlace_row_lbd, B); break; default: /* Parameter is the pixel size in bytes */ - write_row_buffered(png_ptr, row, - row_number == PNG_PASS_START_ROW(pass), last_pass_row, - end_of_image, interlace_row_byte, input_depth >> 3); + write_row_buffered(png_ptr, row, row_info_flags, + interlace_row_byte, input_depth >> 3); break; } } else /* pass 6; no interlacing required */ - write_row_core(png_ptr, row, row_number == 1U, last_pass_row, - last_pass_row); + write_row_core(png_ptr, row, row_info_flags); } if (row_number+1U < png_ptr->height) @@ -1099,20 +1099,8 @@ png_write_destroy(png_structrp png_ptr) { png_debug(1, "in png_write_destroy"); - /* Free any memory zlib uses */ - if (png_ptr->zstream.state != NULL) - { - int ret = deflateEnd(&png_ptr->zstream); + png_deflate_destroy(png_ptr); - if (ret != Z_OK) - { - png_zstream_error(&png_ptr->zstream, ret); - png_warning(png_ptr, png_ptr->zstream.msg); - } - } - - /* Free our memory. png_free checks NULL for us. */ - png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); #ifdef PNG_WRITE_FILTER_SUPPORTED png_free(png_ptr, png_ptr->row_buffer); png_ptr->row_buffer = NULL; diff --git a/pngwutil.c b/pngwutil.c index 3eff9d1cb..bd124be40 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -458,7 +458,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, } /* Clean up (or trim) a linked list of compression buffers. */ -void /* PRIVATE */ +static void png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) { png_compression_bufferp list = *listp; @@ -478,6 +478,26 @@ png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) } } +/* Release memory used by the deflate mechanism */ +void /* PRIVATE */ +png_deflate_destroy(png_structrp png_ptr) +{ + /* Free any memory zlib uses */ + if (png_ptr->zstream.state != NULL) + { + int ret = deflateEnd(&png_ptr->zstream); + + if (ret != Z_OK) + { + png_zstream_error(&png_ptr->zstream, ret); + png_warning(png_ptr, png_ptr->zstream.msg); + } + } + + /* Free our memory. png_free checks NULL for us. */ + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); +} + /* Compress the given data given a compression buffer list. The passed in * z_stream must have already been claimed (if required) and the compression * buffer list pointer initialized to NULL or an existing list. @@ -2140,7 +2160,7 @@ png_write_flush(png_structrp png_ptr) static void write_filtered_row(png_structrp png_ptr, png_const_voidp filtered_row, - unsigned int row_bytes, png_byte filter /*if at start of row*/, + unsigned int row_bytes, unsigned int filter /*if at start of row*/, int end_of_image) { /* This handles writing a row that has been filtered, or did not need to be @@ -2155,7 +2175,7 @@ write_filtered_row(png_structrp png_ptr, png_const_voidp filtered_row, { png_byte buffer[1]; - buffer[0] = filter; + buffer[0] = PNG_BYTE(filter); png_compress_IDAT(png_ptr, buffer, 1U/*len*/, Z_NO_FLUSH); } @@ -2341,35 +2361,25 @@ filter_block(png_const_bytep prev_row, png_bytep prev_pixels, static void filter_row(png_structrp png_ptr, png_const_bytep prev_row, png_bytep prev_pixels, png_const_bytep unfiltered_row, - unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try, + unsigned int row_bits, unsigned int bpp, unsigned int filter, int start_of_row, int end_of_image) { /* filters_to_try identifies a single filter and it is not PNG_FILTER_NONE. */ - png_byte filter = PNG_FILTER_VALUE_LAST /* not at start */; png_byte filtered_row[PNG_ROW_BUFFER_SIZE]; - affirm((row_bits+7U) >> 3 <= PNG_ROW_BUFFER_SIZE); + affirm((row_bits+7U) >> 3 <= PNG_ROW_BUFFER_SIZE && + filter >= PNG_FILTER_VALUE_SUB && filter <= PNG_FILTER_VALUE_PAETH); debug((row_bits % bpp) == 0U); - if (start_of_row) switch (filters_to_try) - { - case PNG_FILTER_SUB: filter = PNG_FILTER_VALUE_SUB; break; - case PNG_FILTER_UP: filter = PNG_FILTER_VALUE_UP; break; - case PNG_FILTER_AVG: filter = PNG_FILTER_VALUE_AVG; break; - case PNG_FILTER_PAETH: filter = PNG_FILTER_VALUE_PAETH; break; - default: - impossible("filter list"); - } - filter_block(prev_row, prev_pixels, unfiltered_row, row_bits, bpp, - filters_to_try & PNG_FILTER_SUB ? filtered_row : NULL, - filters_to_try & PNG_FILTER_UP ? filtered_row : NULL, - filters_to_try & PNG_FILTER_AVG ? filtered_row : NULL, - filters_to_try & PNG_FILTER_PAETH ? filtered_row : NULL); + filter == PNG_FILTER_VALUE_SUB ? filtered_row : NULL, + filter == PNG_FILTER_VALUE_UP ? filtered_row : NULL, + filter == PNG_FILTER_VALUE_AVG ? filtered_row : NULL, + filter == PNG_FILTER_VALUE_PAETH ? filtered_row : NULL); - write_filtered_row(png_ptr, filtered_row, (row_bits+7U)>>3, filter, - end_of_image); + write_filtered_row(png_ptr, filtered_row, (row_bits+7U)>>3, + start_of_row ? filter : PNG_FILTER_VALUE_LAST, end_of_image); } /* These two #defines simplify writing code that depends on one or the other of @@ -2386,11 +2396,10 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row, # define heuristic_option\ ((png_ptr->options >> PNG_SELECT_FILTER_HEURISTICALLY) & 3U) -static unsigned int +static void select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row, png_bytep prev_pixels, png_const_bytep unfiltered_row, - unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try, - int end_of_image) + unsigned int row_bits, unsigned int bpp, int end_of_image) { const unsigned int row_bytes = (row_bits+7U) >> 3; png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */ @@ -2411,6 +2420,7 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row, * generated or we expect a count of average 8 per code. */ { + unsigned int filters_to_try = png_ptr->zbuffer_filters; unsigned int filter_max = 257U; png_byte best_filter, test_filter; png_const_bytep best_row, test_row; @@ -2437,6 +2447,9 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row, filter_max = count, best_filter = test_filter, best_row = test_row; } + /* Store the best filter found: */ + png_ptr->zbuffer_filters = best_filter; + /* Calling write_unfiltered_rowbits is necessary here to deal with the * clearly of a partial byte at the end. */ @@ -2447,8 +2460,6 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row, else write_filtered_row(png_ptr, best_row, row_bytes, best_filter, end_of_image); - - return PNG_FILTER_MASK(best_filter); } } #else /* !SELECT_FILTER_HEURISTICALLY */ @@ -2462,11 +2473,10 @@ select_filters_methodically_init(png_structrp png_ptr) affirm(png_ptr->zbuffer_select == NULL); } -static int +static void select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row, png_bytep prev_pixels, png_const_bytep unfiltered_row, - unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try, - int end_of_image) + unsigned int row_bits, unsigned int bpp, int end_of_row, int end_of_image) { const unsigned int row_bytes = (row_bits+7U) >> 3; png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */ @@ -2482,8 +2492,7 @@ select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row, write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, PNG_FILTER_VALUE_LAST, end_of_image); - - return filters_to_try; + PNG_UNUSED(end_of_row) } #endif /* SELECT_FILTER_METHODICALLY */ @@ -2491,15 +2500,15 @@ select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row, * been specified by the application, and then writes the row out with the * chosen filter. */ -unsigned int /* PRIVATE */ +void /* PRIVATE */ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, - unsigned int width/*pixels*/, int first_row_in_pass, int last_pass_row, - unsigned int filters_to_try, int end_of_image) + unsigned int width/*pixels*/, unsigned int row_info_flags) { png_bytep prev_row = png_ptr->row_buffer; const unsigned int bpp = png_ptr->row_output_pixel_depth; const unsigned int row_bits = width * bpp; + unsigned int filters_to_try; /* These invariants are expected from the caller: */ affirm(width < 65536U && bpp <= 64U && width < 65536U/bpp && @@ -2519,7 +2528,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, PNG_ALL_FILTERS : PNG_NO_FILTERS); /* Now work out the filters to try for this row: */ - filters_to_try = png_ptr->filter_mask; /* else caller must preserve */ + filters_to_try = png_ptr->filter_mask; /* If this has a previous row filter in the set to try ensure the row * buffer exists and ensure it is empty when first allocated and at @@ -2541,7 +2550,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, * app warning and disable the filters that would have required * the data. */ - if (!first_row_in_pass) + if (!(row_info_flags & png_pass_first_row)) { png_app_warning(png_ptr, "Previous row filters ignored"); /* And always turn off the filters, to prevent using @@ -2556,7 +2565,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, } } - if (first_row_in_pass) + if ((row_info_flags & png_pass_first_row) != 0U) { /* On the first row UP and NONE are the same, PAETH and SUB are the * same, so if both members of a pair occur together eliminate the one @@ -2569,7 +2578,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP); if (match(PNG_FILTER_SUB+PNG_FILTER_PAETH)) - filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP); + filters_to_try &= PNG_BIC_MASK(PNG_FILTER_PAETH); # undef match } @@ -2588,59 +2597,84 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, if (heuristic_option == PNG_OPTION_OFF) /* don't use heuristics */ # endif /* SELECT_FILTER_HEURISTICALLY */ filters_to_try &= -filters_to_try; + + /* If there is just one bit set in filters_to_try convert it to the filter + * value and store that. + */ + if ((filters_to_try & (filters_to_try-1U)) == 0U) switch (filters_to_try) + { + case PNG_FILTER_NONE: filters_to_try = PNG_FILTER_VALUE_NONE; break; + case PNG_FILTER_SUB: filters_to_try = PNG_FILTER_VALUE_SUB; break; + case PNG_FILTER_UP: filters_to_try = PNG_FILTER_VALUE_UP; break; + case PNG_FILTER_AVG: filters_to_try = PNG_FILTER_VALUE_AVG; break; + case PNG_FILTER_PAETH: filters_to_try = PNG_FILTER_VALUE_PAETH; break; + default: + impossible("bad filter mask"); + } + + png_ptr->zbuffer_filters = filters_to_try; } /* start of row */ - else if (prev_row != NULL) + else { - /* Advance prev_row to the corresponding pixel above row[x], must use - * png_calc_rowbytes here otherwise the calculation using x might - * overflow. - */ - debug(((x * bpp) & 7U) == 0U); - prev_row += png_calc_rowbytes(png_ptr, bpp, x); + if (prev_row != NULL) + { + /* Advance prev_row to the corresponding pixel above row[x], must use + * png_calc_rowbytes here otherwise the calculation using x might + * overflow. + */ + debug(((x * bpp) & 7U) == 0U); + prev_row += png_calc_rowbytes(png_ptr, bpp, x); + } + + filters_to_try = png_ptr->zbuffer_filters; } /* Now choose the correct filter implementation according to the number of * filters in the filters_to_try list. The prev_row parameter is made NULL * on the first row because it is uninitialized at that point. */ - if (filters_to_try == PNG_FILTER_NONE) + if (filters_to_try == PNG_FILTER_VALUE_NONE) write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, - end_of_image); + PNG_IDAT_END(row_info_flags)); - else if ((filters_to_try & -filters_to_try) == filters_to_try) /* 1 filter */ - filter_row(png_ptr, first_row_in_pass ? NULL : prev_row, - prev_pixels, unfiltered_row, row_bits, bpp, filters_to_try, x == 0, - end_of_image); + else + { + png_const_bytep prev = + (row_info_flags & png_pass_first_row) ? NULL : prev_row; -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - else if (png_ptr->zbuffer_select != NULL) - filters_to_try = select_filter_methodically(png_ptr, - first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row, - row_bits, bpp, filters_to_try, end_of_image); -# endif /* SELECT_FILTER_METHODICALLY */ -# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED - /* The heuristic must select a single filter based on the first block of - * pixels: - */ - else - filters_to_try = select_filter_heuristically(png_ptr, - first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row, - row_bits, bpp, filters_to_try, end_of_image); -# else /* !SELECT_FILTER_HEURISTICALLY */ - else - impossible("bad filter select logic"); -# endif /* !SELECT_FILTER_HEURISTICALLY */ + /* Is just one bit set in 'filters_to_try'? */ + if (filters_to_try < PNG_FILTER_MASK(0)) + filter_row(png_ptr, prev, prev_pixels, unfiltered_row, row_bits, bpp, + filters_to_try, x == 0, PNG_IDAT_END(row_info_flags)); + +# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED + else if (png_ptr->zbuffer_select != NULL) + select_filter_methodically(png_ptr, prev, prev_pixels, + unfiltered_row, row_bits, bpp, + (row_info_flags & png_row_end) != 0U, + PNG_IDAT_END(row_info_flags)); +# endif /* SELECT_FILTER_METHODICALLY */ +# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED + /* The heuristic must select a single filter based on the first block + * of pixels; it updates zbuffer_filter to a single filter value. + */ + else + select_filter_heuristically(png_ptr, prev, prev_pixels, + unfiltered_row, row_bits, bpp, PNG_IDAT_END(row_info_flags)); +# else /* !SELECT_FILTER_HEURISTICALLY */ + else + impossible("bad filter select logic"); +# endif /* !SELECT_FILTER_HEURISTICALLY */ + } /* Copy the current row into the previous row buffer, if available, unless * this is the last row in the pass, when there is no point. Note that * prev_row may have garbage in a partial byte at the end. */ - if (prev_row != NULL && !last_pass_row) + if (prev_row != NULL && !(row_info_flags & png_pass_last_row)) memcpy(prev_row, unfiltered_row, (row_bits + 7U) >> 3); - - return filters_to_try; } /* Allow the application to select one or more row filters to use. */