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