Clean up CPDF_AnnotList.
[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   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
789   if (!pDictionary)
790     return FALSE;
791
792   if (vp.IsGetting()) {
793     vp << pDictionary->GetUnicodeText("Author");
794     return TRUE;
795   } else {
796     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
797       return FALSE;
798
799     CFX_WideString csAuthor;
800     vp >> csAuthor;
801     pDictionary->SetAtString("Author", PDF_EncodeText(csAuthor));
802     m_pDocument->SetChangeMark();
803     return TRUE;
804   }
805 }
806
807 FX_BOOL Document::info(IJS_Context* cc,
808                        CJS_PropValue& vp,
809                        CFX_WideString& sError) {
810   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
811   if (!pDictionary)
812     return FALSE;
813
814   CFX_WideString cwAuthor = pDictionary->GetUnicodeText("Author");
815   CFX_WideString cwTitle = pDictionary->GetUnicodeText("Title");
816   CFX_WideString cwSubject = pDictionary->GetUnicodeText("Subject");
817   CFX_WideString cwKeywords = pDictionary->GetUnicodeText("Keywords");
818   CFX_WideString cwCreator = pDictionary->GetUnicodeText("Creator");
819   CFX_WideString cwProducer = pDictionary->GetUnicodeText("Producer");
820   CFX_WideString cwCreationDate = pDictionary->GetUnicodeText("CreationDate");
821   CFX_WideString cwModDate = pDictionary->GetUnicodeText("ModDate");
822   CFX_WideString cwTrapped = pDictionary->GetUnicodeText("Trapped");
823
824   v8::Isolate* isolate = GetIsolate(cc);
825   if (vp.IsGetting()) {
826     CJS_Context* pContext = (CJS_Context*)cc;
827     CJS_Runtime* pRuntime = pContext->GetJSRuntime();
828     v8::Local<v8::Object> pObj =
829         FXJS_NewFxDynamicObj(pRuntime->GetIsolate(), pRuntime, -1);
830     FXJS_PutObjectString(isolate, pObj, L"Author", cwAuthor.c_str());
831     FXJS_PutObjectString(isolate, pObj, L"Title", cwTitle.c_str());
832     FXJS_PutObjectString(isolate, pObj, L"Subject", cwSubject.c_str());
833     FXJS_PutObjectString(isolate, pObj, L"Keywords", cwKeywords.c_str());
834     FXJS_PutObjectString(isolate, pObj, L"Creator", cwCreator.c_str());
835     FXJS_PutObjectString(isolate, pObj, L"Producer", cwProducer.c_str());
836     FXJS_PutObjectString(isolate, pObj, L"CreationDate",
837                          cwCreationDate.c_str());
838     FXJS_PutObjectString(isolate, pObj, L"ModDate", cwModDate.c_str());
839     FXJS_PutObjectString(isolate, pObj, L"Trapped", cwTrapped.c_str());
840
841     // It's to be compatible to non-standard info dictionary.
842     FX_POSITION pos = pDictionary->GetStartPos();
843     while (pos) {
844       CFX_ByteString bsKey;
845       CPDF_Object* pValueObj = pDictionary->GetNextElement(pos, bsKey);
846       CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey, bsKey.GetLength());
847
848       if (pValueObj->IsString() || pValueObj->IsName()) {
849         FXJS_PutObjectString(isolate, pObj, wsKey.c_str(),
850                              pValueObj->GetUnicodeText().c_str());
851       } else if (pValueObj->IsNumber()) {
852         FXJS_PutObjectNumber(isolate, pObj, wsKey.c_str(),
853                              (float)pValueObj->GetNumber());
854       } else if (pValueObj->IsBoolean()) {
855         FXJS_PutObjectBoolean(isolate, pObj, wsKey.c_str(),
856                               (bool)pValueObj->GetInteger());
857       }
858     }
859     vp << pObj;
860   }
861   return TRUE;
862 }
863
864 FX_BOOL Document::creationDate(IJS_Context* cc,
865                                CJS_PropValue& vp,
866                                CFX_WideString& sError) {
867   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
868   if (!pDictionary)
869     return FALSE;
870
871   if (vp.IsGetting()) {
872     vp << pDictionary->GetUnicodeText("CreationDate");
873   } else {
874     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
875       return FALSE;
876
877     CFX_WideString csCreationDate;
878     vp >> csCreationDate;
879     pDictionary->SetAtString("CreationDate", PDF_EncodeText(csCreationDate));
880     m_pDocument->SetChangeMark();
881   }
882   return TRUE;
883 }
884
885 FX_BOOL Document::creator(IJS_Context* cc,
886                           CJS_PropValue& vp,
887                           CFX_WideString& sError) {
888   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
889   if (!pDictionary)
890     return FALSE;
891
892   if (vp.IsGetting()) {
893     vp << pDictionary->GetUnicodeText("Creator");
894   } else {
895     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
896       return FALSE;
897
898     CFX_WideString csCreator;
899     vp >> csCreator;
900     pDictionary->SetAtString("Creator", PDF_EncodeText(csCreator));
901     m_pDocument->SetChangeMark();
902   }
903   return TRUE;
904 }
905
906 FX_BOOL Document::delay(IJS_Context* cc,
907                         CJS_PropValue& vp,
908                         CFX_WideString& sError) {
909   if (vp.IsGetting()) {
910     vp << m_bDelay;
911   } else {
912     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
913       return FALSE;
914
915     vp >> m_bDelay;
916     if (m_bDelay) {
917       for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++)
918         delete m_DelayData.GetAt(i);
919
920       m_DelayData.RemoveAll();
921     } else {
922       CFX_ArrayTemplate<CJS_DelayData*> DelayDataToProcess;
923       for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) {
924         if (CJS_DelayData* pData = m_DelayData.GetAt(i)) {
925           DelayDataToProcess.Add(pData);
926           m_DelayData.SetAt(i, NULL);
927         }
928       }
929       m_DelayData.RemoveAll();
930       for (int i = 0, sz = DelayDataToProcess.GetSize(); i < sz; i++) {
931         CJS_DelayData* pData = DelayDataToProcess.GetAt(i);
932         Field::DoDelay(m_pDocument, pData);
933         DelayDataToProcess.SetAt(i, NULL);
934         delete pData;
935       }
936     }
937   }
938   return TRUE;
939 }
940
941 FX_BOOL Document::keywords(IJS_Context* cc,
942                            CJS_PropValue& vp,
943                            CFX_WideString& sError) {
944   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
945   if (!pDictionary)
946     return FALSE;
947
948   if (vp.IsGetting()) {
949     vp << pDictionary->GetUnicodeText("Keywords");
950   } else {
951     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
952       return FALSE;
953
954     CFX_WideString csKeywords;
955     vp >> csKeywords;
956     pDictionary->SetAtString("Keywords", PDF_EncodeText(csKeywords));
957     m_pDocument->SetChangeMark();
958   }
959   return TRUE;
960 }
961
962 FX_BOOL Document::modDate(IJS_Context* cc,
963                           CJS_PropValue& vp,
964                           CFX_WideString& sError) {
965   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
966   if (!pDictionary)
967     return FALSE;
968
969   if (vp.IsGetting()) {
970     vp << pDictionary->GetUnicodeText("ModDate");
971   } else {
972     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
973       return FALSE;
974
975     CFX_WideString csmodDate;
976     vp >> csmodDate;
977     pDictionary->SetAtString("ModDate", PDF_EncodeText(csmodDate));
978     m_pDocument->SetChangeMark();
979   }
980   return TRUE;
981 }
982
983 FX_BOOL Document::producer(IJS_Context* cc,
984                            CJS_PropValue& vp,
985                            CFX_WideString& sError) {
986   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
987   if (!pDictionary)
988     return FALSE;
989
990   if (vp.IsGetting()) {
991     vp << pDictionary->GetUnicodeText("Producer");
992   } else {
993     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
994       return FALSE;
995
996     CFX_WideString csproducer;
997     vp >> csproducer;
998     pDictionary->SetAtString("Producer", PDF_EncodeText(csproducer));
999     m_pDocument->SetChangeMark();
1000   }
1001   return TRUE;
1002 }
1003
1004 FX_BOOL Document::subject(IJS_Context* cc,
1005                           CJS_PropValue& vp,
1006                           CFX_WideString& sError) {
1007   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
1008   if (!pDictionary)
1009     return FALSE;
1010
1011   if (vp.IsGetting()) {
1012     vp << pDictionary->GetUnicodeText("Subject");
1013   } else {
1014     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
1015       return FALSE;
1016
1017     CFX_WideString cssubject;
1018     vp >> cssubject;
1019     pDictionary->SetAtString("Subject", PDF_EncodeText(cssubject));
1020     m_pDocument->SetChangeMark();
1021   }
1022   return TRUE;
1023 }
1024
1025 FX_BOOL Document::title(IJS_Context* cc,
1026                         CJS_PropValue& vp,
1027                         CFX_WideString& sError) {
1028   if (m_pDocument == NULL || m_pDocument->GetPDFDocument() == NULL)
1029     return FALSE;
1030
1031   CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo();
1032   if (!pDictionary)
1033     return FALSE;
1034
1035   if (vp.IsGetting()) {
1036     vp << pDictionary->GetUnicodeText("Title");
1037   } else {
1038     if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY))
1039       return FALSE;
1040
1041     CFX_WideString cstitle;
1042     vp >> cstitle;
1043     pDictionary->SetAtString("Title", PDF_EncodeText(cstitle));
1044     m_pDocument->SetChangeMark();
1045   }
1046   return TRUE;
1047 }
1048
1049 FX_BOOL Document::numPages(IJS_Context* cc,
1050                            CJS_PropValue& vp,
1051                            CFX_WideString& sError) {
1052   if (vp.IsSetting()) {
1053     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1054     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1055     return FALSE;
1056   }
1057   vp << m_pDocument->GetPageCount();
1058   return TRUE;
1059 }
1060
1061 FX_BOOL Document::external(IJS_Context* cc,
1062                            CJS_PropValue& vp,
1063                            CFX_WideString& sError) {
1064   // In Chrome case,should always return true.
1065   if (vp.IsGetting()) {
1066     vp << true;
1067   }
1068   return TRUE;
1069 }
1070
1071 FX_BOOL Document::filesize(IJS_Context* cc,
1072                            CJS_PropValue& vp,
1073                            CFX_WideString& sError) {
1074   if (vp.IsSetting()) {
1075     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1076     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1077     return FALSE;
1078   }
1079   vp << 0;
1080   return TRUE;
1081 }
1082
1083 FX_BOOL Document::mouseX(IJS_Context* cc,
1084                          CJS_PropValue& vp,
1085                          CFX_WideString& sError) {
1086   return TRUE;
1087 }
1088
1089 FX_BOOL Document::mouseY(IJS_Context* cc,
1090                          CJS_PropValue& vp,
1091                          CFX_WideString& sError) {
1092   return TRUE;
1093 }
1094
1095 FX_BOOL Document::baseURL(IJS_Context* cc,
1096                           CJS_PropValue& vp,
1097                           CFX_WideString& sError) {
1098   if (vp.IsGetting()) {
1099     vp << m_cwBaseURL;
1100   } else {
1101     vp >> m_cwBaseURL;
1102   }
1103   return TRUE;
1104 }
1105
1106 FX_BOOL Document::calculate(IJS_Context* cc,
1107                             CJS_PropValue& vp,
1108                             CFX_WideString& sError) {
1109   ASSERT(m_pDocument != NULL);
1110
1111   CPDFSDK_InterForm* pInterForm =
1112       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
1113   ASSERT(pInterForm != NULL);
1114
1115   if (vp.IsGetting()) {
1116     if (pInterForm->IsCalculateEnabled())
1117       vp << true;
1118     else
1119       vp << false;
1120   } else {
1121     bool bCalculate;
1122     vp >> bCalculate;
1123
1124     pInterForm->EnableCalculate(bCalculate);
1125   }
1126
1127   return TRUE;
1128 }
1129
1130 FX_BOOL Document::documentFileName(IJS_Context* cc,
1131                                    CJS_PropValue& vp,
1132                                    CFX_WideString& sError) {
1133   if (vp.IsSetting()) {
1134     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1135     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1136     return FALSE;
1137   }
1138   CFX_WideString wsFilePath = m_pDocument->GetPath();
1139   int32_t i = wsFilePath.GetLength() - 1;
1140   for (; i >= 0; i--) {
1141     if (wsFilePath.GetAt(i) == L'\\' || wsFilePath.GetAt(i) == L'/')
1142       break;
1143   }
1144   if (i >= 0 && i < wsFilePath.GetLength() - 1) {
1145     vp << (wsFilePath.GetBuffer(wsFilePath.GetLength()) + i + 1);
1146   } else {
1147     vp << L"";
1148   }
1149   return TRUE;
1150 }
1151
1152 CFX_WideString Document::ReversalStr(CFX_WideString cbFrom) {
1153   size_t iLength = cbFrom.GetLength();
1154   pdfium::base::CheckedNumeric<size_t> iSize = sizeof(wchar_t);
1155   iSize *= (iLength + 1);
1156   wchar_t* pResult = (wchar_t*)malloc(iSize.ValueOrDie());
1157   wchar_t* pFrom = (wchar_t*)cbFrom.GetBuffer(iLength);
1158
1159   for (size_t i = 0; i < iLength; i++) {
1160     pResult[i] = *(pFrom + iLength - i - 1);
1161   }
1162   pResult[iLength] = L'\0';
1163
1164   cbFrom.ReleaseBuffer();
1165   CFX_WideString cbRet = CFX_WideString(pResult);
1166   free(pResult);
1167   pResult = NULL;
1168   return cbRet;
1169 }
1170
1171 CFX_WideString Document::CutString(CFX_WideString cbFrom) {
1172   size_t iLength = cbFrom.GetLength();
1173   pdfium::base::CheckedNumeric<size_t> iSize = sizeof(wchar_t);
1174   iSize *= (iLength + 1);
1175   wchar_t* pResult = (wchar_t*)malloc(iSize.ValueOrDie());
1176   wchar_t* pFrom = (wchar_t*)cbFrom.GetBuffer(iLength);
1177
1178   for (size_t i = 0; i < iLength; i++) {
1179     if (pFrom[i] == L'\\' || pFrom[i] == L'/') {
1180       pResult[i] = L'\0';
1181       break;
1182     }
1183     pResult[i] = pFrom[i];
1184   }
1185   pResult[iLength] = L'\0';
1186
1187   cbFrom.ReleaseBuffer();
1188   CFX_WideString cbRet = CFX_WideString(pResult);
1189   free(pResult);
1190   pResult = NULL;
1191   return cbRet;
1192 }
1193
1194 FX_BOOL Document::path(IJS_Context* cc,
1195                        CJS_PropValue& vp,
1196                        CFX_WideString& sError) {
1197   if (vp.IsSetting()) {
1198     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1199     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1200     return FALSE;
1201   }
1202   vp << app::SysPathToPDFPath(m_pDocument->GetPath());
1203   return TRUE;
1204 }
1205
1206 FX_BOOL Document::pageWindowRect(IJS_Context* cc,
1207                                  CJS_PropValue& vp,
1208                                  CFX_WideString& sError) {
1209   return TRUE;
1210 }
1211
1212 FX_BOOL Document::layout(IJS_Context* cc,
1213                          CJS_PropValue& vp,
1214                          CFX_WideString& sError) {
1215   return TRUE;
1216 }
1217
1218 FX_BOOL Document::addLink(IJS_Context* cc,
1219                           const CJS_Parameters& params,
1220                           CJS_Value& vRet,
1221                           CFX_WideString& sError) {
1222   return TRUE;
1223 }
1224
1225 FX_BOOL Document::closeDoc(IJS_Context* cc,
1226                            const CJS_Parameters& params,
1227                            CJS_Value& vRet,
1228                            CFX_WideString& sError) {
1229   ASSERT(m_pDocument != NULL);
1230   return TRUE;
1231 }
1232
1233 FX_BOOL Document::getPageBox(IJS_Context* cc,
1234                              const CJS_Parameters& params,
1235                              CJS_Value& vRet,
1236                              CFX_WideString& sError) {
1237   return TRUE;
1238 }
1239
1240 FX_BOOL Document::getAnnot(IJS_Context* cc,
1241                            const CJS_Parameters& params,
1242                            CJS_Value& vRet,
1243                            CFX_WideString& sError) {
1244   return TRUE;
1245 }
1246
1247 FX_BOOL Document::getAnnots(IJS_Context* cc,
1248                             const CJS_Parameters& params,
1249                             CJS_Value& vRet,
1250                             CFX_WideString& sError) {
1251   vRet.SetNull();
1252   return TRUE;
1253 }
1254
1255 FX_BOOL Document::getAnnot3D(IJS_Context* cc,
1256                              const CJS_Parameters& params,
1257                              CJS_Value& vRet,
1258                              CFX_WideString& sError) {
1259   vRet.SetNull();
1260   return TRUE;
1261 }
1262
1263 FX_BOOL Document::getAnnots3D(IJS_Context* cc,
1264                               const CJS_Parameters& params,
1265                               CJS_Value& vRet,
1266                               CFX_WideString& sError) {
1267   vRet = CJS_Value::VT_undefined;
1268   return TRUE;
1269 }
1270
1271 FX_BOOL Document::getOCGs(IJS_Context* cc,
1272                           const CJS_Parameters& params,
1273                           CJS_Value& vRet,
1274                           CFX_WideString& sError) {
1275   return TRUE;
1276 }
1277
1278 FX_BOOL Document::getLinks(IJS_Context* cc,
1279                            const CJS_Parameters& params,
1280                            CJS_Value& vRet,
1281                            CFX_WideString& sError) {
1282   return TRUE;
1283 }
1284
1285 bool Document::IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect) {
1286   return (rect.left <= LinkRect.left && rect.top <= LinkRect.top &&
1287           rect.right >= LinkRect.right && rect.bottom >= LinkRect.bottom);
1288 }
1289
1290 void IconTree::InsertIconElement(IconElement* pNewIcon) {
1291   if (!pNewIcon)
1292     return;
1293
1294   if (m_pHead == NULL && m_pEnd == NULL) {
1295     m_pHead = m_pEnd = pNewIcon;
1296     m_iLength++;
1297   } else {
1298     m_pEnd->NextIcon = pNewIcon;
1299     m_pEnd = pNewIcon;
1300     m_iLength++;
1301   }
1302 }
1303
1304 void IconTree::DeleteIconTree() {
1305   if (!m_pHead || !m_pEnd)
1306     return;
1307
1308   IconElement* pTemp = NULL;
1309   while (m_pEnd != m_pHead) {
1310     pTemp = m_pHead;
1311     m_pHead = m_pHead->NextIcon;
1312     delete pTemp;
1313   }
1314
1315   delete m_pEnd;
1316   m_pHead = NULL;
1317   m_pEnd = NULL;
1318 }
1319
1320 int IconTree::GetLength() {
1321   return m_iLength;
1322 }
1323
1324 IconElement* IconTree::operator[](int iIndex) {
1325   if (iIndex >= 0 && iIndex <= m_iLength) {
1326     IconElement* pTemp = m_pHead;
1327     for (int i = 0; i < iIndex; i++) {
1328       pTemp = pTemp->NextIcon;
1329     }
1330     return pTemp;
1331   }
1332   return NULL;
1333 }
1334
1335 FX_BOOL Document::addIcon(IJS_Context* cc,
1336                           const CJS_Parameters& params,
1337                           CJS_Value& vRet,
1338                           CFX_WideString& sError) {
1339   CJS_Context* pContext = (CJS_Context*)cc;
1340   if (params.size() != 2) {
1341     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1342     return FALSE;
1343   }
1344   CFX_WideString swIconName = params[0].ToCFXWideString();
1345
1346   if (params[1].GetType() != CJS_Value::VT_object) {
1347     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
1348     return FALSE;
1349   }
1350
1351   v8::Local<v8::Object> pJSIcon = params[1].ToV8Object();
1352   if (FXJS_GetObjDefnID(pJSIcon) != CJS_Icon::g_nObjDefnID) {
1353     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
1354     return FALSE;
1355   }
1356
1357   CJS_EmbedObj* pEmbedObj = params[1].ToCJSObject()->GetEmbedObject();
1358   if (!pEmbedObj) {
1359     sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR);
1360     return FALSE;
1361   }
1362
1363   Icon* pIcon = (Icon*)pEmbedObj;
1364   if (!m_pIconTree)
1365     m_pIconTree = new IconTree();
1366
1367   IconElement* pNewIcon = new IconElement();
1368   pNewIcon->IconName = swIconName;
1369   pNewIcon->NextIcon = NULL;
1370   pNewIcon->IconStream = pIcon;
1371   m_pIconTree->InsertIconElement(pNewIcon);
1372   return TRUE;
1373 }
1374
1375 FX_BOOL Document::icons(IJS_Context* cc,
1376                         CJS_PropValue& vp,
1377                         CFX_WideString& sError) {
1378   if (vp.IsSetting()) {
1379     CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1380     sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY);
1381     return FALSE;
1382   }
1383
1384   if (!m_pIconTree) {
1385     vp.SetNull();
1386     return TRUE;
1387   }
1388
1389   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
1390   CJS_Array Icons(pRuntime);
1391   IconElement* pIconElement = NULL;
1392   int iIconTreeLength = m_pIconTree->GetLength();
1393   for (int i = 0; i < iIconTreeLength; i++) {
1394     pIconElement = (*m_pIconTree)[i];
1395
1396     v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
1397         pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID);
1398     if (pObj.IsEmpty())
1399       return FALSE;
1400
1401     CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(m_isolate, pObj);
1402     if (!pJS_Icon)
1403       return FALSE;
1404
1405     Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
1406     if (!pIcon)
1407       return FALSE;
1408
1409     pIcon->SetStream(pIconElement->IconStream->GetStream());
1410     pIcon->SetIconName(pIconElement->IconName);
1411     Icons.SetElement(i, CJS_Value(pRuntime, pJS_Icon));
1412   }
1413
1414   vp << Icons;
1415   return TRUE;
1416 }
1417
1418 FX_BOOL Document::getIcon(IJS_Context* cc,
1419                           const CJS_Parameters& params,
1420                           CJS_Value& vRet,
1421                           CFX_WideString& sError) {
1422   CJS_Context* pContext = (CJS_Context*)cc;
1423   if (params.size() != 1) {
1424     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1425     return FALSE;
1426   }
1427
1428   if (!m_pIconTree)
1429     return FALSE;
1430   CFX_WideString swIconName = params[0].ToCFXWideString();
1431   int iIconCounts = m_pIconTree->GetLength();
1432
1433   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
1434
1435   for (int i = 0; i < iIconCounts; i++) {
1436     if ((*m_pIconTree)[i]->IconName == swIconName) {
1437       Icon* pRetIcon = (*m_pIconTree)[i]->IconStream;
1438
1439       v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(
1440           pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID);
1441       if (pObj.IsEmpty())
1442         return FALSE;
1443
1444       CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(m_isolate, pObj);
1445       if (!pJS_Icon)
1446         return FALSE;
1447
1448       Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject();
1449       if (!pIcon)
1450         return FALSE;
1451
1452       pIcon->SetIconName(swIconName);
1453       pIcon->SetStream(pRetIcon->GetStream());
1454       vRet = pJS_Icon;
1455       return TRUE;
1456     }
1457   }
1458
1459   return FALSE;
1460 }
1461
1462 FX_BOOL Document::removeIcon(IJS_Context* cc,
1463                              const CJS_Parameters& params,
1464                              CJS_Value& vRet,
1465                              CFX_WideString& sError) {
1466   // Unsafe, no supported.
1467   return TRUE;
1468 }
1469
1470 FX_BOOL Document::createDataObject(IJS_Context* cc,
1471                                    const CJS_Parameters& params,
1472                                    CJS_Value& vRet,
1473                                    CFX_WideString& sError) {
1474   // Unsafe, not implemented.
1475   return TRUE;
1476 }
1477
1478 FX_BOOL Document::media(IJS_Context* cc,
1479                         CJS_PropValue& vp,
1480                         CFX_WideString& sError) {
1481   return TRUE;
1482 }
1483
1484 FX_BOOL Document::calculateNow(IJS_Context* cc,
1485                                const CJS_Parameters& params,
1486                                CJS_Value& vRet,
1487                                CFX_WideString& sError) {
1488   ASSERT(m_pDocument != NULL);
1489
1490   if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) ||
1491         m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM) ||
1492         m_pDocument->GetPermissions(FPDFPERM_FILL_FORM)))
1493     return FALSE;
1494
1495   CPDFSDK_InterForm* pInterForm =
1496       (CPDFSDK_InterForm*)m_pDocument->GetInterForm();
1497   ASSERT(pInterForm != NULL);
1498   pInterForm->OnCalculate();
1499   return TRUE;
1500 }
1501
1502 FX_BOOL Document::Collab(IJS_Context* cc,
1503                          CJS_PropValue& vp,
1504                          CFX_WideString& sError) {
1505   return TRUE;
1506 }
1507
1508 FX_BOOL Document::getPageNthWord(IJS_Context* cc,
1509                                  const CJS_Parameters& params,
1510                                  CJS_Value& vRet,
1511                                  CFX_WideString& sError) {
1512   ASSERT(m_pDocument != NULL);
1513
1514   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
1515     return FALSE;
1516
1517   int nPageNo = params.GetSize() > 0 ? params[0].ToInt() : 0;
1518   int nWordNo = params.GetSize() > 1 ? params[1].ToInt() : 0;
1519   bool bStrip = params.GetSize() > 2 ? params[2].ToBool() : true;
1520
1521   CPDF_Document* pDocument = m_pDocument->GetPDFDocument();
1522   if (!pDocument)
1523     return FALSE;
1524
1525   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1526   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
1527     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
1528     return FALSE;
1529   }
1530
1531   CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
1532   if (!pPageDict)
1533     return FALSE;
1534
1535   CPDF_Page page;
1536   page.Load(pDocument, pPageDict);
1537   page.StartParse();
1538   page.ParseContent();
1539
1540   FX_POSITION pos = page.GetFirstObjectPosition();
1541
1542   int nWords = 0;
1543
1544   CFX_WideString swRet;
1545
1546   while (pos) {
1547     if (CPDF_PageObject* pPageObj = page.GetNextObject(pos)) {
1548       if (pPageObj->m_Type == PDFPAGE_TEXT) {
1549         int nObjWords = CountWords((CPDF_TextObject*)pPageObj);
1550
1551         if (nWords + nObjWords >= nWordNo) {
1552           swRet = GetObjWordStr((CPDF_TextObject*)pPageObj, nWordNo - nWords);
1553           break;
1554         }
1555
1556         nWords += nObjWords;
1557       }
1558     }
1559   }
1560
1561   if (bStrip) {
1562     swRet.TrimLeft();
1563     swRet.TrimRight();
1564   }
1565
1566   vRet = swRet.c_str();
1567   return TRUE;
1568 }
1569
1570 FX_BOOL Document::getPageNthWordQuads(IJS_Context* cc,
1571                                       const CJS_Parameters& params,
1572                                       CJS_Value& vRet,
1573                                       CFX_WideString& sError) {
1574   ASSERT(m_pDocument != NULL);
1575
1576   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
1577     return FALSE;
1578
1579   return FALSE;
1580 }
1581
1582 FX_BOOL Document::getPageNumWords(IJS_Context* cc,
1583                                   const CJS_Parameters& params,
1584                                   CJS_Value& vRet,
1585                                   CFX_WideString& sError) {
1586   ASSERT(m_pDocument != NULL);
1587
1588   if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS))
1589     return FALSE;
1590
1591   int nPageNo = params.GetSize() > 0 ? params[0].ToInt() : 0;
1592
1593   CPDF_Document* pDocument = m_pDocument->GetPDFDocument();
1594   ASSERT(pDocument != NULL);
1595
1596   CJS_Context* pContext = static_cast<CJS_Context*>(cc);
1597   if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) {
1598     sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR);
1599     return FALSE;
1600   }
1601
1602   CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo);
1603   if (!pPageDict)
1604     return FALSE;
1605
1606   CPDF_Page page;
1607   page.Load(pDocument, pPageDict);
1608   page.StartParse();
1609   page.ParseContent();
1610
1611   FX_POSITION pos = page.GetFirstObjectPosition();
1612
1613   int nWords = 0;
1614
1615   while (pos) {
1616     if (CPDF_PageObject* pPageObj = page.GetNextObject(pos)) {
1617       if (pPageObj->m_Type == PDFPAGE_TEXT) {
1618         CPDF_TextObject* pTextObj = (CPDF_TextObject*)pPageObj;
1619         nWords += CountWords(pTextObj);
1620       }
1621     }
1622   }
1623
1624   vRet = nWords;
1625
1626   return TRUE;
1627 }
1628
1629 FX_BOOL Document::getPrintParams(IJS_Context* cc,
1630                                  const CJS_Parameters& params,
1631                                  CJS_Value& vRet,
1632                                  CFX_WideString& sError) {
1633   CJS_Context* pContext = (CJS_Context*)cc;
1634   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
1635   v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj(
1636       pRuntime->GetIsolate(), pRuntime, CJS_PrintParamsObj::g_nObjDefnID);
1637
1638   // Not implemented yet.
1639
1640   vRet = pRetObj;
1641   return TRUE;
1642 }
1643
1644 #define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF)
1645
1646 int Document::CountWords(CPDF_TextObject* pTextObj) {
1647   if (!pTextObj)
1648     return 0;
1649
1650   int nWords = 0;
1651
1652   CPDF_Font* pFont = pTextObj->GetFont();
1653   if (!pFont)
1654     return 0;
1655
1656   FX_BOOL bIsLatin = FALSE;
1657
1658   for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
1659     FX_DWORD charcode = -1;
1660     FX_FLOAT kerning;
1661
1662     pTextObj->GetCharInfo(i, charcode, kerning);
1663     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
1664
1665     FX_WORD unicode = 0;
1666     if (swUnicode.GetLength() > 0)
1667       unicode = swUnicode[0];
1668
1669     if (ISLATINWORD(unicode) && bIsLatin)
1670       continue;
1671
1672     bIsLatin = ISLATINWORD(unicode);
1673     if (unicode != 0x20)
1674       nWords++;
1675   }
1676
1677   return nWords;
1678 }
1679
1680 CFX_WideString Document::GetObjWordStr(CPDF_TextObject* pTextObj,
1681                                        int nWordIndex) {
1682   ASSERT(pTextObj != NULL);
1683
1684   CFX_WideString swRet;
1685
1686   CPDF_Font* pFont = pTextObj->GetFont();
1687   if (!pFont)
1688     return L"";
1689
1690   int nWords = 0;
1691   FX_BOOL bIsLatin = FALSE;
1692
1693   for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) {
1694     FX_DWORD charcode = -1;
1695     FX_FLOAT kerning;
1696
1697     pTextObj->GetCharInfo(i, charcode, kerning);
1698     CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode);
1699
1700     FX_WORD unicode = 0;
1701     if (swUnicode.GetLength() > 0)
1702       unicode = swUnicode[0];
1703
1704     if (ISLATINWORD(unicode) && bIsLatin) {
1705     } else {
1706       bIsLatin = ISLATINWORD(unicode);
1707       if (unicode != 0x20)
1708         nWords++;
1709     }
1710
1711     if (nWords - 1 == nWordIndex)
1712       swRet += unicode;
1713   }
1714
1715   return swRet;
1716 }
1717
1718 FX_BOOL Document::zoom(IJS_Context* cc,
1719                        CJS_PropValue& vp,
1720                        CFX_WideString& sError) {
1721   return TRUE;
1722 }
1723
1724 /**
1725 (none,  NoVary)
1726 (fitP,  FitPage)
1727 (fitW,  FitWidth)
1728 (fitH,  FitHeight)
1729 (fitV,  FitVisibleWidth)
1730 (pref,  Preferred)
1731 (refW,  ReflowWidth)
1732 */
1733
1734 FX_BOOL Document::zoomType(IJS_Context* cc,
1735                            CJS_PropValue& vp,
1736                            CFX_WideString& sError) {
1737   return TRUE;
1738 }
1739
1740 FX_BOOL Document::deletePages(IJS_Context* cc,
1741                               const CJS_Parameters& params,
1742                               CJS_Value& vRet,
1743                               CFX_WideString& sError) {
1744   // Unsafe, no supported.
1745   return TRUE;
1746 }
1747
1748 FX_BOOL Document::extractPages(IJS_Context* cc,
1749                                const CJS_Parameters& params,
1750                                CJS_Value& vRet,
1751                                CFX_WideString& sError) {
1752   // Unsafe, not supported.
1753   return TRUE;
1754 }
1755
1756 FX_BOOL Document::insertPages(IJS_Context* cc,
1757                               const CJS_Parameters& params,
1758                               CJS_Value& vRet,
1759                               CFX_WideString& sError) {
1760   // Unsafe, not supported.
1761   return TRUE;
1762 }
1763
1764 FX_BOOL Document::replacePages(IJS_Context* cc,
1765                                const CJS_Parameters& params,
1766                                CJS_Value& vRet,
1767                                CFX_WideString& sError) {
1768   // Unsafe, not supported.
1769   return TRUE;
1770 }
1771
1772 FX_BOOL Document::getURL(IJS_Context* cc,
1773                          const CJS_Parameters& params,
1774                          CJS_Value& vRet,
1775                          CFX_WideString& sError) {
1776   // Unsafe, not supported.
1777   return TRUE;
1778 }
1779
1780 void Document::AddDelayData(CJS_DelayData* pData) {
1781   m_DelayData.Add(pData);
1782 }
1783
1784 void Document::DoFieldDelay(const CFX_WideString& sFieldName,
1785                             int nControlIndex) {
1786   CFX_DWordArray DelArray;
1787   CFX_ArrayTemplate<CJS_DelayData*> DelayDataForFieldAndControlIndex;
1788
1789   for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) {
1790     if (CJS_DelayData* pData = m_DelayData.GetAt(i)) {
1791       if (pData->sFieldName == sFieldName &&
1792           pData->nControlIndex == nControlIndex) {
1793         DelayDataForFieldAndControlIndex.Add(pData);
1794         m_DelayData.SetAt(i, NULL);
1795         DelArray.Add(i);
1796       }
1797     }
1798   }
1799
1800   for (int j = DelArray.GetSize() - 1; j >= 0; j--) {
1801     m_DelayData.RemoveAt(DelArray[j]);
1802   }
1803
1804   for (int i = 0, sz = DelayDataForFieldAndControlIndex.GetSize(); i < sz;
1805        i++) {
1806     CJS_DelayData* pData = DelayDataForFieldAndControlIndex.GetAt(i);
1807     Field::DoDelay(m_pDocument, pData);
1808     DelayDataForFieldAndControlIndex.SetAt(i, NULL);
1809     delete pData;
1810   }
1811 }
1812
1813 void Document::AddDelayAnnotData(CJS_AnnotObj* pData) {
1814   m_DelayAnnotData.Add(pData);
1815 }
1816
1817 void Document::DoAnnotDelay() {
1818   CFX_DWordArray DelArray;
1819
1820   for (int j = DelArray.GetSize() - 1; j >= 0; j--) {
1821     m_DelayData.RemoveAt(DelArray[j]);
1822   }
1823 }
1824
1825 CJS_Document* Document::GetCJSDoc() const {
1826   return static_cast<CJS_Document*>(m_pJSObject);
1827 }