Adding FPDFAnnot_GetLink to find links from annotation.

To find the action type, url of a link annotation in the embedder,
embedder needs to have the link annotation in form of FPDF_LINK. This
API takes care of converting FPDF_Annotation to FPDF_Link if the
annotation is a link annotation.

Bug: chromium:994500
Change-Id: I2a0160bd1a9065f8c8757fd316a886a6e76658f0
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/69470
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Badhri Ravikumar <bravi@microsoft.com>
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index 6bb583f..d02b1fc 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -1172,3 +1172,11 @@
 
   return true;
 }
+
+FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot) {
+  if (FPDFAnnot_GetSubtype(annot) != FPDF_ANNOT_LINK)
+    return nullptr;
+
+  return FPDFLinkFromCPDFDictionary(
+      CPDFAnnotContextFromFPDFAnnotation(annot)->GetAnnotDict());
+}
diff --git a/fpdfsdk/fpdf_annot_embeddertest.cpp b/fpdfsdk/fpdf_annot_embeddertest.cpp
index 7acd606..6eccf74 100644
--- a/fpdfsdk/fpdf_annot_embeddertest.cpp
+++ b/fpdfsdk/fpdf_annot_embeddertest.cpp
@@ -2573,3 +2573,45 @@
 
   UnloadPage(page);
 }
+
+TEST_F(FPDFAnnotEmbedderTest, GetLinkFromAnnotation) {
+  ASSERT_TRUE(OpenDocument("annots.pdf"));
+  FPDF_PAGE page = LoadPage(0);
+  ASSERT_TRUE(page);
+  {
+    ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 3));
+    ASSERT_TRUE(annot);
+    EXPECT_EQ(FPDF_ANNOT_LINK, FPDFAnnot_GetSubtype(annot.get()));
+    FPDF_LINK link_annot = FPDFAnnot_GetLink(annot.get());
+    ASSERT_TRUE(link_annot);
+
+    FPDF_ACTION action = FPDFLink_GetAction(link_annot);
+    ASSERT_TRUE(action);
+    EXPECT_EQ(static_cast<unsigned long>(PDFACTION_URI),
+              FPDFAction_GetType(action));
+
+    constexpr char kExpectedResult[] =
+        "https://cs.chromium.org/chromium/src/third_party/pdfium/public/"
+        "fpdf_text.h";
+    constexpr unsigned long kExpectedLength = FX_ArraySize(kExpectedResult);
+    unsigned long bufsize =
+        FPDFAction_GetURIPath(document(), action, nullptr, 0);
+    ASSERT_EQ(kExpectedLength, bufsize);
+
+    char buffer[1024];
+    EXPECT_EQ(bufsize,
+              FPDFAction_GetURIPath(document(), action, buffer, bufsize));
+    EXPECT_STREQ(kExpectedResult, buffer);
+  }
+
+  {
+    ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 4));
+    ASSERT_TRUE(annot);
+    EXPECT_EQ(FPDF_ANNOT_HIGHLIGHT, FPDFAnnot_GetSubtype(annot.get()));
+    EXPECT_FALSE(FPDFAnnot_GetLink(annot.get()));
+  }
+
+  EXPECT_FALSE(FPDFAnnot_GetLink(nullptr));
+
+  UnloadPage(page);
+}
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index 6d9d308..aebffe5 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -55,6 +55,7 @@
     CHK(FPDFAnnot_GetFormFieldName);
     CHK(FPDFAnnot_GetFormFieldType);
     CHK(FPDFAnnot_GetFormFieldValue);
+    CHK(FPDFAnnot_GetLink);
     CHK(FPDFAnnot_GetLinkedAnnot);
     CHK(FPDFAnnot_GetNumberValue);
     CHK(FPDFAnnot_GetObject);
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index 27f5eba..f764ed3 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -729,6 +729,15 @@
                                FPDF_ANNOTATION_SUBTYPE* subtypes,
                                size_t count);
 
+// Experimental API.
+// Gets FPDF_LINK object for |annot|. Intended to use for link annotations.
+//
+//   annot   - handle to an annotation.
+//
+// Returns FPDF_LINK from the FPDF_ANNOTATION and NULL on failure,
+// if the input annot is NULL or input annot's subtype is not link.
+FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFAnnot_GetLink(FPDF_ANNOTATION annot);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus