Give CFX_GraphStateData a work-over.

Use std::vector<float> for dash array.
Use compiler-generated default operations.
Squeeze some enums.
Fix obvious logic botch in DashChanged().

Change-Id: If1d809cc46a3cf2db98a09a3f5a49d22138c0640
Reviewed-on: https://pdfium-review.googlesource.com/42613
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfdoc/cpdf_annot.cpp b/core/fpdfdoc/cpdf_annot.cpp
index 961da82..89bcdee 100644
--- a/core/fpdfdoc/cpdf_annot.cpp
+++ b/core/fpdfdoc/cpdf_annot.cpp
@@ -504,8 +504,7 @@
       if (dash_count % 2) {
         dash_count++;
       }
-      graph_state.m_DashArray = FX_Alloc(float, dash_count);
-      graph_state.m_DashCount = dash_count;
+      graph_state.m_DashArray.resize(dash_count);
       size_t i;
       for (i = 0; i < pDashArray->GetCount(); ++i) {
         graph_state.m_DashArray[i] = pDashArray->GetNumberAt(i);
@@ -514,9 +513,7 @@
         graph_state.m_DashArray[i] = graph_state.m_DashArray[i - 1];
       }
     } else {
-      graph_state.m_DashArray = FX_Alloc(float, 2);
-      graph_state.m_DashCount = 2;
-      graph_state.m_DashArray[0] = graph_state.m_DashArray[1] = 3 * 1.0f;
+      graph_state.m_DashArray = {3.0f, 3.0f};
     }
   }
 
diff --git a/core/fxge/agg/fx_agg_driver.cpp b/core/fxge/agg/fx_agg_driver.cpp
index 063f36d..69006b6 100644
--- a/core/fxge/agg/fx_agg_driver.cpp
+++ b/core/fxge/agg/fx_agg_driver.cpp
@@ -285,14 +285,14 @@
         1.0f / ((pObject2Device->GetXUnit() + pObject2Device->GetYUnit()) / 2);
   }
   width = std::max(width, unit);
-  if (pGraphState->m_DashArray) {
+  if (!pGraphState->m_DashArray.empty()) {
     typedef agg::conv_dash<agg::path_storage> dash_converter;
     dash_converter dash(*path_data);
-    for (int i = 0; i < (pGraphState->m_DashCount + 1) / 2; i++) {
+    for (size_t i = 0; i < (pGraphState->m_DashArray.size() + 1) / 2; i++) {
       float on = pGraphState->m_DashArray[i * 2];
       if (on <= 0.000001f)
         on = 1.0f / 10;
-      float off = i * 2 + 1 == pGraphState->m_DashCount
+      float off = i * 2 + 1 == pGraphState->m_DashArray.size()
                       ? on
                       : pGraphState->m_DashArray[i * 2 + 1];
       off = std::max(off, 0.0f);
diff --git a/core/fxge/cfx_graphstate.cpp b/core/fxge/cfx_graphstate.cpp
index ad6b5fc..919faa3 100644
--- a/core/fxge/cfx_graphstate.cpp
+++ b/core/fxge/cfx_graphstate.cpp
@@ -22,7 +22,7 @@
 void CFX_GraphState::SetLineDash(CPDF_Array* pArray, float phase, float scale) {
   CFX_GraphStateData* pData = m_Ref.GetPrivateCopy();
   pData->m_DashPhase = phase * scale;
-  pData->SetDashCount(static_cast<int>(pArray->GetCount()));
+  pData->m_DashArray.resize(pArray->GetCount());
   for (size_t i = 0; i < pArray->GetCount(); i++)
     pData->m_DashArray[i] = pArray->GetNumberAt(i) * scale;
 }
diff --git a/core/fxge/cfx_graphstatedata.cpp b/core/fxge/cfx_graphstatedata.cpp
index 82fede1..3bea040 100644
--- a/core/fxge/cfx_graphstatedata.cpp
+++ b/core/fxge/cfx_graphstatedata.cpp
@@ -6,47 +6,23 @@
 
 #include "core/fxge/cfx_graphstatedata.h"
 
-#include "core/fxcrt/fx_memory.h"
-#include "core/fxcrt/fx_system.h"
-
-CFX_GraphStateData::CFX_GraphStateData()
-    : m_LineCap(LineCapButt),
-      m_DashCount(0),
-      m_DashArray(nullptr),
-      m_DashPhase(0),
-      m_LineJoin(LineJoinMiter),
-      m_MiterLimit(10 * 1.0f),
-      m_LineWidth(1.0f) {}
+CFX_GraphStateData::CFX_GraphStateData() = default;
 
 CFX_GraphStateData::CFX_GraphStateData(const CFX_GraphStateData& src) {
-  m_DashArray = nullptr;
-  Copy(src);
+  *this = src;
 }
 
-void CFX_GraphStateData::Copy(const CFX_GraphStateData& src) {
-  m_LineCap = src.m_LineCap;
-  m_DashCount = src.m_DashCount;
-  FX_Free(m_DashArray);
-  m_DashArray = nullptr;
-  m_DashPhase = src.m_DashPhase;
-  m_LineJoin = src.m_LineJoin;
-  m_MiterLimit = src.m_MiterLimit;
-  m_LineWidth = src.m_LineWidth;
-  if (m_DashCount) {
-    m_DashArray = FX_Alloc(float, m_DashCount);
-    memcpy(m_DashArray, src.m_DashArray, m_DashCount * sizeof(float));
+CFX_GraphStateData::~CFX_GraphStateData() = default;
+
+CFX_GraphStateData& CFX_GraphStateData::operator=(
+    const CFX_GraphStateData& that) {
+  if (this != &that) {
+    m_LineCap = that.m_LineCap;
+    m_LineJoin = that.m_LineJoin;
+    m_DashPhase = that.m_DashPhase;
+    m_MiterLimit = that.m_MiterLimit;
+    m_LineWidth = that.m_LineWidth;
+    m_DashArray = that.m_DashArray;
   }
-}
-
-CFX_GraphStateData::~CFX_GraphStateData() {
-  FX_Free(m_DashArray);
-}
-
-void CFX_GraphStateData::SetDashCount(int count) {
-  FX_Free(m_DashArray);
-  m_DashArray = nullptr;
-  m_DashCount = count;
-  if (count == 0)
-    return;
-  m_DashArray = FX_Alloc(float, count);
+  return *this;
 }
diff --git a/core/fxge/cfx_graphstatedata.h b/core/fxge/cfx_graphstatedata.h
index a907f2a..5604802 100644
--- a/core/fxge/cfx_graphstatedata.h
+++ b/core/fxge/cfx_graphstatedata.h
@@ -7,33 +7,37 @@
 #ifndef CORE_FXGE_CFX_GRAPHSTATEDATA_H_
 #define CORE_FXGE_CFX_GRAPHSTATEDATA_H_
 
+#include <vector>
+
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/retain_ptr.h"
 
 class CFX_GraphStateData final : public Retainable {
  public:
-  enum LineCap { LineCapButt = 0, LineCapRound = 1, LineCapSquare = 2 };
+  enum LineCap : uint8_t {
+    LineCapButt = 0,
+    LineCapRound = 1,
+    LineCapSquare = 2
+  };
+
+  enum LineJoin : uint8_t {
+    LineJoinMiter = 0,
+    LineJoinRound = 1,
+    LineJoinBevel = 2
+  };
 
   CFX_GraphStateData();
   CFX_GraphStateData(const CFX_GraphStateData& src);
   ~CFX_GraphStateData() override;
 
-  void Copy(const CFX_GraphStateData& src);
-  void SetDashCount(int count);
+  CFX_GraphStateData& operator=(const CFX_GraphStateData& src);
 
-  LineCap m_LineCap;
-  int m_DashCount;
-  float* m_DashArray;
-  float m_DashPhase;
-
-  enum LineJoin {
-    LineJoinMiter = 0,
-    LineJoinRound = 1,
-    LineJoinBevel = 2,
-  };
-  LineJoin m_LineJoin;
-  float m_MiterLimit;
-  float m_LineWidth;
+  LineCap m_LineCap = LineCapButt;
+  LineJoin m_LineJoin = LineJoinMiter;
+  float m_DashPhase = 0.0f;
+  float m_MiterLimit = 10.0f;
+  float m_LineWidth = 1.0f;
+  std::vector<float> m_DashArray;
 };
 
 #endif  // CORE_FXGE_CFX_GRAPHSTATEDATA_H_
diff --git a/core/fxge/cfx_renderdevice.cpp b/core/fxge/cfx_renderdevice.cpp
index ab57391..f00d7f9 100644
--- a/core/fxge/cfx_renderdevice.cpp
+++ b/core/fxge/cfx_renderdevice.cpp
@@ -1231,11 +1231,8 @@
             FXPT_TYPE::LineTo, false);
 
         CFX_GraphStateData gsd;
-        gsd.SetDashCount(2);
-        gsd.m_DashArray[0] = 3.0f;
-        gsd.m_DashArray[1] = 3.0f;
+        gsd.m_DashArray = {3.0f, 3.0f};
         gsd.m_DashPhase = 0;
-
         gsd.m_LineWidth = fWidth;
         DrawPath(&path, pUser2Device, &gsd, 0, color.ToFXColor(nTransparency),
                  FXFILL_WINDING);
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index 2ffd446..a06fcaa 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -734,7 +734,7 @@
                                ? SkPath::kEvenOdd_FillType
                                : SkPath::kWinding_FillType);
       if (pDrawState)
-        m_drawState.Copy(*pDrawState);
+        m_drawState = *pDrawState;
       m_fillColor = fill_color;
       m_strokeColor = stroke_color;
       m_blendType = blend_type;
@@ -1139,20 +1139,13 @@
 
   bool DashChanged(const CFX_GraphStateData* pState,
                    const CFX_GraphStateData& refState) const {
-    bool dashArray = pState && pState->m_DashArray;
-    if (!dashArray && !refState.m_DashArray)
+    bool dashArray = pState && !pState->m_DashArray.empty();
+    if (!dashArray && refState.m_DashArray.empty())
       return false;
-    if (!dashArray || !refState.m_DashArray)
+    if (!dashArray || refState.m_DashArray.empty())
       return true;
-    if (pState->m_DashPhase != refState.m_DashPhase ||
-        pState->m_DashCount != refState.m_DashCount) {
-      return true;
-    }
-    for (int index = 0; index < pState->m_DashCount; ++index) {
-      if (pState->m_DashArray[index] != refState.m_DashArray[index])
-        return true;
-    }
-    return true;
+    return pState->m_DashPhase != refState.m_DashPhase ||
+           pState->m_DashArray != refState.m_DashArray;
   }
 
   void AdjustClip(int limit) {
@@ -1476,16 +1469,16 @@
   float width =
       SkTMax(pGraphState->m_LineWidth,
              SkTMin(deviceUnits[0].length(), deviceUnits[1].length()));
-  if (pGraphState->m_DashArray) {
-    int count = (pGraphState->m_DashCount + 1) / 2;
+  if (!pGraphState->m_DashArray.empty()) {
+    size_t count = (pGraphState->m_DashArray.size() + 1) / 2;
     std::unique_ptr<SkScalar, FxFreeDeleter> intervals(
         FX_Alloc2D(SkScalar, count, sizeof(SkScalar)));
     // Set dash pattern
-    for (int i = 0; i < count; i++) {
+    for (size_t i = 0; i < count; i++) {
       float on = pGraphState->m_DashArray[i * 2];
       if (on <= 0.000001f)
         on = 1.f / 10;
-      float off = i * 2 + 1 == pGraphState->m_DashCount
+      float off = i * 2 + 1 == pGraphState->m_DashArray.size()
                       ? on
                       : pGraphState->m_DashArray[i * 2 + 1];
       if (off < 0)
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index dbc2121..12795d0 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -311,13 +311,10 @@
     buf << pGraphState->m_LineCap << " J\n";
   }
   if (!m_bGraphStateSet ||
-      m_CurGraphState.m_DashCount != pGraphState->m_DashCount ||
-      memcmp(m_CurGraphState.m_DashArray, pGraphState->m_DashArray,
-             sizeof(float) * m_CurGraphState.m_DashCount)) {
+      m_CurGraphState.m_DashArray != pGraphState->m_DashArray) {
     buf << "[";
-    for (int i = 0; i < pGraphState->m_DashCount; ++i)
-      buf << pGraphState->m_DashArray[i] << " ";
-
+    for (const auto& dash : pGraphState->m_DashArray)
+      buf << dash << " ";
     buf << "]" << pGraphState->m_DashPhase << " d\n";
   }
   if (!m_bGraphStateSet ||
@@ -332,7 +329,7 @@
       m_CurGraphState.m_MiterLimit != pGraphState->m_MiterLimit) {
     buf << pGraphState->m_MiterLimit << " M\n";
   }
-  m_CurGraphState.Copy(*pGraphState);
+  m_CurGraphState = *pGraphState;
   m_bGraphStateSet = true;
   WriteToStream(&buf);
 }
diff --git a/core/fxge/win32/fx_win32_device.cpp b/core/fxge/win32/fx_win32_device.cpp
index c8f0497..526eea5 100644
--- a/core/fxge/win32/fx_win32_device.cpp
+++ b/core/fxge/win32/fx_win32_device.cpp
@@ -103,7 +103,7 @@
   float width = std::max(scale * pGraphState->m_LineWidth, 1.0f);
 
   uint32_t PenStyle = PS_GEOMETRIC;
-  if (pGraphState->m_DashCount)
+  if (!pGraphState->m_DashArray.empty())
     PenStyle |= PS_USERSTYLE;
   else
     PenStyle |= PS_SOLID;
@@ -137,9 +137,9 @@
   lb.lbStyle = BS_SOLID;
   lb.lbHatch = 0;
   std::vector<uint32_t> dashes;
-  if (pGraphState->m_DashCount) {
-    dashes.resize(pGraphState->m_DashCount);
-    for (int i = 0; i < pGraphState->m_DashCount; i++) {
+  if (!pGraphState->m_DashArray.empty()) {
+    dashes.resize(pGraphState->m_DashArray.size());
+    for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
       dashes[i] = FXSYS_round(
           pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i])
                   : pGraphState->m_DashArray[i]);
@@ -147,7 +147,7 @@
     }
   }
   return ExtCreatePen(PenStyle, (DWORD)ceil(width), &lb,
-                      pGraphState->m_DashCount,
+                      pGraphState->m_DashArray.size(),
                       reinterpret_cast<const DWORD*>(dashes.data()));
 }
 
@@ -994,7 +994,7 @@
   if (pPlatform->m_GdiplusExt.IsAvailable()) {
     if (bDrawAlpha ||
         ((m_DeviceClass != FXDC_PRINTER && !(fill_mode & FXFILL_FULLCOVER)) ||
-         (pGraphState && pGraphState->m_DashCount))) {
+         (pGraphState && !pGraphState->m_DashArray.empty()))) {
       if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
             pGraphState->m_LineWidth == 1.0f &&
             (pPathData->GetPoints().size() == 5 ||
@@ -1023,7 +1023,7 @@
     hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
   }
   if (pPathData->GetPoints().size() == 2 && pGraphState &&
-      pGraphState->m_DashCount) {
+      !pGraphState->m_DashArray.empty()) {
     CFX_PointF pos1 = pPathData->GetPoint(0);
     CFX_PointF pos2 = pPathData->GetPoint(1);
     if (pMatrix) {
diff --git a/core/fxge/win32/fx_win32_gdipext.cpp b/core/fxge/win32/fx_win32_gdipext.cpp
index eee6b87..8d361e7 100644
--- a/core/fxge/win32/fx_win32_gdipext.cpp
+++ b/core/fxge/win32/fx_win32_gdipext.cpp
@@ -770,15 +770,15 @@
       break;
   }
   CallFunc(GdipSetPenLineJoin)(pPen, lineJoin);
-  if (pGraphState->m_DashCount) {
-    float* pDashArray = FX_Alloc(
-        float, pGraphState->m_DashCount + pGraphState->m_DashCount % 2);
+  if (!pGraphState->m_DashArray.empty()) {
+    float* pDashArray =
+        FX_Alloc(float, (pGraphState->m_DashArray.size() + 1) & ~1);
     int nCount = 0;
     float on_leftover = 0, off_leftover = 0;
-    for (int i = 0; i < pGraphState->m_DashCount; i += 2) {
+    for (size_t i = 0; i < pGraphState->m_DashArray.size(); i += 2) {
       float on_phase = pGraphState->m_DashArray[i];
       float off_phase;
-      if (i == pGraphState->m_DashCount - 1)
+      if (i == pGraphState->m_DashArray.size() - 1)
         off_phase = on_phase;
       else
         off_phase = pGraphState->m_DashArray[i + 1];
diff --git a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
index 7feda49..d76ce99 100644
--- a/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
+++ b/fpdfsdk/formfiller/cffl_interactiveformfiller.cpp
@@ -86,8 +86,7 @@
                      false);
 
     CFX_GraphStateData gsd;
-    gsd.SetDashCount(1);
-    gsd.m_DashArray[0] = 1.0f;
+    gsd.m_DashArray = {1.0f};
     gsd.m_DashPhase = 0;
     gsd.m_LineWidth = 1.0f;
     pDevice->DrawPath(&path, pUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
diff --git a/fpdfsdk/pwl/cpwl_edit.cpp b/fpdfsdk/pwl/cpwl_edit.cpp
index c4ff2f4..4cd238b 100644
--- a/fpdfsdk/pwl/cpwl_edit.cpp
+++ b/fpdfsdk/pwl/cpwl_edit.cpp
@@ -201,12 +201,10 @@
       }
       case BorderStyle::DASH: {
         CFX_GraphStateData gsd;
-        gsd.m_LineWidth = (float)GetBorderWidth();
-
-        gsd.SetDashCount(2);
-        gsd.m_DashArray[0] = (float)GetBorderDash().nDash;
-        gsd.m_DashArray[1] = (float)GetBorderDash().nGap;
-        gsd.m_DashPhase = (float)GetBorderDash().nPhase;
+        gsd.m_LineWidth = static_cast<float>(GetBorderWidth());
+        gsd.m_DashArray = {static_cast<float>(GetBorderDash().nDash),
+                           static_cast<float>(GetBorderDash().nGap)};
+        gsd.m_DashPhase = static_cast<float>(GetBorderDash().nPhase);
 
         CFX_PathData path;
         for (int32_t i = 0; i < nCharArray - 1; i++) {
diff --git a/xfa/fxgraphics/cxfa_graphics.cpp b/xfa/fxgraphics/cxfa_graphics.cpp
index 628bd44..03689da 100644
--- a/xfa/fxgraphics/cxfa_graphics.cpp
+++ b/xfa/fxgraphics/cxfa_graphics.cpp
@@ -145,14 +145,14 @@
 
   float scale = m_info.isActOnDash ? m_info.graphState.m_LineWidth : 1.0;
   m_info.graphState.m_DashPhase = dashPhase;
-  m_info.graphState.SetDashCount(dashCount);
+  m_info.graphState.m_DashArray.resize(dashCount);
   for (size_t i = 0; i < dashCount; i++)
     m_info.graphState.m_DashArray[i] = dashArray[i] * scale;
 }
 
 void CXFA_Graphics::SetSolidLineDash() {
   if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    m_info.graphState.SetDashCount(0);
+    m_info.graphState.m_DashArray.clear();
 }
 
 void CXFA_Graphics::SetLineWidth(float lineWidth) {
@@ -439,7 +439,7 @@
       fillColor(info.fillColor) {}
 
 CXFA_Graphics::TInfo& CXFA_Graphics::TInfo::operator=(const TInfo& other) {
-  graphState.Copy(other.graphState);
+  graphState = other.graphState;
   CTM = other.CTM;
   isActOnDash = other.isActOnDash;
   strokeColor = other.strokeColor;