Bug 1509878 - Upgrade libwebp to version 1.0.1 r=jrmuizel
authorAndrew Osmond <aosmond@mozilla.com>
Mon, 26 Nov 2018 09:59:22 -0500
changeset 504455 5fb44413dac138585f4783470e5c9e9d7cf501f3
parent 504454 c4508d6ea52f4654ee131de9b7c4042ad5fc4f43
child 504456 8a7a03bc253d12664de2a396b2483187499af996
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1509878
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1509878 - Upgrade libwebp to version 1.0.1 r=jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D12933
media/libwebp/AUTHORS
media/libwebp/MOZCHANGES
media/libwebp/NEWS
media/libwebp/README
media/libwebp/README.mux
media/libwebp/src/dec/alphai_dec.h
media/libwebp/src/dec/buffer_dec.c
media/libwebp/src/dec/common_dec.h
media/libwebp/src/dec/frame_dec.c
media/libwebp/src/dec/idec_dec.c
media/libwebp/src/dec/vp8_dec.h
media/libwebp/src/dec/vp8i_dec.h
media/libwebp/src/dec/vp8l_dec.c
media/libwebp/src/dec/vp8li_dec.h
media/libwebp/src/dec/webpi_dec.h
media/libwebp/src/demux/demux.c
media/libwebp/src/dsp/dsp.h
media/libwebp/src/dsp/lossless.c
media/libwebp/src/dsp/lossless.h
media/libwebp/src/dsp/msa_macro.h
media/libwebp/src/dsp/rescaler.c
media/libwebp/src/dsp/rescaler_mips32.c
media/libwebp/src/dsp/rescaler_mips_dsp_r2.c
media/libwebp/src/dsp/rescaler_msa.c
media/libwebp/src/dsp/rescaler_neon.c
media/libwebp/src/dsp/rescaler_sse2.c
media/libwebp/src/dsp/yuv.h
media/libwebp/src/enc/cost_enc.h
media/libwebp/src/enc/histogram_enc.h
media/libwebp/src/enc/vp8i_enc.h
media/libwebp/src/enc/vp8li_enc.h
media/libwebp/src/utils/bit_reader_inl_utils.h
media/libwebp/src/utils/bit_reader_utils.h
media/libwebp/src/utils/bit_writer_utils.h
media/libwebp/src/utils/filters_utils.h
media/libwebp/src/utils/quant_levels_dec_utils.c
media/libwebp/src/utils/quant_levels_dec_utils.h
media/libwebp/src/utils/quant_levels_utils.h
media/libwebp/src/utils/random_utils.h
media/libwebp/src/utils/rescaler_utils.h
media/libwebp/src/utils/thread_utils.h
media/libwebp/src/utils/utils.h
media/libwebp/src/webp/decode.h
media/libwebp/src/webp/demux.h
media/libwebp/src/webp/encode.h
media/libwebp/src/webp/format_constants.h
media/libwebp/src/webp/mux.h
media/libwebp/src/webp/mux_types.h
media/libwebp/src/webp/types.h
toolkit/moz.configure
--- a/media/libwebp/AUTHORS
+++ b/media/libwebp/AUTHORS
@@ -1,19 +1,21 @@
 Contributors:
+- Alan Browning (browning at google dot com)
 - Charles Munger (clm at google dot com)
 - Christian Duvivier (cduvivier at google dot com)
 - Djordje Pesut (djordje dot pesut at imgtec dot com)
 - Hui Su (huisu at google dot com)
 - James Zern (jzern at google dot com)
 - Jan Engelhardt (jengelh at medozas dot de)
 - Jehan (jehan at girinstud dot io)
 - Johann (johann dot koenig at duck dot com)
 - Jovan Zelincevic (jovan dot zelincevic at imgtec dot com)
 - Jyrki Alakuijala (jyrki at google dot com)
+- Konstantin Ivlev (tomskside at gmail dot com)
 - Lode Vandevenne (lode at google dot com)
 - Lou Quillio (louquillio at google dot com)
 - Mans Rullgard (mans at mansr dot com)
 - Marcin Kowalczyk (qrczak at google dot com)
 - Martin Olsson (mnemo at minimum dot se)
 - Mikołaj Zalewski (mikolajz at google dot com)
 - Mislav Bradac (mislavm at google dot com)
 - Nico Weber (thakis at chromium dot org)
@@ -32,8 +34,9 @@ Contributors:
 - Sriraman Tallam (tmsriram at google dot com)
 - Tamar Levy (tamar dot levy at intel dot com)
 - Timothy Gu (timothygu99 at gmail dot com)
 - Urvang Joshi (urvang at google dot com)
 - Vikas Arora (vikasa at google dot com)
 - Vincent Rabaud (vrabaud at google dot com)
 - Vlad Tsyrklevich (vtsyrklevich at chromium dot org)
 - Yang Zhang (yang dot zhang at arm dot com)
+- Yannis Guyon (yguyon at google dot com)
--- a/media/libwebp/MOZCHANGES
+++ b/media/libwebp/MOZCHANGES
@@ -1,3 +1,5 @@
 Changes made to pristine libwebp source by mozilla.org developers.
 
+2018/11/26  -- Synced with libwebp-1.0.1 (bug 1509878).
+
 2018/10/04  -- Synced with libwebp-1.0.0 (bug #1294490).
--- a/media/libwebp/NEWS
+++ b/media/libwebp/NEWS
@@ -1,8 +1,20 @@
+- 11/2/2018: version 1.0.1
+  This is a binary compatible release.
+  * lossless encoder speedups
+  * big-endian fix for alpha decoding (issue #393)
+  * gif2webp fix for loop count=65535 transcode (issue #382)
+  * further security related hardening in libwebp & libwebpmux
+    (issues #383, #385, #386, #387, #388, #391)
+    (oss-fuzz #9099, #9100, #9105, #9106, #9111, #9112, #9119, #9123, #9170,
+              #9178, #9179, #9183, #9186, #9191, #9364, #9417, #9496, #10349,
+              #10423, #10634, #10700, #10838, #10922, #11021, #11088, #11152)
+  * miscellaneous bug & build fixes (issues #381, #394, #396, #397, #400)
+
 - 4/2/2018: version 1.0.0
   This is a binary compatible release.
   * lossy encoder improvements to avoid chroma shifts in various circumstances
     (issues #308, #340)
   * big-endian fixes for decode, RGBA import and WebPPictureDistortion
   Tool updates:
     gifwebp, anim_diff - default duration behavior (<= 10ms) changed to match
                          web browsers, transcoding tools (issue #379)
--- a/media/libwebp/README
+++ b/media/libwebp/README
@@ -1,15 +1,15 @@
           __   __  ____  ____  ____
          /  \\/  \/  _ \/  _ )/  _ \
          \       /   __/  _  \   __/
           \__\__/\____/\_____/__/ ____  ___
                 / _/ /    \    \ /  _ \/ _/
                /  \_/   / /   \ \   __/  \__
-               \____/____/\_____/_____/____/v1.0.0
+               \____/____/\_____/_____/____/v1.0.1
 
 Description:
 ============
 
 WebP codec: library to encode and decode images in WebP format. This package
 contains the library that can be used in other programs to add WebP support,
 as well as the command line tools 'cwebp' and 'dwebp'.
 
@@ -397,22 +397,24 @@ Usage: vwebp in_file [options]
 Decodes the WebP image file and visualize it using OpenGL
 Options are:
   -version ..... print version number and exit
   -noicc ....... don't use the icc profile if present
   -nofancy ..... don't use the fancy YUV420 upscaler
   -nofilter .... disable in-loop filtering
   -dither <int>  dithering strength (0..100), default=50
   -noalphadither disable alpha plane dithering
+  -usebgcolor .. display background color
   -mt .......... use multi-threading
   -info ........ print info
   -h ........... this help message
 
 Keyboard shortcuts:
   'c' ................ toggle use of color profile
+  'b' ................ toggle background color display
   'i' ................ overlay file information
   'd' ................ disable blending & disposal (debug)
   'q' / 'Q' / ESC .... quit
 
 Building:
 ---------
 
 Prerequisites:
@@ -465,16 +467,19 @@ Per-frame options (only used for subsequ
  -lossless  ........... use lossless mode (default)
  -lossy ... ........... use lossy mode
  -q <float> ........... quality
  -m <int> ............. method to use
 
 example: img2webp -loop 2 in0.png -lossy in1.jpg
                   -d 80 in2.tiff -o out.webp
 
+Note: if a single file name is passed as the argument, the arguments will be
+tokenized from this file. The file name must not start with the character '-'.
+
 Animated GIF conversion:
 ========================
 Animated GIF files can be converted to WebP files with animation using the
 gif2webp utility available under examples/. The files can then be viewed using
 vwebp.
 
 Usage:
  gif2webp [options] gif_file -o webp_file
--- a/media/libwebp/README.mux
+++ b/media/libwebp/README.mux
@@ -1,12 +1,12 @@
           __   __  ____  ____  ____  __ __  _     __ __
          /  \\/  \/  _ \/  _ \/  _ \/  \  \/ \___/_ / _\
          \       /   __/  _  \   __/      /  /  (_/  /__
-          \__\__/\_____/_____/__/  \__//_/\_____/__/___/v1.0.0
+          \__\__/\_____/_____/__/  \__//_/\_____/__/___/v1.0.1
 
 
 Description:
 ============
 
 WebPMux: set of two libraries 'Mux' and 'Demux' for creation, extraction and
 manipulation of an extended format WebP file, which can have features like
 color profile, metadata and animation. Reference command-line tools 'webpmux'
@@ -206,16 +206,45 @@ Code example:
   WebPAnimEncoderAssemble(enc, webp_data);
   WebPAnimEncoderDelete(enc);
   // ... (Write the 'webp_data' to a file, or re-mux it further).
 
 
 For a detailed AnimEncoder API reference, please refer to the header file
 (src/webp/mux.h).
 
+AnimDecoder API:
+================
+This AnimDecoder API allows decoding (possibly) animated WebP images.
+
+Code Example:
+
+  WebPAnimDecoderOptions dec_options;
+  WebPAnimDecoderOptionsInit(&dec_options);
+  // Tune 'dec_options' as needed.
+  WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
+  WebPAnimInfo anim_info;
+  WebPAnimDecoderGetInfo(dec, &anim_info);
+  for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
+    while (WebPAnimDecoderHasMoreFrames(dec)) {
+      uint8_t* buf;
+      int timestamp;
+      WebPAnimDecoderGetNext(dec, &buf, &timestamp);
+      // ... (Render 'buf' based on 'timestamp').
+      // ... (Do NOT free 'buf', as it is owned by 'dec').
+    }
+    WebPAnimDecoderReset(dec);
+  }
+  const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
+  // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
+  WebPAnimDecoderDelete(dec);
+
+For a detailed AnimDecoder API reference, please refer to the header file
+(src/webp/demux.h).
+
 
 Bugs:
 =====
 
 Please report all bugs to the issue tracker:
     https://bugs.chromium.org/p/webp
 Patches welcome! See this page to get started:
     http://www.webmproject.org/code/contribute/submitting-patches/
--- a/media/libwebp/src/dec/alphai_dec.h
+++ b/media/libwebp/src/dec/alphai_dec.h
@@ -46,9 +46,9 @@ struct ALPHDecoder {
 void WebPDeallocateAlphaMemory(VP8Decoder* const dec);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DEC_ALPHAI_DEC_H_ */
+#endif  // WEBP_DEC_ALPHAI_DEC_H_
--- a/media/libwebp/src/dec/buffer_dec.c
+++ b/media/libwebp/src/dec/buffer_dec.c
@@ -69,17 +69,18 @@ static VP8StatusCode CheckDecBuffer(cons
     if (mode == MODE_YUVA) {
       ok &= (a_stride >= width);
       ok &= (a_size <= buf->a_size);
       ok &= (buf->a != NULL);
     }
   } else {    // RGB checks
     const WebPRGBABuffer* const buf = &buffer->u.RGBA;
     const int stride = abs(buf->stride);
-    const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
+    const uint64_t size =
+        MIN_BUFFER_SIZE(width * kModeBpp[mode], height, stride);
     ok &= (size <= buf->size);
     ok &= (stride >= width * kModeBpp[mode]);
     ok &= (buf->rgba != NULL);
   }
   return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
 }
 #undef MIN_BUFFER_SIZE
 
--- a/media/libwebp/src/dec/common_dec.h
+++ b/media/libwebp/src/dec/common_dec.h
@@ -46,9 +46,9 @@ enum { MB_FEATURE_TREE_PROBS = 3,
        MAX_NUM_PARTITIONS = 8,
        // Probabilities
        NUM_TYPES = 4,   // 0: i16-AC,  1: i16-DC,  2:chroma-AC,  3:i4-AC
        NUM_BANDS = 8,
        NUM_CTX = 3,
        NUM_PROBAS = 11
      };
 
-#endif    // WEBP_DEC_COMMON_DEC_H_
+#endif  // WEBP_DEC_COMMON_DEC_H_
--- a/media/libwebp/src/dec/frame_dec.c
+++ b/media/libwebp/src/dec/frame_dec.c
@@ -333,17 +333,16 @@ void VP8InitDithering(const WebPDecoderO
     const int max_amp = (1 << VP8_RANDOM_DITHER_FIX) - 1;
     const int f = (d < 0) ? 0 : (d > 100) ? max_amp : (d * max_amp / 100);
     if (f > 0) {
       int s;
       int all_amp = 0;
       for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
         VP8QuantMatrix* const dqm = &dec->dqm_[s];
         if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
-          // TODO(skal): should we specially dither more for uv_quant_ < 0?
           const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
           dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
         }
         all_amp |= dqm->dither_;
       }
       if (all_amp != 0) {
         VP8InitRandom(&dec->dithering_rg_, 1.0f);
         dec->dither_ = 1;
@@ -664,25 +663,19 @@ int VP8GetThreadMethod(const WebPDecoder
   if (options == NULL || options->use_threads == 0) {
     return 0;
   }
   (void)headers;
   (void)width;
   (void)height;
   assert(headers == NULL || !headers->is_lossless);
 #if defined(WEBP_USE_THREAD)
-  if (width < MIN_WIDTH_FOR_THREADS) return 0;
-  // TODO(skal): tune the heuristic further
-#if 0
-  if (height < 2 * width) return 2;
+  if (width >= MIN_WIDTH_FOR_THREADS) return 2;
 #endif
-  return 2;
-#else   // !WEBP_USE_THREAD
   return 0;
-#endif
 }
 
 #undef MT_CACHE_LINES
 #undef ST_CACHE_LINES
 
 //------------------------------------------------------------------------------
 // Memory setup
 
--- a/media/libwebp/src/dec/idec_dec.c
+++ b/media/libwebp/src/dec/idec_dec.c
@@ -135,20 +135,19 @@ static void DoRemap(WebPIDecoder* const 
       {
         const uint8_t* const last_start = dec->parts_[last_part].buf_;
         VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start,
                               mem->buf_ + mem->end_ - last_start);
       }
       if (NeedCompressedAlpha(idec)) {
         ALPHDecoder* const alph_dec = dec->alph_dec_;
         dec->alpha_data_ += offset;
-        if (alph_dec != NULL) {
+        if (alph_dec != NULL && alph_dec->vp8l_dec_ != NULL) {
           if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
             VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
-            assert(alph_vp8l_dec != NULL);
             assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
             VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
                                    dec->alpha_data_ + ALPHA_HEADER_LEN,
                                    dec->alpha_data_size_ - ALPHA_HEADER_LEN);
           } else {  // alph_dec->method_ == ALPHA_NO_COMPRESSION
             // Nothing special to do in this case.
           }
         }
@@ -278,20 +277,18 @@ static void RestoreContext(const MBConte
   dec->mb_info_[dec->mb_x_] = context->info_;
   *token_br = context->token_br_;
 }
 
 //------------------------------------------------------------------------------
 
 static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
   if (idec->state_ == STATE_VP8_DATA) {
-    VP8Io* const io = &idec->io_;
-    if (io->teardown != NULL) {
-      io->teardown(io);
-    }
+    // Synchronize the thread, clean-up and check for errors.
+    VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
   }
   idec->state_ = STATE_ERROR;
   return error;
 }
 
 static void ChangeState(WebPIDecoder* const idec, DecState new_state,
                         size_t consumed_bytes) {
   MemBuffer* const mem = &idec->mem_;
@@ -446,17 +443,20 @@ static VP8StatusCode DecodePartition0(We
   return VP8_STATUS_OK;
 }
 
 // Remaining partitions
 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
   VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
   VP8Io* const io = &idec->io_;
 
-  assert(dec->ready_);
+  // Make sure partition #0 has been read before, to set dec to ready_.
+  if (!dec->ready_) {
+    return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+  }
   for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
     if (idec->last_mb_y_ != dec->mb_y_) {
       if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
         // note: normally, error shouldn't occur since we already have the whole
         // partition0 available here in DecodeRemaining(). Reaching EOF while
         // reading intra modes really means a BITSTREAM_ERROR.
         return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
       }
@@ -468,16 +468,22 @@ static VP8StatusCode DecodeRemaining(Web
       MBContext context;
       SaveContext(dec, token_br, &context);
       if (!VP8DecodeMB(dec, token_br)) {
         // We shouldn't fail when MAX_MB data was available
         if (dec->num_parts_minus_one_ == 0 &&
             MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
           return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
         }
+        // Synchronize the threads.
+        if (dec->mt_method_ > 0) {
+          if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) {
+            return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+          }
+        }
         RestoreContext(&context, dec, token_br);
         return VP8_STATUS_SUSPENDED;
       }
       // Release buffer only if there is only one partition
       if (dec->num_parts_minus_one_ == 0) {
         idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
         assert(idec->mem_.start_ <= idec->mem_.end_);
       }
@@ -486,16 +492,17 @@ static VP8StatusCode DecodeRemaining(Web
 
     // Reconstruct, filter and emit the row.
     if (!VP8ProcessRow(dec, io)) {
       return IDecError(idec, VP8_STATUS_USER_ABORT);
     }
   }
   // Synchronize the thread and check for errors.
   if (!VP8ExitCritical(dec, io)) {
+    idec->state_ = STATE_ERROR;  // prevent re-entry in IDecError
     return IDecError(idec, VP8_STATUS_USER_ABORT);
   }
   dec->ready_ = 0;
   return FinishDecoding(idec);
 }
 
 static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
                                          VP8StatusCode status) {
@@ -566,16 +573,20 @@ static VP8StatusCode IDecode(WebPIDecode
   }
   if (idec->state_ == STATE_VP8_HEADER) {
     status = DecodeVP8FrameHeader(idec);
   }
   if (idec->state_ == STATE_VP8_PARTS0) {
     status = DecodePartition0(idec);
   }
   if (idec->state_ == STATE_VP8_DATA) {
+    const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+    if (dec == NULL) {
+      return VP8_STATUS_SUSPENDED;  // can't continue if we have no decoder.
+    }
     status = DecodeRemaining(idec);
   }
   if (idec->state_ == STATE_VP8L_HEADER) {
     status = DecodeVP8LHeader(idec);
   }
   if (idec->state_ == STATE_VP8L_DATA) {
     status = DecodeVP8LData(idec);
   }
--- a/media/libwebp/src/dec/vp8_dec.h
+++ b/media/libwebp/src/dec/vp8_dec.h
@@ -177,9 +177,9 @@ WEBP_EXTERN int VP8LCheckSignature(const
 WEBP_EXTERN int VP8LGetInfo(
     const uint8_t* data, size_t data_size,  // data available so far
     int* const width, int* const height, int* const has_alpha);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DEC_VP8_DEC_H_ */
+#endif  // WEBP_DEC_VP8_DEC_H_
--- a/media/libwebp/src/dec/vp8i_dec.h
+++ b/media/libwebp/src/dec/vp8i_dec.h
@@ -27,17 +27,17 @@ extern "C" {
 #endif
 
 //------------------------------------------------------------------------------
 // Various defines and enums
 
 // version numbers
 #define DEC_MAJ_VERSION 1
 #define DEC_MIN_VERSION 0
-#define DEC_REV_VERSION 0
+#define DEC_REV_VERSION 1
 
 // YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
 // Constraints are: We need to store one 16x16 block of luma samples (y),
 // and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned,
 // in order to be SIMD-friendly. We also need to store the top, left and
 // top-left samples (from previously decoded blocks), along with four
 // extra top-right samples for luma (intra4x4 prediction only).
 // One possible layout is, using 32 * (17 + 9) bytes:
@@ -311,9 +311,9 @@ const uint8_t* VP8DecompressAlphaRows(VP
                                       int row, int num_rows);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DEC_VP8I_DEC_H_ */
+#endif  // WEBP_DEC_VP8I_DEC_H_
--- a/media/libwebp/src/dec/vp8l_dec.c
+++ b/media/libwebp/src/dec/vp8l_dec.c
@@ -357,134 +357,183 @@ static int ReadHuffmanCode(int alphabet_
 
 static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
                             int color_cache_bits, int allow_recursion) {
   int i, j;
   VP8LBitReader* const br = &dec->br_;
   VP8LMetadata* const hdr = &dec->hdr_;
   uint32_t* huffman_image = NULL;
   HTreeGroup* htree_groups = NULL;
+  // When reading htrees, some might be unused, as the format allows it.
+  // We will still read them but put them in this htree_group_bogus.
+  HTreeGroup htree_group_bogus;
   HuffmanCode* huffman_tables = NULL;
+  HuffmanCode* huffman_tables_bogus = NULL;
   HuffmanCode* next = NULL;
   int num_htree_groups = 1;
+  int num_htree_groups_max = 1;
   int max_alphabet_size = 0;
   int* code_lengths = NULL;
   const int table_size = kTableSize[color_cache_bits];
+  int* mapping = NULL;
+  int ok = 0;
 
   if (allow_recursion && VP8LReadBits(br, 1)) {
     // use meta Huffman codes.
     const int huffman_precision = VP8LReadBits(br, 3) + 2;
     const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
     const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
     const int huffman_pixs = huffman_xsize * huffman_ysize;
     if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
                            &huffman_image)) {
       goto Error;
     }
     hdr->huffman_subsample_bits_ = huffman_precision;
     for (i = 0; i < huffman_pixs; ++i) {
       // The huffman data is stored in red and green bytes.
       const int group = (huffman_image[i] >> 8) & 0xffff;
       huffman_image[i] = group;
-      if (group >= num_htree_groups) {
-        num_htree_groups = group + 1;
+      if (group >= num_htree_groups_max) {
+        num_htree_groups_max = group + 1;
+      }
+    }
+    // Check the validity of num_htree_groups_max. If it seems too big, use a
+    // smaller value for later. This will prevent big memory allocations to end
+    // up with a bad bitstream anyway.
+    // The value of 1000 is totally arbitrary. We know that num_htree_groups_max
+    // is smaller than (1 << 16) and should be smaller than the number of pixels
+    // (though the format allows it to be bigger).
+    if (num_htree_groups_max > 1000 || num_htree_groups_max > xsize * ysize) {
+      // Create a mapping from the used indices to the minimal set of used
+      // values [0, num_htree_groups)
+      mapping = (int*)WebPSafeMalloc(num_htree_groups_max, sizeof(*mapping));
+      if (mapping == NULL) {
+        dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+        goto Error;
       }
+      // -1 means a value is unmapped, and therefore unused in the Huffman
+      // image.
+      memset(mapping, 0xff, num_htree_groups_max * sizeof(*mapping));
+      for (num_htree_groups = 0, i = 0; i < huffman_pixs; ++i) {
+        // Get the current mapping for the group and remap the Huffman image.
+        int* const mapped_group = &mapping[huffman_image[i]];
+        if (*mapped_group == -1) *mapped_group = num_htree_groups++;
+        huffman_image[i] = *mapped_group;
+      }
+      huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
+          table_size, sizeof(*huffman_tables_bogus));
+      if (huffman_tables_bogus == NULL) {
+        dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+        goto Error;
+      }
+    } else {
+      num_htree_groups = num_htree_groups_max;
     }
   }
 
   if (br->eos_) goto Error;
 
   // Find maximum alphabet size for the htree group.
   for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
     int alphabet_size = kAlphabetSize[j];
     if (j == 0 && color_cache_bits > 0) {
       alphabet_size += 1 << color_cache_bits;
     }
     if (max_alphabet_size < alphabet_size) {
       max_alphabet_size = alphabet_size;
     }
   }
 
+  code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
+                                      sizeof(*code_lengths));
   huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
                                                 sizeof(*huffman_tables));
   htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
-  code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
-                                      sizeof(*code_lengths));
 
   if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
     dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
     goto Error;
   }
 
   next = huffman_tables;
-  for (i = 0; i < num_htree_groups; ++i) {
-    HTreeGroup* const htree_group = &htree_groups[i];
+  for (i = 0; i < num_htree_groups_max; ++i) {
+    // If the index "i" is unused in the Huffman image, read the coefficients
+    // but store them to a bogus htree_group.
+    const int is_bogus = (mapping != NULL && mapping[i] == -1);
+    HTreeGroup* const htree_group =
+        is_bogus ? &htree_group_bogus :
+        &htree_groups[(mapping == NULL) ? i : mapping[i]];
     HuffmanCode** const htrees = htree_group->htrees;
+    HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
     int size;
     int total_size = 0;
     int is_trivial_literal = 1;
     int max_bits = 0;
     for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
       int alphabet_size = kAlphabetSize[j];
-      htrees[j] = next;
+      htrees[j] = huffman_tables_i;
       if (j == 0 && color_cache_bits > 0) {
         alphabet_size += 1 << color_cache_bits;
       }
-      size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
+      size =
+          ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
       if (size == 0) {
         goto Error;
       }
       if (is_trivial_literal && kLiteralMap[j] == 1) {
-        is_trivial_literal = (next->bits == 0);
+        is_trivial_literal = (huffman_tables_i->bits == 0);
       }
-      total_size += next->bits;
-      next += size;
+      total_size += huffman_tables_i->bits;
+      huffman_tables_i += size;
       if (j <= ALPHA) {
         int local_max_bits = code_lengths[0];
         int k;
         for (k = 1; k < alphabet_size; ++k) {
           if (code_lengths[k] > local_max_bits) {
             local_max_bits = code_lengths[k];
           }
         }
         max_bits += local_max_bits;
       }
     }
+    if (!is_bogus) next = huffman_tables_i;
     htree_group->is_trivial_literal = is_trivial_literal;
     htree_group->is_trivial_code = 0;
     if (is_trivial_literal) {
       const int red = htrees[RED][0].value;
       const int blue = htrees[BLUE][0].value;
       const int alpha = htrees[ALPHA][0].value;
-      htree_group->literal_arb =
-          ((uint32_t)alpha << 24) | (red << 16) | blue;
+      htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
       if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
         htree_group->is_trivial_code = 1;
         htree_group->literal_arb |= htrees[GREEN][0].value << 8;
       }
     }
-    htree_group->use_packed_table = !htree_group->is_trivial_code &&
-                                    (max_bits < HUFFMAN_PACKED_BITS);
+    htree_group->use_packed_table =
+        !htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
     if (htree_group->use_packed_table) BuildPackedTable(htree_group);
   }
-  WebPSafeFree(code_lengths);
+  ok = 1;
 
-  // All OK. Finalize pointers and return.
+  // All OK. Finalize pointers.
   hdr->huffman_image_ = huffman_image;
   hdr->num_htree_groups_ = num_htree_groups;
   hdr->htree_groups_ = htree_groups;
   hdr->huffman_tables_ = huffman_tables;
-  return 1;
 
  Error:
   WebPSafeFree(code_lengths);
-  WebPSafeFree(huffman_image);
-  WebPSafeFree(huffman_tables);
-  VP8LHtreeGroupsFree(htree_groups);
-  return 0;
+  WebPSafeFree(huffman_tables_bogus);
+  WebPSafeFree(mapping);
+  if (!ok) {
+    WebPSafeFree(huffman_image);
+    WebPSafeFree(huffman_tables);
+    VP8LHtreeGroupsFree(htree_groups);
+  }
+  return ok;
 }
 
 //------------------------------------------------------------------------------
 // Scaling.
 
 #if !defined(WEBP_REDUCE_SIZE)
 static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
   const int num_channels = 4;
@@ -879,17 +928,21 @@ static WEBP_INLINE void CopyBlock8b(uint
         pattern |= pattern << 16;
 #elif defined(WEBP_USE_MIPS_DSP_R2)
         __asm__ volatile ("replv.qb %0, %0" : "+r"(pattern));
 #else
         pattern = 0x01010101u * pattern;
 #endif
         break;
       case 2:
+#if !defined(WORDS_BIGENDIAN)
         memcpy(&pattern, src, sizeof(uint16_t));
+#else
+        pattern = ((uint32_t)src[0] << 8) | src[1];
+#endif
 #if defined(__arm__) || defined(_M_ARM)
         pattern |= pattern << 16;
 #elif defined(WEBP_USE_MIPS_DSP_R2)
         __asm__ volatile ("replv.ph %0, %0" : "+r"(pattern));
 #else
         pattern = 0x00010001u * pattern;
 #endif
         break;
@@ -1518,17 +1571,16 @@ static void ExtractAlphaRows(VP8LDecoder
 int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
                           const uint8_t* const data, size_t data_size) {
   int ok = 0;
   VP8LDecoder* dec = VP8LNew();
 
   if (dec == NULL) return 0;
 
   assert(alph_dec != NULL);
-  alph_dec->vp8l_dec_ = dec;
 
   dec->width_ = alph_dec->width_;
   dec->height_ = alph_dec->height_;
   dec->io_ = &alph_dec->io_;
   dec->io_->opaque = alph_dec;
   dec->io_->width = alph_dec->width_;
   dec->io_->height = alph_dec->height_;
 
@@ -1550,21 +1602,22 @@ int VP8LDecodeAlphaHeader(ALPHDecoder* c
   } else {
     // Allocate internal buffers (note that dec->width_ may have changed here).
     alph_dec->use_8b_decode_ = 0;
     ok = AllocateInternalBuffers32b(dec, alph_dec->width_);
   }
 
   if (!ok) goto Err;
 
+  // Only set here, once we are sure it is valid (to avoid thread races).
+  alph_dec->vp8l_dec_ = dec;
   return 1;
 
  Err:
-  VP8LDelete(alph_dec->vp8l_dec_);
-  alph_dec->vp8l_dec_ = NULL;
+  VP8LDelete(dec);
   return 0;
 }
 
 int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
   VP8LDecoder* const dec = alph_dec->vp8l_dec_;
   assert(dec != NULL);
   assert(last_row <= dec->height_);
 
--- a/media/libwebp/src/dec/vp8li_dec.h
+++ b/media/libwebp/src/dec/vp8li_dec.h
@@ -127,9 +127,9 @@ void VP8LClear(VP8LDecoder* const dec);
 void VP8LDelete(VP8LDecoder* const dec);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DEC_VP8LI_DEC_H_ */
+#endif  // WEBP_DEC_VP8LI_DEC_H_
--- a/media/libwebp/src/dec/webpi_dec.h
+++ b/media/libwebp/src/dec/webpi_dec.h
@@ -125,9 +125,9 @@ int WebPAvoidSlowMemory(const WebPDecBuf
                         const WebPBitstreamFeatures* const features);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DEC_WEBPI_DEC_H_ */
+#endif  // WEBP_DEC_WEBPI_DEC_H_
--- a/media/libwebp/src/demux/demux.c
+++ b/media/libwebp/src/demux/demux.c
@@ -20,17 +20,17 @@
 
 #include "src/utils/utils.h"
 #include "src/webp/decode.h"     // WebPGetFeatures
 #include "src/webp/demux.h"
 #include "src/webp/format_constants.h"
 
 #define DMUX_MAJ_VERSION 1
 #define DMUX_MIN_VERSION 0
-#define DMUX_REV_VERSION 0
+#define DMUX_REV_VERSION 1
 
 typedef struct {
   size_t start_;        // start location of the data
   size_t end_;          // end location
   size_t riff_end_;     // riff chunk end location, can be > end_.
   size_t buf_size_;     // size of the buffer
   const uint8_t* buf_;
 } MemBuffer;
--- a/media/libwebp/src/dsp/dsp.h
+++ b/media/libwebp/src/dsp/dsp.h
@@ -71,20 +71,16 @@ extern "C" {
 #if defined(__SSE2__) || defined(WEBP_MSC_SSE2) || defined(WEBP_HAVE_SSE2)
 #define WEBP_USE_SSE2
 #endif
 
 #if defined(__SSE4_1__) || defined(WEBP_MSC_SSE41) || defined(WEBP_HAVE_SSE41)
 #define WEBP_USE_SSE41
 #endif
 
-#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2)
-#define WEBP_USE_AVX2
-#endif
-
 // The intrinsics currently cause compiler errors with arm-nacl-gcc and the
 // inline assembly would need to be modified for use with Native Client.
 #if (defined(__ARM_NEON__) || \
      defined(__aarch64__) || defined(WEBP_HAVE_NEON)) && \
     !defined(__native_client__)
 #define WEBP_USE_NEON
 #endif
 
@@ -674,9 +670,9 @@ extern WebPUnfilterFunc WebPUnfilters[WE
 
 // To be called first before using the above.
 void VP8FiltersInit(void);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DSP_DSP_H_ */
+#endif  // WEBP_DSP_DSP_H_
--- a/media/libwebp/src/dsp/lossless.c
+++ b/media/libwebp/src/dsp/lossless.c
@@ -18,18 +18,16 @@
 #include <assert.h>
 #include <math.h>
 #include <stdlib.h>
 #include "src/dec/vp8li_dec.h"
 #include "src/utils/endian_inl_utils.h"
 #include "src/dsp/lossless.h"
 #include "src/dsp/lossless_common.h"
 
-#define MAX_DIFF_COST (1e30f)
-
 //------------------------------------------------------------------------------
 // Image transforms.
 
 static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
   return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1);
 }
 
 static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
--- a/media/libwebp/src/dsp/lossless.h
+++ b/media/libwebp/src/dsp/lossless.h
@@ -158,17 +158,17 @@ typedef double (*VP8LCostCombinedFunc)(c
 typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256],
                                                 const int Y[256]);
 
 extern VP8LCostFunc VP8LExtraCost;
 extern VP8LCostCombinedFunc VP8LExtraCostCombined;
 extern VP8LCombinedShannonEntropyFunc VP8LCombinedShannonEntropy;
 
 typedef struct {        // small struct to hold counters
-  int counts[2];        // index: 0=zero steak, 1=non-zero streak
+  int counts[2];        // index: 0=zero streak, 1=non-zero streak
   int streaks[2][2];    // [zero/non-zero][streak<3 / streak>=3]
 } VP8LStreaks;
 
 typedef struct {            // small struct to hold bit entropy results
   double entropy;           // entropy
   uint32_t sum;             // sum of the population
   int nonzeros;             // number of non-zero elements in the population
   uint32_t max_val;         // maximum value in the population
@@ -189,20 +189,24 @@ extern VP8LGetCombinedEntropyUnrefinedFu
 typedef void (*VP8LGetEntropyUnrefinedFunc)(const uint32_t X[], int length,
                                             VP8LBitEntropy* const bit_entropy,
                                             VP8LStreaks* const stats);
 extern VP8LGetEntropyUnrefinedFunc VP8LGetEntropyUnrefined;
 
 void VP8LBitsEntropyUnrefined(const uint32_t* const array, int n,
                               VP8LBitEntropy* const entropy);
 
-typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a,
-                                     const VP8LHistogram* const b,
-                                     VP8LHistogram* const out);
-extern VP8LHistogramAddFunc VP8LHistogramAdd;
+typedef void (*VP8LAddVectorFunc)(const uint32_t* a, const uint32_t* b,
+                                  uint32_t* out, int size);
+extern VP8LAddVectorFunc VP8LAddVector;
+typedef void (*VP8LAddVectorEqFunc)(const uint32_t* a, uint32_t* out, int size);
+extern VP8LAddVectorEqFunc VP8LAddVectorEq;
+void VP8LHistogramAdd(const VP8LHistogram* const a,
+                      const VP8LHistogram* const b,
+                      VP8LHistogram* const out);
 
 // -----------------------------------------------------------------------------
 // PrefixEncode()
 
 typedef int (*VP8LVectorMismatchFunc)(const uint32_t* const array1,
                                       const uint32_t* const array2, int length);
 // Returns the first index where array1 and array2 are different.
 extern VP8LVectorMismatchFunc VP8LVectorMismatch;
--- a/media/libwebp/src/dsp/msa_macro.h
+++ b/media/libwebp/src/dsp/msa_macro.h
@@ -1384,9 +1384,9 @@ static WEBP_INLINE uint32_t func_hadd_uh
  *               with rounding is calculated and written to 'out0'
  */
 #define AVER_UB2(RTYPE, in0, in1, in2, in3, out0, out1) do {  \
   out0 = (RTYPE)__msa_aver_u_b((v16u8)in0, (v16u8)in1);       \
   out1 = (RTYPE)__msa_aver_u_b((v16u8)in2, (v16u8)in3);       \
 } while (0)
 #define AVER_UB2_UB(...) AVER_UB2(v16u8, __VA_ARGS__)
 
-#endif  /* WEBP_DSP_MSA_MACRO_H_ */
+#endif  // WEBP_DSP_MSA_MACRO_H_
--- a/media/libwebp/src/dsp/rescaler.c
+++ b/media/libwebp/src/dsp/rescaler.c
@@ -16,16 +16,17 @@
 #include "src/dsp/dsp.h"
 #include "src/utils/rescaler_utils.h"
 
 //------------------------------------------------------------------------------
 // Implementations of critical functions ImportRow / ExportRow
 
 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
 
 //------------------------------------------------------------------------------
 // Row import
 
 void WebPRescalerImportRowExpand_C(WebPRescaler* const wrk,
                                    const uint8_t* src) {
   const int x_stride = wrk->num_channels;
   const int x_out_max = wrk->dst_width * wrk->num_channels;
@@ -133,31 +134,32 @@ void WebPRescalerExportRowShrink_C(WebPR
   const rescaler_t* const frow = wrk->frow;
   const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
   assert(!WebPRescalerOutputDone(wrk));
   assert(wrk->y_accum <= 0);
   assert(!wrk->y_expand);
   if (yscale) {
     for (x_out = 0; x_out < x_out_max; ++x_out) {
       const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
-      const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+      const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = frac;   // new fractional start
     }
   } else {
     for (x_out = 0; x_out < x_out_max; ++x_out) {
       const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = 0;
     }
   }
 }
 
+#undef MULT_FIX_FLOOR
 #undef MULT_FIX
 #undef ROUNDER
 
 //------------------------------------------------------------------------------
 // Main entry calls
 
 void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
   assert(!WebPRescalerInputDone(wrk));
--- a/media/libwebp/src/dsp/rescaler_mips32.c
+++ b/media/libwebp/src/dsp/rescaler_mips32.c
@@ -204,16 +204,17 @@ static void ExportRowExpand_MIPS32(WebPR
         [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
         [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
       : [temp2]"r"(temp2), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B)
       : "memory", "hi", "lo"
     );
   }
 }
 
+#if 0  // disabled for now. TODO(skal): make match the C-code
 static void ExportRowShrink_MIPS32(WebPRescaler* const wrk) {
   const int x_out_max = wrk->dst_width * wrk->num_channels;
   uint8_t* dst = wrk->dst;
   rescaler_t* irow = wrk->irow;
   const rescaler_t* frow = wrk->frow;
   const int yscale = wrk->fy_scale * (-wrk->y_accum);
   int temp0, temp1, temp3, temp4, temp5, loop_end;
   const int temp2 = (int)wrk->fxy_scale;
@@ -268,26 +269,27 @@ static void ExportRowShrink_MIPS32(WebPR
       : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
         [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow),
         [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
       : [temp2]"r"(temp2), [temp6]"r"(temp6)
       : "memory", "hi", "lo"
     );
   }
 }
+#endif  // 0
 
 //------------------------------------------------------------------------------
 // Entry point
 
 extern void WebPRescalerDspInitMIPS32(void);
 
 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPS32(void) {
   WebPRescalerImportRowExpand = ImportRowExpand_MIPS32;
   WebPRescalerImportRowShrink = ImportRowShrink_MIPS32;
   WebPRescalerExportRowExpand = ExportRowExpand_MIPS32;
-  WebPRescalerExportRowShrink = ExportRowShrink_MIPS32;
+//  WebPRescalerExportRowShrink = ExportRowShrink_MIPS32;
 }
 
 #else  // !WEBP_USE_MIPS32
 
 WEBP_DSP_INIT_STUB(WebPRescalerDspInitMIPS32)
 
 #endif  // WEBP_USE_MIPS32
--- a/media/libwebp/src/dsp/rescaler_mips_dsp_r2.c
+++ b/media/libwebp/src/dsp/rescaler_mips_dsp_r2.c
@@ -15,20 +15,22 @@
 
 #if defined(WEBP_USE_MIPS_DSP_R2) && !defined(WEBP_REDUCE_SIZE)
 
 #include <assert.h>
 #include "src/utils/rescaler_utils.h"
 
 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
 
 //------------------------------------------------------------------------------
 // Row export
 
+#if 0  // disabled for now. TODO(skal): make match the C-code
 static void ExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
   int i;
   const int x_out_max = wrk->dst_width * wrk->num_channels;
   uint8_t* dst = wrk->dst;
   rescaler_t* irow = wrk->irow;
   const rescaler_t* frow = wrk->frow;
   const int yscale = wrk->fy_scale * (-wrk->y_accum);
   int temp0, temp1, temp2, temp3, temp4, temp5, loop_end;
@@ -101,17 +103,17 @@ static void ExportRowShrink_MIPSdspR2(We
           [temp11]"=&r"(temp11), [temp2]"=&r"(temp2)
         : [temp7]"r"(temp7), [yscale]"r"(yscale), [temp6]"r"(temp6)
         : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
           "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
       );
     }
     for (i = 0; i < (x_out_max & 0x3); ++i) {
       const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale);
-      const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
+      const int v = (int)MULT_FIX_FLOOR(*irow - frac, wrk->fxy_scale);
       assert(v >= 0 && v <= 255);
       *dst++ = v;
       *irow++ = frac;   // new fractional start
     }
   } else {
     if (x_out_max >= 4) {
       __asm__ volatile (
         "li       %[temp3],    0x10000                    \n\t"
@@ -149,23 +151,24 @@ static void ExportRowShrink_MIPSdspR2(We
           [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow),
           [dst]"+r"(dst), [loop_end]"=&r"(loop_end), [temp2]"=&r"(temp2)
         : [temp7]"r"(temp7), [temp6]"r"(temp6)
         : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
           "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
       );
     }
     for (i = 0; i < (x_out_max & 0x3); ++i) {
-      const int v = (int)MULT_FIX(*irow, wrk->fxy_scale);
+      const int v = (int)MULT_FIX_FLOOR(*irow, wrk->fxy_scale);
       assert(v >= 0 && v <= 255);
       *dst++ = v;
       *irow++ = 0;
     }
   }
 }
+#endif  // 0
 
 static void ExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
   int i;
   uint8_t* dst = wrk->dst;
   rescaler_t* irow = wrk->irow;
   const int x_out_max = wrk->dst_width * wrk->num_channels;
   const rescaler_t* frow = wrk->frow;
   int temp0, temp1, temp2, temp3, temp4, temp5, loop_end;
@@ -289,26 +292,27 @@ static void ExportRowExpand_MIPSdspR2(We
       const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
       const int v = (int)MULT_FIX(J, wrk->fy_scale);
       assert(v >= 0 && v <= 255);
       *dst++ = v;
     }
   }
 }
 
+#undef MULT_FIX_FLOOR
 #undef MULT_FIX
 #undef ROUNDER
 
 //------------------------------------------------------------------------------
 // Entry point
 
 extern void WebPRescalerDspInitMIPSdspR2(void);
 
 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPSdspR2(void) {
   WebPRescalerExportRowExpand = ExportRowExpand_MIPSdspR2;
-  WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2;
+//  WebPRescalerExportRowShrink = ExportRowShrink_MIPSdspR2;
 }
 
 #else  // !WEBP_USE_MIPS_DSP_R2
 
 WEBP_DSP_INIT_STUB(WebPRescalerDspInitMIPSdspR2)
 
 #endif  // WEBP_USE_MIPS_DSP_R2
--- a/media/libwebp/src/dsp/rescaler_msa.c
+++ b/media/libwebp/src/dsp/rescaler_msa.c
@@ -17,16 +17,17 @@
 
 #include <assert.h>
 
 #include "src/utils/rescaler_utils.h"
 #include "src/dsp/msa_macro.h"
 
 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
 
 #define CALC_MULT_FIX_16(in0, in1, in2, in3, scale, shift, dst) do {  \
   v4u32 tmp0, tmp1, tmp2, tmp3;                                       \
   v16u8 t0, t1, t2, t3, t4, t5;                                       \
   v2u64 out0, out1, out2, out3;                                       \
   ILVRL_W2_UW(zero, in0, tmp0, tmp1);                                 \
   ILVRL_W2_UW(zero, in1, tmp2, tmp3);                                 \
   DOTP_UW2_UD(tmp0, tmp1, scale, scale, out0, out1);                  \
@@ -257,16 +258,17 @@ static void RescalerExportRowExpand_MIPS
   assert(wrk->y_sub != 0);
   if (wrk->y_accum == 0) {
     ExportRowExpand_0(frow, dst, x_out_max, wrk);
   } else {
     ExportRowExpand_1(frow, irow, dst, x_out_max, wrk);
   }
 }
 
+#if 0  // disabled for now. TODO(skal): make match the C-code
 static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
                                           uint8_t* dst, int length,
                                           const uint32_t yscale,
                                           WebPRescaler* const wrk) {
   const v4u32 y_scale = (v4u32)__msa_fill_w(yscale);
   const v4u32 fxyscale = (v4u32)__msa_fill_w(wrk->fxy_scale);
   const v4u32 shiftval = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX);
   const v4i32 zero = { 0 };
@@ -336,17 +338,17 @@ static WEBP_INLINE void ExportRowShrink_
       ST_UW(frac0, irow);
       frow   += 4;
       irow   += 4;
       dst    += 4;
       length -= 4;
     }
     for (x_out = 0; x_out < length; ++x_out) {
       const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
-      const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+      const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = frac;
     }
   }
 }
 
 static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst,
@@ -421,24 +423,25 @@ static void RescalerExportRowShrink_MIPS
   assert(wrk->y_accum <= 0);
   assert(!wrk->y_expand);
   if (yscale) {
     ExportRowShrink_0(frow, irow, dst, x_out_max, yscale, wrk);
   } else {
     ExportRowShrink_1(irow, dst, x_out_max, wrk);
   }
 }
+#endif  // 0
 
 //------------------------------------------------------------------------------
 // Entry point
 
 extern void WebPRescalerDspInitMSA(void);
 
 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMSA(void) {
   WebPRescalerExportRowExpand = RescalerExportRowExpand_MIPSdspR2;
-  WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2;
+//  WebPRescalerExportRowShrink = RescalerExportRowShrink_MIPSdspR2;
 }
 
 #else     // !WEBP_USE_MSA
 
 WEBP_DSP_INIT_STUB(WebPRescalerDspInitMSA)
 
 #endif    // WEBP_USE_MSA
--- a/media/libwebp/src/dsp/rescaler_neon.c
+++ b/media/libwebp/src/dsp/rescaler_neon.c
@@ -17,31 +17,35 @@
 
 #include <arm_neon.h>
 #include <assert.h>
 #include "src/dsp/neon.h"
 #include "src/utils/rescaler_utils.h"
 
 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
 #define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR_C(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
 
 #define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC))
 #define LOAD_32x8(SRC, DST0, DST1)                                    \
     LOAD_32x4(SRC + 0, DST0);                                         \
     LOAD_32x4(SRC + 4, DST1)
 
 #define STORE_32x8(SRC0, SRC1, DST) do {                              \
     vst1q_u32((DST) + 0, SRC0);                                       \
     vst1q_u32((DST) + 4, SRC1);                                       \
 } while (0);
 
 #if (WEBP_RESCALER_RFIX == 32)
 #define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
-#define MULT_FIX(A, B) /* note: B is actualy scale>>1. See MAKE_HALF_CST */ \
+// note: B is actualy scale>>1. See MAKE_HALF_CST
+#define MULT_FIX(A, B) \
     vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
+#define MULT_FIX_FLOOR(A, B) \
+    vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
 #else
 #error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
 #endif
 
 static uint32x4_t Interpolate_NEON(const rescaler_t* const frow,
                                    const rescaler_t* const irow,
                                    uint32_t A, uint32_t B) {
   LOAD_32x4(frow, A0);
@@ -130,27 +134,27 @@ static void RescalerExportRowShrink_NEON
   if (yscale) {
     for (x_out = 0; x_out < max_span; x_out += 8) {
       LOAD_32x8(frow + x_out, in0, in1);
       LOAD_32x8(irow + x_out, in2, in3);
       const uint32x4_t A0 = MULT_FIX(in0, yscale_half);
       const uint32x4_t A1 = MULT_FIX(in1, yscale_half);
       const uint32x4_t B0 = vqsubq_u32(in2, A0);
       const uint32x4_t B1 = vqsubq_u32(in3, A1);
-      const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
-      const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
+      const uint32x4_t C0 = MULT_FIX_FLOOR(B0, fxy_scale_half);
+      const uint32x4_t C1 = MULT_FIX_FLOOR(B1, fxy_scale_half);
       const uint16x4_t D0 = vmovn_u32(C0);
       const uint16x4_t D1 = vmovn_u32(C1);
       const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1));
       vst1_u8(dst + x_out, E);
       STORE_32x8(A0, A1, irow + x_out);
     }
     for (; x_out < x_out_max; ++x_out) {
       const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale);
-      const int v = (int)MULT_FIX_C(irow[x_out] - frac, wrk->fxy_scale);
+      const int v = (int)MULT_FIX_FLOOR_C(irow[x_out] - frac, fxy_scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = frac;   // new fractional start
     }
   } else {
     for (x_out = 0; x_out < max_span; x_out += 8) {
       LOAD_32x8(irow + x_out, in0, in1);
       const uint32x4_t A0 = MULT_FIX(in0, fxy_scale_half);
@@ -165,16 +169,22 @@ static void RescalerExportRowShrink_NEON
       const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = 0;
     }
   }
 }
 
+#undef MULT_FIX_FLOOR_C
+#undef MULT_FIX_C
+#undef MULT_FIX_FLOOR
+#undef MULT_FIX
+#undef ROUNDER
+
 //------------------------------------------------------------------------------
 
 extern void WebPRescalerDspInitNEON(void);
 
 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitNEON(void) {
   WebPRescalerExportRowExpand = RescalerExportRowExpand_NEON;
   WebPRescalerExportRowShrink = RescalerExportRowShrink_NEON;
 }
--- a/media/libwebp/src/dsp/rescaler_sse2.c
+++ b/media/libwebp/src/dsp/rescaler_sse2.c
@@ -20,16 +20,17 @@
 #include "src/utils/rescaler_utils.h"
 #include "src/utils/utils.h"
 
 //------------------------------------------------------------------------------
 // Implementations of critical functions ImportRow / ExportRow
 
 #define ROUNDER (WEBP_RESCALER_ONE >> 1)
 #define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+#define MULT_FIX_FLOOR(x, y) (((uint64_t)(x) * (y)) >> WEBP_RESCALER_RFIX)
 
 // input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
 static void LoadTwoPixels_SSE2(const uint8_t* const src, __m128i* out) {
   const __m128i zero = _mm_setzero_si128();
   const __m128i A = _mm_loadl_epi64((const __m128i*)(src));  // ABCDEFGH
   const __m128i B = _mm_unpacklo_epi8(A, zero);              // A0B0C0D0E0F0G0H0
   const __m128i C = _mm_srli_si128(B, 8);                    // E0F0G0H0
   *out = _mm_unpacklo_epi16(B, C);
@@ -219,16 +220,45 @@ static WEBP_INLINE void ProcessRow_SSE2(
 #endif
   const __m128i E0 = _mm_or_si128(D0, D2);
   const __m128i E1 = _mm_or_si128(D1, D3);
   const __m128i F = _mm_packs_epi32(E0, E1);
   const __m128i G = _mm_packus_epi16(F, F);
   _mm_storel_epi64((__m128i*)dst, G);
 }
 
+static WEBP_INLINE void ProcessRow_Floor_SSE2(const __m128i* const A0,
+                                              const __m128i* const A1,
+                                              const __m128i* const A2,
+                                              const __m128i* const A3,
+                                              const __m128i* const mult,
+                                              uint8_t* const dst) {
+  const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
+  const __m128i B0 = _mm_mul_epu32(*A0, *mult);
+  const __m128i B1 = _mm_mul_epu32(*A1, *mult);
+  const __m128i B2 = _mm_mul_epu32(*A2, *mult);
+  const __m128i B3 = _mm_mul_epu32(*A3, *mult);
+  const __m128i D0 = _mm_srli_epi64(B0, WEBP_RESCALER_RFIX);
+  const __m128i D1 = _mm_srli_epi64(B1, WEBP_RESCALER_RFIX);
+#if (WEBP_RESCALER_RFIX < 32)
+  const __m128i D2 =
+      _mm_and_si128(_mm_slli_epi64(B2, 32 - WEBP_RESCALER_RFIX), mask);
+  const __m128i D3 =
+      _mm_and_si128(_mm_slli_epi64(B3, 32 - WEBP_RESCALER_RFIX), mask);
+#else
+  const __m128i D2 = _mm_and_si128(B2, mask);
+  const __m128i D3 = _mm_and_si128(B3, mask);
+#endif
+  const __m128i E0 = _mm_or_si128(D0, D2);
+  const __m128i E1 = _mm_or_si128(D1, D3);
+  const __m128i F = _mm_packs_epi32(E0, E1);
+  const __m128i G = _mm_packus_epi16(F, F);
+  _mm_storel_epi64((__m128i*)dst, G);
+}
+
 static void RescalerExportRowExpand_SSE2(WebPRescaler* const wrk) {
   int x_out;
   uint8_t* const dst = wrk->dst;
   rescaler_t* const irow = wrk->irow;
   const int x_out_max = wrk->dst_width * wrk->num_channels;
   const rescaler_t* const frow = wrk->frow;
   const __m128i mult = _mm_set_epi32(0, wrk->fy_scale, 0, wrk->fy_scale);
 
@@ -317,22 +347,22 @@ static void RescalerExportRowShrink_SSE2
         const __m128i E2 = _mm_sub_epi64(A2, D2);
         const __m128i E3 = _mm_sub_epi64(A3, D3);
         const __m128i F2 = _mm_slli_epi64(D2, 32);
         const __m128i F3 = _mm_slli_epi64(D3, 32);
         const __m128i G0 = _mm_or_si128(D0, F2);
         const __m128i G1 = _mm_or_si128(D1, F3);
         _mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
         _mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
-        ProcessRow_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
+        ProcessRow_Floor_SSE2(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
       }
     }
     for (; x_out < x_out_max; ++x_out) {
       const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale);
-      const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+      const int v = (int)MULT_FIX_FLOOR(irow[x_out] - frac, wrk->fxy_scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = frac;   // new fractional start
     }
   } else {
     const uint32_t scale = wrk->fxy_scale;
     const __m128i mult = _mm_set_epi32(0, scale, 0, scale);
     const __m128i zero = _mm_setzero_si128();
@@ -347,16 +377,17 @@ static void RescalerExportRowShrink_SSE2
       const int v = (int)MULT_FIX(irow[x_out], scale);
       assert(v >= 0 && v <= 255);
       dst[x_out] = v;
       irow[x_out] = 0;
     }
   }
 }
 
+#undef MULT_FIX_FLOOR
 #undef MULT_FIX
 #undef ROUNDER
 
 //------------------------------------------------------------------------------
 
 extern void WebPRescalerDspInitSSE2(void);
 
 WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitSSE2(void) {
--- a/media/libwebp/src/dsp/yuv.h
+++ b/media/libwebp/src/dsp/yuv.h
@@ -202,9 +202,9 @@ static WEBP_INLINE int VP8RGBToV(int r, 
   const int v = +28800 * r - 24116 * g - 4684 * b;
   return VP8ClipUV(v, rounding);
 }
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_DSP_YUV_H_ */
+#endif  // WEBP_DSP_YUV_H_
--- a/media/libwebp/src/enc/cost_enc.h
+++ b/media/libwebp/src/enc/cost_enc.h
@@ -74,9 +74,9 @@ extern const uint16_t VP8FixedCostsI16[4
 extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_ENC_COST_ENC_H_ */
+#endif  // WEBP_ENC_COST_ENC_H_
--- a/media/libwebp/src/enc/histogram_enc.h
+++ b/media/libwebp/src/enc/histogram_enc.h
@@ -39,16 +39,17 @@ typedef struct {
   uint32_t distance_[NUM_DISTANCE_CODES];
   int palette_code_bits_;
   uint32_t trivial_symbol_;  // True, if histograms for Red, Blue & Alpha
                              // literal symbols are single valued.
   double bit_cost_;          // cached value of bit cost.
   double literal_cost_;      // Cached values of dominant entropy costs:
   double red_cost_;          // literal, red & blue.
   double blue_cost_;
+  uint8_t is_used_[5];       // 5 for literal, red, blue, alpha, distance
 } VP8LHistogram;
 
 // Collection of histograms with fixed capacity, allocated as one
 // big memory chunk. Can be destroyed by calling WebPSafeFree().
 typedef struct {
   int size;         // number of slots currently in use
   int max_size;     // maximum capacity
   VP8LHistogram** histograms;
@@ -62,32 +63,37 @@ typedef struct {
 void VP8LHistogramCreate(VP8LHistogram* const p,
                          const VP8LBackwardRefs* const refs,
                          int palette_code_bits);
 
 // Return the size of the histogram for a given palette_code_bits.
 int VP8LGetHistogramSize(int palette_code_bits);
 
 // Set the palette_code_bits and reset the stats.
-void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
+// If init_arrays is true, the arrays are also filled with 0's.
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
+                       int init_arrays);
 
 // Collect all the references into a histogram (without reset)
 void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
                             VP8LHistogram* const histo);
 
 // Free the memory allocated for the histogram.
 void VP8LFreeHistogram(VP8LHistogram* const histo);
 
 // Free the memory allocated for the histogram set.
 void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
 
 // Allocate an array of pointer to histograms, allocated and initialized
 // using 'cache_bits'. Return NULL in case of memory error.
 VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
 
+// Set the histograms in set to 0.
+void VP8LHistogramSetClear(VP8LHistogramSet* const set);
+
 // Allocate and initialize histogram object with specified 'cache_bits'.
 // Returns NULL in case of memory error.
 // Special case of VP8LAllocateHistogramSet, with size equals 1.
 VP8LHistogram* VP8LAllocateHistogram(int cache_bits);
 
 // Accumulate a token 'v' into a histogram.
 void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
                                      const PixOrCopy* const v,
@@ -108,15 +114,15 @@ int VP8LGetHistoImageSymbols(int xsize, 
                              VP8LHistogram* const tmp_histo,
                              uint16_t* const histogram_symbols);
 
 // Returns the entropy for the symbols in the input array.
 double VP8LBitsEntropy(const uint32_t* const array, int n);
 
 // Estimate how many bits the combined entropy of literals and distance
 // approximately maps to.
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
+double VP8LHistogramEstimateBits(VP8LHistogram* const p);
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif  // WEBP_ENC_HISTOGRAM_ENC_H_
--- a/media/libwebp/src/enc/vp8i_enc.h
+++ b/media/libwebp/src/enc/vp8i_enc.h
@@ -27,17 +27,17 @@ extern "C" {
 #endif
 
 //------------------------------------------------------------------------------
 // Various defines and enums
 
 // version numbers
 #define ENC_MAJ_VERSION 1
 #define ENC_MIN_VERSION 0
-#define ENC_REV_VERSION 0
+#define ENC_REV_VERSION 1
 
 enum { MAX_LF_LEVELS = 64,       // Maximum loop filter level
        MAX_VARIABLE_LEVEL = 67,  // last (inclusive) level with variable cost
        MAX_LEVEL = 2047          // max level (note: max codable is 2047 + 67)
      };
 
 typedef enum {   // Rate-distortion optimization levels
   RD_OPT_NONE        = 0,  // no rd-opt
@@ -273,17 +273,17 @@ void VP8IteratorReset(VP8EncIterator* co
 void VP8IteratorSetRow(VP8EncIterator* const it, int y);
 // set count down (=number of iterations to go)
 void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down);
 // return true if iteration is finished
 int VP8IteratorIsDone(const VP8EncIterator* const it);
 // Import uncompressed samples from source.
 // If tmp_32 is not NULL, import boundary samples too.
 // tmp_32 is a 32-bytes scratch buffer that must be aligned in memory.
-void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32);
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* const tmp_32);
 // export decimated samples
 void VP8IteratorExport(const VP8EncIterator* const it);
 // go to next macroblock. Returns false if not finished.
 int VP8IteratorNext(VP8EncIterator* const it);
 // save the yuv_out_ boundary values to top_/left_ arrays for next iterations.
 void VP8IteratorSaveBoundary(VP8EncIterator* const it);
 // Report progression based on macroblock rows. Return 0 for user-abort request.
 int VP8IteratorProgress(const VP8EncIterator* const it,
@@ -510,9 +510,9 @@ int WebPPictureAllocYUVA(WebPPicture* co
 void WebPCleanupTransparentAreaLossless(WebPPicture* const pic);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_ENC_VP8I_ENC_H_ */
+#endif  // WEBP_ENC_VP8I_ENC_H_
--- a/media/libwebp/src/enc/vp8li_enc.h
+++ b/media/libwebp/src/enc/vp8li_enc.h
@@ -110,9 +110,9 @@ void VP8LColorSpaceTransform(int width, 
                              uint32_t* const argb, uint32_t* image);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_ENC_VP8LI_ENC_H_ */
+#endif  // WEBP_ENC_VP8LI_ENC_H_
--- a/media/libwebp/src/utils/bit_reader_inl_utils.h
+++ b/media/libwebp/src/utils/bit_reader_inl_utils.h
@@ -182,9 +182,9 @@ static WEBP_INLINE int VP8GetBitAlt(VP8B
     return bit;
   }
 }
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif   // WEBP_UTILS_BIT_READER_INL_UTILS_H_
+#endif  // WEBP_UTILS_BIT_READER_INL_UTILS_H_
--- a/media/libwebp/src/utils/bit_reader_utils.h
+++ b/media/libwebp/src/utils/bit_reader_utils.h
@@ -167,9 +167,9 @@ extern void VP8LDoFillBitWindow(VP8LBitR
 static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
   if (br->bit_pos_ >= VP8L_WBITS) VP8LDoFillBitWindow(br);
 }
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_BIT_READER_UTILS_H_ */
+#endif  // WEBP_UTILS_BIT_READER_UTILS_H_
--- a/media/libwebp/src/utils/bit_writer_utils.h
+++ b/media/libwebp/src/utils/bit_writer_utils.h
@@ -146,9 +146,9 @@ static WEBP_INLINE void VP8LPutBits(VP8L
 }
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_BIT_WRITER_UTILS_H_ */
+#endif  // WEBP_UTILS_BIT_WRITER_UTILS_H_
--- a/media/libwebp/src/utils/filters_utils.h
+++ b/media/libwebp/src/utils/filters_utils.h
@@ -24,9 +24,9 @@ extern "C" {
 // Fast estimate of a potentially good filter.
 WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
                                         int width, int height, int stride);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_FILTERS_UTILS_H_ */
+#endif  // WEBP_UTILS_FILTERS_UTILS_H_
--- a/media/libwebp/src/utils/quant_levels_dec_utils.c
+++ b/media/libwebp/src/utils/quant_levels_dec_utils.c
@@ -256,19 +256,25 @@ static int InitParams(uint8_t* const dat
 }
 
 static void CleanupParams(SmoothParams* const p) {
   WebPSafeFree(p->mem_);
 }
 
 int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
                          int strength) {
-  const int radius = 4 * strength / 100;
+  int radius = 4 * strength / 100;
+
   if (strength < 0 || strength > 100) return 0;
   if (data == NULL || width <= 0 || height <= 0) return 0;  // bad params
+
+  // limit the filter size to not exceed the image dimensions
+  if (2 * radius + 1 > width) radius = (width - 1) >> 1;
+  if (2 * radius + 1 > height) radius = (height - 1) >> 1;
+
   if (radius > 0) {
     SmoothParams p;
     memset(&p, 0, sizeof(p));
     if (!InitParams(data, width, height, stride, radius, &p)) return 0;
     if (p.num_levels_ > 2) {
       for (; p.row_ < p.height_; ++p.row_) {
         VFilter(&p);  // accumulate average of input
         // Need to wait few rows in order to prime the filter,
--- a/media/libwebp/src/utils/quant_levels_dec_utils.h
+++ b/media/libwebp/src/utils/quant_levels_dec_utils.h
@@ -27,9 +27,9 @@ extern "C" {
 // malloc failure, ...).
 int WebPDequantizeLevels(uint8_t* const data, int width, int height, int stride,
                          int strength);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_ */
+#endif  // WEBP_UTILS_QUANT_LEVELS_DEC_UTILS_H_
--- a/media/libwebp/src/utils/quant_levels_utils.h
+++ b/media/libwebp/src/utils/quant_levels_utils.h
@@ -28,9 +28,9 @@ extern "C" {
 // Returns false in case of error (data is NULL, or parameters are invalid).
 int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
                    uint64_t* const sse);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_QUANT_LEVELS_UTILS_H_ */
+#endif  // WEBP_UTILS_QUANT_LEVELS_UTILS_H_
--- a/media/libwebp/src/utils/random_utils.h
+++ b/media/libwebp/src/utils/random_utils.h
@@ -55,9 +55,9 @@ static WEBP_INLINE int VP8RandomBits2(VP
 static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
   return VP8RandomBits2(rg, num_bits, rg->amp_);
 }
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_RANDOM_UTILS_H_ */
+#endif  // WEBP_UTILS_RANDOM_UTILS_H_
--- a/media/libwebp/src/utils/rescaler_utils.h
+++ b/media/libwebp/src/utils/rescaler_utils.h
@@ -93,9 +93,9 @@ int WebPRescalerHasPendingOutput(const W
 }
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_RESCALER_UTILS_H_ */
+#endif  // WEBP_UTILS_RESCALER_UTILS_H_
--- a/media/libwebp/src/utils/thread_utils.h
+++ b/media/libwebp/src/utils/thread_utils.h
@@ -82,9 +82,9 @@ WEBP_EXTERN int WebPSetWorkerInterface(
 WEBP_EXTERN const WebPWorkerInterface* WebPGetWorkerInterface(void);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_THREAD_UTILS_H_ */
+#endif  // WEBP_UTILS_THREAD_UTILS_H_
--- a/media/libwebp/src/utils/utils.h
+++ b/media/libwebp/src/utils/utils.h
@@ -170,9 +170,9 @@ WEBP_EXTERN int WebPGetColorPalette(cons
                                     uint32_t* const palette);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_UTILS_UTILS_H_ */
+#endif  // WEBP_UTILS_UTILS_H_
--- a/media/libwebp/src/webp/decode.h
+++ b/media/libwebp/src/webp/decode.h
@@ -486,9 +486,9 @@ WEBP_EXTERN WebPIDecoder* WebPIDecode(co
 // if the decoding was successful). Note that 'config' cannot be NULL.
 WEBP_EXTERN VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
                                      WebPDecoderConfig* config);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_WEBP_DECODE_H_ */
+#endif  // WEBP_WEBP_DECODE_H_
--- a/media/libwebp/src/webp/demux.h
+++ b/media/libwebp/src/webp/demux.h
@@ -355,9 +355,9 @@ WEBP_EXTERN const WebPDemuxer* WebPAnimD
 // Parameters:
 //   dec - (in/out) decoder instance to be deleted
 WEBP_EXTERN void WebPAnimDecoderDelete(WebPAnimDecoder* dec);
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_WEBP_DEMUX_H_ */
+#endif  // WEBP_WEBP_DEMUX_H_
--- a/media/libwebp/src/webp/encode.h
+++ b/media/libwebp/src/webp/encode.h
@@ -537,9 +537,9 @@ WEBP_EXTERN void WebPBlendAlpha(WebPPict
 WEBP_EXTERN int WebPEncode(const WebPConfig* config, WebPPicture* picture);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_WEBP_ENCODE_H_ */
+#endif  // WEBP_WEBP_ENCODE_H_
--- a/media/libwebp/src/webp/format_constants.h
+++ b/media/libwebp/src/webp/format_constants.h
@@ -79,9 +79,9 @@ typedef enum {
 #define MAX_LOOP_COUNT      (1 << 16)     // maximum value for loop-count
 #define MAX_DURATION        (1 << 24)     // maximum duration
 #define MAX_POSITION_OFFSET (1 << 24)     // maximum frame x/y offset
 
 // Maximum chunk payload is such that adding the header and padding won't
 // overflow a uint32_t.
 #define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1)
 
-#endif  /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */
+#endif  // WEBP_WEBP_FORMAT_CONSTANTS_H_
--- a/media/libwebp/src/webp/mux.h
+++ b/media/libwebp/src/webp/mux.h
@@ -522,9 +522,9 @@ WEBP_EXTERN const char* WebPAnimEncoderG
 WEBP_EXTERN void WebPAnimEncoderDelete(WebPAnimEncoder* enc);
 
 //------------------------------------------------------------------------------
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_WEBP_MUX_H_ */
+#endif  // WEBP_WEBP_MUX_H_
--- a/media/libwebp/src/webp/mux_types.h
+++ b/media/libwebp/src/webp/mux_types.h
@@ -90,9 +90,9 @@ static WEBP_INLINE int WebPDataCopy(cons
   }
   return 1;
 }
 
 #ifdef __cplusplus
 }    // extern "C"
 #endif
 
-#endif  /* WEBP_WEBP_MUX_TYPES_H_ */
+#endif  // WEBP_WEBP_MUX_TYPES_H_
--- a/media/libwebp/src/webp/types.h
+++ b/media/libwebp/src/webp/types.h
@@ -44,9 +44,9 @@ typedef long long int int64_t;
 # else
 #  define WEBP_EXTERN extern
 # endif  /* __GNUC__ >= 4 */
 #endif  /* WEBP_EXTERN */
 
 // Macro to check ABI compatibility (same major revision number)
 #define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))
 
-#endif  /* WEBP_WEBP_TYPES_H_ */
+#endif  // WEBP_WEBP_TYPES_H_
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -831,17 +831,17 @@ def skia_includes(skia):
         ]
     return includes
 
 set_config('SKIA_INCLUDES', skia_includes)
 
 option('--with-system-webp',
        help='Use system libwebp (located with pkgconfig)')
 
-system_webp = pkg_check_modules('MOZ_WEBP', 'libwebp >= 1.0.0 libwebpdemux >= 1.0.0',
+system_webp = pkg_check_modules('MOZ_WEBP', 'libwebp >= 1.0.1 libwebpdemux >= 1.0.1',
                                 when='--with-system-webp')
 
 set_config('MOZ_SYSTEM_WEBP', depends(when=system_webp)(lambda: True))
 
 # Build Freetype in the tree
 # ==============================================================
 @depends(target, skia_pdf)
 def tree_freetype(target, skia_pdf):