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