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