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