Add FPDFFormObj_GetMatrix() API

This is similar to FPDFText_GetMatrix() (wrapping
CPDF_TextObject::GetTextMatrix()) and FPDFPath_GetMatrix() (wrapping
CPDF_PathObject::m_Matrix), but wraps the matrix of form objects:
CPDF_FormObject::form_matrix().

Change-Id: Ic4ce7ad8050012f54de356bb936263d3e4f097ca
Reviewed-on: https://pdfium-review.googlesource.com/39930
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index e692a94..b957ca3 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/page/cpdf_formobject.h"
 #include "core/fpdfapi/page/cpdf_page.h"
 #include "core/fpdfapi/page/cpdf_pageobject.h"
 #include "core/fpdfapi/parser/cpdf_array.h"
@@ -1823,6 +1824,39 @@
   ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
   ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
 
+  // Reset the form object matrix to identity.
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(form);
+  CPDF_FormObject* pFormObj = pPageObj->AsForm();
+  pFormObj->Transform(pFormObj->form_matrix().GetInverse());
+
+  // FPDFFormObj_GetMatrix() positive testing.
+  static constexpr float kFloats[6] = {1.0, 1.5, 2.0, 2.5, 100.0, 200.0};
+  CFX_Matrix matrix(kFloats);
+  pFormObj->Transform(matrix);
+
+  double matrix_a = 0;
+  double matrix_b = 0;
+  double matrix_c = 0;
+  double matrix_d = 0;
+  double matrix_e = 0;
+  double matrix_f = 0;
+  EXPECT_TRUE(FPDFFormObj_GetMatrix(form, &matrix_a, &matrix_b, &matrix_c,
+                                    &matrix_d, &matrix_e, &matrix_f));
+  EXPECT_DOUBLE_EQ(kFloats[0], matrix_a);
+  EXPECT_DOUBLE_EQ(kFloats[1], matrix_b);
+  EXPECT_DOUBLE_EQ(kFloats[2], matrix_c);
+  EXPECT_DOUBLE_EQ(kFloats[3], matrix_d);
+  EXPECT_DOUBLE_EQ(kFloats[4], matrix_e);
+  EXPECT_DOUBLE_EQ(kFloats[5], matrix_f);
+
+  // FPDFFormObj_GetMatrix() negative testing.
+  EXPECT_FALSE(FPDFFormObj_GetMatrix(nullptr, &matrix_a, &matrix_b, &matrix_c,
+                                     &matrix_d, &matrix_e, &matrix_f));
+  EXPECT_FALSE(FPDFFormObj_GetMatrix(form, nullptr, nullptr, nullptr, nullptr,
+                                     nullptr, nullptr));
+  EXPECT_FALSE(FPDFFormObj_GetMatrix(nullptr, nullptr, nullptr, nullptr,
+                                     nullptr, nullptr, nullptr));
+
   UnloadPage(page);
 }
 
diff --git a/fpdfsdk/fpdf_editpage.cpp b/fpdfsdk/fpdf_editpage.cpp
index 438a062..0ff7a11 100644
--- a/fpdfsdk/fpdf_editpage.cpp
+++ b/fpdfsdk/fpdf_editpage.cpp
@@ -842,3 +842,30 @@
   return FPDFPageObjectFromCPDFPageObject(
       pObjectList->GetPageObjectByIndex(index));
 }
+
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFFormObj_GetMatrix(FPDF_PAGEOBJECT form_object,
+                      double* a,
+                      double* b,
+                      double* c,
+                      double* d,
+                      double* e,
+                      double* f) {
+  if (!form_object || !a || !b || !c || !d || !e || !f)
+    return false;
+
+  auto* pPageObj = CPDFPageObjectFromFPDFPageObject(form_object);
+  CPDF_FormObject* pFormObj = pPageObj->AsForm();
+  if (!pFormObj)
+    return false;
+
+  const CFX_Matrix& matrix = pFormObj->form_matrix();
+  *a = matrix.a;
+  *b = matrix.b;
+  *c = matrix.c;
+  *d = matrix.d;
+  *e = matrix.e;
+  *f = matrix.f;
+
+  return true;
+}
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 7dbe164..d92ae78 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -127,6 +127,7 @@
     // fpdf_edit.h
     CHK(FPDFFont_Close);
     CHK(FPDFFormObj_CountObjects);
+    CHK(FPDFFormObj_GetMatrix);
     CHK(FPDFFormObj_GetObject);
     CHK(FPDFImageObj_GetBitmap);
     CHK(FPDFImageObj_GetImageDataDecoded);
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index 83fedba..577ae7f 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -1313,6 +1313,32 @@
 FPDF_EXPORT FPDF_PAGEOBJECT FPDF_CALLCONV
 FPDFFormObj_GetObject(FPDF_PAGEOBJECT form_object, unsigned long index);
 
+// Experimental API.
+// Get the transform matrix of a form object.
+//
+//   form_object - handle to a form.
+//   a           - pointer to out variable to receive matrix value.
+//   b           - pointer to out variable to receive matrix value.
+//   c           - pointer to out variable to receive matrix value.
+//   d           - pointer to out variable to receive matrix value.
+//   e           - pointer to out variable to receive matrix value.
+//   f           - pointer to out variable to receive matrix value.
+//
+// The matrix is composed as:
+//   |a c e|
+//   |b d f|
+// and used to scale, rotate, shear and translate the form object.
+//
+// Returns TRUE on success.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFFormObj_GetMatrix(FPDF_PAGEOBJECT form_object,
+                      double* a,
+                      double* b,
+                      double* c,
+                      double* d,
+                      double* e,
+                      double* f);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus