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