Add APIs for path construction and painting

Added methods to create paths, set their colors, determine whether they will be
stroked and/or filled. FPDFPage_InsertObject should be used to add a path to a
page.

BUG=pdfium:661

Change-Id: I8fd17b33a09c5126e517bfd1a69a893216c160e8
Reviewed-on: https://pdfium-review.googlesource.com/2534
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Nicolás Peña <npm@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index aa75afc..cd3fa3f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -112,6 +112,7 @@
     "fpdfsdk/fpdfdoc.cpp",
     "fpdfsdk/fpdfeditimg.cpp",
     "fpdfsdk/fpdfeditpage.cpp",
+    "fpdfsdk/fpdfeditpath.cpp",
     "fpdfsdk/fpdfformfill.cpp",
     "fpdfsdk/fpdfppo.cpp",
     "fpdfsdk/fpdfsave.cpp",
diff --git a/core/fpdfapi/page/cpdf_path.cpp b/core/fpdfapi/page/cpdf_path.cpp
index 8151ae4..96d6b72 100644
--- a/core/fpdfapi/page/cpdf_path.cpp
+++ b/core/fpdfapi/page/cpdf_path.cpp
@@ -67,3 +67,13 @@
                            FX_FLOAT top) {
   m_Ref.GetPrivateCopy()->AppendRect(left, bottom, right, top);
 }
+
+void CPDF_Path::AppendPoint(FX_FLOAT x,
+                            FX_FLOAT y,
+                            FXPT_TYPE type,
+                            bool close) {
+  CFX_PathData data;
+  data.SetPointCount(1);
+  data.SetPoint(0, x, y, type, close);
+  Append(&data, nullptr);
+}
diff --git a/core/fpdfapi/page/cpdf_path.h b/core/fpdfapi/page/cpdf_path.h
index 252be26..21a94be 100644
--- a/core/fpdfapi/page/cpdf_path.h
+++ b/core/fpdfapi/page/cpdf_path.h
@@ -38,6 +38,7 @@
   void Append(const CPDF_Path& other, const CFX_Matrix* pMatrix);
   void Append(const CFX_PathData* pData, const CFX_Matrix* pMatrix);
   void AppendRect(FX_FLOAT left, FX_FLOAT bottom, FX_FLOAT right, FX_FLOAT top);
+  void AppendPoint(FX_FLOAT x, FX_FLOAT y, FXPT_TYPE type, bool close);
 
   // TODO(tsepez): Remove when all access thru this class.
   const CFX_PathData* GetObject() const { return m_Ref.GetObject(); }
diff --git a/fpdfsdk/fpdfeditpath.cpp b/fpdfsdk/fpdfeditpath.cpp
new file mode 100644
index 0000000..1641510
--- /dev/null
+++ b/fpdfsdk/fpdfeditpath.cpp
@@ -0,0 +1,126 @@
+// Copyright 2017 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 "public/fpdf_edit.h"
+
+#include "core/fpdfapi/page/cpdf_path.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "core/fxcrt/fx_system.h"
+
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewPath(float x, float y) {
+  CPDF_PathObject* pPathObj = new CPDF_PathObject;
+  pPathObj->m_Path.AppendPoint(x, y, FXPT_TYPE::MoveTo, false);
+  return pPathObj;
+}
+
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewRect(float x,
+                                                            float y,
+                                                            float w,
+                                                            float h) {
+  CPDF_PathObject* pPathObj = new CPDF_PathObject;
+  pPathObj->m_Path.AppendRect(x, y, x + w, y + h);
+  return pPathObj;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
+                                            unsigned int R,
+                                            unsigned int G,
+                                            unsigned int B,
+                                            unsigned int A) {
+  if (!path || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
+  FX_FLOAT rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
+  pPathObj->m_ColorState.SetStrokeColor(
+      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
+                                          unsigned int R,
+                                          unsigned int G,
+                                          unsigned int B,
+                                          unsigned int A) {
+  if (!path || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_GeneralState.SetFillAlpha(A / 255.f);
+  FX_FLOAT rgb[3] = {R / 255.f, G / 255.f, B / 255.f};
+  pPathObj->m_ColorState.SetFillColor(
+      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb, 3);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_Path.AppendPoint(x, y, FXPT_TYPE::MoveTo, false);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_Path.AppendPoint(x, y, FXPT_TYPE::LineTo, false);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
+                                      float x1,
+                                      float y1,
+                                      float x2,
+                                      float y2,
+                                      float x3,
+                                      float y3) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  pPathObj->m_Path.AppendPoint(x1, y1, FXPT_TYPE::BezierTo, false);
+  pPathObj->m_Path.AppendPoint(x2, y2, FXPT_TYPE::BezierTo, false);
+  pPathObj->m_Path.AppendPoint(x3, y3, FXPT_TYPE::BezierTo, false);
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_Close(FPDF_PAGEOBJECT path) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+  int numPoints = pPathObj->m_Path.GetPointCount();
+  if (numPoints == 0)
+    return false;
+
+  FX_PATHPOINT* pPoints = pPathObj->m_Path.GetMutablePoints();
+  if (pPoints[numPoints - 1].m_CloseFigure)
+    return true;
+
+  pPoints[numPoints - 1].m_CloseFigure = true;
+  return true;
+}
+
+DLLEXPORT FPDF_BOOL FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
+                                         int fillmode,
+                                         FPDF_BOOL stroke) {
+  if (!path)
+    return false;
+
+  auto pPathObj = reinterpret_cast<CPDF_PathObject*>(path);
+
+  if (fillmode == FPDF_FILLMODE_ALTERNATE)
+    pPathObj->m_FillType = FXFILL_ALTERNATE;
+  else if (fillmode == FPDF_FILLMODE_WINDING)
+    pPathObj->m_FillType = FXFILL_WINDING;
+  else
+    pPathObj->m_FillType = 0;
+  pPathObj->m_bStroke = stroke != 0;
+  return true;
+}
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 98478f0..8ec3a26 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -85,6 +85,15 @@
     CHK(FPDFImageObj_LoadJpegFile);
     CHK(FPDFImageObj_SetMatrix);
     CHK(FPDFImageObj_SetBitmap);
+    CHK(FPDFPageObj_CreateNewPath);
+    CHK(FPDFPageObj_CreateNewRect);
+    CHK(FPDFPath_SetStrokeColor);
+    CHK(FPDFPath_SetFillColor);
+    CHK(FPDFPath_MoveTo);
+    CHK(FPDFPath_LineTo);
+    CHK(FPDFPath_BezierTo);
+    CHK(FPDFPath_Close);
+    CHK(FPDFPath_SetDrawMode);
 
     // fpdf_ext.h
     CHK(FSDK_SetUnSpObjProcessHandler);
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index 640d97e..d151c5c 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -27,6 +27,9 @@
 #define FPDF_PAGEOBJ_SHADING 4
 #define FPDF_PAGEOBJ_FORM 5
 
+#define FPDF_FILLMODE_ALTERNATE 1
+#define FPDF_FILLMODE_WINDING 2
+
 #ifdef __cplusplus
 extern "C" {
 #endif  // __cplusplus
@@ -260,6 +263,121 @@
                                                    FPDF_PAGEOBJECT image_object,
                                                    FPDF_BITMAP bitmap);
 
+// Create a new path object at an initial position.
+//
+//   x - initial horizontal position.
+//   y - initial vertical position.
+//
+// Returns a handle to a new path object.
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewPath(float x, float y);
+
+// Create a closed path consisting of a rectangle.
+//
+//   x - horizontal position for the left boundary of the rectangle.
+//   y - vertical position for the bottom boundary of the rectangle.
+//   w - width of the rectangle.
+//   h - height of the rectangle.
+//
+// Returns a handle to the new path object.
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_CreateNewRect(float x,
+                                                            float y,
+                                                            float w,
+                                                            float h);
+
+// Set the stroke RGBA of a path. Range of values: 0 - 255.
+//
+// path   - the handle to the path object.
+// R      - the red component for the path stroke color.
+// G      - the green component for the path stroke color.
+// B      - the blue component for the path stroke color.
+// A      - the stroke alpha for the path.
+//
+// Returns TRUE on success.
+DLLEXPORT FPDF_BOOL FPDFPath_SetStrokeColor(FPDF_PAGEOBJECT path,
+                                            unsigned int R,
+                                            unsigned int G,
+                                            unsigned int B,
+                                            unsigned int A);
+
+// Set the fill RGBA of a path. Range of values: 0 - 255.
+//
+// path   - the handle to the path object.
+// R      - the red component for the path fill color.
+// G      - the green component for the path fill color.
+// B      - the blue component for the path fill color.
+// A      - the fill alpha for the path.
+//
+// Returns TRUE on success.
+DLLEXPORT FPDF_BOOL FPDFPath_SetFillColor(FPDF_PAGEOBJECT path,
+                                          unsigned int R,
+                                          unsigned int G,
+                                          unsigned int B,
+                                          unsigned int A);
+
+// Move a path's current point.
+//
+// path   - the handle to the path object.
+// x      - the horizontal position of the new current point.
+// y      - the vertical position of the new current point.
+//
+// Note that no line will be created between the previous current point and the
+// new one.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_MoveTo(FPDF_PAGEOBJECT path, float x, float y);
+
+// Add a line between the current point and a new point in the path.
+//
+// path   - the handle to the path object.
+// x      - the horizontal position of the new point.
+// y      - the vertical position of the new point.
+//
+// The path's current point is changed to (x, y).
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_LineTo(FPDF_PAGEOBJECT path, float x, float y);
+
+// Add a cubic Bezier curve to the given path, starting at the current point.
+//
+// path   - the handle to the path object.
+// x1     - the horizontal position of the first Bezier control point.
+// y1     - the vertical position of the first Bezier control point.
+// x2     - the horizontal position of the second Bezier control point.
+// y2     - the vertical position of the second Bezier control point.
+// x3     - the horizontal position of the ending point of the Bezier curve.
+// y3     - the vertical position of the ending point of the Bezier curve.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_BezierTo(FPDF_PAGEOBJECT path,
+                                      float x1,
+                                      float y1,
+                                      float x2,
+                                      float y2,
+                                      float x3,
+                                      float y3);
+
+// Close the current subpath of a given path.
+//
+// path   - the handle to the path object.
+//
+// This will add a line between the current point and the initial point of the
+// subpath, thus terminating the current subpath.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_Close(FPDF_PAGEOBJECT path);
+
+// Set the drawing mode of a path.
+//
+// path     - the handle to the path object.
+// fillmode - the filling mode to be set: 0 for no fill, 1 for alternate, 2 for
+// winding.
+// stroke   - a boolean specifying if the path should be stroked or not.
+//
+// Returns TRUE on success
+DLLEXPORT FPDF_BOOL FPDFPath_SetDrawMode(FPDF_PAGEOBJECT path,
+                                         int fillmode,
+                                         FPDF_BOOL stroke);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus