Add a fuzzer for the public methods of CFX_ScanlineCompositor.

The public methods for CFX_ScanlineCompositor are exercised through
callers CFX_DIBitmap::CompositeMask() and
CFX_DIBitmap::CompositeBitmap().

Change-Id: I386bbab5ae6f2ff262246cfe12bec98a5806ba2b
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/61490
Commit-Queue: Hui Yingst <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/fx_dib.h b/core/fxge/fx_dib.h
index c292e99..e16957c 100644
--- a/core/fxge/fx_dib.h
+++ b/core/fxge/fx_dib.h
@@ -78,6 +78,7 @@
   kSaturation,
   kColor,
   kLuminosity,
+  kLast = kLuminosity,
 };
 
 constexpr uint32_t FXSYS_BGR(uint8_t b, uint8_t g, uint8_t r) {
diff --git a/testing/fuzzers/BUILD.gn b/testing/fuzzers/BUILD.gn
index dccf6b6..c890469 100644
--- a/testing/fuzzers/BUILD.gn
+++ b/testing/fuzzers/BUILD.gn
@@ -27,6 +27,7 @@
   "pdf_hint_table_fuzzer",
   "pdf_jpx_fuzzer",
   "pdf_psengine_fuzzer",
+  "pdf_scanlinecompositor_fuzzer",
   "pdf_streamparser_fuzzer",
   "pdf_xml_fuzzer",
   "pdfium_fuzzer",
@@ -539,6 +540,17 @@
   ]
 }
 
+pdfium_fuzzer("pdf_scanlinecompositor_fuzzer") {
+  sources = [
+    "pdf_scanlinecompositor_fuzzer.cc",
+  ]
+  deps = [
+    ":fuzzer_utils",
+    "../../core/fxge",
+    "../../third_party:pdfium_base",
+  ]
+}
+
 pdfium_fuzzer("pdf_streamparser_fuzzer") {
   sources = [
     "pdf_streamparser_fuzzer.cc",
diff --git a/testing/fuzzers/pdf_scanlinecompositor_fuzzer.cc b/testing/fuzzers/pdf_scanlinecompositor_fuzzer.cc
new file mode 100644
index 0000000..4b20068
--- /dev/null
+++ b/testing/fuzzers/pdf_scanlinecompositor_fuzzer.cc
@@ -0,0 +1,66 @@
+// Copyright 2019 The PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fxge/cfx_cliprgn.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
+#include "core/fxge/fx_dib.h"
+#include "testing/fuzzers/pdfium_fuzzer_util.h"
+#include "third_party/base/ptr_util.h"
+
+namespace {
+
+constexpr FXDIB_Format kFormat[] = {
+    FXDIB_Invalid, FXDIB_1bppRgb,   FXDIB_8bppRgb,  FXDIB_Rgb,
+    FXDIB_Rgb32,   FXDIB_1bppMask,  FXDIB_8bppMask, FXDIB_8bppRgba,
+    FXDIB_Rgba,    FXDIB_Argb,      FXDIB_1bppCmyk, FXDIB_8bppCmyk,
+    FXDIB_Cmyk,    FXDIB_8bppCmyka, FXDIB_Cmyka};
+
+}  // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  constexpr size_t kParameterSize = 33;
+  if (size < kParameterSize)
+    return 0;
+
+  int width = GetInteger(data);
+  int height = GetInteger(data + 4);
+  uint32_t argb = GetInteger(data + 8);
+  int src_left = GetInteger(data + 12);
+  int src_top = GetInteger(data + 16);
+  int dest_left = GetInteger(data + 20);
+  int dest_top = GetInteger(data + 24);
+
+  BlendMode blend_mode = static_cast<BlendMode>(
+      data[28] % (static_cast<int>(BlendMode::kLast) + 1));
+  FXDIB_Format dest_format = kFormat[data[29] % FX_ArraySize(kFormat)];
+  FXDIB_Format src_format = kFormat[data[30] % FX_ArraySize(kFormat)];
+  bool is_clip = !(data[31] % 2);
+  bool is_rgb_byte_order = !(data[32] % 2);
+  size -= kParameterSize;
+  data += kParameterSize;
+
+  auto src_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  auto dest_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  if (!src_bitmap->Create(width, height, src_format) ||
+      !dest_bitmap->Create(width, height, dest_format)) {
+    return 0;
+  }
+  if (!src_bitmap->GetBuffer() || !dest_bitmap->GetBuffer()) {
+    return 0;
+  }
+
+  std::unique_ptr<CFX_ClipRgn> clip_rgn;
+  if (is_clip)
+    clip_rgn = pdfium::MakeUnique<CFX_ClipRgn>(width, height);
+  if (src_bitmap->IsAlphaMask()) {
+    dest_bitmap->CompositeMask(dest_left, dest_top, width, height, src_bitmap,
+                               argb, src_left, src_top, blend_mode,
+                               clip_rgn.get(), is_rgb_byte_order);
+  } else {
+    dest_bitmap->CompositeBitmap(dest_left, dest_top, width, height, src_bitmap,
+                                 src_left, src_top, blend_mode, clip_rgn.get(),
+                                 is_rgb_byte_order);
+  }
+  return 0;
+}