Add several FPDFPageObj_* APIs

This CL adds the following APIs:
FPDFPageObj_SetStrokeColor
FPDFPageObj_GetStrokeColor
FPDFPageObj_SetStrokeWidth
FPDFPageObj_SetLineJoin
FPDFPageObj_SetLineCap
FPDFPageObj_SetFillColor
FPDFPageObj_GetFillColor

Bug: pdfium:980
Change-Id: I19f9abb6756314ba8bd2f66a6c38e2e722cd8473
Reviewed-on: https://pdfium-review.googlesource.com/32192
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Nicolás Peña Moreno <npm@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_helpers.h b/fpdfsdk/cpdfsdk_helpers.h
index 214fa72..d93ecfc 100644
--- a/fpdfsdk/cpdfsdk_helpers.h
+++ b/fpdfsdk/cpdfsdk_helpers.h
@@ -262,11 +262,4 @@
 
 void ProcessParseError(CPDF_Parser::Error err);
 
-// TODO(dsinclair): This seems like it should be a public API?
-FPDF_BOOL FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
-                                   unsigned int R,
-                                   unsigned int G,
-                                   unsigned int B,
-                                   unsigned int A);
-
 #endif  // FPDFSDK_CPDFSDK_HELPERS_H_
diff --git a/fpdfsdk/fpdf_editpage.cpp b/fpdfsdk/fpdf_editpage.cpp
index ce597d6..ec29891 100644
--- a/fpdfsdk/fpdf_editpage.cpp
+++ b/fpdfsdk/fpdf_editpage.cpp
@@ -120,6 +120,10 @@
   return nullptr;
 }
 
+unsigned int GetUnsignedAlpha(float alpha) {
+  return static_cast<unsigned int>(alpha * 255.f + 0.5f);
+}
+
 }  // namespace
 
 FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_CreateNewDocument() {
@@ -505,6 +509,24 @@
 }
 
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,
+                         unsigned int* R,
+                         unsigned int* G,
+                         unsigned int* B,
+                         unsigned int* A) {
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  if (!pPageObj || !R || !G || !B || !A)
+    return false;
+
+  FX_COLORREF fillColor = pPageObj->m_ColorState.GetFillColorRef();
+  *R = FXSYS_GetRValue(fillColor);
+  *G = FXSYS_GetGValue(fillColor);
+  *B = FXSYS_GetBValue(fillColor);
+  *A = GetUnsignedAlpha(pPageObj->m_GeneralState.GetFillAlpha());
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFPageObj_GetBounds(FPDF_PAGEOBJECT pageObject,
                       float* left,
                       float* bottom,
@@ -521,3 +543,84 @@
   *top = bbox.top;
   return true;
 }
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,
+                           unsigned int R,
+                           unsigned int G,
+                           unsigned int B,
+                           unsigned int A) {
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  if (!pPageObj || R > 255 || G > 255 || B > 255 || A > 255)
+    return false;
+
+  std::vector<float> rgb = {R / 255.f, G / 255.f, B / 255.f};
+  pPageObj->m_GeneralState.SetStrokeAlpha(A / 255.f);
+  pPageObj->m_ColorState.SetStrokeColor(
+      CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB), rgb);
+  pPageObj->SetDirty(true);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,
+                           unsigned int* R,
+                           unsigned int* G,
+                           unsigned int* B,
+                           unsigned int* A) {
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  if (!pPageObj || !R || !G || !B || !A)
+    return false;
+
+  FX_COLORREF strokeColor = pPageObj->m_ColorState.GetStrokeColorRef();
+  *R = FXSYS_GetRValue(strokeColor);
+  *G = FXSYS_GetGValue(strokeColor);
+  *B = FXSYS_GetBValue(strokeColor);
+  *A = GetUnsignedAlpha(pPageObj->m_GeneralState.GetStrokeAlpha());
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width) {
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  if (!pPageObj || width < 0.0f)
+    return false;
+
+  pPageObj->m_GraphState.SetLineWidth(width);
+  pPageObj->SetDirty(true);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join) {
+  if (!page_object)
+    return false;
+  if (line_join <
+          static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinMiter) ||
+      line_join >
+          static_cast<int>(CFX_GraphStateData::LineJoin::LineJoinBevel)) {
+    return false;
+  }
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  CFX_GraphStateData::LineJoin lineJoin =
+      static_cast<CFX_GraphStateData::LineJoin>(line_join);
+  pPageObj->m_GraphState.SetLineJoin(lineJoin);
+  pPageObj->SetDirty(true);
+  return true;
+}
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap) {
+  if (!page_object)
+    return false;
+  if (line_cap < static_cast<int>(CFX_GraphStateData::LineCap::LineCapButt) ||
+      line_cap > static_cast<int>(CFX_GraphStateData::LineCap::LineCapSquare)) {
+    return false;
+  }
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(page_object);
+  CFX_GraphStateData::LineCap lineCap =
+      static_cast<CFX_GraphStateData::LineCap>(line_cap);
+  pPageObj->m_GraphState.SetLineCap(lineCap);
+  pPageObj->SetDirty(true);
+  return true;
+}
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 782d35d..15d893d 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -166,10 +166,15 @@
     CHK(FPDFPageObj_CreateNewPath);
     CHK(FPDFPageObj_CreateNewRect);
     CHK(FPDFPath_SetStrokeColor);
+    CHK(FPDFPageObj_SetStrokeColor);
     CHK(FPDFPath_GetStrokeColor);
+    CHK(FPDFPageObj_GetStrokeColor);
     CHK(FPDFPath_SetStrokeWidth);
+    CHK(FPDFPageObj_SetStrokeWidth);
     CHK(FPDFPath_SetFillColor);
+    CHK(FPDFPageObj_SetFillColor);
     CHK(FPDFPath_GetFillColor);
+    CHK(FPDFPageObj_GetFillColor);
     CHK(FPDFPath_CountSegments);
     CHK(FPDFPath_GetPathSegment);
     CHK(FPDFPathSegment_GetPoint);
@@ -181,7 +186,9 @@
     CHK(FPDFPath_Close);
     CHK(FPDFPath_SetDrawMode);
     CHK(FPDFPath_SetLineCap);
+    CHK(FPDFPageObj_SetLineCap);
     CHK(FPDFPath_SetLineJoin);
+    CHK(FPDFPageObj_SetLineJoin);
     CHK(FPDFPageObj_NewTextObj);
     CHK(FPDFText_SetText);
     CHK(FPDFText_SetFillColor);
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index 74c2700..c0766a3 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -612,6 +612,22 @@
                         unsigned int B,
                         unsigned int A);
 
+// Set the stroke RGBA of a page object. Range of values: 0 - 255.
+//
+// page_object  - the handle to the page object.
+// R            - the red component for the object's stroke color.
+// G            - the green component for the object's stroke color.
+// B            - the blue component for the object's stroke color.
+// A            - the stroke alpha for the object.
+//
+// Returns TRUE on success.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetStrokeColor(FPDF_PAGEOBJECT page_object,
+                           unsigned int R,
+                           unsigned int G,
+                           unsigned int B,
+                           unsigned int A);
+
 // Get the stroke RGBA of a path. Range of values: 0 - 255.
 //
 // path   - the handle to the path object.
@@ -628,6 +644,22 @@
                         unsigned int* B,
                         unsigned int* A);
 
+// Get the stroke RGBA of a page object. Range of values: 0 - 255.
+//
+// page_object  - the handle to the page object.
+// R            - the red component of the path stroke color.
+// G            - the green component of the object's stroke color.
+// B            - the blue component of the object's stroke color.
+// A            - the stroke alpha of the object.
+//
+// Returns TRUE on success.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_GetStrokeColor(FPDF_PAGEOBJECT page_object,
+                           unsigned int* R,
+                           unsigned int* G,
+                           unsigned int* B,
+                           unsigned int* A);
+
 // Set the stroke width of a path.
 //
 // path   - the handle to the path object.
@@ -637,6 +669,15 @@
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
 FPDFPath_SetStrokeWidth(FPDF_PAGEOBJECT path, float width);
 
+// Set the stroke width of a page object.
+//
+// path   - the handle to the page object.
+// width  - the width of the stroke.
+//
+// Returns TRUE on success
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetStrokeWidth(FPDF_PAGEOBJECT page_object, float width);
+
 // Set the line join of |page_object|.
 //
 // page_object  - handle to a page object.
@@ -647,6 +688,16 @@
 FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineJoin(FPDF_PAGEOBJECT page_object,
                                                     int line_join);
 
+// Set the line join of |page_object|.
+//
+// page_object  - handle to a page object.
+// line_join    - line join
+//
+// Line join can be one of following: FPDF_LINEJOIN_MITER, FPDF_LINEJOIN_ROUND,
+// FPDF_LINEJOIN_BEVEL
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetLineJoin(FPDF_PAGEOBJECT page_object, int line_join);
+
 // Set the line cap of |page_object|.
 //
 // page_object - handle to a page object.
@@ -657,6 +708,16 @@
 FPDF_EXPORT void FPDF_CALLCONV FPDFPath_SetLineCap(FPDF_PAGEOBJECT page_object,
                                                    int line_cap);
 
+// Set the line cap of |page_object|.
+//
+// page_object - handle to a page object.
+// line_cap    - line cap
+//
+// Line cap can be one of following: FPDF_LINECAP_BUTT, FPDF_LINECAP_ROUND,
+// FPDF_LINECAP_PROJECTING_SQUARE
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetLineCap(FPDF_PAGEOBJECT page_object, int line_cap);
+
 // Set the fill RGBA of a path. Range of values: 0 - 255.
 //
 // path   - the handle to the path object.
@@ -672,6 +733,22 @@
                                                           unsigned int B,
                                                           unsigned int A);
 
+// Set the fill RGBA of a page object. Range of values: 0 - 255.
+//
+// page_object  - the handle to the page object.
+// R            - the red component for the object's fill color.
+// G            - the green component for the object's fill color.
+// B            - the blue component for the object's fill color.
+// A            - the fill alpha for the object.
+//
+// Returns TRUE on success.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_SetFillColor(FPDF_PAGEOBJECT page_object,
+                         unsigned int R,
+                         unsigned int G,
+                         unsigned int B,
+                         unsigned int A);
+
 // Get the fill RGBA of a path. Range of values: 0 - 255.
 //
 // path   - the handle to the path object.
@@ -687,6 +764,22 @@
                                                           unsigned int* B,
                                                           unsigned int* A);
 
+// Get the fill RGBA of a page object. Range of values: 0 - 255.
+//
+// page_object  - the handle to the page object.
+// R            - the red component of the object's fill color.
+// G            - the green component of the object's fill color.
+// B            - the blue component of the object's fill color.
+// A            - the fill alpha of the object.
+//
+// Returns TRUE on success.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFPageObj_GetFillColor(FPDF_PAGEOBJECT page_object,
+                         unsigned int* R,
+                         unsigned int* G,
+                         unsigned int* B,
+                         unsigned int* A);
+
 // Experimental API.
 // Get number of segments inside |path|.
 //