clang-format all pdfium code.
[pdfium.git] / fpdfsdk / src / javascript / Document.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/javascript/JavaScript.h"
8 #include "../../include/javascript/IJavaScript.h"
9 #include "../../include/javascript/JS_Define.h"
10 #include "../../include/javascript/JS_Object.h"
11 #include "../../include/javascript/JS_Value.h"
12 #include "../../include/javascript/Document.h"
13 #include "../../include/javascript/JS_EventHandler.h"
14 #include "../../include/javascript/JS_Context.h"
15 #include "../../include/javascript/JS_Runtime.h"
16 #include "../../include/javascript/app.h"
17 #include "../../include/javascript/Field.h"
18 #include "../../include/javascript/Icon.h"
19 #include "../../include/javascript/resource.h"
20
21 #include "../../../third_party/base/numerics/safe_math.h"
22
23 static v8::Isolate* GetIsolate(IFXJS_Context* cc) {
24   CJS_Context* pContext = (CJS_Context*)cc;
25   ASSERT(pContext != NULL);
26
27   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
28   ASSERT(pRuntime != NULL);
29
30   return pRuntime->GetIsolate();
31 }
32
33 BEGIN_JS_STATIC_CONST(CJS_PrintParamsObj)
34 END_JS_STATIC_CONST()
35
36 BEGIN_JS_STATIC_PROP(CJS_PrintParamsObj)
37 END_JS_STATIC_PROP()
38
39 BEGIN_JS_STATIC_METHOD(CJS_PrintParamsObj)
40 END_JS_STATIC_METHOD()
41
42 IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj)
43
44 PrintParamsObj::PrintParamsObj(CJS_Object* pJSObject)
45     : CJS_EmbedObj(pJSObject) {
46   bUI = TRUE;
47   nStart = 0;
48   nEnd = 0;
49   bSilent = FALSE;
50   bShrinkToFit = FALSE;
51   bPrintAsImage = FALSE;
52   bReverse = FALSE;
53   bAnnotations = TRUE;
54 }
55
56 /* ---------------------- Document ---------------------- */
57
58 #define MINWIDTH 5.0f
59 #define MINHEIGHT 5.0f
60
61 BEGIN_JS_STATIC_CONST(CJS_Document)
62 END_JS_STATIC_CONST()
63
64 BEGIN_JS_STATIC_PROP(CJS_Document)
65 JS_STATIC_PROP_ENTRY(ADBE)
66 JS_STATIC_PROP_ENTRY(author)
67 JS_STATIC_PROP_ENTRY(baseURL)
68 JS_STATIC_PROP_ENTRY(bookmarkRoot)
69 JS_STATIC_PROP_ENTRY(calculate)
70 JS_STATIC_PROP_ENTRY(Collab)
71 JS_STATIC_PROP_ENTRY(creationDate)
72 JS_STATIC_PROP_ENTRY(creator)
73 JS_STATIC_PROP_ENTRY(delay)
74 JS_STATIC_PROP_ENTRY(dirty)
75 JS_STATIC_PROP_ENTRY(documentFileName)
76 JS_STATIC_PROP_ENTRY(external)
77 JS_STATIC_PROP_ENTRY(filesize)
78 JS_STATIC_PROP_ENTRY(icons)
79 JS_STATIC_PROP_ENTRY(info)
80 JS_STATIC_PROP_ENTRY(keywords)
81 JS_STATIC_PROP_ENTRY(layout)
82 JS_STATIC_PROP_ENTRY(media)
83 JS_STATIC_PROP_ENTRY(modDate)
84 JS_STATIC_PROP_ENTRY(mouseX)
85 JS_STATIC_PROP_ENTRY(mouseY)
86 JS_STATIC_PROP_ENTRY(numFields)
87 JS_STATIC_PROP_ENTRY(numPages)
88 JS_STATIC_PROP_ENTRY(pageNum)
89 JS_STATIC_PROP_ENTRY(pageWindowRect)
90 JS_STATIC_PROP_ENTRY(path)
91 JS_STATIC_PROP_ENTRY(producer)
92 JS_STATIC_PROP_ENTRY(subject)
93 JS_STATIC_PROP_ENTRY(title)
94 JS_STATIC_PROP_ENTRY(zoom)
95 JS_STATIC_PROP_ENTRY(zoomType)
96 END_JS_STATIC_PROP()
97
98 BEGIN_JS_STATIC_METHOD(CJS_Document)
99 JS_STATIC_METHOD_ENTRY(addAnnot)
100 JS_STATIC_METHOD_ENTRY(addField)
101 JS_STATIC_METHOD_ENTRY(addLink)
102 JS_STATIC_METHOD_ENTRY(addIcon)
103 JS_STATIC_METHOD_ENTRY(calculateNow)
104 JS_STATIC_METHOD_ENTRY(closeDoc)
105 JS_STATIC_METHOD_ENTRY(createDataObject)
106 JS_STATIC_METHOD_ENTRY(deletePages)
107 JS_STATIC_METHOD_ENTRY(exportAsText)
108 JS_STATIC_METHOD_ENTRY(exportAsFDF)
109 JS_STATIC_METHOD_ENTRY(exportAsXFDF)
110 JS_STATIC_METHOD_ENTRY(extractPages)
111 JS_STATIC_METHOD_ENTRY(getAnnot)
112 JS_STATIC_METHOD_ENTRY(getAnnots)
113 JS_STATIC_METHOD_ENTRY(getAnnot3D)
114 JS_STATIC_METHOD_ENTRY(getAnnots3D)
115 JS_STATIC_METHOD_ENTRY(getField)
116 JS_STATIC_METHOD_ENTRY(getIcon)
117 JS_STATIC_METHOD_ENTRY(getLinks)
118 JS_STATIC_METHOD_ENTRY(getNthFieldName)
119 JS_STATIC_METHOD_ENTRY(getOCGs)
120 JS_STATIC_METHOD_ENTRY(getPageBox)
121 JS_STATIC_METHOD_ENTRY(getPageNthWord)
122 JS_STATIC_METHOD_ENTRY(getPageNthWordQuads)
123 JS_STATIC_METHOD_ENTRY(getPageNumWords)
124 JS_STATIC_METHOD_ENTRY(getPrintParams)
125 JS_STATIC_METHOD_ENTRY(getURL)
126 JS_STATIC_METHOD_ENTRY(importAnFDF)
127 JS_STATIC_METHOD_ENTRY(importAnXFDF)
128 JS_STATIC_METHOD_ENTRY(importTextData)
129 JS_STATIC_METHOD_ENTRY(insertPages)
130 JS_STATIC_METHOD_ENTRY(mailForm)
131 JS_STATIC_METHOD_ENTRY(print)
132 JS_STATIC_METHOD_ENTRY(removeField)
133 JS_STATIC_METHOD_ENTRY(replacePages)
134 JS_STATIC_METHOD_ENTRY(resetForm)
135 JS_STATIC_METHOD_ENTRY(removeIcon)
136 JS_STATIC_METHOD_ENTRY(saveAs)
137 JS_STATIC_METHOD_ENTRY(submitForm)
138 JS_STATIC_METHOD_ENTRY(mailDoc)
139 END_JS_STATIC_METHOD()
140
141 IMPLEMENT_JS_CLASS(CJS_Document, Document)
142
143 FX_BOOL CJS_Document::InitInstance(IFXJS_Context* cc) {
144   CJS_Context* pContext = (CJS_Context*)cc;
145   ASSERT(pContext != NULL);
146
147   Document* pDoc = (Document*)GetEmbedObject();
148   ASSERT(pDoc != NULL);
149
150   pDoc->AttachDoc(pContext->GetReaderDocument());
151   pDoc->SetIsolate(pContext->GetJSRuntime()->GetIsolate());
152   return TRUE;
153 };
154
155 /* --------------------------------- Document ---------------------------------
156  */
157
158 Document::Document(CJS_Object* pJSObject)
159     : CJS_EmbedObj(pJSObject),
160       m_isolate(NULL),
161       m_pIconTree(NULL),
162       m_pDocument(NULL),
163       m_cwBaseURL(L""),
164       m_bDelay(FALSE) {}
165
166 Document::~Document() {
167   if (m_pIconTree) {
168     m_pIconTree->DeleteIconTree();
169     delete m_pIconTree;
170     m_pIconTree = NULL;
171   }
172   for (int i = 0; i < m_DelayData.GetSize(); i++) {
173     if (CJS_DelayData* pData = m_DelayData.GetAt(i)) {
174       delete pData;
175       pData = NULL;
176       m_DelayData.SetAt(i, NULL);
177     }
178   }
179
180   m_DelayData.RemoveAll();
181   m_DelayAnnotData.RemoveAll();
182 }
183
184 // the total number of fileds in document.
185 FX_BOOL Document::numFields(IFXJS_Context* cc,
186                             CJS_PropValue& vp,
187                             CFX_WideString& sError) {
188   if (vp.IsSetting()) {
189     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
190     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
191     return FALSE;
192   }
193   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
194   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
195   vp << (int)pPDFForm->CountFields();
196   return TRUE;
197 }
198
199 FX_BOOL Document::dirty(IFXJS_Context* cc,
200                         CJS_PropValue& vp,
201                         CFX_WideString& sError) {
202   ASSERT(m_pDocument != NULL);
203
204   if (vp.IsGetting()) {
205     if (m_pDocument->GetChangeMark())
206       vp << true;
207     else
208       vp << false;
209   } else {
210     bool bChanged = false;
211
212     vp >> bChanged;
213
214     if (bChanged)
215       m_pDocument->SetChangeMark();
216     else
217       m_pDocument->ClearChangeMark();
218   }
219
220   return TRUE;
221 }
222
223 FX_BOOL Document::ADBE(IFXJS_Context* cc,
224                        CJS_PropValue& vp,
225                        CFX_WideString& sError) {
226   ASSERT(m_pDocument != NULL);
227
228   if (vp.IsGetting()) {
229     vp.SetNull();
230   } else {
231   }
232
233   return TRUE;
234 }
235
236 FX_BOOL Document::pageNum(IFXJS_Context* cc,
237                           CJS_PropValue& vp,
238                           CFX_WideString& sError) {
239   ASSERT(m_pDocument != NULL);
240
241   if (vp.IsGetting()) {
242     if (CPDFSDK_PageView* pPageView = m_pDocument->GetCurrentView()) {
243       vp << pPageView->GetPageIndex();
244     }
245   } else {
246     int iPageCount = m_pDocument->GetPageCount();
247     int iPageNum = 0;
248     vp >> iPageNum;
249
250     CPDFDoc_Environment* pEnv = m_pDocument->GetEnv();
251     if (iPageNum >= 0 && iPageNum < iPageCount) {
252       pEnv->JS_docgotoPage(iPageNum);
253     } else if (iPageNum >= iPageCount) {
254       pEnv->JS_docgotoPage(iPageCount - 1);
255     } else if (iPageNum < 0) {
256       pEnv->JS_docgotoPage(0);
257     }
258   }
259
260   return TRUE;
261 }
262
263 FX_BOOL Document::ParserParams(JSObject* pObj, CJS_AnnotObj& annotobj) {
264   // Not supported.
265   return TRUE;
266 }
267
268 FX_BOOL Document::addAnnot(IFXJS_Context* cc,
269                            const CJS_Parameters& params,
270                            CJS_Value& vRet,
271                            CFX_WideString& sError) {
272   // Not supported.
273   return TRUE;
274 }
275
276 FX_BOOL Document::addField(IFXJS_Context* cc,
277                            const CJS_Parameters& params,
278                            CJS_Value& vRet,
279                            CFX_WideString& sError) {
280   // Not supported.
281   return TRUE;
282 }
283
284 FX_BOOL Document::exportAsText(IFXJS_Context* cc,
285                                const CJS_Parameters& params,
286                                CJS_Value& vRet,
287                                CFX_WideString& sError) {
288   // Unsafe, not supported.
289   return TRUE;
290 }
291
292 FX_BOOL Document::exportAsFDF(IFXJS_Context* cc,
293                               const CJS_Parameters& params,
294                               CJS_Value& vRet,
295                               CFX_WideString& sError) {
296   // Unsafe, not supported.
297   return TRUE;
298 }
299
300 FX_BOOL Document::exportAsXFDF(IFXJS_Context* cc,
301                                const CJS_Parameters& params,
302                                CJS_Value& vRet,
303                                CFX_WideString& sError) {
304   // Unsafe, not supported.
305   return TRUE;
306 }
307
308 // Maps a field object in PDF document to a JavaScript variable
309 // comment:
310 // note: the paremter cName, this is clue how to treat if the cName is not a
311 // valiable filed name in this document
312
313 FX_BOOL Document::getField(IFXJS_Context* cc,
314                            const CJS_Parameters& params,
315                            CJS_Value& vRet,
316                            CFX_WideString& sError) {
317   CJS_Context* pContext = (CJS_Context*)cc;
318   if (params.size() < 1) {
319     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
320     return FALSE;
321   }
322
323   CFX_WideString wideName = params[0].ToCFXWideString();
324
325   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
326   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
327   if (pPDFForm->CountFields(wideName) <= 0) {
328     vRet.SetNull();
329     return TRUE;
330   }
331
332   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
333   JSFXObject pFieldObj = JS_NewFxDynamicObj(
334       *pRuntime, pContext, JS_GetObjDefnID(*pRuntime, L"Field"));
335
336   v8::Isolate* isolate = GetIsolate(cc);
337   CJS_Field* pJSField = (CJS_Field*)JS_GetPrivate(isolate, pFieldObj);
338   Field* pField = (Field*)pJSField->GetEmbedObject();
339   pField->AttachField(this, wideName);
340
341   vRet = pJSField;
342   return TRUE;
343 }
344
345 // Gets the name of the nth field in the document
346 FX_BOOL Document::getNthFieldName(IFXJS_Context* cc,
347                                   const CJS_Parameters& params,
348                                   CJS_Value& vRet,
349                                   CFX_WideString& sError) {
350   CJS_Context* pContext = (CJS_Context*)cc;
351   if (params.size() != 1) {
352     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
353     return FALSE;
354   }
355
356   int nIndex = params[0].ToInt();
357   if (nIndex < 0) {
358     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
359     return FALSE;
360   }
361
362   CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm();
363   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
364   CPDF_FormField* pField = pPDFForm->GetField(nIndex);
365   if (!pField)
366     return FALSE;
367
368   vRet = pField->GetFullName().c_str();
369   return TRUE;
370 }
371
372 FX_BOOL Document::importAnFDF(IFXJS_Context* cc,
373                               const CJS_Parameters& params,
374                               CJS_Value& vRet,
375                               CFX_WideString& sError) {
376   // Unsafe, not supported.
377   return TRUE;
378 }
379
380 FX_BOOL Document::importAnXFDF(IFXJS_Context* cc,
381                                const CJS_Parameters& params,
382                                CJS_Value& vRet,
383                                CFX_WideString& sError) {
384   // Unsafe, not supported.
385   return TRUE;
386 }
387
388 FX_BOOL Document::importTextData(IFXJS_Context* cc,
389                                  const CJS_Parameters& params,
390                                  CJS_Value& vRet,
391                                  CFX_WideString& sError) {
392   // Unsafe, not supported.
393   return TRUE;
394 }
395
396 // exports the form data and mails the resulting fdf file as an attachment to
397 // all recipients.
398 // comment: need reader supports
399 // note:
400 // int CPDFSDK_Document::mailForm(FX_BOOL bUI,String cto,string ccc,string
401 // cbcc,string cSubject,string cms);
402
403 FX_BOOL Document::mailForm(IFXJS_Context* cc,
404                            const CJS_Parameters& params,
405                            CJS_Value& vRet,
406                            CFX_WideString& sError) {
407   ASSERT(m_pDocument != NULL);
408
409   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
410     return FALSE;
411
412   int iLength = params.size();
413
414   FX_BOOL bUI = iLength > 0 ? params[0].ToBool() : TRUE;
415   CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString() : L"";
416   CFX_WideString cCc = iLength > 2 ? params[2].ToCFXWideString() : L"";
417   CFX_WideString cBcc = iLength > 3 ? params[3].ToCFXWideString() : L"";
418   CFX_WideString cSubject = iLength > 4 ? params[4].ToCFXWideString() : L"";
419   CFX_WideString cMsg = iLength > 5 ? params[5].ToCFXWideString() : L"";
420
421   CPDFSDK_InterForm* pInterForm =
422       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
423   ASSERT(pInterForm != NULL);
424
425   CFX_ByteTextBuf textBuf;
426   if (!pInterForm->ExportFormToFDFTextBuf(textBuf))
427     return FALSE;
428
429   CJS_Context* pContext = (CJS_Context*)cc;
430   ASSERT(pContext != NULL);
431   CPDFDoc_Environment* pEnv = pContext->GetReaderApp();
432   ASSERT(pEnv != NULL);
433   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
434   ASSERT(pRuntime != NULL);
435
436   pRuntime->BeginBlock();
437   pEnv->JS_docmailForm(textBuf.GetBuffer(), textBuf.GetLength(), bUI,
438                        cTo.c_str(), cSubject.c_str(), cCc.c_str(), cBcc.c_str(),
439                        cMsg.c_str());
440   pRuntime->EndBlock();
441   return TRUE;
442 }
443
444 FX_BOOL Document::print(IFXJS_Context* cc,
445                         const CJS_Parameters& params,
446                         CJS_Value& vRet,
447                         CFX_WideString& sError) {
448   CJS_Context* pContext = (CJS_Context*)cc;
449   ASSERT(pContext != NULL);
450   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
451   ASSERT(pRuntime != NULL);
452
453   FX_BOOL bUI = TRUE;
454   int nStart = 0;
455   int nEnd = 0;
456   FX_BOOL bSilent = FALSE;
457   FX_BOOL bShrinkToFit = FALSE;
458   FX_BOOL bPrintAsImage = FALSE;
459   FX_BOOL bReverse = FALSE;
460   FX_BOOL bAnnotations = FALSE;
461
462   int nlength = params.size();
463   if (nlength == 9) {
464     if (params[8].GetType() == VT_fxobject) {
465       JSFXObject pObj = params[8].ToV8Object();
466       {
467         if (JS_GetObjDefnID(pObj) ==
468             JS_GetObjDefnID(*pRuntime, L"PrintParamsObj")) {
469           if (CJS_Object* pJSObj = params[8].ToCJSObject()) {
470             if (PrintParamsObj* pprintparamsObj =
471                     (PrintParamsObj*)pJSObj->GetEmbedObject()) {
472               bUI = pprintparamsObj->bUI;
473               nStart = pprintparamsObj->nStart;
474               nEnd = pprintparamsObj->nEnd;
475               bSilent = pprintparamsObj->bSilent;
476               bShrinkToFit = pprintparamsObj->bShrinkToFit;
477               bPrintAsImage = pprintparamsObj->bPrintAsImage;
478               bReverse = pprintparamsObj->bReverse;
479               bAnnotations = pprintparamsObj->bAnnotations;
480             }
481           }
482         }
483       }
484     }
485   } else {
486     if (nlength >= 1)
487       bUI = params[0].ToBool();
488     if (nlength >= 2)
489       nStart = params[1].ToInt();
490     if (nlength >= 3)
491       nEnd = params[2].ToInt();
492     if (nlength >= 4)
493       bSilent = params[3].ToBool();
494     if (nlength >= 5)
495       bShrinkToFit = params[4].ToBool();
496     if (nlength >= 6)
497       bPrintAsImage = params[5].ToBool();
498     if (nlength >= 7)
499       bReverse = params[6].ToBool();
500     if (nlength >= 8)
501       bAnnotations = params[7].ToBool();
502   }
503
504   ASSERT(m_pDocument != NULL);
505
506   if (CPDFDoc_Environment* pEnv = m_pDocument->GetEnv()) {
507     pEnv->JS_docprint(bUI, nStart, nEnd, bSilent, bShrinkToFit, bPrintAsImage,
508                       bReverse, bAnnotations);
509     return TRUE;
510   }
511   return FALSE;
512 }
513
514 // removes the specified field from the document.
515 // comment:
516 // note: if the filed name is not retional, adobe is dumb for it.
517
518 FX_BOOL Document::removeField(IFXJS_Context* cc,
519                               const CJS_Parameters& params,
520                               CJS_Value& vRet,
521                               CFX_WideString& sError) {
522   ASSERT(m_pDocument != NULL);
523
524   if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) ||
525         m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM)))
526     return FALSE;
527
528   CJS_Context* pContext = (CJS_Context*)cc;
529   if (params.size() != 1) {
530     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
531     return FALSE;
532   }
533
534   CFX_WideString sFieldName = params[0].ToCFXWideString();
535   CPDFSDK_InterForm* pInterForm =
536       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
537   ASSERT(pInterForm != NULL);
538
539   CFX_PtrArray widgets;
540   pInterForm->GetWidgets(sFieldName, widgets);
541
542   int nSize = widgets.GetSize();
543
544   if (nSize > 0) {
545     for (int i = 0; i < nSize; i++) {
546       CPDFSDK_Widget* pWidget = (CPDFSDK_Widget*)widgets[i];
547       ASSERT(pWidget != NULL);
548
549       CPDF_Rect rcAnnot = pWidget->GetRect();
550       rcAnnot.left -= 1;
551       rcAnnot.bottom -= 1;
552       rcAnnot.right += 1;
553       rcAnnot.top += 1;
554
555       CFX_RectArray aRefresh;
556       aRefresh.Add(rcAnnot);
557
558       CPDF_Page* pPage = pWidget->GetPDFPage();
559       ASSERT(pPage != NULL);
560
561       CPDFSDK_PageView* pPageView = m_pDocument->GetPageView(pPage);
562       pPageView->DeleteAnnot(pWidget);
563
564       pPageView->UpdateRects(aRefresh);
565     }
566     m_pDocument->SetChangeMark();
567   }
568
569   return TRUE;
570 }
571
572 // reset filed values within a document.
573 // comment:
574 // note: if the fields names r not rational, aodbe is dumb for it.
575
576 FX_BOOL Document::resetForm(IFXJS_Context* cc,
577                             const CJS_Parameters& params,
578                             CJS_Value& vRet,
579                             CFX_WideString& sError) {
580   ASSERT(m_pDocument != NULL);
581
582   if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) ||
583         m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM) ||
584         m_pDocument->GetPermissions(FPDFPERM_FILL_FORM)))
585     return FALSE;
586
587   CPDFSDK_InterForm* pInterForm =
588       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
589   ASSERT(pInterForm != NULL);
590
591   CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
592   ASSERT(pPDFForm != NULL);
593
594   v8::Isolate* isolate = GetIsolate(cc);
595   CJS_Array aName(isolate);
596
597   if (params.size() > 0) {
598     switch (params[0].GetType()) {
599       default:
600         aName.Attach(params[0].ToV8Array());
601         break;
602       case VT_string:
603         aName.SetElement(0, params[0]);
604         break;
605     }
606
607     CFX_PtrArray aFields;
608
609     for (int i = 0, isz = aName.GetLength(); i < isz; i++) {
610       CJS_Value valElement(isolate);
611       aName.GetElement(i, valElement);
612       CFX_WideString swVal = valElement.ToCFXWideString();
613
614       for (int j = 0, jsz = pPDFForm->CountFields(swVal); j < jsz; j++) {
615         aFields.Add((void*)pPDFForm->GetField(j, swVal));
616       }
617     }
618
619     if (aFields.GetSize() > 0) {
620       pPDFForm->ResetForm(aFields, TRUE, TRUE);
621       m_pDocument->SetChangeMark();
622     }
623   } else {
624     pPDFForm->ResetForm(TRUE);
625     m_pDocument->SetChangeMark();
626   }
627
628   return TRUE;
629 }
630
631 FX_BOOL Document::saveAs(IFXJS_Context* cc,
632                          const CJS_Parameters& params,
633                          CJS_Value& vRet,
634                          CFX_WideString& sError) {
635   // Unsafe, not supported.
636   return TRUE;
637 }
638
639 FX_BOOL Document::submitForm(IFXJS_Context* cc,
640                              const CJS_Parameters& params,
641                              CJS_Value& vRet,
642                              CFX_WideString& sError) {
643   ASSERT(m_pDocument != NULL);
644   CJS_Context* pContext = (CJS_Context*)cc;
645   int nSize = params.size();
646   if (nSize < 1) {
647     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
648     return FALSE;
649   }
650
651   CFX_WideString strURL;
652   FX_BOOL bFDF = TRUE;
653   FX_BOOL bEmpty = FALSE;
654   v8::Isolate* isolate = GetIsolate(cc);
655   CJS_Array aFields(isolate);
656
657   CJS_Value v = params[0];
658   if (v.GetType() == VT_string) {
659     strURL = params[0].ToCFXWideString();
660     if (nSize > 1)
661       bFDF = params[1].ToBool();
662     if (nSize > 2)
663       bEmpty = params[2].ToBool();
664     if (nSize > 3)
665       aFields.Attach(params[3].ToV8Array());
666   } else if (v.GetType() == VT_object) {
667     JSObject pObj = params[0].ToV8Object();
668     v8::Local<v8::Value> pValue = JS_GetObjectElement(isolate, pObj, L"cURL");
669     if (!pValue.IsEmpty())
670       strURL =
671           CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
672     pValue = JS_GetObjectElement(isolate, pObj, L"bFDF");
673     bFDF = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToBool();
674     pValue = JS_GetObjectElement(isolate, pObj, L"bEmpty");
675     bEmpty = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToBool();
676     pValue = JS_GetObjectElement(isolate, pObj, L"aFields");
677     aFields.Attach(
678         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToV8Array());
679   }
680
681   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
682   CPDFSDK_InterForm* pInterForm =
683       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
684   CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
685   FX_BOOL bAll = (aFields.GetLength() == 0);
686   if (bAll && bEmpty) {
687     if (pPDFInterForm->CheckRequiredFields()) {
688       pRuntime->BeginBlock();
689       pInterForm->SubmitForm(strURL, FALSE);
690       pRuntime->EndBlock();
691     }
692     return TRUE;
693   }
694
695   CFX_PtrArray fieldObjects;
696   for (int i = 0, sz = aFields.GetLength(); i < sz; i++) {
697     CJS_Value valName(isolate);
698     aFields.GetElement(i, valName);
699
700     CFX_WideString sName = valName.ToCFXWideString();
701     CPDF_InterForm* pPDFForm = pInterForm->GetInterForm();
702     for (int j = 0, jsz = pPDFForm->CountFields(sName); j < jsz; ++j) {
703       CPDF_FormField* pField = pPDFForm->GetField(j, sName);
704       if (!bEmpty && pField->GetValue().IsEmpty())
705         continue;
706
707       fieldObjects.Add(pField);
708     }
709   }
710
711   if (pPDFInterForm->CheckRequiredFields(&fieldObjects, TRUE)) {
712     pRuntime->BeginBlock();
713     pInterForm->SubmitFields(strURL, fieldObjects, TRUE, !bFDF);
714     pRuntime->EndBlock();
715   }
716   return TRUE;
717 }
718
719 //////////////////////////////////////////////////////////////////////////////////////////////
720
721 void Document::AttachDoc(CPDFSDK_Document* pDoc) {
722   m_pDocument = pDoc;
723 }
724
725 CPDFSDK_Document* Document::GetReaderDoc() {
726   return m_pDocument;
727 }
728
729 FX_BOOL Document::ExtractFileName(CPDFSDK_Document* pDoc,
730                                   CFX_ByteString& strFileName) {
731   return FALSE;
732 }
733
734 FX_BOOL Document::ExtractFolderName(CPDFSDK_Document* pDoc,
735                                     CFX_ByteString& strFolderName) {
736   return FALSE;
737 }
738
739 FX_BOOL Document::bookmarkRoot(IFXJS_Context* cc,
740                                CJS_PropValue& vp,
741                                CFX_WideString& sError) {
742   return TRUE;
743 }
744
745 FX_BOOL Document::mailDoc(IFXJS_Context* cc,
746                           const CJS_Parameters& params,
747                           CJS_Value& vRet,
748                           CFX_WideString& sError) {
749   ASSERT(m_pDocument != NULL);
750
751   FX_BOOL bUI = TRUE;
752   CFX_WideString cTo = L"";
753   CFX_WideString cCc = L"";
754   CFX_WideString cBcc = L"";
755   CFX_WideString cSubject = L"";
756   CFX_WideString cMsg = L"";
757
758   if (params.size() >= 1)
759     bUI = params[0].ToBool();
760   if (params.size() >= 2)
761     cTo = params[1].ToCFXWideString();
762   if (params.size() >= 3)
763     cCc = params[2].ToCFXWideString();
764   if (params.size() >= 4)
765     cBcc = params[3].ToCFXWideString();
766   if (params.size() >= 5)
767     cSubject = params[4].ToCFXWideString();
768   if (params.size() >= 6)
769     cMsg = params[5].ToCFXWideString();
770
771   v8::Isolate* isolate = GetIsolate(cc);
772
773   if (params.size() >= 1 && params[0].GetType() == VT_object) {
774     JSObject pObj = params[0].ToV8Object();
775
776     v8::Local<v8::Value> pValue = JS_GetObjectElement(isolate, pObj, L"bUI");
777     bUI = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToInt();
778
779     pValue = JS_GetObjectElement(isolate, pObj, L"cTo");
780     cTo = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
781
782     pValue = JS_GetObjectElement(isolate, pObj, L"cCc");
783     cCc = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
784
785     pValue = JS_GetObjectElement(isolate, pObj, L"cBcc");
786     cBcc = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
787
788     pValue = JS_GetObjectElement(isolate, pObj, L"cSubject");
789     cSubject =
790         CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
791
792     pValue = JS_GetObjectElement(isolate, pObj, L"cMsg");
793     cMsg = CJS_Value(isolate, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString();
794   }
795
796   CJS_Context* pContext = (CJS_Context*)cc;
797   ASSERT(pContext != NULL);
798   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
799   ASSERT(pRuntime != NULL);
800
801   pRuntime->BeginBlock();
802   CPDFDoc_Environment* pEnv = pRuntime->GetReaderApp();
803   pEnv->JS_docmailForm(NULL, 0, bUI, cTo.c_str(), cSubject.c_str(), cCc.c_str(),
804                        cBcc.c_str(), cMsg.c_str());
805   pRuntime->EndBlock();
806
807   return TRUE;
808 }
809
810 FX_BOOL Document::author(IFXJS_Context* cc,
811                          CJS_PropValue& vp,
812                          CFX_WideString& sError) {
813   ASSERT(m_pDocument != NULL);
814
815   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
816   if (!pDictionary)
817     return FALSE;
818
819   if (vp.IsGetting()) {
820     vp << pDictionary->GetUnicodeText("Author");
821     return TRUE;
822   } else {
823     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
824       return FALSE;
825
826     CFX_WideString csAuthor;
827     vp >> csAuthor;
828     pDictionary->SetAtString("Author", PDF_EncodeText(csAuthor));
829     m_pDocument->SetChangeMark();
830     return TRUE;
831   }
832 }
833
834 FX_BOOL Document::info(IFXJS_Context* cc,
835                        CJS_PropValue& vp,
836                        CFX_WideString& sError) {
837   ASSERT(m_pDocument != NULL);
838
839   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
840   if (!pDictionary)
841     return FALSE;
842
843   CFX_WideString cwAuthor = pDictionary->GetUnicodeText("Author");
844   CFX_WideString cwTitle = pDictionary->GetUnicodeText("Title");
845   CFX_WideString cwSubject = pDictionary->GetUnicodeText("Subject");
846   CFX_WideString cwKeywords = pDictionary->GetUnicodeText("Keywords");
847   CFX_WideString cwCreator = pDictionary->GetUnicodeText("Creator");
848   CFX_WideString cwProducer = pDictionary->GetUnicodeText("Producer");
849   CFX_WideString cwCreationDate = pDictionary->GetUnicodeText("CreationDate");
850   CFX_WideString cwModDate = pDictionary->GetUnicodeText("ModDate");
851   CFX_WideString cwTrapped = pDictionary->GetUnicodeText("Trapped");
852
853   v8::Isolate* isolate = GetIsolate(cc);
854   if (vp.IsGetting()) {
855     CJS_Context* pContext = (CJS_Context*)cc;
856     CJS_Runtime* pRuntime = pContext->GetJSRuntime();
857     JSFXObject pObj = JS_NewFxDynamicObj(*pRuntime, pContext, -1);
858     JS_PutObjectString(isolate, pObj, L"Author", cwAuthor.c_str());
859     JS_PutObjectString(isolate, pObj, L"Title", cwTitle.c_str());
860     JS_PutObjectString(isolate, pObj, L"Subject", cwSubject.c_str());
861     JS_PutObjectString(isolate, pObj, L"Keywords", cwKeywords.c_str());
862     JS_PutObjectString(isolate, pObj, L"Creator", cwCreator.c_str());
863     JS_PutObjectString(isolate, pObj, L"Producer", cwProducer.c_str());
864     JS_PutObjectString(isolate, pObj, L"CreationDate", cwCreationDate.c_str());
865     JS_PutObjectString(isolate, pObj, L"ModDate", cwModDate.c_str());
866     JS_PutObjectString(isolate, pObj, L"Trapped", cwTrapped.c_str());
867
868     // It's to be compatible to non-standard info dictionary.
869     FX_POSITION pos = pDictionary->GetStartPos();
870     while (pos) {
871       CFX_ByteString bsKey;
872       CPDF_Object* pValueObj = pDictionary->GetNextElement(pos, bsKey);
873       CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey, bsKey.GetLength());
874       if ((pValueObj->GetType() == PDFOBJ_STRING) ||
875           (pValueObj->GetType() == PDFOBJ_NAME))
876         JS_PutObjectString(isolate, pObj, wsKey.c_str(),
877                            pValueObj->GetUnicodeText().c_str());
878       if (pValueObj->GetType() == PDFOBJ_NUMBER)
879         JS_PutObjectNumber(isolate, pObj, wsKey.c_str(),
880                            (float)pValueObj->GetNumber());
881       if (pValueObj->GetType() == PDFOBJ_BOOLEAN)
882         JS_PutObjectBoolean(isolate, pObj, wsKey.c_str(),
883                             (bool)pValueObj->GetInteger());
884     }
885     vp << pObj;
886   }
887   return TRUE;
888 }
889
890 FX_BOOL Document::creationDate(IFXJS_Context* cc,
891                                CJS_PropValue& vp,
892                                CFX_WideString& sError) {
893   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
894   if (!pDictionary)
895     return FALSE;
896
897   if (vp.IsGetting()) {
898     vp << pDictionary->GetUnicodeText("CreationDate");
899   } else {
900     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
901       return FALSE;
902
903     CFX_WideString csCreationDate;
904     vp >> csCreationDate;
905     pDictionary->SetAtString("CreationDate", PDF_EncodeText(csCreationDate));
906     m_pDocument->SetChangeMark();
907   }
908   return TRUE;
909 }
910
911 FX_BOOL Document::creator(IFXJS_Context* cc,
912                           CJS_PropValue& vp,
913                           CFX_WideString& sError) {
914   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
915   if (!pDictionary)
916     return FALSE;
917
918   if (vp.IsGetting()) {
919     vp << pDictionary->GetUnicodeText("Creator");
920   } else {
921     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
922       return FALSE;
923
924     CFX_WideString csCreator;
925     vp >> csCreator;
926     pDictionary->SetAtString("Creator", PDF_EncodeText(csCreator));
927     m_pDocument->SetChangeMark();
928   }
929   return TRUE;
930 }
931
932 FX_BOOL Document::delay(IFXJS_Context* cc,
933                         CJS_PropValue& vp,
934                         CFX_WideString& sError) {
935   if (vp.IsGetting()) {
936     vp << m_bDelay;
937   } else {
938     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
939       return FALSE;
940
941     vp >> m_bDelay;
942     if (m_bDelay) {
943       for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++)
944         delete m_DelayData.GetAt(i);
945
946       m_DelayData.RemoveAll();
947     } else {
948       CFX_ArrayTemplate<CJS_DelayData*> DelayDataToProcess;
949       for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) {
950         if (CJS_DelayData* pData = m_DelayData.GetAt(i)) {
951           DelayDataToProcess.Add(pData);
952           m_DelayData.SetAt(i, NULL);
953         }
954       }
955       m_DelayData.RemoveAll();
956       for (int i = 0, sz = DelayDataToProcess.GetSize(); i < sz; i++) {
957         CJS_DelayData* pData = DelayDataToProcess.GetAt(i);
958         Field::DoDelay(m_pDocument, pData);
959         DelayDataToProcess.SetAt(i, NULL);
960         delete pData;
961       }
962     }
963   }
964   return TRUE;
965 }
966
967 FX_BOOL Document::keywords(IFXJS_Context* cc,
968                            CJS_PropValue& vp,
969                            CFX_WideString& sError) {
970   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
971   if (!pDictionary)
972     return FALSE;
973
974   if (vp.IsGetting()) {
975     vp << pDictionary->GetUnicodeText("Keywords");
976   } else {
977     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
978       return FALSE;
979
980     CFX_WideString csKeywords;
981     vp >> csKeywords;
982     pDictionary->SetAtString("Keywords", PDF_EncodeText(csKeywords));
983     m_pDocument->SetChangeMark();
984   }
985   return TRUE;
986 }
987
988 FX_BOOL Document::modDate(IFXJS_Context* cc,
989                           CJS_PropValue& vp,
990                           CFX_WideString& sError) {
991   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
992   if (!pDictionary)
993     return FALSE;
994
995   if (vp.IsGetting()) {
996     vp << pDictionary->GetUnicodeText("ModDate");
997   } else {
998     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
999       return FALSE;
1000
1001     CFX_WideString csmodDate;
1002     vp >> csmodDate;
1003     pDictionary->SetAtString("ModDate", PDF_EncodeText(csmodDate));
1004     m_pDocument->SetChangeMark();
1005   }
1006   return TRUE;
1007 }
1008
1009 FX_BOOL Document::producer(IFXJS_Context* cc,
1010                            CJS_PropValue& vp,
1011                            CFX_WideString& sError) {
1012   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
1013   if (!pDictionary)
1014     return FALSE;
1015
1016   if (vp.IsGetting()) {
1017     vp << pDictionary->GetUnicodeText("Producer");
1018   } else {
1019     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
1020       return FALSE;
1021
1022     CFX_WideString csproducer;
1023     vp >> csproducer;
1024     pDictionary->SetAtString("Producer", PDF_EncodeText(csproducer));
1025     m_pDocument->SetChangeMark();
1026   }
1027   return TRUE;
1028 }
1029
1030 FX_BOOL Document::subject(IFXJS_Context* cc,
1031                           CJS_PropValue& vp,
1032                           CFX_WideString& sError) {
1033   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
1034   if (!pDictionary)
1035     return FALSE;
1036
1037   if (vp.IsGetting()) {
1038     vp << pDictionary->GetUnicodeText("Subject");
1039   } else {
1040     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
1041       return FALSE;
1042
1043     CFX_WideString cssubject;
1044     vp >> cssubject;
1045     pDictionary->SetAtString("Subject", PDF_EncodeText(cssubject));
1046     m_pDocument->SetChangeMark();
1047   }
1048   return TRUE;
1049 }
1050
1051 FX_BOOL Document::title(IFXJS_Context* cc,
1052                         CJS_PropValue& vp,
1053                         CFX_WideString& sError) {
1054   if (m_pDocument == NULL || m_pDocument->GetDocument() == NULL)
1055     return FALSE;
1056
1057   CPDF_Dictionary* pDictionary = m_pDocument->GetDocument()->GetInfo();
1058   if (!pDictionary)
1059     return FALSE;
1060
1061   if (vp.IsGetting()) {
1062     vp << pDictionary->GetUnicodeText("Title");
1063   } else {
1064     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
1065       return FALSE;
1066
1067     CFX_WideString cstitle;
1068     vp >> cstitle;
1069     pDictionary->SetAtString("Title", PDF_EncodeText(cstitle));
1070     m_pDocument->SetChangeMark();
1071   }
1072   return TRUE;
1073 }
1074
1075 FX_BOOL Document::numPages(IFXJS_Context* cc,
1076                            CJS_PropValue& vp,
1077                            CFX_WideString& sError) {
1078   if (vp.IsSetting()) {
1079     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1080     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1081     return FALSE;
1082   }
1083   vp << m_pDocument->GetPageCount();
1084   return TRUE;
1085 }
1086
1087 FX_BOOL Document::external(IFXJS_Context* cc,
1088                            CJS_PropValue& vp,
1089                            CFX_WideString& sError) {
1090   // In Chrome case,should always return true.
1091   if (vp.IsGetting()) {
1092     vp << true;
1093   }
1094   return TRUE;
1095 }
1096
1097 FX_BOOL Document::filesize(IFXJS_Context* cc,
1098                            CJS_PropValue& vp,
1099                            CFX_WideString& sError) {
1100   if (vp.IsSetting()) {
1101     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1102     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1103     return FALSE;
1104   }
1105   vp << 0;
1106   return TRUE;
1107 }
1108
1109 FX_BOOL Document::mouseX(IFXJS_Context* cc,
1110                          CJS_PropValue& vp,
1111                          CFX_WideString& sError) {
1112   return TRUE;
1113 }
1114
1115 FX_BOOL Document::mouseY(IFXJS_Context* cc,
1116                          CJS_PropValue& vp,
1117                          CFX_WideString& sError) {
1118   return TRUE;
1119 }
1120
1121 FX_BOOL Document::baseURL(IFXJS_Context* cc,
1122                           CJS_PropValue& vp,
1123                           CFX_WideString& sError) {
1124   if (vp.IsGetting()) {
1125     vp << m_cwBaseURL;
1126   } else {
1127     vp >> m_cwBaseURL;
1128   }
1129   return TRUE;
1130 }
1131
1132 FX_BOOL Document::calculate(IFXJS_Context* cc,
1133                             CJS_PropValue& vp,
1134                             CFX_WideString& sError) {
1135   ASSERT(m_pDocument != NULL);
1136
1137   CPDFSDK_InterForm* pInterForm =
1138       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
1139   ASSERT(pInterForm != NULL);
1140
1141   if (vp.IsGetting()) {
1142     if (pInterForm->IsCalculateEnabled())
1143       vp << true;
1144     else
1145       vp << false;
1146   } else {
1147     bool bCalculate;
1148     vp >> bCalculate;
1149
1150     pInterForm->EnableCalculate(bCalculate);
1151   }
1152
1153   return TRUE;
1154 }
1155
1156 FX_BOOL Document::documentFileName(IFXJS_Context* cc,
1157                                    CJS_PropValue& vp,
1158                                    CFX_WideString& sError) {
1159   if (vp.IsSetting()) {
1160     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1161     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1162     return FALSE;
1163   }
1164   CFX_WideString wsFilePath = m_pDocument->GetPath();
1165   int32_t i = wsFilePath.GetLength() - 1;
1166   for (; i >= 0; i--) {
1167     if (wsFilePath.GetAt(i) == L'\\' || wsFilePath.GetAt(i) == L'/')
1168       break;
1169   }
1170   if (i >= 0 && i < wsFilePath.GetLength() - 1) {
1171     vp << (wsFilePath.GetBuffer(wsFilePath.GetLength()) + i + 1);
1172   } else {
1173     vp << L"";
1174   }
1175   return TRUE;
1176 }
1177
1178 CFX_WideString Document::ReversalStr(CFX_WideString cbFrom) {
1179   size_t iLength = cbFrom.GetLength();
1180   pdfium::base::CheckedNumeric<size_t> iSize = sizeof(wchar_t);
1181   iSize *= (iLength + 1);
1182   wchar_t* pResult = (wchar_t*)malloc(iSize.ValueOrDie());
1183   wchar_t* pFrom = (wchar_t*)cbFrom.GetBuffer(iLength);
1184
1185   for (size_t i = 0; i < iLength; i++) {
1186     pResult[i] = *(pFrom + iLength - i - 1);
1187   }
1188   pResult[iLength] = L'\0';
1189
1190   cbFrom.ReleaseBuffer();
1191   CFX_WideString cbRet = CFX_WideString(pResult);
1192   free(pResult);
1193   pResult = NULL;
1194   return cbRet;
1195 }
1196
1197 CFX_WideString Document::CutString(CFX_WideString cbFrom) {
1198   size_t iLength = cbFrom.GetLength();
1199   pdfium::base::CheckedNumeric<size_t> iSize = sizeof(wchar_t);
1200   iSize *= (iLength + 1);
1201   wchar_t* pResult = (wchar_t*)malloc(iSize.ValueOrDie());
1202   wchar_t* pFrom = (wchar_t*)cbFrom.GetBuffer(iLength);
1203
1204   for (int i = 0; i < iLength; i++) {
1205     if (pFrom[i] == L'\\' || pFrom[i] == L'/') {
1206       pResult[i] = L'\0';
1207       break;
1208     }
1209     pResult[i] = pFrom[i];
1210   }
1211   pResult[iLength] = L'\0';
1212
1213   cbFrom.ReleaseBuffer();
1214   CFX_WideString cbRet = CFX_WideString(pResult);
1215   free(pResult);
1216   pResult = NULL;
1217   return cbRet;
1218 }
1219
1220 FX_BOOL Document::path(IFXJS_Context* cc,
1221                        CJS_PropValue& vp,
1222                        CFX_WideString& sError) {
1223   if (vp.IsSetting()) {
1224     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1225     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1226     return FALSE;
1227   }
1228   vp << app::SysPathToPDFPath(m_pDocument->GetPath());
1229   return TRUE;
1230 }
1231
1232 FX_BOOL Document::pageWindowRect(IFXJS_Context* cc,
1233                                  CJS_PropValue& vp,
1234                                  CFX_WideString& sError) {
1235   return TRUE;
1236 }
1237
1238 FX_BOOL Document::layout(IFXJS_Context* cc,
1239                          CJS_PropValue& vp,
1240                          CFX_WideString& sError) {
1241   return TRUE;
1242 }
1243
1244 FX_BOOL Document::addLink(IFXJS_Context* cc,
1245                           const CJS_Parameters& params,
1246                           CJS_Value& vRet,
1247                           CFX_WideString& sError) {
1248   return TRUE;
1249 }
1250
1251 FX_BOOL Document::closeDoc(IFXJS_Context* cc,
1252                            const CJS_Parameters& params,
1253                            CJS_Value& vRet,
1254                            CFX_WideString& sError) {
1255   ASSERT(m_pDocument != NULL);
1256   return TRUE;
1257 }
1258
1259 FX_BOOL Document::getPageBox(IFXJS_Context* cc,
1260                              const CJS_Parameters& params,
1261                              CJS_Value& vRet,
1262                              CFX_WideString& sError) {
1263   return TRUE;
1264 }
1265
1266 FX_BOOL Document::getAnnot(IFXJS_Context* cc,
1267                            const CJS_Parameters& params,
1268                            CJS_Value& vRet,
1269                            CFX_WideString& sError) {
1270   return TRUE;
1271 }
1272
1273 FX_BOOL Document::getAnnots(IFXJS_Context* cc,
1274                             const CJS_Parameters& params,
1275                             CJS_Value& vRet,
1276                             CFX_WideString& sError) {
1277   vRet.SetNull();
1278   return TRUE;
1279 }
1280
1281 FX_BOOL Document::getAnnot3D(IFXJS_Context* cc,
1282                              const CJS_Parameters& params,
1283                              CJS_Value& vRet,
1284                              CFX_WideString& sError) {
1285   vRet.SetNull();
1286   return TRUE;
1287 }
1288
1289 FX_BOOL Document::getAnnots3D(IFXJS_Context* cc,
1290                               const CJS_Parameters& params,
1291                               CJS_Value& vRet,
1292                               CFX_WideString& sError) {
1293   vRet = VT_undefined;
1294   return TRUE;
1295 }
1296
1297 FX_BOOL Document::getOCGs(IFXJS_Context* cc,
1298                           const CJS_Parameters& params,
1299                           CJS_Value& vRet,
1300                           CFX_WideString& sError) {
1301   return TRUE;
1302 }
1303
1304 FX_BOOL Document::getLinks(IFXJS_Context* cc,
1305                            const CJS_Parameters& params,
1306                            CJS_Value& vRet,
1307                            CFX_WideString& sError) {
1308   return TRUE;
1309 }
1310
1311 bool Document::IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect) {
1312   return (rect.left <= LinkRect.left && rect.top <= LinkRect.top &&
1313           rect.right >= LinkRect.right && rect.bottom >= LinkRect.bottom);
1314 }
1315
1316 void IconTree::InsertIconElement(IconElement* pNewIcon) {
1317   if (!pNewIcon)
1318     return;
1319
1320   if (m_pHead == NULL && m_pEnd == NULL) {
1321     m_pHead = m_pEnd = pNewIcon;
1322     m_iLength++;
1323   } else {
1324     m_pEnd->NextIcon = pNewIcon;
1325     m_pEnd = pNewIcon;
1326     m_iLength++;
1327   }
1328 }
1329
1330 void IconTree::DeleteIconTree() {
1331   if (!m_pHead || !m_pEnd)
1332     return;
1333
1334   IconElement* pTemp = NULL;
1335   while (m_pEnd != m_pHead) {
1336     pTemp = m_pHead;
1337     m_pHead = m_pHead->NextIcon;
1338     delete pTemp;
1339   }
1340
1341   delete m_pEnd;
1342   m_pHead = NULL;
1343   m_pEnd = NULL;
1344 }
1345
1346 int IconTree::GetLength() {
1347   return m_iLength;
1348 }
1349
1350 IconElement* IconTree::operator[](int iIndex) {
1351   if (iIndex >= 0 && iIndex <= m_iLength) {
1352     IconElement* pTemp = m_pHead;
1353     for (int i = 0; i < iIndex; i++) {
1354       pTemp = pTemp->NextIcon;
1355     }
1356     return pTemp;
1357   }
1358   return NULL;
1359 }
1360
1361 FX_BOOL Document::addIcon(IFXJS_Context* cc,
1362                           const CJS_Parameters& params,
1363                           CJS_Value& vRet,
1364                           CFX_WideString& sError) {
1365   CJS_Context* pContext = (CJS_Context*)cc;
1366   if (params.size() != 2) {
1367     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1368     return FALSE;
1369   }
1370
1371   CFX_WideString swIconName = params[0].ToCFXWideString();
1372   JSFXObject pJSIcon = params[1].ToV8Object();
1373
1374   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
1375   if (JS_GetObjDefnID(pJSIcon) != JS_GetObjDefnID(*pRuntime, L"Icon")) {
1376     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
1377     return FALSE;
1378   }
1379
1380   CJS_EmbedObj* pEmbedObj = params[1].ToCJSObject()->GetEmbedObject();
1381   if (!pEmbedObj) {
1382     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
1383     return FALSE;
1384   }
1385
1386   Icon* pIcon = (Icon*)pEmbedObj;
1387   if (!m_pIconTree)
1388     m_pIconTree = new IconTree();
1389
1390   IconElement* pNewIcon = new IconElement();
1391   pNewIcon->IconName = swIconName;
1392   pNewIcon->NextIcon = NULL;
1393   pNewIcon->IconStream = pIcon;
1394   m_pIconTree->InsertIconElement(pNewIcon);
1395   return TRUE;
1396 }
1397
1398 FX_BOOL Document::icons(IFXJS_Context* cc,
1399                         CJS_PropValue& vp,
1400                         CFX_WideString& sError) {
1401   if (vp.IsSetting()) {
1402     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1403     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1404     return FALSE;
1405   }
1406
1407   if (!m_pIconTree) {
1408     vp.SetNull();
1409     return TRUE;
1410   }
1411
1412   CJS_Array Icons(m_isolate);
1413   IconElement* pIconElement = NULL;
1414   int iIconTreeLength = m_pIconTree->GetLength();
1415
1416   CJS_Context* pContext = (CJS_Context*)cc;
1417   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
1418
1419   for (int i = 0; i < iIconTreeLength; i++) {
1420     pIconElement = (*m_pIconTree)[i];
1421
1422     JSFXObject pObj = JS_NewFxDynamicObj(*pRuntime, pContext,
1423                                          JS_GetObjDefnID(*pRuntime, L"Icon"));
1424     if (pObj.IsEmpty())
1425       return FALSE;
1426
1427     CJS_Icon* pJS_Icon = (CJS_Icon*)JS_GetPrivate(pObj);
1428     if (!pJS_Icon)
1429       return FALSE;
1430
1431     Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
1432     if (!pIcon)
1433       return FALSE;
1434
1435     pIcon->SetStream(pIconElement->IconStream->GetStream());
1436     pIcon->SetIconName(pIconElement->IconName);
1437     Icons.SetElement(i, CJS_Value(m_isolate, pJS_Icon));
1438   }
1439
1440   vp << Icons;
1441   return TRUE;
1442 }
1443
1444 FX_BOOL Document::getIcon(IFXJS_Context* cc,
1445                           const CJS_Parameters& params,
1446                           CJS_Value& vRet,
1447                           CFX_WideString& sError) {
1448   CJS_Context* pContext = (CJS_Context*)cc;
1449   if (params.size() != 1) {
1450     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1451     return FALSE;
1452   }
1453
1454   if (!m_pIconTree)
1455     return FALSE;
1456   CFX_WideString swIconName = params[0].ToCFXWideString();
1457   int iIconCounts = m_pIconTree->GetLength();
1458
1459   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
1460
1461   for (int i = 0; i < iIconCounts; i++) {
1462     if ((*m_pIconTree)[i]->IconName == swIconName) {
1463       Icon* pRetIcon = (*m_pIconTree)[i]->IconStream;
1464
1465       JSFXObject pObj = JS_NewFxDynamicObj(*pRuntime, pContext,
1466                                            JS_GetObjDefnID(*pRuntime, L"Icon"));
1467       if (pObj.IsEmpty())
1468         return FALSE;
1469
1470       CJS_Icon* pJS_Icon = (CJS_Icon*)JS_GetPrivate(pObj);
1471       if (!pJS_Icon)
1472         return FALSE;
1473
1474       Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
1475       if (!pIcon)
1476         return FALSE;
1477
1478       pIcon->SetIconName(swIconName);
1479       pIcon->SetStream(pRetIcon->GetStream());
1480       vRet = pJS_Icon;
1481       return TRUE;
1482     }
1483   }
1484
1485   return FALSE;
1486 }
1487
1488 FX_BOOL Document::removeIcon(IFXJS_Context* cc,
1489                              const CJS_Parameters& params,
1490                              CJS_Value& vRet,
1491                              CFX_WideString& sError) {
1492   // Unsafe, no supported.
1493   return TRUE;
1494 }
1495
1496 FX_BOOL Document::createDataObject(IFXJS_Context* cc,
1497                                    const CJS_Parameters& params,
1498                                    CJS_Value& vRet,
1499                                    CFX_WideString& sError) {
1500   // Unsafe, not implemented.
1501   return TRUE;
1502 }
1503
1504 FX_BOOL Document::media(IFXJS_Context* cc,
1505                         CJS_PropValue& vp,
1506                         CFX_WideString& sError) {
1507   return TRUE;
1508 }
1509
1510 FX_BOOL Document::calculateNow(IFXJS_Context* cc,
1511                                const CJS_Parameters& params,
1512                                CJS_Value& vRet,
1513                                CFX_WideString& sError) {
1514   ASSERT(m_pDocument != NULL);
1515
1516   if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) ||
1517         m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM) ||
1518         m_pDocument->GetPermissions(FPDFPERM_FILL_FORM)))
1519     return FALSE;
1520
1521   CPDFSDK_InterForm* pInterForm =
1522       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
1523   ASSERT(pInterForm != NULL);
1524   pInterForm->OnCalculate();
1525   return TRUE;
1526 }
1527
1528 FX_BOOL Document::Collab(IFXJS_Context* cc,
1529                          CJS_PropValue& vp,
1530                          CFX_WideString& sError) {
1531   return TRUE;
1532 }
1533
1534 FX_BOOL Document::getPageNthWord(IFXJS_Context* cc,
1535                                  const CJS_Parameters& params,
1536                                  CJS_Value& vRet,
1537                                  CFX_WideString& sError) {
1538   ASSERT(m_pDocument != NULL);
1539
1540   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
1541     return FALSE;
1542
1543   int nPageNo = params.GetSize() > 0 ? params[0].ToInt() : 0;
1544   int nWordNo = params.GetSize() > 1 ? params[1].ToInt() : 0;
1545   bool bStrip = params.GetSize() > 2 ? params[2].ToBool() : true;
1546
1547   CPDF_Document* pDocument = m_pDocument->GetDocument();
1548   if (!pDocument)
1549     return FALSE;
1550
1551   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1552   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
1553     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
1554     return FALSE;
1555   }
1556
1557   CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
1558   if (!pPageDict)
1559     return FALSE;
1560
1561   CPDF_Page page;
1562   page.Load(pDocument, pPageDict);
1563   page.StartParse();
1564   page.ParseContent();
1565
1566   FX_POSITION pos = page.GetFirstObjectPosition();
1567
1568   int nWords = 0;
1569
1570   CFX_WideString swRet;
1571
1572   while (pos) {
1573     if (CPDF_PageObject* pPageObj = page.GetNextObject(pos)) {
1574       if (pPageObj->m_Type == PDFPAGE_TEXT) {
1575         int nObjWords = CountWords((CPDF_TextObject*)pPageObj);
1576
1577         if (nWords + nObjWords >= nWordNo) {
1578           swRet = GetObjWordStr((CPDF_TextObject*)pPageObj, nWordNo - nWords);
1579           break;
1580         }
1581
1582         nWords += nObjWords;
1583       }
1584     }
1585   }
1586
1587   if (bStrip) {
1588     swRet.TrimLeft();
1589     swRet.TrimRight();
1590   }
1591
1592   vRet = swRet.c_str();
1593   return TRUE;
1594 }
1595
1596 FX_BOOL Document::getPageNthWordQuads(IFXJS_Context* cc,
1597                                       const CJS_Parameters& params,
1598                                       CJS_Value& vRet,
1599                                       CFX_WideString& sError) {
1600   ASSERT(m_pDocument != NULL);
1601
1602   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
1603     return FALSE;
1604
1605   return FALSE;
1606 }
1607
1608 FX_BOOL Document::getPageNumWords(IFXJS_Context* cc,
1609                                   const CJS_Parameters& params,
1610                                   CJS_Value& vRet,
1611                                   CFX_WideString& sError) {
1612   ASSERT(m_pDocument != NULL);
1613
1614   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
1615     return FALSE;
1616
1617   int nPageNo = params.GetSize() > 0 ? params[0].ToInt() : 0;
1618
1619   CPDF_Document* pDocument = m_pDocument->GetDocument();
1620   ASSERT(pDocument != NULL);
1621
1622   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1623   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
1624     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
1625     return FALSE;
1626   }
1627
1628   CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
1629   if (!pPageDict)
1630     return FALSE;
1631
1632   CPDF_Page page;
1633   page.Load(pDocument, pPageDict);
1634   page.StartParse();
1635   page.ParseContent();
1636
1637   FX_POSITION pos = page.GetFirstObjectPosition();
1638
1639   int nWords = 0;
1640
1641   while (pos) {
1642     if (CPDF_PageObject* pPageObj = page.GetNextObject(pos)) {
1643       if (pPageObj->m_Type == PDFPAGE_TEXT) {
1644         CPDF_TextObject* pTextObj = (CPDF_TextObject*)pPageObj;
1645         nWords += CountWords(pTextObj);
1646       }
1647     }
1648   }
1649
1650   vRet = nWords;
1651
1652   return TRUE;
1653 }
1654
1655 FX_BOOL Document::getPrintParams(IFXJS_Context* cc,
1656                                  const CJS_Parameters& params,
1657                                  CJS_Value& vRet,
1658                                  CFX_WideString& sError) {
1659   CJS_Context* pContext = (CJS_Context*)cc;
1660   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
1661   JSFXObject pRetObj = JS_NewFxDynamicObj(
1662       *pRuntime, pContext, JS_GetObjDefnID(*pRuntime, L"PrintParamsObj"));
1663
1664   // Not implemented yet.
1665
1666   vRet = pRetObj;
1667   return TRUE;
1668 }
1669
1670 #define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF)
1671
1672 int Document::CountWords(CPDF_TextObject* pTextObj) {
1673   if (!pTextObj)
1674     return 0;
1675
1676   int nWords = 0;
1677
1678   CPDF_Font* pFont = pTextObj->GetFont();
1679   if (!pFont)
1680     return 0;
1681
1682   FX_BOOL bIsLatin = FALSE;
1683
1684   for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
1685     FX_DWORD charcode = -1;
1686     FX_FLOAT kerning;
1687
1688     pTextObj->GetCharInfo(i, charcode, kerning);
1689     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
1690
1691     FX_WORD unicode = 0;
1692     if (swUnicode.GetLength() > 0)
1693       unicode = swUnicode[0];
1694
1695     if (ISLATINWORD(unicode) && bIsLatin)
1696       continue;
1697
1698     bIsLatin = ISLATINWORD(unicode);
1699     if (unicode != 0x20)
1700       nWords++;
1701   }
1702
1703   return nWords;
1704 }
1705
1706 CFX_WideString Document::GetObjWordStr(CPDF_TextObject* pTextObj,
1707                                        int nWordIndex) {
1708   ASSERT(pTextObj != NULL);
1709
1710   CFX_WideString swRet;
1711
1712   CPDF_Font* pFont = pTextObj->GetFont();
1713   if (!pFont)
1714     return L"";
1715
1716   int nWords = 0;
1717   FX_BOOL bIsLatin = FALSE;
1718
1719   for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
1720     FX_DWORD charcode = -1;
1721     FX_FLOAT kerning;
1722
1723     pTextObj->GetCharInfo(i, charcode, kerning);
1724     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
1725
1726     FX_WORD unicode = 0;
1727     if (swUnicode.GetLength() > 0)
1728       unicode = swUnicode[0];
1729
1730     if (ISLATINWORD(unicode) && bIsLatin) {
1731     } else {
1732       bIsLatin = ISLATINWORD(unicode);
1733       if (unicode != 0x20)
1734         nWords++;
1735     }
1736
1737     if (nWords - 1 == nWordIndex)
1738       swRet += unicode;
1739   }
1740
1741   return swRet;
1742 }
1743
1744 FX_BOOL Document::zoom(IFXJS_Context* cc,
1745                        CJS_PropValue& vp,
1746                        CFX_WideString& sError) {
1747   return TRUE;
1748 }
1749
1750 /**
1751 (none,  NoVary)
1752 (fitP,  FitPage)
1753 (fitW,  FitWidth)
1754 (fitH,  FitHeight)
1755 (fitV,  FitVisibleWidth)
1756 (pref,  Preferred)
1757 (refW,  ReflowWidth)
1758 */
1759
1760 FX_BOOL Document::zoomType(IFXJS_Context* cc,
1761                            CJS_PropValue& vp,
1762                            CFX_WideString& sError) {
1763   return TRUE;
1764 }
1765
1766 FX_BOOL Document::deletePages(IFXJS_Context* cc,
1767                               const CJS_Parameters& params,
1768                               CJS_Value& vRet,
1769                               CFX_WideString& sError) {
1770   // Unsafe, no supported.
1771   return TRUE;
1772 }
1773
1774 FX_BOOL Document::extractPages(IFXJS_Context* cc,
1775                                const CJS_Parameters& params,
1776                                CJS_Value& vRet,
1777                                CFX_WideString& sError) {
1778   // Unsafe, not supported.
1779   return TRUE;
1780 }
1781
1782 FX_BOOL Document::insertPages(IFXJS_Context* cc,
1783                               const CJS_Parameters& params,
1784                               CJS_Value& vRet,
1785                               CFX_WideString& sError) {
1786   // Unsafe, not supported.
1787   return TRUE;
1788 }
1789
1790 FX_BOOL Document::replacePages(IFXJS_Context* cc,
1791                                const CJS_Parameters& params,
1792                                CJS_Value& vRet,
1793                                CFX_WideString& sError) {
1794   // Unsafe, not supported.
1795   return TRUE;
1796 }
1797
1798 FX_BOOL Document::getURL(IFXJS_Context* cc,
1799                          const CJS_Parameters& params,
1800                          CJS_Value& vRet,
1801                          CFX_WideString& sError) {
1802   // Unsafe, not supported.
1803   return TRUE;
1804 }
1805
1806 void Document::AddDelayData(CJS_DelayData* pData) {
1807   m_DelayData.Add(pData);
1808 }
1809
1810 void Document::DoFieldDelay(const CFX_WideString& sFieldName,
1811                             int nControlIndex) {
1812   CFX_DWordArray DelArray;
1813   CFX_ArrayTemplate<CJS_DelayData*> DelayDataForFieldAndControlIndex;
1814
1815   for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) {
1816     if (CJS_DelayData* pData = m_DelayData.GetAt(i)) {
1817       if (pData->sFieldName == sFieldName &&
1818           pData->nControlIndex == nControlIndex) {
1819         DelayDataForFieldAndControlIndex.Add(pData);
1820         m_DelayData.SetAt(i, NULL);
1821         DelArray.Add(i);
1822       }
1823     }
1824   }
1825
1826   for (int j = DelArray.GetSize() - 1; j >= 0; j--) {
1827     m_DelayData.RemoveAt(DelArray[j]);
1828   }
1829
1830   for (int i = 0, sz = DelayDataForFieldAndControlIndex.GetSize(); i < sz;
1831        i++) {
1832     CJS_DelayData* pData = DelayDataForFieldAndControlIndex.GetAt(i);
1833     Field::DoDelay(m_pDocument, pData);
1834     DelayDataForFieldAndControlIndex.SetAt(i, NULL);
1835     delete pData;
1836   }
1837 }
1838
1839 void Document::AddDelayAnnotData(CJS_AnnotObj* pData) {
1840   m_DelayAnnotData.Add(pData);
1841 }
1842
1843 void Document::DoAnnotDelay() {
1844   CFX_DWordArray DelArray;
1845
1846   for (int j = DelArray.GetSize() - 1; j >= 0; j--) {
1847     m_DelayData.RemoveAt(DelArray[j]);
1848   }
1849 }
1850
1851 CJS_Document* Document::GetCJSDoc() const {
1852   return static_cast<CJS_Document*>(m_pJSObject);
1853 }