Create CFX_FillRenderOptions struct to represent fill options.

1. Create a new struct CFX_FillRenderOptions to represent fill rendering
   options. It can be used to replace the integer fill rendering flags
   and avoid bitwise operations in the future, which will make changing
   fill rendering options more easily.

2. As part of a large refactoring, create two helpers
   GetFillRenderOptionsFromIntegerFlag() and
   GetIntegerFlagFromFillRenderOptions() to convert between
   integer flags and struct CFX_FillRenderOptions.

3. Replace integer |fill_mode| with struct CFX_FillRenderOptions
   |fill_options| as one of the parameters for DrawPathWithBlend().

4. For GetFillOptionsForDrawPathWithBlend(), change the type of
   parameter |fill_type| from integer to
   CFX_FillRenderOptions::FillType.

Bug: pdfium:1531
Change-Id: I3bf5be5d1af09c1b70ea39b10984b2fa9aaba92d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/71030
Commit-Queue: Hui Yingst <nigi@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index de23ac2..1cb7ebb 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -54,6 +54,7 @@
 #include "core/fxcrt/fx_safe_types.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_defaultrenderdevice.h"
+#include "core/fxge/cfx_fillrenderoptions.h"
 #include "core/fxge/cfx_glyphbitmap.h"
 #include "core/fxge/cfx_pathdata.h"
 #include "core/fxge/dib/cfx_dibitmap.h"
@@ -73,23 +74,23 @@
 constexpr int kRenderMaxRecursionDepth = 64;
 int g_CurrentRecursionDepth = 0;
 
-int GetFillOptionsForDrawPathWithBlend(
+CFX_FillRenderOptions GetFillOptionsForDrawPathWithBlend(
     const CPDF_RenderOptions::Options& options,
     const CPDF_PathObject* path_obj,
-    int fill_type,
+    CFX_FillRenderOptions::FillType fill_type,
     bool is_stroke,
     bool is_type3_char) {
-  int fill_options = fill_type;
-  if (fill_type && options.bRectAA)
-    fill_options |= FXFILL_RECT_AA;
+  CFX_FillRenderOptions fill_options(fill_type);
+  if (fill_type != CFX_FillRenderOptions::FillType::kNoFill && options.bRectAA)
+    fill_options.rect_aa = true;
   if (options.bNoPathSmooth)
-    fill_options |= FXFILL_NOPATHSMOOTH;
+    fill_options.aliased_path = true;
   if (path_obj->m_GeneralState.GetStrokeAdjust())
-    fill_options |= FX_STROKE_ADJUST;
+    fill_options.adjust_stroke = true;
   if (is_stroke)
-    fill_options |= FX_FILL_STROKE;
+    fill_options.stroke = true;
   if (is_type3_char)
-    fill_options |= FX_FILL_TEXT_MODE;
+    fill_options.text_mode = true;
 
   return fill_options;
 }
@@ -421,8 +422,8 @@
   return m_pDevice->DrawPathWithBlend(
       path_obj->path().GetObject(), &path_matrix,
       path_obj->m_GraphState.GetObject(), fill_argb, stroke_argb,
-      GetFillOptionsForDrawPathWithBlend(options, path_obj, fill_type, stroke,
-                                         m_pType3Char),
+      GetFillOptionsForDrawPathWithBlend(
+          options, path_obj, GetFillType(fill_type), stroke, m_pType3Char),
       m_curBlend);
 }
 
diff --git a/core/fxge/BUILD.gn b/core/fxge/BUILD.gn
index 3d1d0a1..db8b658 100644
--- a/core/fxge/BUILD.gn
+++ b/core/fxge/BUILD.gn
@@ -27,6 +27,8 @@
     "cfx_drawutils.h",
     "cfx_face.cpp",
     "cfx_face.h",
+    "cfx_fillrenderoptions.cpp",
+    "cfx_fillrenderoptions.h",
     "cfx_folderfontinfo.cpp",
     "cfx_folderfontinfo.h",
     "cfx_font.cpp",
diff --git a/core/fxge/cfx_fillrenderoptions.cpp b/core/fxge/cfx_fillrenderoptions.cpp
new file mode 100644
index 0000000..ca34c5b
--- /dev/null
+++ b/core/fxge/cfx_fillrenderoptions.cpp
@@ -0,0 +1,63 @@
+// Copyright 2020 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_fillrenderoptions.h"
+
+#include "core/fxcrt/fx_system.h"
+#include "core/fxge/render_defines.h"
+#include "third_party/base/no_destructor.h"
+
+CFX_FillRenderOptions::CFX_FillRenderOptions() = default;
+
+CFX_FillRenderOptions::CFX_FillRenderOptions(
+    CFX_FillRenderOptions::FillType fill_type)
+    : fill_type(fill_type) {}
+
+CFX_FillRenderOptions::FillType GetFillType(int fill_type) {
+  ASSERT(fill_type >= 0);
+  ASSERT(fill_type <= 2);
+  return static_cast<CFX_FillRenderOptions::FillType>(fill_type);
+}
+
+CFX_FillRenderOptions GetFillOptionsFromIntegerFlags(int flags) {
+  CFX_FillRenderOptions options(GetFillType(flags & 3));
+  if (flags & FX_STROKE_ADJUST)
+    options.adjust_stroke = true;
+  if (flags & FXFILL_NOPATHSMOOTH)
+    options.aliased_path = true;
+  if (flags & FXFILL_FULLCOVER)
+    options.full_cover = true;
+  if (flags & FXFILL_RECT_AA)
+    options.rect_aa = true;
+  if (flags & FX_FILL_STROKE)
+    options.stroke = true;
+  if (flags & FX_STROKE_TEXT_MODE)
+    options.stroke_text_mode = true;
+  if (flags & FX_FILL_TEXT_MODE)
+    options.text_mode = true;
+  if (flags & FX_ZEROAREA_FILL)
+    options.zero_area = true;
+  return options;
+}
+
+int GetIntegerFlagsFromFillOptions(const CFX_FillRenderOptions& options) {
+  int flags = static_cast<int>(options.fill_type);
+  if (options.adjust_stroke)
+    flags |= FX_STROKE_ADJUST;
+  if (options.aliased_path)
+    flags |= FXFILL_NOPATHSMOOTH;
+  if (options.full_cover)
+    flags |= FXFILL_FULLCOVER;
+  if (options.rect_aa)
+    flags |= FXFILL_RECT_AA;
+  if (options.stroke)
+    flags |= FX_FILL_STROKE;
+  if (options.stroke_text_mode)
+    flags |= FX_STROKE_TEXT_MODE;
+  if (options.text_mode)
+    flags |= FX_FILL_TEXT_MODE;
+  if (options.zero_area)
+    flags |= FX_ZEROAREA_FILL;
+  return flags;
+}
diff --git a/core/fxge/cfx_fillrenderoptions.h b/core/fxge/cfx_fillrenderoptions.h
new file mode 100644
index 0000000..34caa8b
--- /dev/null
+++ b/core/fxge/cfx_fillrenderoptions.h
@@ -0,0 +1,74 @@
+// Copyright 2020 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.
+
+#ifndef CORE_FXGE_CFX_FILLRENDEROPTIONS_H_
+#define CORE_FXGE_CFX_FILLRENDEROPTIONS_H_
+
+// Represents the options for filling paths.
+struct CFX_FillRenderOptions {
+  // FillType defines how path is filled.
+  enum class FillType {
+    // No filling needed.
+    kNoFill = 0,
+
+    // Use even-odd or inverse even-odd algorithms to decide if the area needs
+    // to be filled.
+    kEvenOdd = 1,
+
+    // Use winding or inverse winding algorithms to decide whether the area
+    // needs to be filled.
+    kWinding = 2,
+  };
+
+  CFX_FillRenderOptions();
+  explicit CFX_FillRenderOptions(FillType fill_type);
+
+  // Fill type.
+  FillType fill_type = FillType::kNoFill;
+
+  // Adjusted stroke rendering is enabled.
+  bool adjust_stroke = false;
+
+  // Whether anti aliasing is enabled for path rendering.
+  bool aliased_path = false;
+
+  // Fills with the sum of colors from both cover and source.
+  bool full_cover = false;
+
+  // Rect paths use anti-aliasing.
+  bool rect_aa = false;
+
+  // Path is stroke.
+  bool stroke = false;
+
+  // Renders text by filling strokes.
+  bool stroke_text_mode = false;
+
+  // Path is text.
+  bool text_mode = false;
+
+  // Path encloses zero area.
+  bool zero_area = false;
+};
+
+// Converts integer |fill_type| into CFX_FillRenderOptions::FillType.
+// |fill_type| can be 0, FXFILL_ALTERNATE or FXFILL_WINDING.
+// TODO(https://crbug.com/pdfium/1531): Remove this function when all existence
+// of FXFILL_ALTERNATE and FXFILL_WINDING are replaced by FillType::kEvenOdd and
+// FillType::kWinding.
+CFX_FillRenderOptions::FillType GetFillType(int fill_type);
+
+// TODO(https://crbug.com/pdfium/1531): Remove the converter functions
+// GetFillOptionsFromIntegerFlags() and GetIntegerFlagsFromFillOptions() once
+// all integer rendering flags are replaced with CFX_FillRenderOptions.
+
+// Generates a matching CFX_FillRenderOptions struct from integer |flags| which
+// contains fill rendering options.
+CFX_FillRenderOptions GetFillOptionsFromIntegerFlags(int flags);
+
+// Generates an integer which represents fill options from CFX_FillRenderOptions
+// struct |options|.
+int GetIntegerFlagsFromFillOptions(const CFX_FillRenderOptions& options);
+
+#endif  // CORE_FXGE_CFX_FILLRENDEROPTIONS_H_
diff --git a/core/fxge/cfx_renderdevice.cpp b/core/fxge/cfx_renderdevice.cpp
index e37b662..82cec48 100644
--- a/core/fxge/cfx_renderdevice.cpp
+++ b/core/fxge/cfx_renderdevice.cpp
@@ -14,6 +14,7 @@
 #include "core/fxcrt/fx_safe_types.h"
 #include "core/fxge/cfx_color.h"
 #include "core/fxge/cfx_defaultrenderdevice.h"
+#include "core/fxge/cfx_fillrenderoptions.h"
 #include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_fontmgr.h"
 #include "core/fxge/cfx_gemodule.h"
@@ -509,15 +510,30 @@
   m_ClipBox.bottom = m_Height;
 }
 
-bool CFX_RenderDevice::DrawPathWithBlend(const CFX_PathData* pPathData,
-                                         const CFX_Matrix* pObject2Device,
-                                         const CFX_GraphStateData* pGraphState,
-                                         uint32_t fill_color,
-                                         uint32_t stroke_color,
-                                         int fill_mode,
-                                         BlendMode blend_type) {
+bool CFX_RenderDevice::DrawPath(const CFX_PathData* pPathData,
+                                const CFX_Matrix* pObject2Device,
+                                const CFX_GraphStateData* pGraphState,
+                                uint32_t fill_color,
+                                uint32_t stroke_color,
+                                int fill_mode) {
+  return DrawPathWithBlend(
+      pPathData, pObject2Device, pGraphState, fill_color, stroke_color,
+      GetFillOptionsFromIntegerFlags(fill_mode), BlendMode::kNormal);
+}
+
+bool CFX_RenderDevice::DrawPathWithBlend(
+    const CFX_PathData* pPathData,
+    const CFX_Matrix* pObject2Device,
+    const CFX_GraphStateData* pGraphState,
+    uint32_t fill_color,
+    uint32_t stroke_color,
+    const CFX_FillRenderOptions& fill_options,
+    BlendMode blend_type) {
   uint8_t stroke_alpha = pGraphState ? FXARGB_A(stroke_color) : 0;
-  uint8_t fill_alpha = (fill_mode & 3) ? FXARGB_A(fill_color) : 0;
+  uint8_t fill_alpha =
+      fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill
+          ? FXARGB_A(fill_color)
+          : 0;
   pdfium::span<const FX_PATHPOINT> points = pPathData->GetPoints();
   if (stroke_alpha == 0 && points.size() == 2) {
     CFX_PointF pos1 = points[0].m_Point;
@@ -526,12 +542,13 @@
       pos1 = pObject2Device->Transform(pos1);
       pos2 = pObject2Device->Transform(pos2);
     }
-    DrawCosmeticLine(pos1, pos2, fill_color, fill_mode, blend_type);
+    DrawCosmeticLine(pos1, pos2, fill_color,
+                     GetIntegerFlagsFromFillOptions(fill_options), blend_type);
     return true;
   }
 
   if ((points.size() == 5 || points.size() == 4) && stroke_alpha == 0 &&
-      !(fill_mode & FXFILL_RECT_AA)) {
+      !fill_options.rect_aa) {
     Optional<CFX_FloatRect> maybe_rect_f = pPathData->GetRect(pObject2Device);
     if (maybe_rect_f.has_value()) {
       const CFX_FloatRect& rect_f = maybe_rect_f.value();
@@ -575,8 +592,8 @@
         return true;
     }
   }
-  if ((fill_mode & 3) && stroke_alpha == 0 && !(fill_mode & FX_FILL_STROKE) &&
-      !(fill_mode & FX_FILL_TEXT_MODE)) {
+  if (fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill &&
+      stroke_alpha == 0 && !fill_options.stroke && !fill_options.text_mode) {
     CFX_PathData newPath;
     bool bThin = false;
     bool setIdentity = false;
@@ -595,15 +612,17 @@
         pMatrix = pObject2Device;
 
       int smooth_path = FX_ZEROAREA_FILL;
-      if (fill_mode & FXFILL_NOPATHSMOOTH)
+      if (fill_options.aliased_path)
         smooth_path |= FXFILL_NOPATHSMOOTH;
 
       m_pDeviceDriver->DrawPath(&newPath, pMatrix, &graphState, 0, strokecolor,
                                 smooth_path, blend_type);
     }
   }
-  if ((fill_mode & 3) && fill_alpha && stroke_alpha < 0xff &&
-      (fill_mode & FX_FILL_STROKE)) {
+
+  const int fill_mode = GetIntegerFlagsFromFillOptions(fill_options);
+  if (fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill &&
+      fill_alpha && stroke_alpha < 0xff && fill_options.stroke) {
     if (m_RenderCaps & FXRC_FILLSTROKE_PATH) {
       return m_pDeviceDriver->DrawPath(pPathData, pObject2Device, pGraphState,
                                        fill_color, stroke_color, fill_mode,
@@ -1071,12 +1090,13 @@
     CFX_PathData TransformedPath(*pPath);
     TransformedPath.Transform(matrix);
     if (fill_color || stroke_color) {
-      int fill_mode = nFlag;
+      CFX_FillRenderOptions fill_options =
+          GetFillOptionsFromIntegerFlags(nFlag);
       if (fill_color)
-        fill_mode |= FXFILL_WINDING;
-      fill_mode |= FX_FILL_TEXT_MODE;
+        fill_options.fill_type = CFX_FillRenderOptions::FillType::kWinding;
+      fill_options.text_mode = true;
       if (!DrawPathWithBlend(&TransformedPath, pUser2Device, pGraphState,
-                             fill_color, stroke_color, fill_mode,
+                             fill_color, stroke_color, fill_options,
                              BlendMode::kNormal)) {
         return false;
       }
diff --git a/core/fxge/cfx_renderdevice.h b/core/fxge/cfx_renderdevice.h
index 20aa16b..33edfb8 100644
--- a/core/fxge/cfx_renderdevice.h
+++ b/core/fxge/cfx_renderdevice.h
@@ -26,6 +26,7 @@
 class PauseIndicatorIface;
 class TextCharPos;
 struct CFX_Color;
+struct CFX_FillRenderOptions;
 struct CFX_TextRenderOptions;
 
 enum class BorderStyle { kSolid, kDash, kBeveled, kInset, kUnderline };
@@ -82,16 +83,13 @@
                 const CFX_GraphStateData* pGraphState,
                 uint32_t fill_color,
                 uint32_t stroke_color,
-                int fill_mode) {
-    return DrawPathWithBlend(pPathData, pObject2Device, pGraphState, fill_color,
-                             stroke_color, fill_mode, BlendMode::kNormal);
-  }
+                int fill_mode);
   bool DrawPathWithBlend(const CFX_PathData* pPathData,
                          const CFX_Matrix* pObject2Device,
                          const CFX_GraphStateData* pGraphState,
                          uint32_t fill_color,
                          uint32_t stroke_color,
-                         int fill_mode,
+                         const CFX_FillRenderOptions& fill_options,
                          BlendMode blend_type);
   bool FillRect(const FX_RECT& rect, uint32_t color) {
     return FillRectWithBlend(rect, color, BlendMode::kNormal);