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