[xfa] Fix GIF decode continuation

Fixes the GIF decoder to continue decoding across various boundaries.
The old logic only works for a single scanline within a single image
data sub-block, which obviously doesn't hold for real GIF images.

Critically, the existing logic fails to recover from source buffer
underflow and destination buffer overflow correctly. To fix this:

1. LZWDecompressor::Decode() doesn't discard previously-decoded state.
2. ProgressiveDecoder incrementally feeds LZWDecompressor new data.

Note that ProgressiveDecoder.BUG_895009 does not contain a valid GIF,
which the fixed decoder correctly fails to decode; the test expectations
have been updated accordingly.

Fixed: pdfium:904, pdfium:1337
Change-Id: I79db5c8962ff40a9b47e680f5e34e62950c1d495
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/92390
Auto-Submit: K. Moon <kmoon@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcodec/gif/cfx_gifcontext.cpp b/core/fxcodec/gif/cfx_gifcontext.cpp
index 6ce9570..a377998 100644
--- a/core/fxcodec/gif/cfx_gifcontext.cpp
+++ b/core/fxcodec/gif/cfx_gifcontext.cpp
@@ -213,6 +213,8 @@
   std::vector<uint8_t, FxAllocAllocator<uint8_t>> img_data;
   size_t read_marker = input_buffer_->GetPosition();
 
+  // TODO(crbug.com/pdfium/1793): This logic can be simplified a lot, but it
+  // probably makes more sense to switch to a different GIF decoder altogether.
   if (decode_status_ == GIF_D_STATUS_IMG_DATA) {
     if (!ReadAllOrNone(&img_data_size, sizeof(img_data_size)))
       return GifDecoder::Status::kUnfinished;
@@ -224,20 +226,21 @@
         return GifDecoder::Status::kUnfinished;
       }
 
-      if (!lzw_decompressor_.get()) {
+      if (!lzw_decompressor_) {
         lzw_decompressor_ = LZWDecompressor::Create(GetPaletteExp(gif_image),
                                                     gif_image->code_exp);
+        if (!lzw_decompressor_) {
+          DecodingFailureAtTailCleanup(gif_image);
+          return GifDecoder::Status::kError;
+        }
       }
+      lzw_decompressor_->SetSource(img_data.data(), img_data_size);
+
       SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
       img_row_offset_ += img_row_avail_size_;
       img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
-      LZWDecompressor::Status ret =
-          lzw_decompressor_.get()
-              ? lzw_decompressor_->Decode(
-                    img_data.data(), img_data_size,
-                    gif_image->row_buffer.data() + img_row_offset_,
-                    &img_row_avail_size_)
-              : LZWDecompressor::Status::kError;
+      LZWDecompressor::Status ret = lzw_decompressor_->Decode(
+          gif_image->row_buffer.data() + img_row_offset_, &img_row_avail_size_);
       if (ret == LZWDecompressor::Status::kError) {
         DecodingFailureAtTailCleanup(gif_image);
         return GifDecoder::Status::kError;
@@ -263,19 +266,14 @@
               return GifDecoder::Status::kUnfinished;
             }
 
-            if (!lzw_decompressor_.get()) {
-              lzw_decompressor_ = LZWDecompressor::Create(
-                  GetPaletteExp(gif_image), gif_image->code_exp);
-            }
+            lzw_decompressor_->SetSource(img_data.data(), img_data_size);
+
             SaveDecodingStatus(GIF_D_STATUS_IMG_DATA);
             img_row_offset_ += img_row_avail_size_;
             img_row_avail_size_ = gif_img_row_bytes - img_row_offset_;
-            ret = lzw_decompressor_.get()
-                      ? lzw_decompressor_->Decode(
-                            img_data.data(), img_data_size,
-                            gif_image->row_buffer.data() + img_row_offset_,
-                            &img_row_avail_size_)
-                      : LZWDecompressor::Status::kError;
+            ret = lzw_decompressor_->Decode(
+                gif_image->row_buffer.data() + img_row_offset_,
+                &img_row_avail_size_);
           }
         }
 
@@ -295,18 +293,15 @@
           } else {
             ReadScanline(gif_image->row_num++, gif_image->row_buffer.data());
           }
+
           img_row_offset_ = 0;
           img_row_avail_size_ = gif_img_row_bytes;
-          ret = lzw_decompressor_.get()
-                    ? lzw_decompressor_->Decode(
-                          img_data.data(), img_data_size,
-                          gif_image->row_buffer.data() + img_row_offset_,
-                          &img_row_avail_size_)
-                    : LZWDecompressor::Status::kError;
+          ret = lzw_decompressor_->Decode(
+              gif_image->row_buffer.data() + img_row_offset_,
+              &img_row_avail_size_);
         }
 
-        if (ret == LZWDecompressor::Status::kInsufficientDestSize ||
-            ret == LZWDecompressor::Status::kError) {
+        if (ret == LZWDecompressor::Status::kError) {
           DecodingFailureAtTailCleanup(gif_image);
           return GifDecoder::Status::kError;
         }
diff --git a/core/fxcodec/gif/lzw_decompressor.cpp b/core/fxcodec/gif/lzw_decompressor.cpp
index 50469aa..8325ce2 100644
--- a/core/fxcodec/gif/lzw_decompressor.cpp
+++ b/core/fxcodec/gif/lzw_decompressor.cpp
@@ -33,25 +33,28 @@
     : code_size_(code_exp),
       code_color_end_(static_cast<uint16_t>(1 << (color_exp + 1))),
       code_clear_(static_cast<uint16_t>(1 << code_exp)),
-      code_end_(static_cast<uint16_t>((1 << code_exp) + 1)) {}
+      code_end_(static_cast<uint16_t>((1 << code_exp) + 1)) {
+  ClearTable();
+}
 
 LZWDecompressor::~LZWDecompressor() = default;
 
-LZWDecompressor::Status LZWDecompressor::Decode(const uint8_t* src_buf,
-                                                uint32_t src_size,
-                                                uint8_t* dest_buf,
+void LZWDecompressor::SetSource(const uint8_t* src_buf, uint32_t src_size) {
+  next_in_ = src_buf;
+  avail_in_ = src_size;
+}
+
+LZWDecompressor::Status LZWDecompressor::Decode(uint8_t* dest_buf,
                                                 uint32_t* dest_size) {
-  if (!src_buf || src_size == 0 || !dest_buf || !dest_size)
+  if (!next_in_ || !dest_buf || !dest_size)
     return Status::kError;
 
+  if (avail_in_ == 0)
+    return Status::kUnfinished;
+
   if (*dest_size == 0)
     return Status::kInsufficientDestSize;
 
-  next_in_ = src_buf;
-  avail_in_ = src_size;
-
-  ClearTable();
-
   uint32_t i = 0;
   if (decompressed_next_ != 0) {
     uint32_t extracted_size = ExtractData(dest_buf, *dest_size);
diff --git a/core/fxcodec/gif/lzw_decompressor.h b/core/fxcodec/gif/lzw_decompressor.h
index 390cedb..b99b473 100644
--- a/core/fxcodec/gif/lzw_decompressor.h
+++ b/core/fxcodec/gif/lzw_decompressor.h
@@ -34,10 +34,8 @@
                                                  uint8_t code_exp);
   ~LZWDecompressor();
 
-  Status Decode(const uint8_t* src_buf,
-                uint32_t src_size,
-                uint8_t* dest_buf,
-                uint32_t* dest_size);
+  void SetSource(const uint8_t* src_buf, uint32_t src_size);
+  Status Decode(uint8_t* dest_buf, uint32_t* dest_size);
 
   // Used by unittests, should not be called in production code.
   uint32_t ExtractDataForTest(uint8_t* dest_buf, uint32_t dest_size) {
diff --git a/core/fxcodec/gif/lzw_decompressor_unittest.cpp b/core/fxcodec/gif/lzw_decompressor_unittest.cpp
index 99e186e..f14fa14 100644
--- a/core/fxcodec/gif/lzw_decompressor_unittest.cpp
+++ b/core/fxcodec/gif/lzw_decompressor_unittest.cpp
@@ -4,9 +4,15 @@
 
 #include "core/fxcodec/gif/lzw_decompressor.h"
 
+#include <stdint.h>
+#include <string.h>
+
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/base/cxx17_backports.h"
 
+using ::testing::ElementsAreArray;
+
 TEST(LZWDecompressor, CreateBadParams) {
   EXPECT_EQ(nullptr, LZWDecompressor::Create(0x10, 0x02));
   EXPECT_EQ(nullptr, LZWDecompressor::Create(0x04, 0x0F));
@@ -91,21 +97,23 @@
   uint8_t output_data[10];
   uint32_t output_size = pdfium::size(output_data);
 
-  EXPECT_EQ(
-      LZWDecompressor::Status::kError,
-      decompressor->Decode(nullptr, image_size, output_data, &output_size));
+  decompressor->SetSource(nullptr, image_size);
   EXPECT_EQ(LZWDecompressor::Status::kError,
-            decompressor->Decode(image_data, 0, output_data, &output_size));
-  EXPECT_EQ(
-      LZWDecompressor::Status::kError,
-      decompressor->Decode(image_data, image_size, nullptr, &output_size));
+            decompressor->Decode(output_data, &output_size));
+
+  decompressor->SetSource(image_data, 0);
+  EXPECT_EQ(LZWDecompressor::Status::kUnfinished,
+            decompressor->Decode(output_data, &output_size));
+
+  decompressor->SetSource(image_data, image_size);
   EXPECT_EQ(LZWDecompressor::Status::kError,
-            decompressor->Decode(image_data, image_size, output_data, nullptr));
+            decompressor->Decode(nullptr, &output_size));
+  EXPECT_EQ(LZWDecompressor::Status::kError,
+            decompressor->Decode(output_data, nullptr));
 
   output_size = 0;
-  EXPECT_EQ(
-      LZWDecompressor::Status::kInsufficientDestSize,
-      decompressor->Decode(image_data, image_size, output_data, &output_size));
+  EXPECT_EQ(LZWDecompressor::Status::kInsufficientDestSize,
+            decompressor->Decode(output_data, &output_size));
 }
 
 TEST(LZWDecompressor, Decode1x1SingleColour) {
@@ -122,9 +130,9 @@
   memset(output_data, 0, sizeof(output_data));
   uint32_t output_size = pdfium::size(output_data);
 
-  EXPECT_EQ(
-      LZWDecompressor::Status::kSuccess,
-      decompressor->Decode(image_data, image_size, output_data, &output_size));
+  decompressor->SetSource(image_data, image_size);
+  EXPECT_EQ(LZWDecompressor::Status::kSuccess,
+            decompressor->Decode(output_data, &output_size));
 
   EXPECT_EQ(pdfium::size(output_data), output_size);
   EXPECT_TRUE(0 == memcmp(expected_data, output_data, sizeof(expected_data)));
@@ -154,9 +162,9 @@
   memset(output_data, 0, sizeof(output_data));
   uint32_t output_size = pdfium::size(output_data);
 
-  EXPECT_EQ(
-      LZWDecompressor::Status::kSuccess,
-      decompressor->Decode(kImageData, image_size, output_data, &output_size));
+  decompressor->SetSource(kImageData, image_size);
+  EXPECT_EQ(LZWDecompressor::Status::kSuccess,
+            decompressor->Decode(output_data, &output_size));
 
   EXPECT_EQ(pdfium::size(output_data), output_size);
   EXPECT_TRUE(0 == memcmp(kExpectedData, output_data, sizeof(kExpectedData)));
@@ -188,14 +196,39 @@
   memset(output_data, 0, sizeof(output_data));
   uint32_t output_size = pdfium::size(output_data);
 
-  EXPECT_EQ(
-      LZWDecompressor::Status::kSuccess,
-      decompressor->Decode(kImageData, image_size, output_data, &output_size));
+  decompressor->SetSource(kImageData, image_size);
+  EXPECT_EQ(LZWDecompressor::Status::kSuccess,
+            decompressor->Decode(output_data, &output_size));
 
   EXPECT_EQ(pdfium::size(output_data), output_size);
   EXPECT_TRUE(0 == memcmp(kExpectedData, output_data, sizeof(kExpectedData)));
 }
 
+TEST(LZWDecompressor, MultipleDecodes) {
+  auto decompressor = LZWDecompressor::Create(/*color_exp=*/0, /*code_exp=*/2);
+  ASSERT_NE(nullptr, decompressor);
+
+  static constexpr uint8_t kImageData[] = {0x84, 0x6f, 0x05};
+  decompressor->SetSource(kImageData, pdfium::size(kImageData));
+
+  static constexpr uint8_t kExpectedScanline[] = {0x00, 0x00, 0x00, 0x00};
+  uint8_t output_data[pdfium::size(kExpectedScanline)];
+
+  memset(output_data, 0xFF, sizeof(output_data));
+  uint32_t output_size = pdfium::size(output_data);
+  EXPECT_EQ(LZWDecompressor::Status::kInsufficientDestSize,
+            decompressor->Decode(output_data, &output_size));
+  EXPECT_EQ(pdfium::size(kExpectedScanline), output_size);
+  EXPECT_THAT(output_data, ElementsAreArray(kExpectedScanline));
+
+  memset(output_data, 0xFF, sizeof(output_data));
+  output_size = pdfium::size(output_data);
+  EXPECT_EQ(LZWDecompressor::Status::kSuccess,
+            decompressor->Decode(output_data, &output_size));
+  EXPECT_EQ(pdfium::size(kExpectedScanline), output_size);
+  EXPECT_THAT(output_data, ElementsAreArray(kExpectedScanline));
+}
+
 TEST(LZWDecompressor, HandleColourCodeOutOfPalette) {
   uint8_t palette_exp = 0x2;  // Image uses 10 colours, so the palette exp
                               // should be 3, 2^(3+1) = 16 colours.
@@ -213,7 +246,7 @@
   memset(output_data, 0, sizeof(output_data));
   uint32_t output_size = pdfium::size(output_data);
 
-  EXPECT_EQ(
-      LZWDecompressor::Status::kError,
-      decompressor->Decode(kImageData, image_size, output_data, &output_size));
+  decompressor->SetSource(kImageData, image_size);
+  EXPECT_EQ(LZWDecompressor::Status::kError,
+            decompressor->Decode(output_data, &output_size));
 }
diff --git a/core/fxcodec/progressive_decoder_unittest.cpp b/core/fxcodec/progressive_decoder_unittest.cpp
index 4c1b2c4..8902f6b 100644
--- a/core/fxcodec/progressive_decoder_unittest.cpp
+++ b/core/fxcodec/progressive_decoder_unittest.cpp
@@ -105,6 +105,117 @@
   EXPECT_THAT(bitmap->GetScanline(0), ElementsAre(0xc0, 0x80, 0x40, 0xff));
 }
 
+TEST(ProgressiveDecoder, GifInsufficientCodeSize) {
+  // This GIF causes `LZWDecompressor::Create()` to fail because the minimum
+  // code size is too small for the palette.
+  static constexpr uint8_t kInput[] = {
+      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x01, 0x00, 0x01, 0x00, 0x82,
+      0x01, 0x00, 0x40, 0x80, 0xc0, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81,
+      0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85,
+      0x85, 0x86, 0x86, 0x86, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+      0x01, 0x00, 0x00, 0x02, 0x2,  0x44, 0x01, 0x00, 0x3b};
+
+  auto decoder = std::make_unique<ProgressiveDecoder>();
+
+  auto source = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(kInput);
+  CFX_DIBAttribute attr;
+  FXCODEC_STATUS status =
+      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+  ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
+
+  ASSERT_EQ(1, decoder->GetWidth());
+  ASSERT_EQ(1, decoder->GetHeight());
+
+  auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
+                 FXDIB_Format::kArgb);
+
+  size_t frames;
+  std::tie(status, frames) = decoder->GetFrames();
+  ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
+  ASSERT_EQ(1u, frames);
+
+  status = DecodeToBitmap(*decoder, bitmap);
+  EXPECT_EQ(FXCODEC_STATUS::kError, status);
+}
+
+TEST(ProgressiveDecoder, GifDecodeAcrossScanlines) {
+  // This GIF contains an LZW code unit split across 2 scanlines. The decoder
+  // must continue decoding the second scanline using the residual data.
+  static constexpr uint8_t kInput[] = {
+      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x02, 0x00, 0x80, 0x01,
+      0x00, 0x40, 0x80, 0xc0, 0x80, 0x80, 0x80, 0x2c, 0x00, 0x00, 0x00, 0x00,
+      0x04, 0x00, 0x02, 0x00, 0x00, 0x02, 0x03, 0x84, 0x6f, 0x05, 0x00, 0x3b};
+
+  auto decoder = std::make_unique<ProgressiveDecoder>();
+
+  auto source = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(kInput);
+  CFX_DIBAttribute attr;
+  FXCODEC_STATUS status =
+      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+  ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
+
+  ASSERT_EQ(4, decoder->GetWidth());
+  ASSERT_EQ(2, decoder->GetHeight());
+
+  auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
+                 FXDIB_Format::kArgb);
+
+  size_t frames;
+  std::tie(status, frames) = decoder->GetFrames();
+  ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
+  ASSERT_EQ(1u, frames);
+
+  status = DecodeToBitmap(*decoder, bitmap);
+  EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
+  EXPECT_THAT(bitmap->GetScanline(0),
+              ElementsAre(0xc0, 0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff, 0xc0,
+                          0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff));
+  EXPECT_THAT(bitmap->GetScanline(1),
+              ElementsAre(0xc0, 0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff, 0xc0,
+                          0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff));
+}
+
+TEST(ProgressiveDecoder, GifDecodeAcrossSubblocks) {
+  // This GIF contains a scanline split across 2 data sub-blocks. The decoder
+  // must continue decoding in the second sub-block.
+  static constexpr uint8_t kInput[] = {
+      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x02, 0x00,
+      0x80, 0x01, 0x00, 0x40, 0x80, 0xc0, 0x80, 0x80, 0x80, 0x2c,
+      0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x02,
+      0x02, 0x84, 0x6f, 0x01, 0x05, 0x00, 0x3b};
+
+  auto decoder = std::make_unique<ProgressiveDecoder>();
+
+  auto source = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(kInput);
+  CFX_DIBAttribute attr;
+  FXCODEC_STATUS status =
+      decoder->LoadImageInfo(source, FXCODEC_IMAGE_GIF, &attr, true);
+  ASSERT_EQ(FXCODEC_STATUS::kFrameReady, status);
+
+  ASSERT_EQ(4, decoder->GetWidth());
+  ASSERT_EQ(2, decoder->GetHeight());
+
+  auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  bitmap->Create(decoder->GetWidth(), decoder->GetHeight(),
+                 FXDIB_Format::kArgb);
+
+  size_t frames;
+  std::tie(status, frames) = decoder->GetFrames();
+  ASSERT_EQ(FXCODEC_STATUS::kDecodeReady, status);
+  ASSERT_EQ(1u, frames);
+
+  status = DecodeToBitmap(*decoder, bitmap);
+  EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
+  EXPECT_THAT(bitmap->GetScanline(0),
+              ElementsAre(0xc0, 0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff, 0xc0,
+                          0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff));
+  EXPECT_THAT(bitmap->GetScanline(1),
+              ElementsAre(0xc0, 0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff, 0xc0,
+                          0x80, 0x40, 0xff, 0xc0, 0x80, 0x40, 0xff));
+}
+
 TEST(ProgressiveDecoder, BUG_895009) {
   static constexpr uint8_t kInput[] = {
       0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x62, 0x00, 0x21, 0x1b, 0x27, 0x01,
@@ -478,7 +589,7 @@
   ASSERT_EQ(1u, frames);
 
   status = DecodeToBitmap(*decoder, bitmap);
-  EXPECT_EQ(FXCODEC_STATUS::kDecodeFinished, status);
+  EXPECT_EQ(FXCODEC_STATUS::kError, status);
 }
 #endif  // PDF_ENABLE_XFA_GIF
 
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index 24ca5c0..0784cb3 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -386,8 +386,6 @@
 xfa_example.in win * * *
 # TODO(pdfium:1354): Remove after associated bug is fixed
 xfa_example.in * * * skia,skiapaths
-# TODO(pdfium:1167): Remove after associated bug is fixed
-xfa_gif_image.in * * * *
 # TODO(pdfium:1743): Remove after associated bug is fixed
 xfa_node_caption.pdf * * * skia,skiapaths
 # TODO(pdfium:1095): Remove after associated bug is fixed
diff --git a/testing/fuzzers/pdf_lzw_fuzzer.cc b/testing/fuzzers/pdf_lzw_fuzzer.cc
index f019b66..1292ec0 100644
--- a/testing/fuzzers/pdf_lzw_fuzzer.cc
+++ b/testing/fuzzers/pdf_lzw_fuzzer.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stddef.h>
+#include <stdint.h>
+
 #include <vector>
 
 #include "core/fxcodec/gif/lzw_decompressor.h"
@@ -15,7 +18,7 @@
 static constexpr size_t kMaxFuzzBytes = 1024 * 1024 * 1024;  // 1 GB.
 
 void LZWFuzz(const uint8_t* src_buf,
-             size_t src_size,
+             uint32_t src_size,
              uint8_t color_exp,
              uint8_t code_exp) {
   std::unique_ptr<LZWDecompressor> decompressor =
@@ -29,9 +32,9 @@
     // This cast should be safe since the caller is checking for overflow on
     // the initial data.
     uint32_t dest_size = static_cast<uint32_t>(dest_buf.size());
+    decompressor->SetSource(src_buf, src_size);
     if (LZWDecompressor::Status::kInsufficientDestSize !=
-        decompressor->Decode(src_buf, static_cast<uint32_t>(src_size),
-                             dest_buf.data(), &dest_size)) {
+        decompressor->Decode(dest_buf.data(), &dest_size)) {
       return;
     }
   }
diff --git a/testing/resources/pixel/xfa_specific/bug_1337_expected.pdf.0.png b/testing/resources/pixel/xfa_specific/bug_1337_expected.pdf.0.png
index 08c11b0..c0d8380 100644
--- a/testing/resources/pixel/xfa_specific/bug_1337_expected.pdf.0.png
+++ b/testing/resources/pixel/xfa_specific/bug_1337_expected.pdf.0.png
Binary files differ