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