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