| Index: third_party/libwebp/dec/vp8l.c
|
| diff --git a/third_party/libwebp/dec/vp8l.c b/third_party/libwebp/dec/vp8l.c
|
| index a76ad6a13ac8e3bb76b76feed410d94836af6370..cb2e3176b6346051f5250ea5fe5a265fc3731978 100644
|
| --- a/third_party/libwebp/dec/vp8l.c
|
| +++ b/third_party/libwebp/dec/vp8l.c
|
| @@ -714,34 +714,22 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
|
| }
|
| }
|
|
|
| -// Special method for paletted alpha data.
|
| -static void ApplyInverseTransformsAlpha(VP8LDecoder* const dec, int num_rows,
|
| - const uint8_t* const rows) {
|
| - const int start_row = dec->last_row_;
|
| - const int end_row = start_row + num_rows;
|
| - const uint8_t* rows_in = rows;
|
| - uint8_t* rows_out = (uint8_t*)dec->io_->opaque + dec->io_->width * start_row;
|
| - VP8LTransform* const transform = &dec->transforms_[0];
|
| - assert(dec->next_transform_ == 1);
|
| - assert(transform->type_ == COLOR_INDEXING_TRANSFORM);
|
| - VP8LColorIndexInverseTransformAlpha(transform, start_row, end_row, rows_in,
|
| - rows_out);
|
| -}
|
| -
|
| // Processes (transforms, scales & color-converts) the rows decoded after the
|
| // last call.
|
| static void ProcessRows(VP8LDecoder* const dec, int row) {
|
| const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_;
|
| const int num_rows = row - dec->last_row_;
|
|
|
| - if (num_rows <= 0) return; // Nothing to be done.
|
| - ApplyInverseTransforms(dec, num_rows, rows);
|
| -
|
| - // Emit output.
|
| - {
|
| + assert(row <= dec->io_->crop_bottom);
|
| + // We can't process more than NUM_ARGB_CACHE_ROWS at a time (that's the size
|
| + // of argb_cache_), but we currently don't need more than that.
|
| + assert(num_rows <= NUM_ARGB_CACHE_ROWS);
|
| + if (num_rows > 0) { // Emit output.
|
| VP8Io* const io = dec->io_;
|
| uint8_t* rows_data = (uint8_t*)dec->argb_cache_;
|
| const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA
|
| +
|
| + ApplyInverseTransforms(dec, num_rows, rows);
|
| if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) {
|
| // Nothing to output (this time).
|
| } else {
|
| @@ -786,14 +774,46 @@ static int Is8bOptimizable(const VP8LMetadata* const hdr) {
|
| return 1;
|
| }
|
|
|
| -static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int row) {
|
| - const int num_rows = row - dec->last_row_;
|
| - const uint8_t* const in =
|
| - (uint8_t*)dec->pixels_ + dec->width_ * dec->last_row_;
|
| - if (num_rows > 0) {
|
| - ApplyInverseTransformsAlpha(dec, num_rows, in);
|
| +static void AlphaApplyFilter(ALPHDecoder* const alph_dec,
|
| + int first_row, int last_row,
|
| + uint8_t* out, int stride) {
|
| + if (alph_dec->filter_ != WEBP_FILTER_NONE) {
|
| + int y;
|
| + const uint8_t* prev_line = alph_dec->prev_line_;
|
| + assert(WebPUnfilters[alph_dec->filter_] != NULL);
|
| + for (y = first_row; y < last_row; ++y) {
|
| + WebPUnfilters[alph_dec->filter_](prev_line, out, out, stride);
|
| + prev_line = out;
|
| + out += stride;
|
| + }
|
| + alph_dec->prev_line_ = prev_line;
|
| }
|
| - dec->last_row_ = dec->last_out_row_ = row;
|
| +}
|
| +
|
| +static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int last_row) {
|
| + // For vertical and gradient filtering, we need to decode the part above the
|
| + // crop_top row, in order to have the correct spatial predictors.
|
| + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque;
|
| + const int top_row =
|
| + (alph_dec->filter_ == WEBP_FILTER_NONE ||
|
| + alph_dec->filter_ == WEBP_FILTER_HORIZONTAL) ? dec->io_->crop_top
|
| + : dec->last_row_;
|
| + const int first_row = (dec->last_row_ < top_row) ? top_row : dec->last_row_;
|
| + assert(last_row <= dec->io_->crop_bottom);
|
| + if (last_row > first_row) {
|
| + // Special method for paletted alpha data. We only process the cropped area.
|
| + const int width = dec->io_->width;
|
| + uint8_t* out = alph_dec->output_ + width * first_row;
|
| + const uint8_t* const in =
|
| + (uint8_t*)dec->pixels_ + dec->width_ * first_row;
|
| + VP8LTransform* const transform = &dec->transforms_[0];
|
| + assert(dec->next_transform_ == 1);
|
| + assert(transform->type_ == COLOR_INDEXING_TRANSFORM);
|
| + VP8LColorIndexInverseTransformAlpha(transform, first_row, last_row,
|
| + in, out);
|
| + AlphaApplyFilter(alph_dec, first_row, last_row, out, width);
|
| + }
|
| + dec->last_row_ = dec->last_out_row_ = last_row;
|
| }
|
|
|
| //------------------------------------------------------------------------------
|
| @@ -922,14 +942,14 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
| int col = dec->last_pixel_ % width;
|
| VP8LBitReader* const br = &dec->br_;
|
| VP8LMetadata* const hdr = &dec->hdr_;
|
| - const HTreeGroup* htree_group = GetHtreeGroupForPos(hdr, col, row);
|
| int pos = dec->last_pixel_; // current position
|
| const int end = width * height; // End of data
|
| const int last = width * last_row; // Last pixel to decode
|
| const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
|
| const int mask = hdr->huffman_mask_;
|
| - assert(htree_group != NULL);
|
| - assert(pos < end);
|
| + const HTreeGroup* htree_group =
|
| + (pos < last) ? GetHtreeGroupForPos(hdr, col, row) : NULL;
|
| + assert(pos <= end);
|
| assert(last_row <= height);
|
| assert(Is8bOptimizable(hdr));
|
|
|
| @@ -939,6 +959,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
| if ((col & mask) == 0) {
|
| htree_group = GetHtreeGroupForPos(hdr, col, row);
|
| }
|
| + assert(htree_group != NULL);
|
| VP8LFillBitWindow(br);
|
| code = ReadSymbol(htree_group->htrees[GREEN], br);
|
| if (code < NUM_LITERAL_CODES) { // Literal
|
| @@ -948,7 +969,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
| if (col >= width) {
|
| col = 0;
|
| ++row;
|
| - if (row % NUM_ARGB_CACHE_ROWS == 0) {
|
| + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
|
| ExtractPalettedAlphaRows(dec, row);
|
| }
|
| }
|
| @@ -971,7 +992,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
| while (col >= width) {
|
| col -= width;
|
| ++row;
|
| - if (row % NUM_ARGB_CACHE_ROWS == 0) {
|
| + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
|
| ExtractPalettedAlphaRows(dec, row);
|
| }
|
| }
|
| @@ -985,7 +1006,7 @@ static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
|
| assert(br->eos_ == VP8LIsEndOfStream(br));
|
| }
|
| // Process the remaining rows corresponding to last row-block.
|
| - ExtractPalettedAlphaRows(dec, row);
|
| + ExtractPalettedAlphaRows(dec, row > last_row ? last_row : row);
|
|
|
| End:
|
| if (!ok || (br->eos_ && pos < end)) {
|
| @@ -1025,7 +1046,6 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
| int col = dec->last_pixel_ % width;
|
| VP8LBitReader* const br = &dec->br_;
|
| VP8LMetadata* const hdr = &dec->hdr_;
|
| - HTreeGroup* htree_group = GetHtreeGroupForPos(hdr, col, row);
|
| uint32_t* src = data + dec->last_pixel_;
|
| uint32_t* last_cached = src;
|
| uint32_t* const src_end = data + width * height; // End of data
|
| @@ -1036,8 +1056,9 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
| VP8LColorCache* const color_cache =
|
| (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
|
| const int mask = hdr->huffman_mask_;
|
| - assert(htree_group != NULL);
|
| - assert(src < src_end);
|
| + const HTreeGroup* htree_group =
|
| + (src < src_last) ? GetHtreeGroupForPos(hdr, col, row) : NULL;
|
| + assert(dec->last_row_ < last_row);
|
| assert(src_last <= src_end);
|
|
|
| while (src < src_last) {
|
| @@ -1049,7 +1070,10 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
| // Only update when changing tile. Note we could use this test:
|
| // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
|
| // but that's actually slower and needs storing the previous col/row.
|
| - if ((col & mask) == 0) htree_group = GetHtreeGroupForPos(hdr, col, row);
|
| + if ((col & mask) == 0) {
|
| + htree_group = GetHtreeGroupForPos(hdr, col, row);
|
| + }
|
| + assert(htree_group != NULL);
|
| if (htree_group->is_trivial_code) {
|
| *src = htree_group->literal_arb;
|
| goto AdvanceByOne;
|
| @@ -1080,8 +1104,10 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
| if (col >= width) {
|
| col = 0;
|
| ++row;
|
| - if ((row % NUM_ARGB_CACHE_ROWS == 0) && (process_func != NULL)) {
|
| - process_func(dec, row);
|
| + if (process_func != NULL) {
|
| + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
|
| + process_func(dec, row);
|
| + }
|
| }
|
| if (color_cache != NULL) {
|
| while (last_cached < src) {
|
| @@ -1108,8 +1134,10 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
| while (col >= width) {
|
| col -= width;
|
| ++row;
|
| - if ((row % NUM_ARGB_CACHE_ROWS == 0) && (process_func != NULL)) {
|
| - process_func(dec, row);
|
| + if (process_func != NULL) {
|
| + if (row <= last_row && (row % NUM_ARGB_CACHE_ROWS == 0)) {
|
| + process_func(dec, row);
|
| + }
|
| }
|
| }
|
| // Because of the check done above (before 'src' was incremented by
|
| @@ -1140,7 +1168,7 @@ static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
|
| } else if (!br->eos_) {
|
| // Process the remaining rows corresponding to last row-block.
|
| if (process_func != NULL) {
|
| - process_func(dec, row);
|
| + process_func(dec, row > last_row ? last_row : row);
|
| }
|
| dec->status_ = VP8_STATUS_OK;
|
| dec->last_pixel_ = (int)(src - data); // end-of-scan marker
|
| @@ -1438,46 +1466,51 @@ static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
|
| //------------------------------------------------------------------------------
|
|
|
| // Special row-processing that only stores the alpha data.
|
| -static void ExtractAlphaRows(VP8LDecoder* const dec, int row) {
|
| - const int num_rows = row - dec->last_row_;
|
| - const uint32_t* const in = dec->pixels_ + dec->width_ * dec->last_row_;
|
| -
|
| - if (num_rows <= 0) return; // Nothing to be done.
|
| - ApplyInverseTransforms(dec, num_rows, in);
|
| -
|
| - // Extract alpha (which is stored in the green plane).
|
| - {
|
| +static void ExtractAlphaRows(VP8LDecoder* const dec, int last_row) {
|
| + int cur_row = dec->last_row_;
|
| + int num_rows = last_row - cur_row;
|
| + const uint32_t* in = dec->pixels_ + dec->width_ * cur_row;
|
| +
|
| + assert(last_row <= dec->io_->crop_bottom);
|
| + while (num_rows > 0) {
|
| + const int num_rows_to_process =
|
| + (num_rows > NUM_ARGB_CACHE_ROWS) ? NUM_ARGB_CACHE_ROWS : num_rows;
|
| + // Extract alpha (which is stored in the green plane).
|
| + ALPHDecoder* const alph_dec = (ALPHDecoder*)dec->io_->opaque;
|
| + uint8_t* const output = alph_dec->output_;
|
| const int width = dec->io_->width; // the final width (!= dec->width_)
|
| - const int cache_pixs = width * num_rows;
|
| - uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_;
|
| + const int cache_pixs = width * num_rows_to_process;
|
| + uint8_t* const dst = output + width * cur_row;
|
| const uint32_t* const src = dec->argb_cache_;
|
| int i;
|
| + ApplyInverseTransforms(dec, num_rows_to_process, in);
|
| for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff;
|
| - }
|
| - dec->last_row_ = dec->last_out_row_ = row;
|
| + AlphaApplyFilter(alph_dec,
|
| + cur_row, cur_row + num_rows_to_process, dst, width);
|
| + num_rows -= num_rows_to_process;
|
| + in += num_rows_to_process * dec->width_;
|
| + cur_row += num_rows_to_process;
|
| + }
|
| + assert(cur_row == last_row);
|
| + dec->last_row_ = dec->last_out_row_ = last_row;
|
| }
|
|
|
| int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
|
| - const uint8_t* const data, size_t data_size,
|
| - uint8_t* const output) {
|
| + const uint8_t* const data, size_t data_size) {
|
| int ok = 0;
|
| - VP8LDecoder* dec;
|
| - VP8Io* io;
|
| + VP8LDecoder* dec = VP8LNew();
|
| +
|
| + if (dec == NULL) return 0;
|
| +
|
| assert(alph_dec != NULL);
|
| - alph_dec->vp8l_dec_ = VP8LNew();
|
| - if (alph_dec->vp8l_dec_ == NULL) return 0;
|
| - dec = alph_dec->vp8l_dec_;
|
| + alph_dec->vp8l_dec_ = dec;
|
|
|
| dec->width_ = alph_dec->width_;
|
| dec->height_ = alph_dec->height_;
|
| dec->io_ = &alph_dec->io_;
|
| - io = dec->io_;
|
| -
|
| - VP8InitIo(io);
|
| - WebPInitCustomIo(NULL, io); // Just a sanity Init. io won't be used.
|
| - io->opaque = output;
|
| - io->width = alph_dec->width_;
|
| - io->height = alph_dec->height_;
|
| + dec->io_->opaque = alph_dec;
|
| + dec->io_->width = alph_dec->width_;
|
| + dec->io_->height = alph_dec->height_;
|
|
|
| dec->status_ = VP8_STATUS_OK;
|
| VP8LInitBitReader(&dec->br_, data, data_size);
|
| @@ -1492,11 +1525,11 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
|
| if (dec->next_transform_ == 1 &&
|
| dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM &&
|
| Is8bOptimizable(&dec->hdr_)) {
|
| - alph_dec->use_8b_decode = 1;
|
| + alph_dec->use_8b_decode_ = 1;
|
| ok = AllocateInternalBuffers8b(dec);
|
| } else {
|
| // Allocate internal buffers (note that dec->width_ may have changed here).
|
| - alph_dec->use_8b_decode = 0;
|
| + alph_dec->use_8b_decode_ = 0;
|
| ok = AllocateInternalBuffers32b(dec, alph_dec->width_);
|
| }
|
|
|
| @@ -1515,12 +1548,12 @@ int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
|
| assert(dec != NULL);
|
| assert(last_row <= dec->height_);
|
|
|
| - if (dec->last_pixel_ == dec->width_ * dec->height_) {
|
| + if (dec->last_row_ >= last_row) {
|
| return 1; // done
|
| }
|
|
|
| // Decode (with special row processing).
|
| - return alph_dec->use_8b_decode ?
|
| + return alph_dec->use_8b_decode_ ?
|
| DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
|
| last_row) :
|
| DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
|
| @@ -1611,7 +1644,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
|
|
|
| // Decode.
|
| if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
|
| - dec->height_, ProcessRows)) {
|
| + io->crop_bottom, ProcessRows)) {
|
| goto Err;
|
| }
|
|
|
|
|