[Skia] Create a new palette when upsampling 1-bit-per-pixel bitmaps

For a 1-bit-per-pixel bitmap, its color palette sometimes stands for
the boundary of a range of colors instead of just 2 colors.

In Upsample(), this CL adds the process to create a new palette based
on this range and uses it for upsampling the bitmap to 32 bits per
pixel.

Meanwhile, move the process that fills a 32-bit-per-pixel buffer with
the palette into a helper Fill32BppDestStorageWithPalette() so that
this process can be reused within Upsample().

Bug: pdfium:1810
Change-Id: Ia2c4394d8d7d0809a3987d5a3304e7c7892ade6f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98175
Commit-Queue: Nigi <nigi@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/DEPS b/DEPS
index 7185232..aaae84c 100644
--- a/DEPS
+++ b/DEPS
@@ -130,7 +130,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling pdfium_tests
   # and whatever else without interference from each other.
-  'pdfium_tests_revision': '75cce6244b9c04dbe67ce0d7929e0ca0ab7f0ae7',
+  'pdfium_tests_revision': 'de98839600918731c7247d5202240acdb7c4b092',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling skia
   # and whatever else without interference from each other.
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index c4040ae..3acca4e 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -292,6 +292,33 @@
          FXARGB_R(color) == FXARGB_B(color);
 }
 
+// Called by Upsample(), returns a 32 bit-per-pixel buffer filled with colors
+// from `palette`.
+DataVector<uint32_t> Fill32BppDestStorageWithPalette(
+    const RetainPtr<CFX_DIBBase>& source,
+    pdfium::span<const uint32_t> palette) {
+  int width = source->GetWidth();
+  int height = source->GetHeight();
+  void* buffer = source->GetBuffer();
+  DCHECK(buffer);
+  DataVector<uint32_t> dst32_storage(Fx2DSizeOrDie(width, height));
+  pdfium::span<SkPMColor> dst32_pixels(dst32_storage);
+
+  for (int y = 0; y < height; ++y) {
+    const uint8_t* src_row =
+        static_cast<const uint8_t*>(buffer) + y * source->GetPitch();
+    pdfium::span<uint32_t> dst_row = dst32_pixels.subspan(y * width);
+    for (int x = 0; x < width; ++x) {
+      unsigned index = src_row[x];
+      if (index >= palette.size()) {
+        index = 0;
+      }
+      dst_row[x] = palette[index];
+    }
+  }
+  return dst32_storage;
+}
+
 static void DebugValidate(const RetainPtr<CFX_DIBitmap>& bitmap,
                           const RetainPtr<CFX_DIBitmap>& device) {
   if (bitmap) {
@@ -689,7 +716,7 @@
       // are specified in the palette.
       uint8_t color0 = 0x00;
       uint8_t color1 = 0xFF;
-      bool use_two_colors = true;
+
       if (pSource->GetFormat() == FXDIB_Format::k1bppRgb &&
           pSource->HasPalette()) {
         // When `pSource` has 1 bit per pixel, its palette will contain 2
@@ -700,52 +727,47 @@
         // differently depending on these conditions.
         uint32_t palette_color0 = pSource->GetPaletteArgb(0);
         uint32_t palette_color1 = pSource->GetPaletteArgb(1);
-        use_two_colors = IsRGBColorGrayScale(palette_color0) &&
-                         IsRGBColorGrayScale(palette_color1);
-        if (use_two_colors) {
-          color0 = FXARGB_R(palette_color0);
-          color1 = FXARGB_R(palette_color1);
+        bool use_two_colors = IsRGBColorGrayScale(palette_color0) &&
+                              IsRGBColorGrayScale(palette_color1);
+        if (!use_two_colors) {
+          // If more than 2 colors are provided, calculate the range of colors
+          // and store them in `new_palette`
+          FX_ARGB new_palette[CFX_DIBBase::kPaletteSize];
+          CFX_ImageStretcher::BuildPaletteFrom1BppSource(pSource, new_palette);
+          dst32_storage = Fill32BppDestStorageWithPalette(pSource, new_palette);
+          buffer = dst32_storage.data();
+          rowBytes = width * sizeof(uint32_t);
+          colorType = Get32BitSkColorType(bRgbByteOrder);
+          break;
         }
 
-        // TODO(pdfium:1810): Handle upsampling when a range of colors (more
-        // than 2 colors) are provided in the source palette.
+        color0 = FXARGB_R(palette_color0);
+        color1 = FXARGB_R(palette_color1);
       }
 
-      if (use_two_colors) {
-        dst8_storage = DataVector<uint8_t>(Fx2DSizeOrDie(width, height));
-        pdfium::span<uint8_t> dst8_pixels(dst8_storage);
-        for (int y = 0; y < height; ++y) {
-          const uint8_t* srcRow =
-              static_cast<const uint8_t*>(buffer) + y * rowBytes;
-          pdfium::span<uint8_t> dst_row = dst8_pixels.subspan(y * width);
-          for (int x = 0; x < width; ++x)
-            dst_row[x] = srcRow[x >> 3] & (1 << (~x & 0x07)) ? color1 : color0;
-        }
-        buffer = dst8_storage.data();
-        rowBytes = width;
+      dst8_storage = DataVector<uint8_t>(Fx2DSizeOrDie(width, height));
+      pdfium::span<uint8_t> dst8_pixels(dst8_storage);
+      for (int y = 0; y < height; ++y) {
+        const uint8_t* srcRow =
+            static_cast<const uint8_t*>(buffer) + y * rowBytes;
+        pdfium::span<uint8_t> dst_row = dst8_pixels.subspan(y * width);
+        for (int x = 0; x < width; ++x)
+          dst_row[x] = srcRow[x >> 3] & (1 << (~x & 0x07)) ? color1 : color0;
       }
+      buffer = dst8_storage.data();
+      rowBytes = width;
       break;
     }
     case 8:
       // we upscale ctables to 32bit.
       if (pSource->HasPalette()) {
-        dst32_storage = DataVector<uint32_t>(Fx2DSizeOrDie(width, height));
-        pdfium::span<SkPMColor> dst32_pixels(dst32_storage);
         const size_t src_palette_size = pSource->GetRequiredPaletteSize();
         pdfium::span<const uint32_t> src_palette = pSource->GetPaletteSpan();
         CHECK_LE(src_palette_size, src_palette.size());
-        for (int y = 0; y < height; ++y) {
-          const uint8_t* srcRow =
-              static_cast<const uint8_t*>(buffer) + y * rowBytes;
-          pdfium::span<uint32_t> dst_row = dst32_pixels.subspan(y * width);
-          for (int x = 0; x < width; ++x) {
-            unsigned index = srcRow[x];
-            if (index >= src_palette_size) {
-              index = 0;
-            }
-            dst_row[x] = src_palette[index];
-          }
-        }
+        if (src_palette_size < src_palette.size())
+          src_palette = src_palette.first(src_palette_size);
+
+        dst32_storage = Fill32BppDestStorageWithPalette(pSource, src_palette);
         buffer = dst32_storage.data();
         rowBytes = width * sizeof(uint32_t);
         colorType = Get32BitSkColorType(bRgbByteOrder);
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index 1378ece..1f64695 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -208,10 +208,6 @@
 en_contact.pdf mac * * *
 en_diy.pdf mac * * *
 en_foxit.pdf mac * * *
-
-# TODO(pdfium:1810): Remove after associated bug is fixed
-en_fqa.pdf * * * skia
-
 en_fqa2.pdf mac * * *
 en_introduce.pdf mac * * *
 en_tem.pdf mac * * *