Add FPDFAnnot_GetLine() API

This is similar to FPDFAnnot_GetVertices() for polygon/polyline
annotations, but this one is for line annotations and the point list has
a fixed size of 2.

Change-Id: If910caaef8c41a9965f2ba47f87c34ea33355f99
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/76730
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/constants/annotation_common.h b/constants/annotation_common.h
index be64206..656842b 100644
--- a/constants/annotation_common.h
+++ b/constants/annotation_common.h
@@ -32,6 +32,9 @@
 // Entries for ink annotations
 constexpr char kInkList[] = "InkList";
 
+// Entries for line annotations
+constexpr char kL[] = "L";
+
 }  // namespace annotation
 }  // namespace pdfium
 
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index 51b4332..85f86e5 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -887,6 +887,32 @@
   return points_len;
 }
 
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot,
+                                                      FS_POINTF* start,
+                                                      FS_POINTF* end) {
+  if (!start || !end)
+    return false;
+
+  FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
+  if (subtype != FPDF_ANNOT_LINE)
+    return false;
+
+  CPDF_Dictionary* annot_dict = GetAnnotDictFromFPDFAnnotation(annot);
+  if (!annot_dict)
+    return false;
+
+  CPDF_Array* line = annot_dict->GetArrayFor(pdfium::annotation::kL);
+  if (!line || line->size() < 4)
+    return false;
+
+  start->x = line->GetNumberAt(0);
+  start->y = line->GetNumberAt(1);
+  end->x = line->GetNumberAt(2);
+  end->y = line->GetNumberAt(3);
+
+  return true;
+}
+
 FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_HasKey(FPDF_ANNOTATION annot,
                                                      FPDF_BYTESTRING key) {
   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
diff --git a/fpdfsdk/fpdf_annot_embeddertest.cpp b/fpdfsdk/fpdf_annot_embeddertest.cpp
index 233f842..8a016b9 100644
--- a/fpdfsdk/fpdf_annot_embeddertest.cpp
+++ b/fpdfsdk/fpdf_annot_embeddertest.cpp
@@ -3377,3 +3377,48 @@
 
   UnloadPage(page);
 }
+
+TEST_F(FPDFAnnotEmbedderTest, LineAnnotation) {
+  ASSERT_TRUE(OpenDocument("line_annot.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+  EXPECT_EQ(2, FPDFPage_GetAnnotCount(page));
+
+  {
+    ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
+    ASSERT_TRUE(annot);
+
+    // FPDFAnnot_GetVertices() positive testing.
+    FS_POINTF start;
+    FS_POINTF end;
+    ASSERT_TRUE(FPDFAnnot_GetLine(annot.get(), &start, &end));
+    EXPECT_FLOAT_EQ(159.0f, start.x);
+    EXPECT_FLOAT_EQ(296.0f, start.y);
+    EXPECT_FLOAT_EQ(472.0f, end.x);
+    EXPECT_FLOAT_EQ(243.42f, end.y);
+
+    // FPDFAnnot_GetVertices() negative testing.
+    EXPECT_FALSE(FPDFAnnot_GetLine(nullptr, nullptr, nullptr));
+    EXPECT_FALSE(FPDFAnnot_GetLine(annot.get(), nullptr, nullptr));
+  }
+
+  {
+    ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 1));
+    ASSERT_TRUE(annot);
+
+    // Too few elements in the line array.
+    FS_POINTF start;
+    FS_POINTF end;
+    EXPECT_FALSE(FPDFAnnot_GetLine(annot.get(), &start, &end));
+  }
+
+  {
+    // Wrong annotation type.
+    ScopedFPDFAnnotation ink_annot(FPDFPage_CreateAnnot(page, FPDF_ANNOT_INK));
+    FS_POINTF start;
+    FS_POINTF end;
+    EXPECT_FALSE(FPDFAnnot_GetLine(ink_annot.get(), &start, &end));
+  }
+
+  UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index b47b04f..ff511f4 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -61,6 +61,7 @@
     CHK(FPDFAnnot_GetFormFieldValue);
     CHK(FPDFAnnot_GetInkListCount);
     CHK(FPDFAnnot_GetInkListPath);
+    CHK(FPDFAnnot_GetLine);
     CHK(FPDFAnnot_GetLink);
     CHK(FPDFAnnot_GetLinkedAnnot);
     CHK(FPDFAnnot_GetNumberValue);
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index d121344..6c8a237 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -440,6 +440,19 @@
                          unsigned long length);
 
 // Experimental API.
+// Get the starting and ending coordinates of a line annotation.
+//
+//   annot  - handle to an annotation, as returned by e.g. FPDFPage_GetAnnot()
+//   start - starting point
+//   end - ending point
+//
+// Returns true if the annotation is of type line, |start| and |end| are not
+// NULL, false otherwise.
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFAnnot_GetLine(FPDF_ANNOTATION annot,
+                                                      FS_POINTF* start,
+                                                      FS_POINTF* end);
+
+// Experimental API.
 // Check if |annot|'s dictionary has |key| as a key.
 //
 //   annot  - handle to an annotation.
diff --git a/testing/resources/line_annot.in b/testing/resources/line_annot.in
new file mode 100644
index 0000000..f8aecf2
--- /dev/null
+++ b/testing/resources/line_annot.in
@@ -0,0 +1,48 @@
+{{header}}
+{{object 1 0}} <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+  /Type /Page
+  /Parent 2 0 R
+  /MediaBox [0 0 612 792]
+  /Annots [
+    4 0 R 5 0 R
+  ]
+  /Tabs /R
+>>
+endobj
+{{object 4 0}} <<
+  /Type /Annot
+  /Subtype /Line
+  /NM (Line-1)
+  /F 4
+  /L [159 296 472 243.42]
+  /P 3 0 R
+  /C [1 0.90196 0]
+  /Rect [293 530 349 542]
+>>
+endobj
+{{object 5 0}} <<
+  /Type /Annot
+  /Subtype /Line
+  /NM (Line-2)
+  /F 4
+  /L [159 296 472]
+  /P 3 0 R
+  /C [1 0.90196 0]
+  /Rect [293 530 349 542]
+>>
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/line_annot.pdf b/testing/resources/line_annot.pdf
new file mode 100644
index 0000000..0511d4c
--- /dev/null
+++ b/testing/resources/line_annot.pdf
@@ -0,0 +1,60 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+  /Type /Catalog
+  /Pages 2 0 R
+>>
+endobj
+2 0 obj <<
+  /Type /Pages
+  /Count 1
+  /Kids [3 0 R]
+>>
+endobj
+3 0 obj <<
+  /Type /Page
+  /Parent 2 0 R
+  /MediaBox [0 0 612 792]
+  /Annots [
+    4 0 R 5 0 R
+  ]
+  /Tabs /R
+>>
+endobj
+4 0 obj <<
+  /Type /Annot
+  /Subtype /Line
+  /NM (Line-1)
+  /F 4
+  /L [159 296 472 243.42]
+  /P 3 0 R
+  /C [1 0.90196 0]
+  /Rect [293 530 349 542]
+>>
+endobj
+5 0 obj <<
+  /Type /Annot
+  /Subtype /Line
+  /NM (Line-2)
+  /F 4
+  /L [159 296 472]
+  /P 3 0 R
+  /C [1 0.90196 0]
+  /Rect [293 530 349 542]
+>>
+endobj
+xref
+0 6
+0000000000 65535 f 
+0000000015 00000 n 
+0000000068 00000 n 
+0000000131 00000 n 
+0000000251 00000 n 
+0000000408 00000 n 
+trailer <<
+  /Root 1 0 R
+  /Size 6
+>>
+startxref
+558
+%%EOF