Add new public APIs to find the z-order for links and widgets.
authorLei Zhang <thestig@chromium.org>
Sat, 15 Aug 2015 02:02:30 +0000 (19:02 -0700)
committerLei Zhang <thestig@chromium.org>
Sat, 15 Aug 2015 02:02:30 +0000 (19:02 -0700)
- Implement FPDFLink_GetLinkZOrderAtPoint().
- Implement FPDFPage_FormFieldZOrderAtPoint().
- Mark FPDPage_HasFormFieldAtPoint() as deprecated.
- Modify CPDF_LinkList and CPDF_InterForm to support new APIs.
- Clean up dead code in CPDF_LinkList and CPDF_InterForm.

BUG=chromium:515837
R=jun_fang@foxitsoftware.com, tsepez@chromium.org

Review URL: https://codereview.chromium.org/1278053004 .

core/include/fpdfdoc/fpdf_doc.h
core/src/fpdfdoc/doc_form.cpp
core/src/fpdfdoc/doc_formcontrol.cpp
core/src/fpdfdoc/doc_link.cpp
fpdfsdk/src/fpdfdoc.cpp
fpdfsdk/src/fpdfformfill.cpp
fpdfsdk/src/fpdfview_c_api_test.c
public/fpdf_doc.h
public/fpdf_formfill.h

index e0c6d33..2d37a48 100644 (file)
@@ -8,6 +8,7 @@
 #define CORE_INCLUDE_FPDFDOC_FPDF_DOC_H_
 
 #include <map>
+#include <vector>
 
 #include "../../../third_party/base/nonstd_unique_ptr.h"
 #include "../fpdfapi/fpdf_parser.h"
@@ -32,7 +33,6 @@ class CPDF_FormNotify;
 class CPDF_IconFit;
 class CPDF_InterForm;
 class CPDF_Link;
-class CPDF_LinkList;
 class CPDF_LWinParam;
 class CPDF_Metadata;
 class CPDF_NumberTree;
@@ -357,29 +357,25 @@ class CPDF_FileSpec {
  protected:
   CPDF_Object* m_pObj;
 };
+
 class CPDF_LinkList {
  public:
-  CPDF_LinkList(CPDF_Document* pDoc) { m_pDocument = pDoc; }
-
+  CPDF_LinkList();
   ~CPDF_LinkList();
 
-  CPDF_Link GetLinkAtPoint(CPDF_Page* pPage, FX_FLOAT pdf_x, FX_FLOAT pdf_y);
-
-  int CountLinks(CPDF_Page* pPage);
-
-  CPDF_Link GetLink(CPDF_Page* pPage, int index);
-
-  CPDF_Document* GetDocument() const { return m_pDocument; }
-
- protected:
-  CPDF_Document* m_pDocument;
+  CPDF_Link GetLinkAtPoint(CPDF_Page* pPage,
+                           FX_FLOAT pdf_x,
+                           FX_FLOAT pdf_y,
+                           int* z_order);
 
-  CFX_MapPtrToPtr m_PageMap;
+ private:
+  const std::vector<CPDF_Dictionary*>* GetPageLinks(CPDF_Page* pPage);
 
-  CFX_PtrArray* GetPageLinks(CPDF_Page* pPage);
+  void LoadPageLinks(CPDF_Page* pPage, std::vector<CPDF_Dictionary*>* pList);
 
-  void LoadPageLinks(CPDF_Page* pPage, CFX_PtrArray* pList);
+  std::map<FX_DWORD, std::vector<CPDF_Dictionary*>> m_PageMap;
 };
+
 class CPDF_Link {
  public:
   CPDF_Link() : m_pDict(nullptr) {}
@@ -642,29 +638,13 @@ class CPDF_InterForm : public CFX_PrivateData {
 
   CPDF_FormField* GetFieldByDict(CPDF_Dictionary* pFieldDict) const;
 
-  FX_DWORD CountControls(CFX_WideString csFieldName = L"");
-
-  CPDF_FormControl* GetControl(FX_DWORD index,
-                               CFX_WideString csFieldName = L"");
-
-  FX_BOOL IsValidFormControl(const void* pControl);
-
-  int CountPageControls(CPDF_Page* pPage) const;
-
-  CPDF_FormControl* GetPageControl(CPDF_Page* pPage, int index) const;
-
   CPDF_FormControl* GetControlAtPoint(CPDF_Page* pPage,
                                       FX_FLOAT pdf_x,
-                                      FX_FLOAT pdf_y) const;
+                                      FX_FLOAT pdf_y,
+                                      int* z_order) const;
 
   CPDF_FormControl* GetControlByDict(CPDF_Dictionary* pWidgetDict) const;
 
-  FX_DWORD CountInternalFields(const CFX_WideString& csFieldName = L"") const;
-
-  CPDF_Dictionary* GetInternalField(
-      FX_DWORD index,
-      const CFX_WideString& csFieldName = L"") const;
-
   CPDF_Document* GetDocument() const { return m_pDocument; }
 
   CPDF_Dictionary* GetFormDict() const { return m_pFormDict; }
@@ -738,14 +718,10 @@ class CPDF_InterForm : public CFX_PrivateData {
 
   FX_BOOL ResetForm(FX_BOOL bNotify = FALSE);
 
-  void ReloadForm();
-
   CPDF_FormNotify* GetFormNotify() const { return m_pFormNotify; }
 
   void SetFormNotify(const CPDF_FormNotify* pNotify);
 
-  int GetPageWithWidget(int iCurPage, FX_BOOL bNext);
-
   FX_BOOL IsUpdated() { return m_bUpdated; }
 
   void ClearUpdatedFlag() { m_bUpdated = FALSE; }
@@ -788,7 +764,7 @@ class CPDF_InterForm : public CFX_PrivateData {
 
   CPDF_Dictionary* m_pFormDict;
 
-  CFX_MapPtrToPtr m_ControlMap;
+  std::map<const CPDF_Dictionary*, CPDF_FormControl*> m_ControlMap;
 
   CFieldTree* m_pFieldTree;
 
@@ -832,8 +808,6 @@ class CPDF_FormField {
 
   FX_DWORD GetFlags() { return m_Flags; }
 
-  CPDF_InterForm* GetInterForm() const { return m_pForm; }
-
   CPDF_Dictionary* GetFieldDict() const { return m_pDict; }
 
   void SetFieldDict(CPDF_Dictionary* pDict) { m_pDict = pDict; }
@@ -1000,7 +974,7 @@ class CPDF_FormControl {
 
   CPDF_Dictionary* GetWidget() const { return m_pWidgetDict; }
 
-  CFX_FloatRect GetRect();
+  CFX_FloatRect GetRect() const;
 
   void DrawControl(CFX_RenderDevice* pDevice,
                    CFX_AffineMatrix* pMatrix,
index a59f35e..970b4b9 100644 (file)
@@ -253,23 +253,19 @@ CPDF_InterForm::CPDF_InterForm(CPDF_Document* pDocument, FX_BOOL bGenerateAP)
     LoadField(pFields->GetDict(i));
   }
 }
+
 CPDF_InterForm::~CPDF_InterForm() {
-  FX_POSITION pos = m_ControlMap.GetStartPosition();
-  while (pos) {
-    void* key;
-    void* value;
-    m_ControlMap.GetNextAssoc(pos, key, value);
-    delete (CPDF_FormControl*)value;
-  }
-  if (m_pFieldTree != NULL) {
+  for (auto it : m_ControlMap)
+    delete it.second;
+  if (m_pFieldTree) {
     int nCount = m_pFieldTree->m_Root.CountFields();
-    for (int i = 0; i < nCount; i++) {
-      CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(i);
-      delete pField;
+    for (int i = 0; i < nCount; ++i) {
+      delete m_pFieldTree->m_Root.GetField(i);
     }
     delete m_pFieldTree;
   }
 }
+
 FX_BOOL CPDF_InterForm::m_bUpdateAP = TRUE;
 FX_BOOL CPDF_InterForm::UpdatingAPEnabled() {
   return m_bUpdateAP;
@@ -788,215 +784,43 @@ CPDF_FormField* CPDF_InterForm::GetFieldByDict(
   CFX_WideString csWName = GetFullName(pFieldDict);
   return m_pFieldTree->GetField(csWName);
 }
-FX_DWORD CPDF_InterForm::CountControls(CFX_WideString csFieldName) {
-  if (csFieldName.IsEmpty()) {
-    return (FX_DWORD)m_ControlMap.GetCount();
-  }
-  CPDF_FormField* pField = m_pFieldTree->GetField(csFieldName);
-  if (pField == NULL) {
-    return 0;
-  }
-  return pField->m_ControlList.GetSize();
-}
-CPDF_FormControl* CPDF_InterForm::GetControl(FX_DWORD index,
-                                             CFX_WideString csFieldName) {
-  CPDF_FormField* pField = m_pFieldTree->GetField(csFieldName);
-  if (pField == NULL) {
-    return NULL;
-  }
-  if (index < (FX_DWORD)pField->m_ControlList.GetSize()) {
-    return (CPDF_FormControl*)pField->m_ControlList.GetAt(index);
-  }
-  return NULL;
-}
-FX_BOOL CPDF_InterForm::IsValidFormControl(const void* pControl) {
-  if (pControl == NULL) {
-    return FALSE;
-  }
-  FX_POSITION pos = m_ControlMap.GetStartPosition();
-  while (pos) {
-    CPDF_Dictionary* pWidgetDict = NULL;
-    void* pFormControl = NULL;
-    m_ControlMap.GetNextAssoc(pos, (void*&)pWidgetDict, pFormControl);
-    if (pControl == pFormControl) {
-      return TRUE;
-    }
-  }
-  return FALSE;
-}
-int CPDF_InterForm::CountPageControls(CPDF_Page* pPage) const {
-  CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArray("Annots");
-  if (pAnnotList == NULL) {
-    return 0;
-  }
-  int count = 0;
-  for (FX_DWORD i = 0; i < pAnnotList->GetCount(); i++) {
-    CPDF_Dictionary* pAnnot = pAnnotList->GetDict(i);
-    if (pAnnot == NULL) {
-      continue;
-    }
-    CPDF_FormControl* pControl;
-    if (!m_ControlMap.Lookup(pAnnot, (void*&)pControl)) {
-      continue;
-    }
-    count++;
-  }
-  return count;
-}
-CPDF_FormControl* CPDF_InterForm::GetPageControl(CPDF_Page* pPage,
-                                                 int index) const {
-  CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArray("Annots");
-  if (pAnnotList == NULL) {
-    return NULL;
-  }
-  int count = 0;
-  for (FX_DWORD i = 0; i < pAnnotList->GetCount(); i++) {
-    CPDF_Dictionary* pAnnot = pAnnotList->GetDict(i);
-    if (pAnnot == NULL) {
-      continue;
-    }
-    CPDF_FormControl* pControl;
-    if (!m_ControlMap.Lookup(pAnnot, (void*&)pControl)) {
-      continue;
-    }
-    if (index == count) {
-      return pControl;
-    }
-    count++;
-  }
-  return NULL;
-}
+
 CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage,
                                                     FX_FLOAT pdf_x,
-                                                    FX_FLOAT pdf_y) const {
+                                                    FX_FLOAT pdf_y,
+                                                    int* z_order) const {
   CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArray("Annots");
-  if (pAnnotList == NULL) {
-    return NULL;
-  }
-  for (FX_DWORD i = pAnnotList->GetCount(); i > 0; i--) {
-    CPDF_Dictionary* pAnnot = pAnnotList->GetDict(i - 1);
-    if (pAnnot == NULL) {
+  if (!pAnnotList)
+    return nullptr;
+
+  for (FX_DWORD i = pAnnotList->GetCount(); i > 0; --i) {
+    FX_DWORD annot_index = i - 1;
+    CPDF_Dictionary* pAnnot = pAnnotList->GetDict(annot_index);
+    if (!pAnnot)
       continue;
-    }
-    CPDF_FormControl* pControl;
-    if (!m_ControlMap.Lookup(pAnnot, (void*&)pControl)) {
+
+    const auto it = m_ControlMap.find(pAnnot);
+    if (it == m_ControlMap.end())
       continue;
-    }
+
+    CPDF_FormControl* pControl = it->second;
     CFX_FloatRect rect = pControl->GetRect();
-    if (rect.Contains(pdf_x, pdf_y)) {
-      return pControl;
-    }
+    if (!rect.Contains(pdf_x, pdf_y))
+      continue;
+
+    if (z_order)
+      *z_order = annot_index;
+    return pControl;
   }
-  return NULL;
+  return nullptr;
 }
+
 CPDF_FormControl* CPDF_InterForm::GetControlByDict(
     CPDF_Dictionary* pWidgetDict) const {
-  CPDF_FormControl* pControl = NULL;
-  m_ControlMap.Lookup(pWidgetDict, (void*&)pControl);
-  return pControl;
-}
-FX_DWORD CPDF_InterForm::CountInternalFields(
-    const CFX_WideString& csFieldName) const {
-  if (!m_pFormDict) {
-    return 0;
-  }
-  CPDF_Array* pArray = m_pFormDict->GetArray("Fields");
-  if (!pArray) {
-    return 0;
-  }
-  if (csFieldName.IsEmpty()) {
-    return pArray->GetCount();
-  }
-  int iLength = csFieldName.GetLength();
-  int iPos = 0;
-  CPDF_Dictionary* pDict = NULL;
-  while (pArray != NULL) {
-    CFX_WideString csSub;
-    if (iPos < iLength && csFieldName[iPos] == L'.') {
-      iPos++;
-    }
-    while (iPos < iLength && csFieldName[iPos] != L'.') {
-      csSub += csFieldName[iPos++];
-    }
-    int iCount = pArray->GetCount();
-    FX_BOOL bFind = FALSE;
-    for (int i = 0; i < iCount; i++) {
-      pDict = pArray->GetDict(i);
-      if (pDict == NULL) {
-        continue;
-      }
-      CFX_WideString csT = pDict->GetUnicodeText("T");
-      if (csT == csSub) {
-        bFind = TRUE;
-        break;
-      }
-    }
-    if (!bFind) {
-      return 0;
-    }
-    if (iPos >= iLength) {
-      break;
-    }
-    pArray = pDict->GetArray("Kids");
-  }
-  if (!pDict) {
-    return 0;
-  }
-  pArray = pDict->GetArray("Kids");
-  return pArray ? pArray->GetCount() : 1;
+  const auto it = m_ControlMap.find(pWidgetDict);
+  return it != m_ControlMap.end() ? it->second : nullptr;
 }
 
-CPDF_Dictionary* CPDF_InterForm::GetInternalField(
-    FX_DWORD index,
-    const CFX_WideString& csFieldName) const {
-  if (!m_pFormDict) {
-    return nullptr;
-  }
-  CPDF_Array* pArray = m_pFormDict->GetArray("Fields");
-  if (!pArray) {
-    return nullptr;
-  }
-  if (csFieldName.IsEmpty()) {
-    return pArray->GetDict(index);
-  }
-  int iLength = csFieldName.GetLength();
-  int iPos = 0;
-  CPDF_Dictionary* pDict = NULL;
-  while (pArray != NULL) {
-    CFX_WideString csSub;
-    if (iPos < iLength && csFieldName[iPos] == L'.') {
-      iPos++;
-    }
-    while (iPos < iLength && csFieldName[iPos] != L'.') {
-      csSub += csFieldName[iPos++];
-    }
-    int iCount = pArray->GetCount();
-    FX_BOOL bFind = FALSE;
-    for (int i = 0; i < iCount; i++) {
-      pDict = pArray->GetDict(i);
-      if (pDict == NULL) {
-        continue;
-      }
-      CFX_WideString csT = pDict->GetUnicodeText("T");
-      if (csT == csSub) {
-        bFind = TRUE;
-        break;
-      }
-    }
-    if (!bFind) {
-      return NULL;
-    }
-    if (iPos >= iLength) {
-      break;
-    }
-    pArray = pDict->GetArray("Kids");
-  }
-  if (!pDict) {
-    return nullptr;
-  }
-  pArray = pDict->GetArray("Kids");
-  return pArray ? pArray->GetDict(index) : pDict;
-}
 FX_BOOL CPDF_InterForm::NeedConstructAP() {
   if (m_pFormDict == NULL) {
     return FALSE;
@@ -1172,33 +996,6 @@ FX_BOOL CPDF_InterForm::ResetForm(FX_BOOL bNotify) {
   }
   return TRUE;
 }
-void CPDF_InterForm::ReloadForm() {
-  FX_POSITION pos = m_ControlMap.GetStartPosition();
-  while (pos) {
-    CPDF_Dictionary* pWidgetDict;
-    CPDF_FormControl* pControl;
-    m_ControlMap.GetNextAssoc(pos, (void*&)pWidgetDict, (void*&)pControl);
-    delete pControl;
-  }
-  m_ControlMap.RemoveAll();
-  int nCount = m_pFieldTree->m_Root.CountFields();
-  for (int k = 0; k < nCount; k++) {
-    CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(k);
-    delete pField;
-  }
-  m_pFieldTree->RemoveAll();
-  if (m_pFormDict == NULL) {
-    return;
-  }
-  CPDF_Array* pFields = m_pFormDict->GetArray("Fields");
-  if (pFields == NULL) {
-    return;
-  }
-  int iCount = pFields->GetCount();
-  for (int i = 0; i < iCount; i++) {
-    LoadField(pFields->GetDict(i));
-  }
-}
 void CPDF_InterForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) {
   if (nLevel > nMaxRecursion) {
     return;
@@ -1320,13 +1117,13 @@ CPDF_FormField* CPDF_InterForm::AddTerminalField(
 CPDF_FormControl* CPDF_InterForm::AddControl(
     const CPDF_FormField* pField,
     const CPDF_Dictionary* pWidgetDict) {
-  void* rValue = NULL;
-  if (m_ControlMap.Lookup((CPDF_Dictionary*)pWidgetDict, rValue)) {
-    return (CPDF_FormControl*)rValue;
-  }
+  const auto it = m_ControlMap.find(pWidgetDict);
+  if (it != m_ControlMap.end())
+    return it->second;
+
   CPDF_FormControl* pControl = new CPDF_FormControl(
       (CPDF_FormField*)pField, (CPDF_Dictionary*)pWidgetDict);
-  m_ControlMap.SetAt((CPDF_Dictionary*)pWidgetDict, pControl);
+  m_ControlMap[pWidgetDict] = pControl;
   ((CPDF_FormField*)pField)->m_ControlList.Add(pControl);
   return pControl;
 }
@@ -1581,45 +1378,3 @@ FX_BOOL CPDF_InterForm::ImportFromFDF(const CFDF_Document* pFDF,
 void CPDF_InterForm::SetFormNotify(const CPDF_FormNotify* pNotify) {
   m_pFormNotify = (CPDF_FormNotify*)pNotify;
 }
-int CPDF_InterForm::GetPageWithWidget(int iCurPage, FX_BOOL bNext) {
-  if (iCurPage < 0) {
-    return -1;
-  }
-  int iPageCount = m_pDocument->GetPageCount();
-  if (iCurPage >= iPageCount) {
-    return -1;
-  }
-  int iNewPage = iCurPage;
-  do {
-    iNewPage += bNext ? 1 : -1;
-    if (iNewPage >= iPageCount) {
-      iNewPage = 0;
-    }
-    if (iNewPage < 0) {
-      iNewPage = iPageCount - 1;
-    }
-    if (iNewPage == iCurPage) {
-      break;
-    }
-    CPDF_Dictionary* pPageDict = m_pDocument->GetPage(iNewPage);
-    if (pPageDict == NULL) {
-      continue;
-    }
-    CPDF_Array* pAnnots = pPageDict->GetArray("Annots");
-    if (pAnnots == NULL) {
-      continue;
-    }
-    FX_DWORD dwCount = pAnnots->GetCount();
-    for (FX_DWORD i = 0; i < dwCount; i++) {
-      CPDF_Object* pAnnotDict = pAnnots->GetElementValue(i);
-      if (pAnnotDict == NULL) {
-        continue;
-      }
-      CPDF_FormControl* pControl = NULL;
-      if (m_ControlMap.Lookup(pAnnotDict, (void*&)pControl)) {
-        return iNewPage;
-      }
-    }
-  } while (TRUE);
-  return -1;
-}
index db7cf37..410f9a1 100644 (file)
@@ -11,7 +11,7 @@ CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField,
   m_pWidgetDict = pWidgetDict;
   m_pForm = m_pField->m_pForm;
 }
-CFX_FloatRect CPDF_FormControl::GetRect() {
+CFX_FloatRect CPDF_FormControl::GetRect() const {
   return m_pWidgetDict->GetRect("Rect");
 }
 CFX_ByteString CPDF_FormControl::GetOnStateName() {
index 15bd14c..fbf18f9 100644 (file)
@@ -6,75 +6,68 @@
 
 #include "../../include/fpdfdoc/fpdf_doc.h"
 
+CPDF_LinkList::CPDF_LinkList() {
+}
+
 CPDF_LinkList::~CPDF_LinkList() {
-  FX_POSITION pos = m_PageMap.GetStartPosition();
-  while (pos) {
-    void* key;
-    void* value;
-    m_PageMap.GetNextAssoc(pos, key, value);
-    delete (CFX_PtrArray*)value;
-  }
 }
-CFX_PtrArray* CPDF_LinkList::GetPageLinks(CPDF_Page* pPage) {
+
+const std::vector<CPDF_Dictionary*>* CPDF_LinkList::GetPageLinks(
+    CPDF_Page* pPage) {
   FX_DWORD objnum = pPage->m_pFormDict->GetObjNum();
-  if (objnum == 0) {
-    return NULL;
-  }
-  CFX_PtrArray* pPageLinkList = NULL;
-  if (!m_PageMap.Lookup((void*)(uintptr_t)objnum, (void*&)pPageLinkList)) {
-    pPageLinkList = new CFX_PtrArray;
-    m_PageMap.SetAt((void*)(uintptr_t)objnum, pPageLinkList);
-    LoadPageLinks(pPage, pPageLinkList);
-  }
-  return pPageLinkList;
-}
-int CPDF_LinkList::CountLinks(CPDF_Page* pPage) {
-  CFX_PtrArray* pPageLinkList = GetPageLinks(pPage);
-  if (pPageLinkList == NULL) {
-    return 0;
-  }
-  return pPageLinkList->GetSize();
-}
-CPDF_Link CPDF_LinkList::GetLink(CPDF_Page* pPage, int index) {
-  CFX_PtrArray* pPageLinkList = GetPageLinks(pPage);
-  if (!pPageLinkList) {
-    return CPDF_Link();
-  }
-  return CPDF_Link((CPDF_Dictionary*)pPageLinkList->GetAt(index));
+  if (objnum == 0)
+    return nullptr;
+
+  auto it = m_PageMap.find(objnum);
+  if (it != m_PageMap.end())
+    return &it->second;
+
+  // std::map::operator[] forces the creation of a map entry.
+  std::vector<CPDF_Dictionary*>& page_link_list = m_PageMap[objnum];
+  LoadPageLinks(pPage, &page_link_list);
+  return &page_link_list;
 }
+
 CPDF_Link CPDF_LinkList::GetLinkAtPoint(CPDF_Page* pPage,
                                         FX_FLOAT pdf_x,
-                                        FX_FLOAT pdf_y) {
-  CFX_PtrArray* pPageLinkList = GetPageLinks(pPage);
-  if (!pPageLinkList) {
+                                        FX_FLOAT pdf_y,
+                                        int* z_order) {
+  const std::vector<CPDF_Dictionary*>* pPageLinkList = GetPageLinks(pPage);
+  if (!pPageLinkList)
     return CPDF_Link();
-  }
-  int size = pPageLinkList->GetSize();
-  for (int i = size - 1; i >= 0; --i) {
-    CPDF_Link link((CPDF_Dictionary*)pPageLinkList->GetAt(i));
+
+  for (size_t i = pPageLinkList->size(); i > 0; --i) {
+    size_t annot_index = i - 1;
+    CPDF_Dictionary* pAnnot = (*pPageLinkList)[annot_index];
+    if (!pAnnot)
+      continue;
+
+    CPDF_Link link(pAnnot);
     CPDF_Rect rect = link.GetRect();
-    if (rect.Contains(pdf_x, pdf_y)) {
-      return link;
-    }
+    if (!rect.Contains(pdf_x, pdf_y))
+      continue;
+
+    if (z_order)
+      *z_order = annot_index;
+    return link;
   }
   return CPDF_Link();
 }
-void CPDF_LinkList::LoadPageLinks(CPDF_Page* pPage, CFX_PtrArray* pList) {
+
+void CPDF_LinkList::LoadPageLinks(CPDF_Page* pPage,
+                                  std::vector<CPDF_Dictionary*>* pList) {
   CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArray("Annots");
-  if (pAnnotList == NULL) {
+  if (!pAnnotList)
     return;
-  }
-  for (FX_DWORD i = 0; i < pAnnotList->GetCount(); i++) {
+
+  for (FX_DWORD i = 0; i < pAnnotList->GetCount(); ++i) {
     CPDF_Dictionary* pAnnot = pAnnotList->GetDict(i);
-    if (pAnnot == NULL) {
-      continue;
-    }
-    if (pAnnot->GetString("Subtype") != "Link") {
-      continue;
-    }
-    pList->Add(pAnnot);
+    bool add_link = (pAnnot && pAnnot->GetString("Subtype") == "Link");
+    // Add non-links as nullptrs to preserve z-order.
+    pList->push_back(add_link ? pAnnot : nullptr);
   }
 }
+
 CPDF_Rect CPDF_Link::GetRect() {
   return m_pDict->GetRect("Rect");
 }
index bcd401b..5d2469c 100644 (file)
@@ -7,11 +7,13 @@
 #include "../include/fsdk_define.h"
 #include "../../public/fpdf_doc.h"
 
-static int THISMODULE = 0;
+namespace {
 
-static CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree,
-                                  CPDF_Bookmark bookmark,
-                                  const CFX_WideString& title) {
+int THISMODULE = 0;
+
+CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree,
+                           CPDF_Bookmark bookmark,
+                           const CFX_WideString& title) {
   if (bookmark && bookmark.GetTitle().CompareNoCase(title.c_str()) == 0) {
     // First check this item
     return bookmark;
@@ -28,6 +30,26 @@ static CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree,
   return CPDF_Bookmark();
 }
 
+void ReleaseLinkList(void* data) {
+  delete (CPDF_LinkList*)data;
+}
+
+CPDF_LinkList* GetLinkList(CPDF_Page* page) {
+  if (!page)
+    return nullptr;
+
+  // Link list is stored with the document
+  CPDF_Document* pDoc = page->m_pDocument;
+  CPDF_LinkList* pLinkList = (CPDF_LinkList*)pDoc->GetPrivateData(&THISMODULE);
+  if (!pLinkList) {
+    pLinkList = new CPDF_LinkList;
+    pDoc->SetPrivateData(&THISMODULE, pLinkList, ReleaseLinkList);
+  }
+  return pLinkList;
+}
+
+}  // namespace
+
 DLLEXPORT FPDF_BOOKMARK STDCALL
 FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) {
   if (!document)
@@ -161,24 +183,27 @@ DLLEXPORT unsigned long STDCALL FPDFDest_GetPageIndex(FPDF_DOCUMENT document,
   return dest.GetPageIndex(pDoc);
 }
 
-static void ReleaseLinkList(void* data) {
-  delete (CPDF_LinkList*)data;
+DLLEXPORT FPDF_LINK STDCALL
+FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y) {
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_LinkList* pLinkList = GetLinkList(pPage);
+  if (!pLinkList)
+    return nullptr;
+
+  return pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y, nullptr)
+      .GetDict();
 }
 
-DLLEXPORT FPDF_LINK STDCALL FPDFLink_GetLinkAtPoint(FPDF_PAGE page,
-                                                    double x,
-                                                    double y) {
-  if (!page)
-    return NULL;
+DLLEXPORT int STDCALL
+FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y) {
   CPDF_Page* pPage = (CPDF_Page*)page;
-  // Link list is stored with the document
-  CPDF_Document* pDoc = pPage->m_pDocument;
-  CPDF_LinkList* pLinkList = (CPDF_LinkList*)pDoc->GetPrivateData(&THISMODULE);
-  if (!pLinkList) {
-    pLinkList = new CPDF_LinkList(pDoc);
-    pDoc->SetPrivateData(&THISMODULE, pLinkList, ReleaseLinkList);
-  }
-  return pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y).GetDict();
+  CPDF_LinkList* pLinkList = GetLinkList(pPage);
+  if (!pLinkList)
+    return -1;
+
+  int z_order = -1;
+  pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y, &z_order);
+  return z_order;
 }
 
 DLLEXPORT FPDF_DEST STDCALL FPDFLink_GetDest(FPDF_DOCUMENT document,
index 170ae15..272e781 100644 (file)
@@ -34,18 +34,17 @@ CPDFSDK_PageView* FormHandleToPageView(FPDF_FORMHANDLE hHandle,
 
 }  // namespace
 
-DLLEXPORT int STDCALL FPDPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
-                                                  FPDF_PAGE page,
-                                                  double page_x,
-                                                  double page_y) {
+DLLEXPORT int STDCALL FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
+                                                   FPDF_PAGE page,
+                                                   double page_x,
+                                                   double page_y) {
   if (!page || !hHandle)
     return -1;
-  CPDF_Page* pPage = (CPDF_Page*)page;
 
-  nonstd::unique_ptr<CPDF_InterForm> pInterForm(
-      new CPDF_InterForm(pPage->m_pDocument, FALSE));
-  CPDF_FormControl* pFormCtrl =
-      pInterForm->GetControlAtPoint(pPage, (FX_FLOAT)page_x, (FX_FLOAT)page_y);
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_InterForm interform(pPage->m_pDocument, FALSE);
+  CPDF_FormControl* pFormCtrl = interform.GetControlAtPoint(
+      pPage, (FX_FLOAT)page_x, (FX_FLOAT)page_y, nullptr);
   if (!pFormCtrl)
     return -1;
 
@@ -56,6 +55,28 @@ DLLEXPORT int STDCALL FPDPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
   return pFormField->GetFieldType();
 }
 
+DLLEXPORT int STDCALL FPDPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
+                                                  FPDF_PAGE page,
+                                                  double page_x,
+                                                  double page_y) {
+  return FPDFPage_HasFormFieldAtPoint(hHandle, page, page_x, page_y);
+}
+
+DLLEXPORT int STDCALL FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,
+                                                      FPDF_PAGE page,
+                                                      double page_x,
+                                                      double page_y) {
+  if (!page || !hHandle)
+    return -1;
+
+  CPDF_Page* pPage = (CPDF_Page*)page;
+  CPDF_InterForm interform(pPage->m_pDocument, FALSE);
+  int z_order = -1;
+  (void)interform.GetControlAtPoint(pPage, (FX_FLOAT)page_x, (FX_FLOAT)page_y,
+                                    &z_order);
+  return z_order;
+}
+
 DLLEXPORT FPDF_FORMHANDLE STDCALL
 FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document,
                                 FPDF_FORMFILLINFO* formInfo) {
index a17f7b6..9bd2747 100644 (file)
@@ -54,6 +54,7 @@ int CheckPDFiumCApi() {
     CHK(FPDFAction_GetURIPath);
     CHK(FPDFDest_GetPageIndex);
     CHK(FPDFLink_GetLinkAtPoint);
+    CHK(FPDFLink_GetLinkZOrderAtPoint);
     CHK(FPDFLink_GetDest);
     CHK(FPDFLink_GetAction);
     CHK(FPDFLink_Enumerate);
@@ -106,7 +107,9 @@ int CheckPDFiumCApi() {
     CHK(FORM_OnKeyUp);
     CHK(FORM_OnChar);
     CHK(FORM_ForceToKillFocus);
-    CHK(FPDPage_HasFormFieldAtPoint);
+    CHK(FPDFPage_HasFormFieldAtPoint);
+    CHK(FPDPage_HasFormFieldAtPoint);  // DEPRECATED. Remove in the future.
+    CHK(FPDFPage_FormFieldZOrderAtPoint);
     CHK(FPDF_SetFormFieldHighlightColor);
     CHK(FPDF_SetFormFieldHighlightAlpha);
     CHK(FPDF_RemoveFormFieldHighlight);
index ed05aed..e537d2b 100644 (file)
@@ -177,24 +177,43 @@ DLLEXPORT unsigned long STDCALL FPDFDest_GetPageIndex(FPDF_DOCUMENT document,
                                                       FPDF_DEST dest);
 
 // Function: FPDFLink_GetLinkAtPoint
-//          Find a link at specified point on a document page.
+//     Find a link at specified point on a document page.
 // Parameters:
-//          page        -   Handle to the document page.
-//          x           -   The x coordinate of the point, specified in page
-//          coordinate system.
-//          y           -   The y coordinate of the point, specified in page
-//          coordinate system.
+//     page        -   Handle to the document page.
+//     x           -   The x coordinate of the point, specified in page
+//                     coordinate system.
+//     y           -   The y coordinate of the point, specified in page
+//                     coordinate system.
 // Return value:
-//          Handle to the link. NULL if no link found at that point.
+//     Handle to the link. NULL if no link found at that point.
 // Comments:
-//          The point coordinates are specified in page coordinate system. You
-//          can convert coordinates
-//          from screen system to page system using FPDF_DeviceToPage functions.
+//     The point coordinates are specified in page coordinate system. You can
+//     convert coordinates from screen system to page system using
+//     FPDF_DeviceToPage().
 //
 DLLEXPORT FPDF_LINK STDCALL FPDFLink_GetLinkAtPoint(FPDF_PAGE page,
                                                     double x,
                                                     double y);
 
+// Function: FPDFLink_GetLinkZOrderAtPoint
+//     Find the z-order of a link at specified point on a document page.
+// Parameters:
+//     page        -   Handle to the document page.
+//     x           -   The x coordinate of the point, specified in page
+//                     coordinate system.
+//     y           -   The y coordinate of the point, specified in page
+//                     coordinate system.
+// Return value:
+//     Z-order of the link, or -1 if no link found at that point.
+//     Higher numbers are closer to the front.
+// Comments:
+//     The point coordinates are specified in page coordinate system. You can
+//     convert coordinates from screen system to page system using
+//     FPDF_DeviceToPage().
+//
+DLLEXPORT int STDCALL
+FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, double x, double y);
+
 // Function: FPDFLink_GetDest
 //          Get destination info of a link.
 // Parameters:
index 625a2b6..128c7ec 100644 (file)
@@ -962,17 +962,26 @@ DLLEXPORT FPDF_BOOL STDCALL FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle);
 #define FPDF_FORMFIELD_TEXTFIELD 6    // text field type.
 
 /**
- * Function: FPDPage_HasFormFieldAtPoint
- *          Check the form filed position by point.
+ * Function: FPDFPage_HasFormFieldAtPoint
+ *     Get the form field type by point.
  * Parameters:
- *          hHandle     -   Handle to the form fill module. Returned by
- *FPDFDOC_InitFormFillEnvironment.
- *          page        -   Handle to the page. Returned by FPDF_LoadPage
- *function.
- *          page_x      -   X position in PDF "user space".
- *          page_y      -   Y position in PDF "user space".
+ *     hHandle     -   Handle to the form fill module. Returned by
+ *                     FPDFDOC_InitFormFillEnvironment().
+ *     page        -   Handle to the page. Returned by FPDF_LoadPage().
+ *     page_x      -   X position in PDF "user space".
+ *     page_y      -   Y position in PDF "user space".
  * Return Value:
- *          Return the type of the formfiled; -1 indicates no fields.
+ *     Return the type of the form field; -1 indicates no field.
+ *     See field types above.
+ **/
+DLLEXPORT int STDCALL FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
+                                                   FPDF_PAGE page,
+                                                   double page_x,
+                                                   double page_y);
+
+/**
+ * Function: FPDPage_HasFormFieldAtPoint
+ *     DEPRECATED. Please use FPDFPage_HasFormFieldAtPoint.
  **/
 DLLEXPORT int STDCALL FPDPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
                                                   FPDF_PAGE page,
@@ -980,6 +989,24 @@ DLLEXPORT int STDCALL FPDPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle,
                                                   double page_y);
 
 /**
+ * Function: FPDFPage_FormFieldZOrderAtPoint
+ *     Get the form field z-order by point.
+ * Parameters:
+ *     hHandle     -   Handle to the form fill module. Returned by
+ *                     FPDFDOC_InitFormFillEnvironment().
+ *     page        -   Handle to the page. Returned by FPDF_LoadPage().
+ *     page_x      -   X position in PDF "user space".
+ *     page_y      -   Y position in PDF "user space".
+ * Return Value:
+ *     Return the z-order of the form field; -1 indicates no field.
+ *     Higher numbers are closer to the front.
+ **/
+DLLEXPORT int STDCALL FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle,
+                                                      FPDF_PAGE page,
+                                                      double page_x,
+                                                      double page_y);
+
+/**
  * Function: FPDF_SetFormFieldHighlightColor
  *          Set the highlight color of specified or all the form fields in the
  *document.