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