XFA: merge patch from CL 828203002, clean up bookmark codes
[pdfium.git] / fpdfsdk / src / fpdfdoc.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4  
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../include/fsdk_define.h"
8 #include "../include/fpdfdoc.h"
9 #include "../include/fpdfxfa/fpdfxfa_doc.h"
10 #include "../include/fpdfxfa/fpdfxfa_page.h"
11
12 static int THISMODULE = 0;
13
14 static CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree, CPDF_Bookmark bookmark, const CFX_WideString& title)
15 {
16         if (bookmark && bookmark.GetTitle().CompareNoCase(title) == 0) {
17                 // First check this item
18                 return bookmark;
19         }
20         // go into children items
21         CPDF_Bookmark child = tree.GetFirstChild(bookmark);
22         while (child) {
23                 // check if this item
24                 CPDF_Bookmark found = FindBookmark(tree, child, title);
25                 if (found)
26                         return found;
27                 child = tree.GetNextSibling(child);
28         }
29         return CPDF_Bookmark();
30 }
31
32 DLLEXPORT FPDF_BOOKMARK STDCALL FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title)
33 {
34         if (!document)
35                 return NULL;
36         if (!title || title[0] == 0)
37                 return NULL;
38         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
39         CPDF_BookmarkTree tree(pDoc);
40         FX_STRSIZE len = CFX_WideString::WStringLength(title);
41         CFX_WideString encodedTitle = CFX_WideString::FromUTF16LE(title, len);
42         return FindBookmark(tree, CPDF_Bookmark(), encodedTitle).GetDict();
43 }
44
45 DLLEXPORT FPDF_DEST STDCALL FPDFBookmark_GetDest(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict)
46 {
47         if (!document)
48                 return NULL;
49         if (!pDict)
50                 return NULL;
51         CPDF_Bookmark bookmark((CPDF_Dictionary*)pDict);
52         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
53         CPDF_Dest dest = bookmark.GetDest(pDoc);
54         if (dest)
55                 return dest;
56         // If this bookmark is not directly associated with a dest, we try to get action
57         CPDF_Action action = bookmark.GetAction();
58         if (!action)
59                 return NULL;
60         return action.GetDest(pDoc);
61 }
62
63 DLLEXPORT FPDF_ACTION STDCALL FPDFBookmark_GetAction(FPDF_BOOKMARK pDict)
64 {
65         if (!pDict)
66                 return NULL;
67         CPDF_Bookmark bookmark((CPDF_Dictionary*)pDict);
68         return bookmark.GetAction();
69 }
70
71 DLLEXPORT unsigned long STDCALL FPDFAction_GetType(FPDF_ACTION pDict)
72 {
73         if (!pDict)
74                 return 0;
75         CPDF_Action action = (CPDF_Dictionary*)pDict;
76         CPDF_Action::ActionType type = action.GetType();
77         switch (type) {
78                 case CPDF_Action::GoTo:
79                         return PDFACTION_GOTO;
80                 case CPDF_Action::GoToR:
81                         return PDFACTION_REMOTEGOTO;
82                 case CPDF_Action::URI:
83                         return PDFACTION_URI;
84                 case CPDF_Action::Launch:
85                         return PDFACTION_LAUNCH;
86                 default:
87                         return PDFACTION_UNSUPPORTED;
88         }
89         return PDFACTION_UNSUPPORTED;
90 }
91
92 DLLEXPORT FPDF_DEST STDCALL FPDFAction_GetDest(FPDF_DOCUMENT document, FPDF_ACTION pDict)
93 {
94         if (!document)
95                 return NULL;
96         if (!pDict)
97                 return NULL;
98         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
99         CPDF_Action action = (CPDF_Dictionary*)pDict;
100         return action.GetDest(pDoc);
101 }
102
103 DLLEXPORT unsigned long STDCALL FPDFAction_GetURIPath(FPDF_DOCUMENT document, FPDF_ACTION pDict,
104                                                                                           void* buffer, unsigned long buflen)
105 {
106         if (!document)
107                 return 0;
108         if (!pDict)
109                 return 0;
110         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
111         CPDF_Action action = (CPDF_Dictionary*)pDict;
112         CFX_ByteString path = action.GetURI(pDoc);
113         unsigned long len = path.GetLength() + 1;
114         if (buffer != NULL && buflen >= len)
115                 FXSYS_memcpy(buffer, path.c_str(), len);
116         return len;
117 }
118
119 DLLEXPORT unsigned long STDCALL FPDFDest_GetPageIndex(FPDF_DOCUMENT document, FPDF_DEST pDict)
120 {
121         if (!document)
122                 return 0;
123         if (!pDict)
124                 return 0;
125         CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
126         CPDF_Dest dest = (CPDF_Array*)pDict;
127         return dest.GetPageIndex(pDoc);
128 }
129
130 static void ReleaseLinkList(FX_LPVOID data)
131 {
132         delete (CPDF_LinkList*)data;
133 }
134
135 DLLEXPORT FPDF_LINK STDCALL FPDFLink_GetLinkAtPoint(FPDF_PAGE page, double x, double y)
136 {
137         if (!page)
138                 return NULL;
139     CPDF_Page* pPage = ((CPDFXFA_Page*)page)->GetPDFPage();
140         // Link list is stored with the document
141         CPDF_Document* pDoc = pPage->m_pDocument;
142         CPDF_LinkList* pLinkList = (CPDF_LinkList*)pDoc->GetPrivateData(&THISMODULE);
143         if (!pLinkList) {
144                 pLinkList = FX_NEW CPDF_LinkList(pDoc);
145                 pDoc->SetPrivateData(&THISMODULE, pLinkList, ReleaseLinkList);
146         }
147         return pLinkList->GetLinkAtPoint(pPage, (FX_FLOAT)x, (FX_FLOAT)y);
148 }
149
150 DLLEXPORT FPDF_DEST STDCALL FPDFLink_GetDest(FPDF_DOCUMENT document, FPDF_LINK pDict)
151 {
152         if (!document)
153                 return NULL;
154     CPDF_Document* pDoc = ((CPDFXFA_Document*)document)->GetPDFDoc();
155         if (!pDict)
156                 return NULL;
157         CPDF_Link link = (CPDF_Dictionary*)pDict;
158
159         FPDF_DEST dest = link.GetDest(pDoc);
160         if (dest)
161                 return dest;
162         // If this link is not directly associated with a dest, we try to get action
163         CPDF_Action action = link.GetAction();
164         if (!action)
165                 return NULL;
166         return action.GetDest(pDoc);
167 }
168
169 DLLEXPORT FPDF_ACTION STDCALL FPDFLink_GetAction(FPDF_LINK pDict)
170 {
171         if (!pDict)
172                 return NULL;
173         CPDF_Link link = (CPDF_Dictionary*)pDict;
174         return link.GetAction();
175 }
176
177 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_Enumerate(FPDF_PAGE page, int* startPos, FPDF_LINK* linkAnnot)
178 {
179         if(!page || !startPos || !linkAnnot)
180                 return FALSE;
181     CPDF_Page* pPage = ((CPDFXFA_Page*)page)->GetPDFPage();
182         if(!pPage->m_pFormDict)
183                 return FALSE;
184         CPDF_Array* pAnnots = pPage->m_pFormDict->GetArray("Annots");
185         if(!pAnnots)
186                 return FALSE;
187         for (int i = *startPos; i < (int)pAnnots->GetCount(); i++) {
188                 CPDF_Dictionary* pDict = (CPDF_Dictionary*)pAnnots->GetElementValue(i);
189                 if (!pDict || pDict->GetType() != PDFOBJ_DICTIONARY)
190                         continue;
191                 if(pDict->GetString(FX_BSTRC("Subtype")).Equal(FX_BSTRC("Link"))) {
192                         *startPos = i + 1;
193                         *linkAnnot = (FPDF_LINK)pDict; 
194                         return TRUE;
195                 }
196         }
197         return FALSE;
198 }
199
200 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetAnnotRect(FPDF_LINK linkAnnot, FS_RECTF* rect)
201 {
202         if(!linkAnnot || !rect)
203                 return FALSE;
204         CPDF_Dictionary* pAnnotDict = (CPDF_Dictionary*)linkAnnot;
205         CPDF_Rect rt = pAnnotDict->GetRect(FX_BSTRC("Rect"));
206         rect->left = rt.left;
207         rect->bottom = rt.bottom;
208         rect->right = rt.right;
209         rect->top = rt.top;
210         return TRUE;
211 }
212
213 DLLEXPORT int STDCALL FPDFLink_CountQuadPoints(FPDF_LINK linkAnnot)
214 {
215         if(!linkAnnot)
216                 return 0;
217         CPDF_Dictionary* pAnnotDict = (CPDF_Dictionary*)linkAnnot;
218         CPDF_Array* pArray = pAnnotDict->GetArray(FX_BSTRC("QuadPoints"));
219         if (!pArray)
220                 return 0;
221         else
222                 return pArray->GetCount() / 8;
223 }
224
225 DLLEXPORT FPDF_BOOL STDCALL FPDFLink_GetQuadPoints(FPDF_LINK linkAnnot, int quadIndex, FS_QUADPOINTSF* quadPoints)
226 {
227         if(!linkAnnot || !quadPoints)
228                 return FALSE;
229         CPDF_Dictionary* pAnnotDict = (CPDF_Dictionary*)linkAnnot;
230         CPDF_Array* pArray = pAnnotDict->GetArray(FX_BSTRC("QuadPoints"));
231         if (pArray) {
232                 if (quadIndex < 0 || quadIndex >= (int)pArray->GetCount()/8 || ((quadIndex*8+7) >= (int)pArray->GetCount()))
233                         return FALSE;
234                 quadPoints->x1 = pArray->GetNumber(quadIndex*8);
235                 quadPoints->y1 = pArray->GetNumber(quadIndex*8+1);
236                 quadPoints->x2 = pArray->GetNumber(quadIndex*8+2);
237                 quadPoints->y2 = pArray->GetNumber(quadIndex*8+3);
238                 quadPoints->x3 = pArray->GetNumber(quadIndex*8+4);
239                 quadPoints->y3 = pArray->GetNumber(quadIndex*8+5);
240                 quadPoints->x4 = pArray->GetNumber(quadIndex*8+6);
241                 quadPoints->y4 = pArray->GetNumber(quadIndex*8+7);
242                 return TRUE;
243         } 
244         return FALSE;
245 }
246
247 DLLEXPORT unsigned long STDCALL FPDF_GetMetaText(FPDF_DOCUMENT doc, FPDF_BYTESTRING tag,
248                                                                                                  void* buffer, unsigned long buflen)
249 {
250         if (!doc || !tag)
251                 return 0;
252     CPDF_Document* pDoc = ((CPDFXFA_Document*)doc)->GetPDFDoc();
253         // Get info dictionary
254         CPDF_Dictionary* pInfo = pDoc->GetInfo();
255         if (!pInfo)
256                 return 0;
257         CFX_WideString text = pInfo->GetUnicodeText(tag);
258         // Use UTF-16LE encoding
259         CFX_ByteString encodedText = text.UTF16LE_Encode();
260         unsigned long len = encodedText.GetLength();
261         if (buffer && buflen >= len + 2) {
262                 FXSYS_memcpy(buffer, encodedText.c_str(), len);
263                 // use double zero as trailer
264                 ((FX_BYTE*)buffer)[len] = 0;
265                 ((FX_BYTE*)buffer)[len + 1] = 0;
266         }
267         return len+2;
268 }