diff options
Diffstat (limited to 'fpdfsdk/javascript')
41 files changed, 16432 insertions, 0 deletions
diff --git a/fpdfsdk/javascript/Consts.cpp b/fpdfsdk/javascript/Consts.cpp new file mode 100644 index 0000000000..3fdbb40ccb --- /dev/null +++ b/fpdfsdk/javascript/Consts.cpp @@ -0,0 +1,206 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/Consts.h" + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" + +BEGIN_JS_STATIC_CONST(CJS_Border) +JS_STATIC_CONST_ENTRY_STRING(L"s", L"solid") +JS_STATIC_CONST_ENTRY_STRING(L"b", L"beveled") +JS_STATIC_CONST_ENTRY_STRING(L"d", L"dashed") +JS_STATIC_CONST_ENTRY_STRING(L"i", L"inset") +JS_STATIC_CONST_ENTRY_STRING(L"u", L"underline") +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Border, border) + +BEGIN_JS_STATIC_CONST(CJS_Display) +JS_STATIC_CONST_ENTRY_NUMBER(L"visible", 0) +JS_STATIC_CONST_ENTRY_NUMBER(L"hidden", 1) +JS_STATIC_CONST_ENTRY_NUMBER(L"noPrint", 2) +JS_STATIC_CONST_ENTRY_NUMBER(L"noView", 3) +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Display, display) + +BEGIN_JS_STATIC_CONST(CJS_Font) +JS_STATIC_CONST_ENTRY_STRING(L"Times", L"Times-Roman") +JS_STATIC_CONST_ENTRY_STRING(L"TimesB", L"Times-Bold") +JS_STATIC_CONST_ENTRY_STRING(L"TimesI", L"Times-Italic") +JS_STATIC_CONST_ENTRY_STRING(L"TimesBI", L"Times-BoldItalic") +JS_STATIC_CONST_ENTRY_STRING(L"Helv", L"Helvetica") +JS_STATIC_CONST_ENTRY_STRING(L"HelvB", L"Helvetica-Bold") +JS_STATIC_CONST_ENTRY_STRING(L"HelvI", L"Helvetica-Oblique") +JS_STATIC_CONST_ENTRY_STRING(L"HelvBI", L"Helvetica-BoldOblique") +JS_STATIC_CONST_ENTRY_STRING(L"Cour", L"Courier") +JS_STATIC_CONST_ENTRY_STRING(L"CourB", L"Courier-Bold") +JS_STATIC_CONST_ENTRY_STRING(L"CourI", L"Courier-Oblique") +JS_STATIC_CONST_ENTRY_STRING(L"CourBI", L"Courier-BoldOblique") +JS_STATIC_CONST_ENTRY_STRING(L"Symbol", L"Symbol") +JS_STATIC_CONST_ENTRY_STRING(L"ZapfD", L"ZapfDingbats") +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Font, font) + +BEGIN_JS_STATIC_CONST(CJS_Highlight) +JS_STATIC_CONST_ENTRY_STRING(L"n", L"none") +JS_STATIC_CONST_ENTRY_STRING(L"i", L"invert") +JS_STATIC_CONST_ENTRY_STRING(L"p", L"push") +JS_STATIC_CONST_ENTRY_STRING(L"o", L"outline") +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Highlight, highlight) + +BEGIN_JS_STATIC_CONST(CJS_Position) +JS_STATIC_CONST_ENTRY_NUMBER(L"textOnly", 0) +JS_STATIC_CONST_ENTRY_NUMBER(L"iconOnly", 1) +JS_STATIC_CONST_ENTRY_NUMBER(L"iconTextV", 2) +JS_STATIC_CONST_ENTRY_NUMBER(L"textIconV", 3) +JS_STATIC_CONST_ENTRY_NUMBER(L"iconTextH", 4) +JS_STATIC_CONST_ENTRY_NUMBER(L"textIconH", 5) +JS_STATIC_CONST_ENTRY_NUMBER(L"overlay", 6) +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Position, position) + +BEGIN_JS_STATIC_CONST(CJS_ScaleHow) +JS_STATIC_CONST_ENTRY_NUMBER(L"proportional", 0) +JS_STATIC_CONST_ENTRY_NUMBER(L"anamorphic", 1) +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_ScaleHow, scaleHow) + +BEGIN_JS_STATIC_CONST(CJS_ScaleWhen) +JS_STATIC_CONST_ENTRY_NUMBER(L"always", 0) +JS_STATIC_CONST_ENTRY_NUMBER(L"never", 1) +JS_STATIC_CONST_ENTRY_NUMBER(L"tooBig", 2) +JS_STATIC_CONST_ENTRY_NUMBER(L"tooSmall", 3) +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_ScaleWhen, scaleWhen) + +BEGIN_JS_STATIC_CONST(CJS_Style) +JS_STATIC_CONST_ENTRY_STRING(L"ch", L"check") +JS_STATIC_CONST_ENTRY_STRING(L"cr", L"cross") +JS_STATIC_CONST_ENTRY_STRING(L"di", L"diamond") +JS_STATIC_CONST_ENTRY_STRING(L"ci", L"circle") +JS_STATIC_CONST_ENTRY_STRING(L"st", L"star") +JS_STATIC_CONST_ENTRY_STRING(L"sq", L"square") +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Style, style) + +BEGIN_JS_STATIC_CONST(CJS_Zoomtype) +JS_STATIC_CONST_ENTRY_STRING(L"none", L"NoVary") +JS_STATIC_CONST_ENTRY_STRING(L"fitP", L"FitPage") +JS_STATIC_CONST_ENTRY_STRING(L"fitW", L"FitWidth") +JS_STATIC_CONST_ENTRY_STRING(L"fitH", L"FitHeight") +JS_STATIC_CONST_ENTRY_STRING(L"fitV", L"FitVisibleWidth") +JS_STATIC_CONST_ENTRY_STRING(L"pref", L"Preferred") +JS_STATIC_CONST_ENTRY_STRING(L"refW", L"ReflowWidth") +END_JS_STATIC_CONST() +IMPLEMENT_JS_CLASS_CONST(CJS_Zoomtype, zoomtype) + +#define GLOBAL_STRING(rt, name, value) \ + FXJS_DefineGlobalConst( \ + (rt)->GetIsolate(), (name), \ + [](const v8::FunctionCallbackInfo<v8::Value>& info) { \ + info.GetReturnValue().Set(FXJS_NewString(info.GetIsolate(), (value))); \ + }) + +void CJS_GlobalConsts::DefineJSObjects(CJS_Runtime* pRuntime) { + GLOBAL_STRING(pRuntime, L"IDS_GREATER_THAN", + L"Invalid value: must be greater than or equal to % s."); + + GLOBAL_STRING(pRuntime, L"IDS_GT_AND_LT", + L"Invalid value: must be greater than or equal to % s " + L"and less than or equal to % s."); + + GLOBAL_STRING(pRuntime, L"IDS_LESS_THAN", + L"Invalid value: must be less than or equal to % s."); + + GLOBAL_STRING(pRuntime, L"IDS_INVALID_MONTH", L"**Invalid**"); + GLOBAL_STRING( + pRuntime, L"IDS_INVALID_DATE", + L"Invalid date / time: please ensure that the date / time exists.Field"); + + GLOBAL_STRING(pRuntime, L"IDS_INVALID_VALUE", + L"The value entered does not match the format of the field"); + + GLOBAL_STRING(pRuntime, L"IDS_AM", L"am"); + GLOBAL_STRING(pRuntime, L"IDS_PM", L"pm"); + GLOBAL_STRING(pRuntime, L"IDS_MONTH_INFO", + L"January[1] February[2] March[3] April[4] May[5] " + L"June[6] July[7] August[8] September[9] October[10] " + L"November[11] December[12] Sept[9] Jan[1] Feb[2] Mar[3] " + L"Apr[4] Jun[6] Jul[7] Aug[8] Sep[9] Oct[10] Nov[11] " + L"Dec[12]"); + + GLOBAL_STRING(pRuntime, L"IDS_STARTUP_CONSOLE_MSG", L"** ^ _ ^ **"); +} + +#define GLOBAL_ARRAY(rt, name, ...) \ + { \ + const FX_WCHAR* values[] = {__VA_ARGS__}; \ + v8::Local<v8::Array> array = FXJS_NewArray((rt)->GetIsolate()); \ + for (size_t i = 0; i < FX_ArraySize(values); ++i) \ + array->Set(i, FXJS_NewString((rt)->GetIsolate(), values[i])); \ + rt->SetConstArray(name, array); \ + FXJS_DefineGlobalConst( \ + (rt)->GetIsolate(), (name), \ + [](const v8::FunctionCallbackInfo<v8::Value>& info) { \ + CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>( \ + FXJS_GetRuntimeFromIsolate(info.GetIsolate())); \ + if (pRuntime) \ + info.GetReturnValue().Set(pRuntime->GetConstArray(name)); \ + }); \ + } + +void CJS_GlobalArrays::DefineJSObjects(CJS_Runtime* pRuntime) { + GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_ENTRY_DOT_SEP", L"[+-]?\\d*\\.?\\d*"); + GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_COMMIT_DOT_SEP", + L"[+-]?\\d+(\\.\\d+)?", // -1.0 or -1 + L"[+-]?\\.\\d+", // -.1 + L"[+-]?\\d+\\."); // -1. + + GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_ENTRY_COMMA_SEP", L"[+-]?\\d*,?\\d*"); + GLOBAL_ARRAY(pRuntime, L"RE_NUMBER_COMMIT_COMMA_SEP", + L"[+-]?\\d+([.,]\\d+)?", // -1,0 or -1 + L"[+-]?[.,]\\d+", // -,1 + L"[+-]?\\d+[.,]"); // -1, + + GLOBAL_ARRAY(pRuntime, L"RE_ZIP_ENTRY", L"\\d{0,5}"); + GLOBAL_ARRAY(pRuntime, L"RE_ZIP_COMMIT", L"\\d{5}"); + GLOBAL_ARRAY(pRuntime, L"RE_ZIP4_ENTRY", L"\\d{0,5}(\\.|[- ])?\\d{0,4}"); + GLOBAL_ARRAY(pRuntime, L"RE_ZIP4_COMMIT", L"\\d{5}(\\.|[- ])?\\d{4}"); + GLOBAL_ARRAY(pRuntime, L"RE_PHONE_ENTRY", + // 555-1234 or 408 555-1234 + L"\\d{0,3}(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}", + + // (408 + L"\\(\\d{0,3}", + + // (408) 555-1234 + // (allow the addition of parens as an afterthought) + L"\\(\\d{0,3}\\)(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}", + + // (408 555-1234 + L"\\(\\d{0,3}(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}", + + // 408) 555-1234 + L"\\d{0,3}\\)(\\.|[- ])?\\d{0,3}(\\.|[- ])?\\d{0,4}", + + // international + L"011(\\.|[- \\d])*"); + + GLOBAL_ARRAY( + pRuntime, L"RE_PHONE_COMMIT", L"\\d{3}(\\.|[- ])?\\d{4}", // 555-1234 + L"\\d{3}(\\.|[- ])?\\d{3}(\\.|[- ])?\\d{4}", // 408 555-1234 + L"\\(\\d{3}\\)(\\.|[- ])?\\d{3}(\\.|[- ])?\\d{4}", // (408) 555-1234 + L"011(\\.|[- \\d])*"); // international + + GLOBAL_ARRAY(pRuntime, L"RE_SSN_ENTRY", + L"\\d{0,3}(\\.|[- ])?\\d{0,2}(\\.|[- ])?\\d{0,4}"); + + GLOBAL_ARRAY(pRuntime, L"RE_SSN_COMMIT", + L"\\d{3}(\\.|[- ])?\\d{2}(\\.|[- ])?\\d{4}"); +} diff --git a/fpdfsdk/javascript/Consts.h b/fpdfsdk/javascript/Consts.h new file mode 100644 index 0000000000..165e91ffaa --- /dev/null +++ b/fpdfsdk/javascript/Consts.h @@ -0,0 +1,116 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_CONSTS_H_ +#define FPDFSDK_JAVASCRIPT_CONSTS_H_ + +#include "fpdfsdk/javascript/JS_Define.h" + +/* ------------------------------ border ------------------------------ */ + +class CJS_Border : public CJS_Object { + public: + explicit CJS_Border(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Border() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ display ------------------------------ */ + +class CJS_Display : public CJS_Object { + public: + explicit CJS_Display(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Display() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ font ------------------------------ */ + +class CJS_Font : public CJS_Object { + public: + explicit CJS_Font(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Font() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ highlight ------------------------------ */ + +class CJS_Highlight : public CJS_Object { + public: + explicit CJS_Highlight(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Highlight() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ position ------------------------------ */ + +class CJS_Position : public CJS_Object { + public: + explicit CJS_Position(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Position() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ scaleHow ------------------------------ */ + +class CJS_ScaleHow : public CJS_Object { + public: + explicit CJS_ScaleHow(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_ScaleHow() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ scaleWhen ------------------------------ */ + +class CJS_ScaleWhen : public CJS_Object { + public: + explicit CJS_ScaleWhen(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_ScaleWhen() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ style ------------------------------ */ + +class CJS_Style : public CJS_Object { + public: + explicit CJS_Style(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Style() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ zoomtype ------------------------------ */ + +class CJS_Zoomtype : public CJS_Object { + public: + explicit CJS_Zoomtype(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Zoomtype() override {} + + DECLARE_JS_CLASS_CONST(); +}; + +/* ------------------------------ CJS_GlobalConsts -------------------------- */ + +class CJS_GlobalConsts : public CJS_Object { + public: + static void DefineJSObjects(CJS_Runtime* pRuntime); +}; + +/* ------------------------------ CJS_GlobalArrays -------------------------- */ + +class CJS_GlobalArrays : public CJS_Object { + public: + static void DefineJSObjects(CJS_Runtime* pRuntmie); +}; + +#endif // FPDFSDK_JAVASCRIPT_CONSTS_H_ diff --git a/fpdfsdk/javascript/Document.cpp b/fpdfsdk/javascript/Document.cpp new file mode 100644 index 0000000000..032ca5467e --- /dev/null +++ b/fpdfsdk/javascript/Document.cpp @@ -0,0 +1,1633 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/Document.h" + +#include <vector> + +#include "core/include/fpdfapi/cpdf_document.h" +#include "fpdfsdk/include/fsdk_mgr.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Field.h" +#include "fpdfsdk/javascript/Icon.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/app.h" +#include "fpdfsdk/javascript/resource.h" +#include "third_party/base/numerics/safe_math.h" + +static v8::Isolate* GetIsolate(IJS_Context* cc) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + return pRuntime->GetIsolate(); +} + +BEGIN_JS_STATIC_CONST(CJS_PrintParamsObj) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_PrintParamsObj) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_PrintParamsObj) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_PrintParamsObj, PrintParamsObj) + +PrintParamsObj::PrintParamsObj(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject) { + bUI = TRUE; + nStart = 0; + nEnd = 0; + bSilent = FALSE; + bShrinkToFit = FALSE; + bPrintAsImage = FALSE; + bReverse = FALSE; + bAnnotations = TRUE; +} + +/* ---------------------- Document ---------------------- */ + +#define MINWIDTH 5.0f +#define MINHEIGHT 5.0f + +BEGIN_JS_STATIC_CONST(CJS_Document) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Document) +JS_STATIC_PROP_ENTRY(ADBE) +JS_STATIC_PROP_ENTRY(author) +JS_STATIC_PROP_ENTRY(baseURL) +JS_STATIC_PROP_ENTRY(bookmarkRoot) +JS_STATIC_PROP_ENTRY(calculate) +JS_STATIC_PROP_ENTRY(Collab) +JS_STATIC_PROP_ENTRY(creationDate) +JS_STATIC_PROP_ENTRY(creator) +JS_STATIC_PROP_ENTRY(delay) +JS_STATIC_PROP_ENTRY(dirty) +JS_STATIC_PROP_ENTRY(documentFileName) +JS_STATIC_PROP_ENTRY(external) +JS_STATIC_PROP_ENTRY(filesize) +JS_STATIC_PROP_ENTRY(icons) +JS_STATIC_PROP_ENTRY(info) +JS_STATIC_PROP_ENTRY(keywords) +JS_STATIC_PROP_ENTRY(layout) +JS_STATIC_PROP_ENTRY(media) +JS_STATIC_PROP_ENTRY(modDate) +JS_STATIC_PROP_ENTRY(mouseX) +JS_STATIC_PROP_ENTRY(mouseY) +JS_STATIC_PROP_ENTRY(numFields) +JS_STATIC_PROP_ENTRY(numPages) +JS_STATIC_PROP_ENTRY(pageNum) +JS_STATIC_PROP_ENTRY(pageWindowRect) +JS_STATIC_PROP_ENTRY(path) +JS_STATIC_PROP_ENTRY(producer) +JS_STATIC_PROP_ENTRY(subject) +JS_STATIC_PROP_ENTRY(title) +JS_STATIC_PROP_ENTRY(zoom) +JS_STATIC_PROP_ENTRY(zoomType) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Document) +JS_STATIC_METHOD_ENTRY(addAnnot) +JS_STATIC_METHOD_ENTRY(addField) +JS_STATIC_METHOD_ENTRY(addLink) +JS_STATIC_METHOD_ENTRY(addIcon) +JS_STATIC_METHOD_ENTRY(calculateNow) +JS_STATIC_METHOD_ENTRY(closeDoc) +JS_STATIC_METHOD_ENTRY(createDataObject) +JS_STATIC_METHOD_ENTRY(deletePages) +JS_STATIC_METHOD_ENTRY(exportAsText) +JS_STATIC_METHOD_ENTRY(exportAsFDF) +JS_STATIC_METHOD_ENTRY(exportAsXFDF) +JS_STATIC_METHOD_ENTRY(extractPages) +JS_STATIC_METHOD_ENTRY(getAnnot) +JS_STATIC_METHOD_ENTRY(getAnnots) +JS_STATIC_METHOD_ENTRY(getAnnot3D) +JS_STATIC_METHOD_ENTRY(getAnnots3D) +JS_STATIC_METHOD_ENTRY(getField) +JS_STATIC_METHOD_ENTRY(getIcon) +JS_STATIC_METHOD_ENTRY(getLinks) +JS_STATIC_METHOD_ENTRY(getNthFieldName) +JS_STATIC_METHOD_ENTRY(getOCGs) +JS_STATIC_METHOD_ENTRY(getPageBox) +JS_STATIC_METHOD_ENTRY(getPageNthWord) +JS_STATIC_METHOD_ENTRY(getPageNthWordQuads) +JS_STATIC_METHOD_ENTRY(getPageNumWords) +JS_STATIC_METHOD_ENTRY(getPrintParams) +JS_STATIC_METHOD_ENTRY(getURL) +JS_STATIC_METHOD_ENTRY(importAnFDF) +JS_STATIC_METHOD_ENTRY(importAnXFDF) +JS_STATIC_METHOD_ENTRY(importTextData) +JS_STATIC_METHOD_ENTRY(insertPages) +JS_STATIC_METHOD_ENTRY(mailForm) +JS_STATIC_METHOD_ENTRY(print) +JS_STATIC_METHOD_ENTRY(removeField) +JS_STATIC_METHOD_ENTRY(replacePages) +JS_STATIC_METHOD_ENTRY(resetForm) +JS_STATIC_METHOD_ENTRY(removeIcon) +JS_STATIC_METHOD_ENTRY(saveAs) +JS_STATIC_METHOD_ENTRY(submitForm) +JS_STATIC_METHOD_ENTRY(mailDoc) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Document, Document) + +void CJS_Document::InitInstance(IJS_Runtime* pIRuntime) { + CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime); + Document* pDoc = static_cast<Document*>(GetEmbedObject()); + pDoc->AttachDoc(pRuntime->GetReaderDocument()); + pDoc->SetIsolate(pRuntime->GetIsolate()); +} + +/* --------------------------------- Document --------------------------------- + */ + +Document::Document(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject), + m_isolate(NULL), + m_pDocument(NULL), + m_cwBaseURL(L""), + m_bDelay(FALSE) {} + +Document::~Document() { + for (int i = 0; i < m_DelayData.GetSize(); i++) { + delete m_DelayData.GetAt(i); + } + + m_DelayData.RemoveAll(); +} + +// the total number of fileds in document. +FX_BOOL Document::numFields(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY); + return FALSE; + } + CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm(); + CPDF_InterForm* pPDFForm = pInterForm->GetInterForm(); + vp << (int)pPDFForm->CountFields(); + return TRUE; +} + +FX_BOOL Document::dirty(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + if (m_pDocument->GetChangeMark()) + vp << true; + else + vp << false; + } else { + bool bChanged = false; + + vp >> bChanged; + + if (bChanged) + m_pDocument->SetChangeMark(); + else + m_pDocument->ClearChangeMark(); + } + + return TRUE; +} + +FX_BOOL Document::ADBE(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp.SetNull(); + } else { + } + + return TRUE; +} + +FX_BOOL Document::pageNum(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + if (CPDFSDK_PageView* pPageView = m_pDocument->GetCurrentView()) { + vp << pPageView->GetPageIndex(); + } + } else { + int iPageCount = m_pDocument->GetPageCount(); + int iPageNum = 0; + vp >> iPageNum; + + CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); + if (iPageNum >= 0 && iPageNum < iPageCount) { + pEnv->JS_docgotoPage(iPageNum); + } else if (iPageNum >= iPageCount) { + pEnv->JS_docgotoPage(iPageCount - 1); + } else if (iPageNum < 0) { + pEnv->JS_docgotoPage(0); + } + } + + return TRUE; +} + +FX_BOOL Document::addAnnot(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Not supported. + return TRUE; +} + +FX_BOOL Document::addField(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Not supported. + return TRUE; +} + +FX_BOOL Document::exportAsText(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::exportAsFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::exportAsXFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +// Maps a field object in PDF document to a JavaScript variable +// comment: +// note: the paremter cName, this is clue how to treat if the cName is not a +// valiable filed name in this document + +FX_BOOL Document::getField(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() < 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CFX_WideString wideName = params[0].ToCFXWideString(); + + CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm(); + CPDF_InterForm* pPDFForm = pInterForm->GetInterForm(); + if (pPDFForm->CountFields(wideName) <= 0) { + vRet.SetNull(); + return TRUE; + } + + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + v8::Local<v8::Object> pFieldObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID); + + v8::Isolate* isolate = GetIsolate(cc); + CJS_Field* pJSField = (CJS_Field*)FXJS_GetPrivate(isolate, pFieldObj); + Field* pField = (Field*)pJSField->GetEmbedObject(); + pField->AttachField(this, wideName); + + vRet = pJSField; + return TRUE; +} + +// Gets the name of the nth field in the document +FX_BOOL Document::getNthFieldName(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + int nIndex = params[0].ToInt(); + if (nIndex < 0) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR); + return FALSE; + } + + CPDFSDK_InterForm* pInterForm = m_pDocument->GetInterForm(); + CPDF_InterForm* pPDFForm = pInterForm->GetInterForm(); + CPDF_FormField* pField = pPDFForm->GetField(nIndex); + if (!pField) + return FALSE; + + vRet = pField->GetFullName().c_str(); + return TRUE; +} + +FX_BOOL Document::importAnFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::importAnXFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::importTextData(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +// exports the form data and mails the resulting fdf file as an attachment to +// all recipients. +// comment: need reader supports +// note: +// int CPDFSDK_Document::mailForm(FX_BOOL bUI,String cto,string ccc,string +// cbcc,string cSubject,string cms); + +FX_BOOL Document::mailForm(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) + return FALSE; + + int iLength = params.size(); + + FX_BOOL bUI = iLength > 0 ? params[0].ToBool() : TRUE; + CFX_WideString cTo = iLength > 1 ? params[1].ToCFXWideString() : L""; + CFX_WideString cCc = iLength > 2 ? params[2].ToCFXWideString() : L""; + CFX_WideString cBcc = iLength > 3 ? params[3].ToCFXWideString() : L""; + CFX_WideString cSubject = iLength > 4 ? params[4].ToCFXWideString() : L""; + CFX_WideString cMsg = iLength > 5 ? params[5].ToCFXWideString() : L""; + + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CFX_ByteTextBuf textBuf; + if (!pInterForm->ExportFormToFDFTextBuf(textBuf)) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CPDFDoc_Environment* pEnv = pContext->GetReaderApp(); + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + + pRuntime->BeginBlock(); + pEnv->JS_docmailForm(textBuf.GetBuffer(), textBuf.GetLength(), bUI, + cTo.c_str(), cSubject.c_str(), cCc.c_str(), cBcc.c_str(), + cMsg.c_str()); + pRuntime->EndBlock(); + return TRUE; +} + +FX_BOOL Document::print(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + FX_BOOL bUI = TRUE; + int nStart = 0; + int nEnd = 0; + FX_BOOL bSilent = FALSE; + FX_BOOL bShrinkToFit = FALSE; + FX_BOOL bPrintAsImage = FALSE; + FX_BOOL bReverse = FALSE; + FX_BOOL bAnnotations = FALSE; + + int nlength = params.size(); + if (nlength == 9) { + if (params[8].GetType() == CJS_Value::VT_fxobject) { + v8::Local<v8::Object> pObj = params[8].ToV8Object(); + { + if (FXJS_GetObjDefnID(pObj) == CJS_PrintParamsObj::g_nObjDefnID) { + if (CJS_Object* pJSObj = params[8].ToCJSObject()) { + if (PrintParamsObj* pprintparamsObj = + (PrintParamsObj*)pJSObj->GetEmbedObject()) { + bUI = pprintparamsObj->bUI; + nStart = pprintparamsObj->nStart; + nEnd = pprintparamsObj->nEnd; + bSilent = pprintparamsObj->bSilent; + bShrinkToFit = pprintparamsObj->bShrinkToFit; + bPrintAsImage = pprintparamsObj->bPrintAsImage; + bReverse = pprintparamsObj->bReverse; + bAnnotations = pprintparamsObj->bAnnotations; + } + } + } + } + } + } else { + if (nlength >= 1) + bUI = params[0].ToBool(); + if (nlength >= 2) + nStart = params[1].ToInt(); + if (nlength >= 3) + nEnd = params[2].ToInt(); + if (nlength >= 4) + bSilent = params[3].ToBool(); + if (nlength >= 5) + bShrinkToFit = params[4].ToBool(); + if (nlength >= 6) + bPrintAsImage = params[5].ToBool(); + if (nlength >= 7) + bReverse = params[6].ToBool(); + if (nlength >= 8) + bAnnotations = params[7].ToBool(); + } + + if (CPDFDoc_Environment* pEnv = m_pDocument->GetEnv()) { + pEnv->JS_docprint(bUI, nStart, nEnd, bSilent, bShrinkToFit, bPrintAsImage, + bReverse, bAnnotations); + return TRUE; + } + return FALSE; +} + +// removes the specified field from the document. +// comment: +// note: if the filed name is not retional, adobe is dumb for it. + +FX_BOOL Document::removeField(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) || + m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM))) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CFX_WideString sFieldName = params[0].ToCFXWideString(); + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + + std::vector<CPDFSDK_Widget*> widgets; + pInterForm->GetWidgets(sFieldName, &widgets); + + if (widgets.empty()) + return TRUE; + + for (CPDFSDK_Widget* pWidget : widgets) { + CFX_FloatRect rcAnnot = pWidget->GetRect(); + --rcAnnot.left; + --rcAnnot.bottom; + ++rcAnnot.right; + ++rcAnnot.top; + + CFX_RectArray aRefresh; + aRefresh.Add(rcAnnot); + + UnderlyingPageType* pPage = pWidget->GetUnderlyingPage(); + ASSERT(pPage); + + CPDFSDK_PageView* pPageView = m_pDocument->GetPageView(pPage); + pPageView->DeleteAnnot(pWidget); + pPageView->UpdateRects(aRefresh); + } + m_pDocument->SetChangeMark(); + + return TRUE; +} + +// reset filed values within a document. +// comment: +// note: if the fields names r not rational, aodbe is dumb for it. + +FX_BOOL Document::resetForm(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) || + m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM) || + m_pDocument->GetPermissions(FPDFPERM_FILL_FORM))) + return FALSE; + + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CPDF_InterForm* pPDFForm = pInterForm->GetInterForm(); + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array aName(pRuntime); + + if (params.empty()) { + pPDFForm->ResetForm(TRUE); + m_pDocument->SetChangeMark(); + return TRUE; + } + + switch (params[0].GetType()) { + default: + aName.Attach(params[0].ToV8Array()); + break; + case CJS_Value::VT_string: + aName.SetElement(0, params[0]); + break; + } + + std::vector<CPDF_FormField*> aFields; + for (int i = 0, isz = aName.GetLength(); i < isz; ++i) { + CJS_Value valElement(pRuntime); + aName.GetElement(i, valElement); + CFX_WideString swVal = valElement.ToCFXWideString(); + for (int j = 0, jsz = pPDFForm->CountFields(swVal); j < jsz; ++j) + aFields.push_back(pPDFForm->GetField(j, swVal)); + } + + if (!aFields.empty()) { + pPDFForm->ResetForm(aFields, TRUE, TRUE); + m_pDocument->SetChangeMark(); + } + + return TRUE; +} + +FX_BOOL Document::saveAs(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::submitForm(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + int nSize = params.size(); + if (nSize < 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + v8::Isolate* isolate = pRuntime->GetIsolate(); + CJS_Array aFields(pRuntime); + CFX_WideString strURL; + FX_BOOL bFDF = TRUE; + FX_BOOL bEmpty = FALSE; + + CJS_Value v = params[0]; + if (v.GetType() == CJS_Value::VT_string) { + strURL = params[0].ToCFXWideString(); + if (nSize > 1) + bFDF = params[1].ToBool(); + if (nSize > 2) + bEmpty = params[2].ToBool(); + if (nSize > 3) + aFields.Attach(params[3].ToV8Array()); + } else if (v.GetType() == CJS_Value::VT_object) { + v8::Local<v8::Object> pObj = params[0].ToV8Object(); + v8::Local<v8::Value> pValue = FXJS_GetObjectElement(isolate, pObj, L"cURL"); + if (!pValue.IsEmpty()) + strURL = + CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"bFDF"); + bFDF = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToBool(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"bEmpty"); + bEmpty = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToBool(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"aFields"); + aFields.Attach( + CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToV8Array()); + } + + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm(); + if (aFields.GetLength() == 0 && bEmpty) { + if (pPDFInterForm->CheckRequiredFields(nullptr, true)) { + pRuntime->BeginBlock(); + pInterForm->SubmitForm(strURL, FALSE); + pRuntime->EndBlock(); + } + return TRUE; + } + + std::vector<CPDF_FormField*> fieldObjects; + for (int i = 0, sz = aFields.GetLength(); i < sz; ++i) { + CJS_Value valName(pRuntime); + aFields.GetElement(i, valName); + + CFX_WideString sName = valName.ToCFXWideString(); + CPDF_InterForm* pPDFForm = pInterForm->GetInterForm(); + for (int j = 0, jsz = pPDFForm->CountFields(sName); j < jsz; ++j) { + CPDF_FormField* pField = pPDFForm->GetField(j, sName); + if (!bEmpty && pField->GetValue().IsEmpty()) + continue; + + fieldObjects.push_back(pField); + } + } + + if (pPDFInterForm->CheckRequiredFields(&fieldObjects, true)) { + pRuntime->BeginBlock(); + pInterForm->SubmitFields(strURL, fieldObjects, true, !bFDF); + pRuntime->EndBlock(); + } + return TRUE; +} + +void Document::AttachDoc(CPDFSDK_Document* pDoc) { + m_pDocument = pDoc; +} + +CPDFSDK_Document* Document::GetReaderDoc() { + return m_pDocument; +} + +FX_BOOL Document::bookmarkRoot(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::mailDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + FX_BOOL bUI = TRUE; + CFX_WideString cTo = L""; + CFX_WideString cCc = L""; + CFX_WideString cBcc = L""; + CFX_WideString cSubject = L""; + CFX_WideString cMsg = L""; + + if (params.size() >= 1) + bUI = params[0].ToBool(); + if (params.size() >= 2) + cTo = params[1].ToCFXWideString(); + if (params.size() >= 3) + cCc = params[2].ToCFXWideString(); + if (params.size() >= 4) + cBcc = params[3].ToCFXWideString(); + if (params.size() >= 5) + cSubject = params[4].ToCFXWideString(); + if (params.size() >= 6) + cMsg = params[5].ToCFXWideString(); + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + v8::Isolate* isolate = pRuntime->GetIsolate(); + + if (params.size() >= 1 && params[0].GetType() == CJS_Value::VT_object) { + v8::Local<v8::Object> pObj = params[0].ToV8Object(); + + v8::Local<v8::Value> pValue = FXJS_GetObjectElement(isolate, pObj, L"bUI"); + bUI = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToInt(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"cTo"); + cTo = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"cCc"); + cCc = CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"cBcc"); + cBcc = + CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"cSubject"); + cSubject = + CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString(); + + pValue = FXJS_GetObjectElement(isolate, pObj, L"cMsg"); + cMsg = + CJS_Value(pRuntime, pValue, GET_VALUE_TYPE(pValue)).ToCFXWideString(); + } + + pRuntime->BeginBlock(); + CPDFDoc_Environment* pEnv = pRuntime->GetReaderApp(); + pEnv->JS_docmailForm(NULL, 0, bUI, cTo.c_str(), cSubject.c_str(), cCc.c_str(), + cBcc.c_str(), cMsg.c_str()); + pRuntime->EndBlock(); + + return TRUE; +} + +FX_BOOL Document::author(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("Author"); + return TRUE; + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString csAuthor; + vp >> csAuthor; + pDictionary->SetAtString("Author", PDF_EncodeText(csAuthor)); + m_pDocument->SetChangeMark(); + return TRUE; + } +} + +FX_BOOL Document::info(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + CFX_WideString cwAuthor = pDictionary->GetUnicodeTextBy("Author"); + CFX_WideString cwTitle = pDictionary->GetUnicodeTextBy("Title"); + CFX_WideString cwSubject = pDictionary->GetUnicodeTextBy("Subject"); + CFX_WideString cwKeywords = pDictionary->GetUnicodeTextBy("Keywords"); + CFX_WideString cwCreator = pDictionary->GetUnicodeTextBy("Creator"); + CFX_WideString cwProducer = pDictionary->GetUnicodeTextBy("Producer"); + CFX_WideString cwCreationDate = pDictionary->GetUnicodeTextBy("CreationDate"); + CFX_WideString cwModDate = pDictionary->GetUnicodeTextBy("ModDate"); + CFX_WideString cwTrapped = pDictionary->GetUnicodeTextBy("Trapped"); + + v8::Isolate* isolate = GetIsolate(cc); + if (vp.IsGetting()) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + v8::Local<v8::Object> pObj = + FXJS_NewFxDynamicObj(pRuntime->GetIsolate(), pRuntime, -1); + FXJS_PutObjectString(isolate, pObj, L"Author", cwAuthor.c_str()); + FXJS_PutObjectString(isolate, pObj, L"Title", cwTitle.c_str()); + FXJS_PutObjectString(isolate, pObj, L"Subject", cwSubject.c_str()); + FXJS_PutObjectString(isolate, pObj, L"Keywords", cwKeywords.c_str()); + FXJS_PutObjectString(isolate, pObj, L"Creator", cwCreator.c_str()); + FXJS_PutObjectString(isolate, pObj, L"Producer", cwProducer.c_str()); + FXJS_PutObjectString(isolate, pObj, L"CreationDate", + cwCreationDate.c_str()); + FXJS_PutObjectString(isolate, pObj, L"ModDate", cwModDate.c_str()); + FXJS_PutObjectString(isolate, pObj, L"Trapped", cwTrapped.c_str()); + + // It's to be compatible to non-standard info dictionary. + for (const auto& it : *pDictionary) { + const CFX_ByteString& bsKey = it.first; + CPDF_Object* pValueObj = it.second; + CFX_WideString wsKey = CFX_WideString::FromUTF8(bsKey, bsKey.GetLength()); + + if (pValueObj->IsString() || pValueObj->IsName()) { + FXJS_PutObjectString(isolate, pObj, wsKey.c_str(), + pValueObj->GetUnicodeText().c_str()); + } else if (pValueObj->IsNumber()) { + FXJS_PutObjectNumber(isolate, pObj, wsKey.c_str(), + (float)pValueObj->GetNumber()); + } else if (pValueObj->IsBoolean()) { + FXJS_PutObjectBoolean(isolate, pObj, wsKey.c_str(), + !!pValueObj->GetInteger()); + } + } + vp << pObj; + } + return TRUE; +} + +FX_BOOL Document::creationDate(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("CreationDate"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString csCreationDate; + vp >> csCreationDate; + pDictionary->SetAtString("CreationDate", PDF_EncodeText(csCreationDate)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::creator(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("Creator"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString csCreator; + vp >> csCreator; + pDictionary->SetAtString("Creator", PDF_EncodeText(csCreator)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::delay(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp << m_bDelay; + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + vp >> m_bDelay; + if (m_bDelay) { + for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) + delete m_DelayData.GetAt(i); + + m_DelayData.RemoveAll(); + } else { + CFX_ArrayTemplate<CJS_DelayData*> DelayDataToProcess; + for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) { + if (CJS_DelayData* pData = m_DelayData.GetAt(i)) { + DelayDataToProcess.Add(pData); + m_DelayData.SetAt(i, NULL); + } + } + m_DelayData.RemoveAll(); + for (int i = 0, sz = DelayDataToProcess.GetSize(); i < sz; i++) { + CJS_DelayData* pData = DelayDataToProcess.GetAt(i); + Field::DoDelay(m_pDocument, pData); + DelayDataToProcess.SetAt(i, NULL); + delete pData; + } + } + } + return TRUE; +} + +FX_BOOL Document::keywords(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("Keywords"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString csKeywords; + vp >> csKeywords; + pDictionary->SetAtString("Keywords", PDF_EncodeText(csKeywords)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::modDate(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("ModDate"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString csmodDate; + vp >> csmodDate; + pDictionary->SetAtString("ModDate", PDF_EncodeText(csmodDate)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::producer(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("Producer"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString csproducer; + vp >> csproducer; + pDictionary->SetAtString("Producer", PDF_EncodeText(csproducer)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::subject(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("Subject"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString cssubject; + vp >> cssubject; + pDictionary->SetAtString("Subject", PDF_EncodeText(cssubject)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::title(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!m_pDocument || !m_pDocument->GetUnderlyingDocument()) + return FALSE; + + CPDF_Dictionary* pDictionary = m_pDocument->GetPDFDocument()->GetInfo(); + if (!pDictionary) + return FALSE; + + if (vp.IsGetting()) { + vp << pDictionary->GetUnicodeTextBy("Title"); + } else { + if (!m_pDocument->GetPermissions(FPDFPERM_MODIFY)) + return FALSE; + + CFX_WideString cstitle; + vp >> cstitle; + pDictionary->SetAtString("Title", PDF_EncodeText(cstitle)); + m_pDocument->SetChangeMark(); + } + return TRUE; +} + +FX_BOOL Document::numPages(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY); + return FALSE; + } + vp << m_pDocument->GetPageCount(); + return TRUE; +} + +FX_BOOL Document::external(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + // In Chrome case,should always return true. + if (vp.IsGetting()) { + vp << true; + } + return TRUE; +} + +FX_BOOL Document::filesize(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY); + return FALSE; + } + vp << 0; + return TRUE; +} + +FX_BOOL Document::mouseX(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::mouseY(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::baseURL(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp << m_cwBaseURL; + } else { + vp >> m_cwBaseURL; + } + return TRUE; +} + +FX_BOOL Document::calculate(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + + if (vp.IsGetting()) { + if (pInterForm->IsCalculateEnabled()) + vp << true; + else + vp << false; + } else { + bool bCalculate; + vp >> bCalculate; + + pInterForm->EnableCalculate(bCalculate); + } + + return TRUE; +} + +FX_BOOL Document::documentFileName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY); + return FALSE; + } + CFX_WideString wsFilePath = m_pDocument->GetPath(); + int32_t i = wsFilePath.GetLength() - 1; + for (; i >= 0; i--) { + if (wsFilePath.GetAt(i) == L'\\' || wsFilePath.GetAt(i) == L'/') + break; + } + if (i >= 0 && i < wsFilePath.GetLength() - 1) { + vp << (wsFilePath.GetBuffer(wsFilePath.GetLength()) + i + 1); + } else { + vp << L""; + } + return TRUE; +} + +FX_BOOL Document::path(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY); + return FALSE; + } + vp << app::SysPathToPDFPath(m_pDocument->GetPath()); + return TRUE; +} + +FX_BOOL Document::pageWindowRect(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::layout(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::addLink(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::closeDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::getPageBox(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::getAnnot(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::getAnnots(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + vRet.SetNull(); + return TRUE; +} + +FX_BOOL Document::getAnnot3D(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + vRet.SetNull(); + return TRUE; +} + +FX_BOOL Document::getAnnots3D(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + vRet = CJS_Value::VT_undefined; + return TRUE; +} + +FX_BOOL Document::getOCGs(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::getLinks(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +bool Document::IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect) { + return (rect.left <= LinkRect.left && rect.top <= LinkRect.top && + rect.right >= LinkRect.right && rect.bottom >= LinkRect.bottom); +} + +FX_BOOL Document::addIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 2) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + CFX_WideString swIconName = params[0].ToCFXWideString(); + + if (params[1].GetType() != CJS_Value::VT_object) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR); + return FALSE; + } + + v8::Local<v8::Object> pJSIcon = params[1].ToV8Object(); + if (FXJS_GetObjDefnID(pJSIcon) != CJS_Icon::g_nObjDefnID) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR); + return FALSE; + } + + CJS_EmbedObj* pEmbedObj = params[1].ToCJSObject()->GetEmbedObject(); + if (!pEmbedObj) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSTYPEERROR); + return FALSE; + } + + m_IconList.push_back(std::unique_ptr<IconElement>( + new IconElement(swIconName, (Icon*)pEmbedObj))); + return TRUE; +} + +FX_BOOL Document::icons(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + sError = JSGetStringFromID(pContext, IDS_STRING_JSREADONLY); + return FALSE; + } + + if (m_IconList.empty()) { + vp.SetNull(); + return TRUE; + } + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array Icons(pRuntime); + + int i = 0; + for (const auto& pIconElement : m_IconList) { + v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID); + if (pObj.IsEmpty()) + return FALSE; + + CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(m_isolate, pObj); + if (!pJS_Icon) + return FALSE; + + Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject(); + if (!pIcon) + return FALSE; + + pIcon->SetStream(pIconElement->IconStream->GetStream()); + pIcon->SetIconName(pIconElement->IconName); + Icons.SetElement(i++, CJS_Value(pRuntime, pJS_Icon)); + } + + vp << Icons; + return TRUE; +} + +FX_BOOL Document::getIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + if (m_IconList.empty()) + return FALSE; + + CFX_WideString swIconName = params[0].ToCFXWideString(); + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + + for (const auto& pIconElement : m_IconList) { + if (pIconElement->IconName == swIconName) { + Icon* pRetIcon = pIconElement->IconStream; + + v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID); + if (pObj.IsEmpty()) + return FALSE; + + CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(m_isolate, pObj); + if (!pJS_Icon) + return FALSE; + + Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject(); + if (!pIcon) + return FALSE; + + pIcon->SetIconName(swIconName); + pIcon->SetStream(pRetIcon->GetStream()); + vRet = pJS_Icon; + return TRUE; + } + } + + return FALSE; +} + +FX_BOOL Document::removeIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, no supported. + return TRUE; +} + +FX_BOOL Document::createDataObject(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not implemented. + return TRUE; +} + +FX_BOOL Document::media(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::calculateNow(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!(m_pDocument->GetPermissions(FPDFPERM_MODIFY) || + m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM) || + m_pDocument->GetPermissions(FPDFPERM_FILL_FORM))) + return FALSE; + + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + pInterForm->OnCalculate(); + return TRUE; +} + +FX_BOOL Document::Collab(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::getPageNthWord(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) + return FALSE; + + int nPageNo = params.size() > 0 ? params[0].ToInt() : 0; + int nWordNo = params.size() > 1 ? params[1].ToInt() : 0; + bool bStrip = params.size() > 2 ? params[2].ToBool() : true; + + CPDF_Document* pDocument = m_pDocument->GetPDFDocument(); + if (!pDocument) + return FALSE; + + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR); + return FALSE; + } + + CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo); + if (!pPageDict) + return FALSE; + + CPDF_Page page; + page.Load(pDocument, pPageDict); + page.ParseContent(nullptr); + + int nWords = 0; + CFX_WideString swRet; + for (auto& pPageObj : *page.GetPageObjectList()) { + if (pPageObj->IsText()) { + CPDF_TextObject* pTextObj = pPageObj->AsText(); + int nObjWords = CountWords(pTextObj); + if (nWords + nObjWords >= nWordNo) { + swRet = GetObjWordStr(pTextObj, nWordNo - nWords); + break; + } + nWords += nObjWords; + } + } + + if (bStrip) { + swRet.TrimLeft(); + swRet.TrimRight(); + } + + vRet = swRet.c_str(); + return TRUE; +} + +FX_BOOL Document::getPageNthWordQuads(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) + return FALSE; + + return FALSE; +} + +FX_BOOL Document::getPageNumWords(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!m_pDocument->GetPermissions(FPDFPERM_EXTRACT_ACCESS)) + return FALSE; + + int nPageNo = params.size() > 0 ? params[0].ToInt() : 0; + CPDF_Document* pDocument = m_pDocument->GetPDFDocument(); + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + if (nPageNo < 0 || nPageNo >= pDocument->GetPageCount()) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSVALUEERROR); + return FALSE; + } + + CPDF_Dictionary* pPageDict = pDocument->GetPage(nPageNo); + if (!pPageDict) + return FALSE; + + CPDF_Page page; + page.Load(pDocument, pPageDict); + page.ParseContent(nullptr); + + int nWords = 0; + for (auto& pPageObj : *page.GetPageObjectList()) { + if (pPageObj->IsText()) + nWords += CountWords(pPageObj->AsText()); + } + + vRet = nWords; + return TRUE; +} + +FX_BOOL Document::getPrintParams(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_PrintParamsObj::g_nObjDefnID); + + // Not implemented yet. + + vRet = pRetObj; + return TRUE; +} + +#define ISLATINWORD(u) (u != 0x20 && u <= 0x28FF) + +int Document::CountWords(CPDF_TextObject* pTextObj) { + if (!pTextObj) + return 0; + + int nWords = 0; + + CPDF_Font* pFont = pTextObj->GetFont(); + if (!pFont) + return 0; + + FX_BOOL bIsLatin = FALSE; + + for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) { + FX_DWORD charcode = -1; + FX_FLOAT kerning; + + pTextObj->GetCharInfo(i, charcode, kerning); + CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode); + + FX_WORD unicode = 0; + if (swUnicode.GetLength() > 0) + unicode = swUnicode[0]; + + if (ISLATINWORD(unicode) && bIsLatin) + continue; + + bIsLatin = ISLATINWORD(unicode); + if (unicode != 0x20) + nWords++; + } + + return nWords; +} + +CFX_WideString Document::GetObjWordStr(CPDF_TextObject* pTextObj, + int nWordIndex) { + CFX_WideString swRet; + + CPDF_Font* pFont = pTextObj->GetFont(); + if (!pFont) + return L""; + + int nWords = 0; + FX_BOOL bIsLatin = FALSE; + + for (int i = 0, sz = pTextObj->CountChars(); i < sz; i++) { + FX_DWORD charcode = -1; + FX_FLOAT kerning; + + pTextObj->GetCharInfo(i, charcode, kerning); + CFX_WideString swUnicode = pFont->UnicodeFromCharCode(charcode); + + FX_WORD unicode = 0; + if (swUnicode.GetLength() > 0) + unicode = swUnicode[0]; + + if (ISLATINWORD(unicode) && bIsLatin) { + } else { + bIsLatin = ISLATINWORD(unicode); + if (unicode != 0x20) + nWords++; + } + + if (nWords - 1 == nWordIndex) + swRet += unicode; + } + + return swRet; +} + +FX_BOOL Document::zoom(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +/** +(none, NoVary) +(fitP, FitPage) +(fitW, FitWidth) +(fitH, FitHeight) +(fitV, FitVisibleWidth) +(pref, Preferred) +(refW, ReflowWidth) +*/ + +FX_BOOL Document::zoomType(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Document::deletePages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, no supported. + return TRUE; +} + +FX_BOOL Document::extractPages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::insertPages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::replacePages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Document::getURL(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +void Document::AddDelayData(CJS_DelayData* pData) { + m_DelayData.Add(pData); +} + +void Document::DoFieldDelay(const CFX_WideString& sFieldName, + int nControlIndex) { + CFX_DWordArray DelArray; + CFX_ArrayTemplate<CJS_DelayData*> DelayDataForFieldAndControlIndex; + + for (int i = 0, sz = m_DelayData.GetSize(); i < sz; i++) { + if (CJS_DelayData* pData = m_DelayData.GetAt(i)) { + if (pData->sFieldName == sFieldName && + pData->nControlIndex == nControlIndex) { + DelayDataForFieldAndControlIndex.Add(pData); + m_DelayData.SetAt(i, NULL); + DelArray.Add(i); + } + } + } + + for (int j = DelArray.GetSize() - 1; j >= 0; j--) { + m_DelayData.RemoveAt(DelArray[j]); + } + + for (int i = 0, sz = DelayDataForFieldAndControlIndex.GetSize(); i < sz; + i++) { + CJS_DelayData* pData = DelayDataForFieldAndControlIndex.GetAt(i); + Field::DoDelay(m_pDocument, pData); + DelayDataForFieldAndControlIndex.SetAt(i, NULL); + delete pData; + } +} + +CJS_Document* Document::GetCJSDoc() const { + return static_cast<CJS_Document*>(m_pJSObject); +} diff --git a/fpdfsdk/javascript/Document.h b/fpdfsdk/javascript/Document.h new file mode 100644 index 0000000000..8ae6c1d21d --- /dev/null +++ b/fpdfsdk/javascript/Document.h @@ -0,0 +1,365 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_DOCUMENT_H_ +#define FPDFSDK_JAVASCRIPT_DOCUMENT_H_ + +#include <list> +#include <memory> +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class PrintParamsObj : public CJS_EmbedObj { + public: + PrintParamsObj(CJS_Object* pJSObject); + ~PrintParamsObj() override {} + + public: + FX_BOOL bUI; + int nStart; + int nEnd; + FX_BOOL bSilent; + FX_BOOL bShrinkToFit; + FX_BOOL bPrintAsImage; + FX_BOOL bReverse; + FX_BOOL bAnnotations; +}; + +class CJS_PrintParamsObj : public CJS_Object { + public: + CJS_PrintParamsObj(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_PrintParamsObj() override {} + + DECLARE_JS_CLASS(); +}; + +class Icon; +class Field; + +struct IconElement { + IconElement(const CFX_WideString& name, Icon* stream) + : IconName(name), IconStream(stream) {} + + CFX_WideString IconName; + Icon* IconStream; +}; + +struct CJS_DelayData; +struct CJS_DelayAnnot; +struct CJS_AnnotObj; + +class Document : public CJS_EmbedObj { + public: + Document(CJS_Object* pJSObject); + ~Document() override; + + FX_BOOL ADBE(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL author(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL baseURL(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL bookmarkRoot(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL calculate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL Collab(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL creationDate(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL creator(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL delay(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL dirty(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL documentFileName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL external(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL filesize(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL icons(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL info(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL keywords(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL layout(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL modDate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL mouseX(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL mouseY(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL numFields(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL numPages(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL pageNum(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL pageWindowRect(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL path(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL producer(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL subject(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL title(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL zoom(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL zoomType(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + + FX_BOOL addAnnot(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL addField(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL addLink(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL addIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL calculateNow(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL closeDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL createDataObject(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL deletePages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL exportAsText(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL exportAsFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL exportAsXFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL extractPages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getAnnot(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getAnnots(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getAnnot3D(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getAnnots3D(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getField(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getLinks(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getNthFieldName(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getOCGs(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getPageBox(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getPageNthWord(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getPageNthWordQuads(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getPageNumWords(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getPrintParams(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getURL(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL importAnFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL importAnXFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL importTextData(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL insertPages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL mailForm(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL print(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL removeField(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL replacePages(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL resetForm(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL saveAs(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL submitForm(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL mailDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL removeIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + + void AttachDoc(CPDFSDK_Document* pDoc); + CPDFSDK_Document* GetReaderDoc(); + void AddDelayData(CJS_DelayData* pData); + void DoFieldDelay(const CFX_WideString& sFieldName, int nControlIndex); + void SetIsolate(v8::Isolate* isolate) { m_isolate = isolate; } + CJS_Document* GetCJSDoc() const; + + private: + bool IsEnclosedInRect(CFX_FloatRect rect, CFX_FloatRect LinkRect); + int CountWords(CPDF_TextObject* pTextObj); + CFX_WideString GetObjWordStr(CPDF_TextObject* pTextObj, int nWordIndex); + + v8::Isolate* m_isolate; + std::list<std::unique_ptr<IconElement>> m_IconList; + CPDFSDK_Document* m_pDocument; + CFX_WideString m_cwBaseURL; + bool m_bDelay; + CFX_ArrayTemplate<CJS_DelayData*> m_DelayData; +}; + +class CJS_Document : public CJS_Object { + public: + explicit CJS_Document(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Document() override {} + + // CJS_Object + void InitInstance(IJS_Runtime* pIRuntime) override; + + DECLARE_JS_CLASS(); + + JS_STATIC_PROP(ADBE, Document); + JS_STATIC_PROP(author, Document); + JS_STATIC_PROP(baseURL, Document); + JS_STATIC_PROP(bookmarkRoot, Document); + JS_STATIC_PROP(calculate, Document); + JS_STATIC_PROP(Collab, Document); + JS_STATIC_PROP(creationDate, Document); + JS_STATIC_PROP(creator, Document); + JS_STATIC_PROP(delay, Document); + JS_STATIC_PROP(dirty, Document); + JS_STATIC_PROP(documentFileName, Document); + JS_STATIC_PROP(external, Document); + JS_STATIC_PROP(filesize, Document); + JS_STATIC_PROP(icons, Document); + JS_STATIC_PROP(info, Document); + JS_STATIC_PROP(keywords, Document); + JS_STATIC_PROP(layout, Document); + JS_STATIC_PROP(media, Document); + JS_STATIC_PROP(modDate, Document); + JS_STATIC_PROP(mouseX, Document); + JS_STATIC_PROP(mouseY, Document); + JS_STATIC_PROP(numFields, Document); + JS_STATIC_PROP(numPages, Document); + JS_STATIC_PROP(pageNum, Document); + JS_STATIC_PROP(pageWindowRect, Document); + JS_STATIC_PROP(path, Document); + JS_STATIC_PROP(producer, Document); + JS_STATIC_PROP(subject, Document); + JS_STATIC_PROP(title, Document); + JS_STATIC_PROP(zoom, Document); + JS_STATIC_PROP(zoomType, Document); + + JS_STATIC_METHOD(addAnnot, Document); + JS_STATIC_METHOD(addField, Document); + JS_STATIC_METHOD(addLink, Document); + JS_STATIC_METHOD(addIcon, Document); + JS_STATIC_METHOD(calculateNow, Document); + JS_STATIC_METHOD(closeDoc, Document); + JS_STATIC_METHOD(createDataObject, Document); + JS_STATIC_METHOD(deletePages, Document); + JS_STATIC_METHOD(exportAsText, Document); + JS_STATIC_METHOD(exportAsFDF, Document); + JS_STATIC_METHOD(exportAsXFDF, Document); + JS_STATIC_METHOD(extractPages, Document); + JS_STATIC_METHOD(getAnnot, Document); + JS_STATIC_METHOD(getAnnots, Document); + JS_STATIC_METHOD(getAnnot3D, Document); + JS_STATIC_METHOD(getAnnots3D, Document); + JS_STATIC_METHOD(getField, Document); + JS_STATIC_METHOD(getIcon, Document); + JS_STATIC_METHOD(getLinks, Document); + JS_STATIC_METHOD(getNthFieldName, Document); + JS_STATIC_METHOD(getOCGs, Document); + JS_STATIC_METHOD(getPageBox, Document); + JS_STATIC_METHOD(getPageNthWord, Document); + JS_STATIC_METHOD(getPageNthWordQuads, Document); + JS_STATIC_METHOD(getPageNumWords, Document); + JS_STATIC_METHOD(getPrintParams, Document); + JS_STATIC_METHOD(getURL, Document); + JS_STATIC_METHOD(importAnFDF, Document); + JS_STATIC_METHOD(importAnXFDF, Document); + JS_STATIC_METHOD(importTextData, Document); + JS_STATIC_METHOD(insertPages, Document); + JS_STATIC_METHOD(mailForm, Document); + JS_STATIC_METHOD(print, Document); + JS_STATIC_METHOD(removeField, Document); + JS_STATIC_METHOD(replacePages, Document); + JS_STATIC_METHOD(removeIcon, Document); + JS_STATIC_METHOD(resetForm, Document); + JS_STATIC_METHOD(saveAs, Document); + JS_STATIC_METHOD(submitForm, Document); + JS_STATIC_METHOD(mailDoc, Document); +}; + +#endif // FPDFSDK_JAVASCRIPT_DOCUMENT_H_ diff --git a/fpdfsdk/javascript/Field.cpp b/fpdfsdk/javascript/Field.cpp new file mode 100644 index 0000000000..abe18f4e36 --- /dev/null +++ b/fpdfsdk/javascript/Field.cpp @@ -0,0 +1,3600 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/Field.h" + +#include <algorithm> +#include <memory> +#include <string> +#include <vector> + +#include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Document.h" +#include "fpdfsdk/javascript/Icon.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/PublicMethods.h" +#include "fpdfsdk/javascript/color.h" + +BEGIN_JS_STATIC_CONST(CJS_Field) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Field) +JS_STATIC_PROP_ENTRY(alignment) +JS_STATIC_PROP_ENTRY(borderStyle) +JS_STATIC_PROP_ENTRY(buttonAlignX) +JS_STATIC_PROP_ENTRY(buttonAlignY) +JS_STATIC_PROP_ENTRY(buttonFitBounds) +JS_STATIC_PROP_ENTRY(buttonPosition) +JS_STATIC_PROP_ENTRY(buttonScaleHow) +JS_STATIC_PROP_ENTRY(buttonScaleWhen) +JS_STATIC_PROP_ENTRY(calcOrderIndex) +JS_STATIC_PROP_ENTRY(charLimit) +JS_STATIC_PROP_ENTRY(comb) +JS_STATIC_PROP_ENTRY(commitOnSelChange) +JS_STATIC_PROP_ENTRY(currentValueIndices) +JS_STATIC_PROP_ENTRY(defaultStyle) +JS_STATIC_PROP_ENTRY(defaultValue) +JS_STATIC_PROP_ENTRY(doNotScroll) +JS_STATIC_PROP_ENTRY(doNotSpellCheck) +JS_STATIC_PROP_ENTRY(delay) +JS_STATIC_PROP_ENTRY(display) +JS_STATIC_PROP_ENTRY(doc) +JS_STATIC_PROP_ENTRY(editable) +JS_STATIC_PROP_ENTRY(exportValues) +JS_STATIC_PROP_ENTRY(hidden) +JS_STATIC_PROP_ENTRY(fileSelect) +JS_STATIC_PROP_ENTRY(fillColor) +JS_STATIC_PROP_ENTRY(lineWidth) +JS_STATIC_PROP_ENTRY(highlight) +JS_STATIC_PROP_ENTRY(multiline) +JS_STATIC_PROP_ENTRY(multipleSelection) +JS_STATIC_PROP_ENTRY(name) +JS_STATIC_PROP_ENTRY(numItems) +JS_STATIC_PROP_ENTRY(page) +JS_STATIC_PROP_ENTRY(password) +JS_STATIC_PROP_ENTRY(print) +JS_STATIC_PROP_ENTRY(radiosInUnison) +JS_STATIC_PROP_ENTRY(readonly) +JS_STATIC_PROP_ENTRY(rect) +JS_STATIC_PROP_ENTRY(required) +JS_STATIC_PROP_ENTRY(richText) +JS_STATIC_PROP_ENTRY(richValue) +JS_STATIC_PROP_ENTRY(rotation) +JS_STATIC_PROP_ENTRY(strokeColor) +JS_STATIC_PROP_ENTRY(style) +JS_STATIC_PROP_ENTRY(submitName) +JS_STATIC_PROP_ENTRY(textColor) +JS_STATIC_PROP_ENTRY(textFont) +JS_STATIC_PROP_ENTRY(textSize) +JS_STATIC_PROP_ENTRY(type) +JS_STATIC_PROP_ENTRY(userName) +JS_STATIC_PROP_ENTRY(value) +JS_STATIC_PROP_ENTRY(valueAsString) +JS_STATIC_PROP_ENTRY(source) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Field) +JS_STATIC_METHOD_ENTRY(browseForFileToSubmit) +JS_STATIC_METHOD_ENTRY(buttonGetCaption) +JS_STATIC_METHOD_ENTRY(buttonGetIcon) +JS_STATIC_METHOD_ENTRY(buttonImportIcon) +JS_STATIC_METHOD_ENTRY(buttonSetCaption) +JS_STATIC_METHOD_ENTRY(buttonSetIcon) +JS_STATIC_METHOD_ENTRY(checkThisBox) +JS_STATIC_METHOD_ENTRY(clearItems) +JS_STATIC_METHOD_ENTRY(defaultIsChecked) +JS_STATIC_METHOD_ENTRY(deleteItemAt) +JS_STATIC_METHOD_ENTRY(getArray) +JS_STATIC_METHOD_ENTRY(getItemAt) +JS_STATIC_METHOD_ENTRY(getLock) +JS_STATIC_METHOD_ENTRY(insertItemAt) +JS_STATIC_METHOD_ENTRY(isBoxChecked) +JS_STATIC_METHOD_ENTRY(isDefaultChecked) +JS_STATIC_METHOD_ENTRY(setAction) +JS_STATIC_METHOD_ENTRY(setFocus) +JS_STATIC_METHOD_ENTRY(setItems) +JS_STATIC_METHOD_ENTRY(setLock) +JS_STATIC_METHOD_ENTRY(signatureGetModifications) +JS_STATIC_METHOD_ENTRY(signatureGetSeedValue) +JS_STATIC_METHOD_ENTRY(signatureInfo) +JS_STATIC_METHOD_ENTRY(signatureSetSeedValue) +JS_STATIC_METHOD_ENTRY(signatureSign) +JS_STATIC_METHOD_ENTRY(signatureValidate) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Field, Field) + +void CJS_Field::InitInstance(IJS_Runtime* pIRuntime) { + CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime); + Field* pField = static_cast<Field*>(GetEmbedObject()); + pField->SetIsolate(pRuntime->GetIsolate()); +} + +Field::Field(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject), + m_pJSDoc(NULL), + m_pDocument(NULL), + m_nFormControlIndex(-1), + m_bCanSet(FALSE), + m_bDelay(FALSE), + m_isolate(NULL) {} + +Field::~Field() {} + +// note: iControlNo = -1, means not a widget. +void Field::ParseFieldName(const std::wstring& strFieldNameParsed, + std::wstring& strFieldName, + int& iControlNo) { + int iStart = strFieldNameParsed.find_last_of(L'.'); + if (iStart == -1) { + strFieldName = strFieldNameParsed; + iControlNo = -1; + return; + } + std::wstring suffixal = strFieldNameParsed.substr(iStart + 1); + iControlNo = FXSYS_wtoi(suffixal.c_str()); + if (iControlNo == 0) { + int iStart; + while ((iStart = suffixal.find_last_of(L" ")) != -1) { + suffixal.erase(iStart, 1); + } + + if (suffixal.compare(L"0") != 0) { + strFieldName = strFieldNameParsed; + iControlNo = -1; + return; + } + } + strFieldName = strFieldNameParsed.substr(0, iStart); +} + +FX_BOOL Field::AttachField(Document* pDocument, + const CFX_WideString& csFieldName) { + m_pJSDoc = pDocument; + m_pDocument = pDocument->GetReaderDoc(); + m_bCanSet = m_pDocument->GetPermissions(FPDFPERM_FILL_FORM) || + m_pDocument->GetPermissions(FPDFPERM_ANNOT_FORM) || + m_pDocument->GetPermissions(FPDFPERM_MODIFY); + + CPDFSDK_InterForm* pRDInterForm = m_pDocument->GetInterForm(); + CPDF_InterForm* pInterForm = pRDInterForm->GetInterForm(); + CFX_WideString swFieldNameTemp = csFieldName; + swFieldNameTemp.Replace(L"..", L"."); + + if (pInterForm->CountFields(swFieldNameTemp) <= 0) { + std::wstring strFieldName; + int iControlNo = -1; + ParseFieldName(swFieldNameTemp.c_str(), strFieldName, iControlNo); + if (iControlNo == -1) + return FALSE; + + m_FieldName = strFieldName.c_str(); + m_nFormControlIndex = iControlNo; + return TRUE; + } + + m_FieldName = swFieldNameTemp; + m_nFormControlIndex = -1; + + return TRUE; +} + +std::vector<CPDF_FormField*> Field::GetFormFields( + CPDFSDK_Document* pDocument, + const CFX_WideString& csFieldName) { + std::vector<CPDF_FormField*> fields; + CPDFSDK_InterForm* pReaderInterForm = pDocument->GetInterForm(); + CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm(); + for (int i = 0, sz = pInterForm->CountFields(csFieldName); i < sz; ++i) { + if (CPDF_FormField* pFormField = pInterForm->GetField(i, csFieldName)) + fields.push_back(pFormField); + } + return fields; +} + +std::vector<CPDF_FormField*> Field::GetFormFields( + const CFX_WideString& csFieldName) const { + return Field::GetFormFields(m_pDocument, csFieldName); +} + +void Field::UpdateFormField(CPDFSDK_Document* pDocument, + CPDF_FormField* pFormField, + FX_BOOL bChangeMark, + FX_BOOL bResetAP, + FX_BOOL bRefresh) { + std::vector<CPDFSDK_Widget*> widgets; + CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm(); + pInterForm->GetWidgets(pFormField, &widgets); + + if (bResetAP) { + int nFieldType = pFormField->GetFieldType(); + if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_TEXTFIELD) { + for (CPDFSDK_Widget* pWidget : widgets) { + FX_BOOL bFormatted = FALSE; + CFX_WideString sValue = pWidget->OnFormat(bFormatted); + pWidget->ResetAppearance(bFormatted ? sValue.c_str() : nullptr, FALSE); + } + } else { + for (CPDFSDK_Widget* pWidget : widgets) { + pWidget->ResetAppearance(nullptr, FALSE); + } + } + } + + if (bRefresh) { + for (CPDFSDK_Widget* pWidget : widgets) { + CPDFSDK_Document* pDoc = pWidget->GetInterForm()->GetDocument(); + pDoc->UpdateAllViews(nullptr, pWidget); + } + } + + if (bChangeMark) + pDocument->SetChangeMark(); +} + +void Field::UpdateFormControl(CPDFSDK_Document* pDocument, + CPDF_FormControl* pFormControl, + FX_BOOL bChangeMark, + FX_BOOL bResetAP, + FX_BOOL bRefresh) { + ASSERT(pFormControl); + + CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm(); + CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl); + + if (pWidget) { + if (bResetAP) { + int nFieldType = pWidget->GetFieldType(); + if (nFieldType == FIELDTYPE_COMBOBOX || + nFieldType == FIELDTYPE_TEXTFIELD) { + FX_BOOL bFormated = FALSE; + CFX_WideString sValue = pWidget->OnFormat(bFormated); + if (bFormated) + pWidget->ResetAppearance(sValue.c_str(), FALSE); + else + pWidget->ResetAppearance(NULL, FALSE); + } else { + pWidget->ResetAppearance(NULL, FALSE); + } + } + + if (bRefresh) { + CPDFSDK_InterForm* pInterForm = pWidget->GetInterForm(); + CPDFSDK_Document* pDoc = pInterForm->GetDocument(); + pDoc->UpdateAllViews(NULL, pWidget); + } + } + + if (bChangeMark) + pDocument->SetChangeMark(); +} + +CPDFSDK_Widget* Field::GetWidget(CPDFSDK_Document* pDocument, + CPDF_FormControl* pFormControl) { + CPDFSDK_InterForm* pInterForm = + static_cast<CPDFSDK_InterForm*>(pDocument->GetInterForm()); + return pInterForm ? pInterForm->GetWidget(pFormControl) : nullptr; +} + +FX_BOOL Field::ValueIsOccur(CPDF_FormField* pFormField, + CFX_WideString csOptLabel) { + for (int i = 0, sz = pFormField->CountOptions(); i < sz; i++) { + if (csOptLabel.Compare(pFormField->GetOptionLabel(i)) == 0) + return TRUE; + } + + return FALSE; +} + +CPDF_FormControl* Field::GetSmartFieldControl(CPDF_FormField* pFormField) { + if (!pFormField->CountControls() || + m_nFormControlIndex >= pFormField->CountControls()) + return NULL; + + if (m_nFormControlIndex < 0) + return pFormField->GetControl(0); + + return pFormField->GetControl(m_nFormControlIndex); +} + +FX_BOOL Field::alignment(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_ByteString alignStr; + vp >> alignStr; + + if (m_bDelay) { + AddDelay_String(FP_ALIGNMENT, alignStr); + } else { + Field::SetAlignment(m_pDocument, m_FieldName, m_nFormControlIndex, + alignStr); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + switch (pFormControl->GetControlAlignment()) { + case 1: + vp << L"center"; + break; + case 0: + vp << L"left"; + break; + case 2: + vp << L"right"; + break; + default: + vp << L""; + } + } + + return TRUE; +} + +void Field::SetAlignment(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string) { + // Not supported. +} + +FX_BOOL Field::borderStyle(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_ByteString strType = ""; + vp >> strType; + + if (m_bDelay) { + AddDelay_String(FP_BORDERSTYLE, strType); + } else { + Field::SetBorderStyle(m_pDocument, m_FieldName, m_nFormControlIndex, + strType); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (!pFormField) + return FALSE; + + CPDFSDK_Widget* pWidget = + GetWidget(m_pDocument, GetSmartFieldControl(pFormField)); + if (!pWidget) + return FALSE; + + int nBorderstyle = pWidget->GetBorderStyle(); + + switch (nBorderstyle) { + case BBS_SOLID: + vp << L"solid"; + break; + case BBS_DASH: + vp << L"dashed"; + break; + case BBS_BEVELED: + vp << L"beveled"; + break; + case BBS_INSET: + vp << L"inset"; + break; + case BBS_UNDERLINE: + vp << L"underline"; + break; + default: + vp << L""; + break; + } + } + + return TRUE; +} + +void Field::SetBorderStyle(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string) { + ASSERT(pDocument); + + int nBorderStyle = 0; + + if (string == "solid") + nBorderStyle = BBS_SOLID; + else if (string == "beveled") + nBorderStyle = BBS_BEVELED; + else if (string == "dashed") + nBorderStyle = BBS_DASH; + else if (string == "inset") + nBorderStyle = BBS_INSET; + else if (string == "underline") + nBorderStyle = BBS_UNDERLINE; + else + return; + + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + for (CPDF_FormField* pFormField : FieldArray) { + if (nControlIndex < 0) { + FX_BOOL bSet = FALSE; + for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) { + if (CPDFSDK_Widget* pWidget = + GetWidget(pDocument, pFormField->GetControl(i))) { + if (pWidget->GetBorderStyle() != nBorderStyle) { + pWidget->SetBorderStyle(nBorderStyle); + bSet = TRUE; + } + } + } + if (bSet) + UpdateFormField(pDocument, pFormField, TRUE, TRUE, TRUE); + } else { + if (nControlIndex >= pFormField->CountControls()) + return; + if (CPDF_FormControl* pFormControl = + pFormField->GetControl(nControlIndex)) { + if (CPDFSDK_Widget* pWidget = GetWidget(pDocument, pFormControl)) { + if (pWidget->GetBorderStyle() != nBorderStyle) { + pWidget->SetBorderStyle(nBorderStyle); + UpdateFormControl(pDocument, pFormControl, TRUE, TRUE, TRUE); + } + } + } + } + } +} + +FX_BOOL Field::buttonAlignX(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_BUTTONALIGNX, nVP); + } else { + Field::SetButtonAlignX(m_pDocument, m_FieldName, m_nFormControlIndex, + nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDF_IconFit IconFit = pFormControl->GetIconFit(); + + FX_FLOAT fLeft, fBottom; + IconFit.GetIconPosition(fLeft, fBottom); + + vp << (int32_t)fLeft; + } + + return TRUE; +} + +void Field::SetButtonAlignX(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::buttonAlignY(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_BUTTONALIGNY, nVP); + } else { + Field::SetButtonAlignY(m_pDocument, m_FieldName, m_nFormControlIndex, + nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDF_IconFit IconFit = pFormControl->GetIconFit(); + + FX_FLOAT fLeft, fBottom; + IconFit.GetIconPosition(fLeft, fBottom); + + vp << (int32_t)fBottom; + } + + return TRUE; +} + +void Field::SetButtonAlignY(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::buttonFitBounds(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_BUTTONFITBOUNDS, bVP); + } else { + Field::SetButtonFitBounds(m_pDocument, m_FieldName, m_nFormControlIndex, + bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDF_IconFit IconFit = pFormControl->GetIconFit(); + vp << IconFit.GetFittingBounds(); + } + + return TRUE; +} + +void Field::SetButtonFitBounds(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::buttonPosition(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_BUTTONPOSITION, nVP); + } else { + Field::SetButtonPosition(m_pDocument, m_FieldName, m_nFormControlIndex, + nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + vp << pFormControl->GetTextPosition(); + } + return TRUE; +} + +void Field::SetButtonPosition(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::buttonScaleHow(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_BUTTONSCALEHOW, nVP); + } else { + Field::SetButtonScaleHow(m_pDocument, m_FieldName, m_nFormControlIndex, + nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDF_IconFit IconFit = pFormControl->GetIconFit(); + if (IconFit.IsProportionalScale()) + vp << (int32_t)0; + else + vp << (int32_t)1; + } + + return TRUE; +} + +void Field::SetButtonScaleHow(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::buttonScaleWhen(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_BUTTONSCALEWHEN, nVP); + } else { + Field::SetButtonScaleWhen(m_pDocument, m_FieldName, m_nFormControlIndex, + nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDF_IconFit IconFit = pFormControl->GetIconFit(); + int ScaleM = IconFit.GetScaleMethod(); + switch (ScaleM) { + case CPDF_IconFit::Always: + vp << (int32_t)CPDF_IconFit::Always; + break; + case CPDF_IconFit::Bigger: + vp << (int32_t)CPDF_IconFit::Bigger; + break; + case CPDF_IconFit::Never: + vp << (int32_t)CPDF_IconFit::Never; + break; + case CPDF_IconFit::Smaller: + vp << (int32_t)CPDF_IconFit::Smaller; + break; + } + } + + return TRUE; +} + +void Field::SetButtonScaleWhen(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::calcOrderIndex(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_CALCORDERINDEX, nVP); + } else { + Field::SetCalcOrderIndex(m_pDocument, m_FieldName, m_nFormControlIndex, + nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX && + pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) { + return FALSE; + } + + CPDFSDK_InterForm* pRDInterForm = m_pDocument->GetInterForm(); + CPDF_InterForm* pInterForm = pRDInterForm->GetInterForm(); + vp << (int32_t)pInterForm->FindFieldInCalculationOrder(pFormField); + } + + return TRUE; +} + +void Field::SetCalcOrderIndex(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::charLimit(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_CHARLIMIT, nVP); + } else { + Field::SetCharLimit(m_pDocument, m_FieldName, m_nFormControlIndex, nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + vp << (int32_t)pFormField->GetMaxLen(); + } + return TRUE; +} + +void Field::SetCharLimit(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::comb(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_COMB, bVP); + } else { + Field::SetComb(m_pDocument, m_FieldName, m_nFormControlIndex, bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_COMB) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetComb(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::commitOnSelChange(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_COMMITONSELCHANGE, bVP); + } else { + Field::SetCommitOnSelChange(m_pDocument, m_FieldName, m_nFormControlIndex, + bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX && + pFormField->GetFieldType() != FIELDTYPE_LISTBOX) { + return FALSE; + } + + if (pFormField->GetFieldFlags() & FIELDFLAG_COMMITONSELCHANGE) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetCommitOnSelChange(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::currentValueIndices(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_DWordArray array; + + if (vp.GetType() == CJS_Value::VT_number) { + int iSelecting = 0; + vp >> iSelecting; + array.Add(iSelecting); + } else if (vp.IsArrayObject()) { + CJS_Array SelArray(pRuntime); + CJS_Value SelValue(pRuntime); + int iSelecting; + vp >> SelArray; + for (int i = 0, sz = SelArray.GetLength(); i < sz; i++) { + SelArray.GetElement(i, SelValue); + iSelecting = SelValue.ToInt(); + array.Add(iSelecting); + } + } + + if (m_bDelay) { + AddDelay_WordArray(FP_CURRENTVALUEINDICES, array); + } else { + Field::SetCurrentValueIndices(m_pDocument, m_FieldName, + m_nFormControlIndex, array); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX && + pFormField->GetFieldType() != FIELDTYPE_LISTBOX) { + return FALSE; + } + + if (pFormField->CountSelectedItems() == 1) { + vp << pFormField->GetSelectedIndex(0); + } else if (pFormField->CountSelectedItems() > 1) { + CJS_Array SelArray(pRuntime); + for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) { + SelArray.SetElement( + i, CJS_Value(pRuntime, pFormField->GetSelectedIndex(i))); + } + vp << SelArray; + } else { + vp << -1; + } + } + + return TRUE; +} + +void Field::SetCurrentValueIndices(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_DWordArray& array) { + ASSERT(pDocument); + + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + for (CPDF_FormField* pFormField : FieldArray) { + int nFieldType = pFormField->GetFieldType(); + if (nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_LISTBOX) { + FX_DWORD dwFieldFlags = pFormField->GetFieldFlags(); + pFormField->ClearSelection(TRUE); + + for (int i = 0, sz = array.GetSize(); i < sz; i++) { + if (i > 0 && !(dwFieldFlags & (1 << 21))) { + break; + } + + int iSelecting = (int32_t)array.GetAt(i); + if (iSelecting < pFormField->CountOptions() && + !pFormField->IsItemSelected(iSelecting)) + pFormField->SetItemSelection(iSelecting, TRUE); + } + UpdateFormField(pDocument, pFormField, TRUE, TRUE, TRUE); + } + } +} + +FX_BOOL Field::defaultStyle(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return FALSE; +} + +void Field::SetDefaultStyle(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex) { + // Not supported. +} + +FX_BOOL Field::defaultValue(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_WideString WideStr; + vp >> WideStr; + + if (m_bDelay) { + AddDelay_WideString(FP_DEFAULTVALUE, WideStr); + } else { + Field::SetDefaultValue(m_pDocument, m_FieldName, m_nFormControlIndex, + WideStr); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON || + pFormField->GetFieldType() == FIELDTYPE_SIGNATURE) { + return FALSE; + } + + vp << pFormField->GetDefaultValue(); + } + return TRUE; +} + +void Field::SetDefaultValue(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_WideString& string) { + // Not supported. +} + +FX_BOOL Field::doNotScroll(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_DONOTSCROLL, bVP); + } else { + Field::SetDoNotScroll(m_pDocument, m_FieldName, m_nFormControlIndex, bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_DONOTSCROLL) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetDoNotScroll(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::doNotSpellCheck(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD && + pFormField->GetFieldType() != FIELDTYPE_COMBOBOX) { + return FALSE; + } + + if (pFormField->GetFieldFlags() & FIELDFLAG_DONOTSPELLCHECK) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetDelay(FX_BOOL bDelay) { + m_bDelay = bDelay; + + if (!m_bDelay) { + if (m_pJSDoc) + m_pJSDoc->DoFieldDelay(m_FieldName, m_nFormControlIndex); + } +} + +FX_BOOL Field::delay(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + SetDelay(bVP); + } else { + vp << m_bDelay; + } + return TRUE; +} + +FX_BOOL Field::display(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_DISPLAY, nVP); + } else { + Field::SetDisplay(m_pDocument, m_FieldName, m_nFormControlIndex, nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + ASSERT(pFormField); + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CPDFSDK_Widget* pWidget = + pInterForm->GetWidget(GetSmartFieldControl(pFormField)); + if (!pWidget) + return FALSE; + + FX_DWORD dwFlag = pWidget->GetFlags(); + + if (ANNOTFLAG_INVISIBLE & dwFlag || ANNOTFLAG_HIDDEN & dwFlag) { + vp << (int32_t)1; + } else { + if (ANNOTFLAG_PRINT & dwFlag) { + if (ANNOTFLAG_NOVIEW & dwFlag) { + vp << (int32_t)3; + } else { + vp << (int32_t)0; + } + } else { + vp << (int32_t)2; + } + } + } + + return TRUE; +} + +void Field::SetDisplay(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm(); + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + for (CPDF_FormField* pFormField : FieldArray) { + if (nControlIndex < 0) { + FX_BOOL bSet = FALSE; + for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) { + CPDF_FormControl* pFormControl = pFormField->GetControl(i); + ASSERT(pFormControl); + + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + FX_DWORD dwFlag = pWidget->GetFlags(); + switch (number) { + case 0: + dwFlag &= (~ANNOTFLAG_INVISIBLE); + dwFlag &= (~ANNOTFLAG_HIDDEN); + dwFlag &= (~ANNOTFLAG_NOVIEW); + dwFlag |= ANNOTFLAG_PRINT; + break; + case 1: + dwFlag &= (~ANNOTFLAG_INVISIBLE); + dwFlag &= (~ANNOTFLAG_NOVIEW); + dwFlag |= (ANNOTFLAG_HIDDEN | ANNOTFLAG_PRINT); + break; + case 2: + dwFlag &= (~ANNOTFLAG_INVISIBLE); + dwFlag &= (~ANNOTFLAG_PRINT); + dwFlag &= (~ANNOTFLAG_HIDDEN); + dwFlag &= (~ANNOTFLAG_NOVIEW); + break; + case 3: + dwFlag |= ANNOTFLAG_NOVIEW; + dwFlag |= ANNOTFLAG_PRINT; + dwFlag &= (~ANNOTFLAG_HIDDEN); + break; + } + + if (dwFlag != pWidget->GetFlags()) { + pWidget->SetFlags(dwFlag); + bSet = TRUE; + } + } + } + + if (bSet) + UpdateFormField(pDocument, pFormField, TRUE, FALSE, TRUE); + } else { + if (nControlIndex >= pFormField->CountControls()) + return; + if (CPDF_FormControl* pFormControl = + pFormField->GetControl(nControlIndex)) { + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + FX_DWORD dwFlag = pWidget->GetFlags(); + switch (number) { + case 0: + dwFlag &= (~ANNOTFLAG_INVISIBLE); + dwFlag &= (~ANNOTFLAG_HIDDEN); + dwFlag &= (~ANNOTFLAG_NOVIEW); + dwFlag |= ANNOTFLAG_PRINT; + break; + case 1: + dwFlag &= (~ANNOTFLAG_INVISIBLE); + dwFlag &= (~ANNOTFLAG_NOVIEW); + dwFlag |= (ANNOTFLAG_HIDDEN | ANNOTFLAG_PRINT); + break; + case 2: + dwFlag &= (~ANNOTFLAG_INVISIBLE); + dwFlag &= (~ANNOTFLAG_PRINT); + dwFlag &= (~ANNOTFLAG_HIDDEN); + dwFlag &= (~ANNOTFLAG_NOVIEW); + break; + case 3: + dwFlag |= ANNOTFLAG_NOVIEW; + dwFlag |= ANNOTFLAG_PRINT; + dwFlag &= (~ANNOTFLAG_HIDDEN); + break; + } + if (dwFlag != pWidget->GetFlags()) { + pWidget->SetFlags(dwFlag); + UpdateFormControl(pDocument, pFormControl, TRUE, FALSE, TRUE); + } + } + } + } + } +} + +FX_BOOL Field::doc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) { + if (!vp.IsGetting()) { + return FALSE; + } + vp << m_pJSDoc->GetCJSDoc(); + return TRUE; +} + +FX_BOOL Field::editable(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_EDIT) + vp << true; + else + vp << false; + } + + return TRUE; +} + +FX_BOOL Field::exportValues(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_CHECKBOX && + pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON) { + return FALSE; + } + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + if (!vp.IsArrayObject()) + return FALSE; + } else { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array ExportValusArray(pRuntime); + if (m_nFormControlIndex < 0) { + for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) { + CPDF_FormControl* pFormControl = pFormField->GetControl(i); + ExportValusArray.SetElement( + i, CJS_Value(pRuntime, pFormControl->GetExportValue().c_str())); + } + } else { + if (m_nFormControlIndex >= pFormField->CountControls()) + return FALSE; + + CPDF_FormControl* pFormControl = + pFormField->GetControl(m_nFormControlIndex); + if (!pFormControl) + return FALSE; + + ExportValusArray.SetElement( + 0, CJS_Value(pRuntime, pFormControl->GetExportValue().c_str())); + } + vp << ExportValusArray; + } + return TRUE; +} + +FX_BOOL Field::fileSelect(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + } else { + if (pFormField->GetFieldFlags() & FIELDFLAG_FILESELECT) + vp << true; + else + vp << false; + } + return TRUE; +} + +FX_BOOL Field::fillColor(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array crArray(pRuntime); + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + if (!vp.IsArrayObject()) + return FALSE; + + vp >> crArray; + + CPWL_Color color; + color::ConvertArrayToPWLColor(crArray, color); + if (m_bDelay) { + AddDelay_Color(FP_FILLCOLOR, color); + } else { + Field::SetFillColor(m_pDocument, m_FieldName, m_nFormControlIndex, color); + } + } else { + CPDF_FormField* pFormField = FieldArray[0]; + ASSERT(pFormField); + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + int iColorType; + pFormControl->GetBackgroundColor(iColorType); + + CPWL_Color color; + if (iColorType == COLORTYPE_TRANSPARENT) { + color = CPWL_Color(COLORTYPE_TRANSPARENT); + } else if (iColorType == COLORTYPE_GRAY) { + color = CPWL_Color(COLORTYPE_GRAY, + pFormControl->GetOriginalBackgroundColor(0)); + } else if (iColorType == COLORTYPE_RGB) { + color = + CPWL_Color(COLORTYPE_RGB, pFormControl->GetOriginalBackgroundColor(0), + pFormControl->GetOriginalBackgroundColor(1), + pFormControl->GetOriginalBackgroundColor(2)); + } else if (iColorType == COLORTYPE_CMYK) { + color = CPWL_Color(COLORTYPE_CMYK, + pFormControl->GetOriginalBackgroundColor(0), + pFormControl->GetOriginalBackgroundColor(1), + pFormControl->GetOriginalBackgroundColor(2), + pFormControl->GetOriginalBackgroundColor(3)); + } else { + return FALSE; + } + + color::ConvertPWLColorToArray(color, crArray); + vp << crArray; + } + + return TRUE; +} + +void Field::SetFillColor(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CPWL_Color& color) { + // Not supported. +} + +FX_BOOL Field::hidden(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_HIDDEN, bVP); + } else { + Field::SetHidden(m_pDocument, m_FieldName, m_nFormControlIndex, bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + ASSERT(pFormField); + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CPDFSDK_Widget* pWidget = + pInterForm->GetWidget(GetSmartFieldControl(pFormField)); + if (!pWidget) + return FALSE; + + FX_DWORD dwFlags = pWidget->GetFlags(); + + if (ANNOTFLAG_INVISIBLE & dwFlags || ANNOTFLAG_HIDDEN & dwFlags) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetHidden(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm(); + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + for (CPDF_FormField* pFormField : FieldArray) { + if (nControlIndex < 0) { + FX_BOOL bSet = FALSE; + for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) { + if (CPDFSDK_Widget* pWidget = + pInterForm->GetWidget(pFormField->GetControl(i))) { + FX_DWORD dwFlags = pWidget->GetFlags(); + + if (b) { + dwFlags &= (~ANNOTFLAG_INVISIBLE); + dwFlags &= (~ANNOTFLAG_NOVIEW); + dwFlags |= (ANNOTFLAG_HIDDEN | ANNOTFLAG_PRINT); + } else { + dwFlags &= (~ANNOTFLAG_INVISIBLE); + dwFlags &= (~ANNOTFLAG_HIDDEN); + dwFlags &= (~ANNOTFLAG_NOVIEW); + dwFlags |= ANNOTFLAG_PRINT; + } + + if (dwFlags != pWidget->GetFlags()) { + pWidget->SetFlags(dwFlags); + bSet = TRUE; + } + } + } + + if (bSet) + UpdateFormField(pDocument, pFormField, TRUE, FALSE, TRUE); + } else { + if (nControlIndex >= pFormField->CountControls()) + return; + if (CPDF_FormControl* pFormControl = + pFormField->GetControl(nControlIndex)) { + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + FX_DWORD dwFlags = pWidget->GetFlags(); + + if (b) { + dwFlags &= (~ANNOTFLAG_INVISIBLE); + dwFlags &= (~ANNOTFLAG_NOVIEW); + dwFlags |= (ANNOTFLAG_HIDDEN | ANNOTFLAG_PRINT); + } else { + dwFlags &= (~ANNOTFLAG_INVISIBLE); + dwFlags &= (~ANNOTFLAG_HIDDEN); + dwFlags &= (~ANNOTFLAG_NOVIEW); + dwFlags |= ANNOTFLAG_PRINT; + } + + if (dwFlags != pWidget->GetFlags()) { + pWidget->SetFlags(dwFlags); + UpdateFormControl(pDocument, pFormControl, TRUE, FALSE, TRUE); + } + } + } + } + } +} + +FX_BOOL Field::highlight(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_ByteString strMode; + vp >> strMode; + + if (m_bDelay) { + AddDelay_String(FP_HIGHLIGHT, strMode); + } else { + Field::SetHighlight(m_pDocument, m_FieldName, m_nFormControlIndex, + strMode); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + int eHM = pFormControl->GetHighlightingMode(); + switch (eHM) { + case CPDF_FormControl::None: + vp << L"none"; + break; + case CPDF_FormControl::Push: + vp << L"push"; + break; + case CPDF_FormControl::Invert: + vp << L"invert"; + break; + case CPDF_FormControl::Outline: + vp << L"outline"; + break; + case CPDF_FormControl::Toggle: + vp << L"toggle"; + break; + } + } + + return TRUE; +} + +void Field::SetHighlight(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string) { + // Not supported. +} + +FX_BOOL Field::lineWidth(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int iWidth; + vp >> iWidth; + + if (m_bDelay) { + AddDelay_Int(FP_LINEWIDTH, iWidth); + } else { + Field::SetLineWidth(m_pDocument, m_FieldName, m_nFormControlIndex, + iWidth); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + ASSERT(pFormField); + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + if (!pFormField->CountControls()) + return FALSE; + + CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormField->GetControl(0)); + if (!pWidget) + return FALSE; + + vp << (int32_t)pWidget->GetBorderWidth(); + } + + return TRUE; +} + +void Field::SetLineWidth(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm(); + + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + for (CPDF_FormField* pFormField : FieldArray) { + if (nControlIndex < 0) { + FX_BOOL bSet = FALSE; + for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) { + CPDF_FormControl* pFormControl = pFormField->GetControl(i); + ASSERT(pFormControl); + + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + if (number != pWidget->GetBorderWidth()) { + pWidget->SetBorderWidth(number); + bSet = TRUE; + } + } + } + if (bSet) + UpdateFormField(pDocument, pFormField, TRUE, TRUE, TRUE); + } else { + if (nControlIndex >= pFormField->CountControls()) + return; + if (CPDF_FormControl* pFormControl = + pFormField->GetControl(nControlIndex)) { + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + if (number != pWidget->GetBorderWidth()) { + pWidget->SetBorderWidth(number); + UpdateFormControl(pDocument, pFormControl, TRUE, TRUE, TRUE); + } + } + } + } + } +} + +FX_BOOL Field::multiline(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_MULTILINE, bVP); + } else { + Field::SetMultiline(m_pDocument, m_FieldName, m_nFormControlIndex, bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_MULTILINE) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetMultiline(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::multipleSelection(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_MULTIPLESELECTION, bVP); + } else { + Field::SetMultipleSelection(m_pDocument, m_FieldName, m_nFormControlIndex, + bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_LISTBOX) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_MULTISELECT) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetMultipleSelection(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::name(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + vp << m_FieldName; + + return TRUE; +} + +FX_BOOL Field::numItems(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_COMBOBOX && + pFormField->GetFieldType() != FIELDTYPE_LISTBOX) { + return FALSE; + } + + vp << (int32_t)pFormField->CountOptions(); + return TRUE; +} + +FX_BOOL Field::page(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (!pFormField) + return FALSE; + + std::vector<CPDFSDK_Widget*> widgets; + m_pDocument->GetInterForm()->GetWidgets(pFormField, &widgets); + + if (widgets.empty()) { + vp << (int32_t)-1; + return TRUE; + } + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array PageArray(pRuntime); + for (size_t i = 0; i < widgets.size(); ++i) { + CPDFSDK_PageView* pPageView = widgets[i]->GetPageView(); + if (!pPageView) + return FALSE; + + PageArray.SetElement( + i, CJS_Value(pRuntime, (int32_t)pPageView->GetPageIndex())); + } + + vp << PageArray; + return TRUE; +} + +FX_BOOL Field::password(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_PASSWORD, bVP); + } else { + Field::SetPassword(m_pDocument, m_FieldName, m_nFormControlIndex, bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_PASSWORD) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetPassword(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::print(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + for (CPDF_FormField* pFormField : FieldArray) { + if (m_nFormControlIndex < 0) { + FX_BOOL bSet = FALSE; + for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) { + if (CPDFSDK_Widget* pWidget = + pInterForm->GetWidget(pFormField->GetControl(i))) { + FX_DWORD dwFlags = pWidget->GetFlags(); + if (bVP) + dwFlags |= ANNOTFLAG_PRINT; + else + dwFlags &= ~ANNOTFLAG_PRINT; + + if (dwFlags != pWidget->GetFlags()) { + pWidget->SetFlags(dwFlags); + bSet = TRUE; + } + } + } + + if (bSet) + UpdateFormField(m_pDocument, pFormField, TRUE, FALSE, TRUE); + } else { + if (m_nFormControlIndex >= pFormField->CountControls()) + return FALSE; + if (CPDF_FormControl* pFormControl = + pFormField->GetControl(m_nFormControlIndex)) { + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + FX_DWORD dwFlags = pWidget->GetFlags(); + if (bVP) + dwFlags |= ANNOTFLAG_PRINT; + else + dwFlags &= ~ANNOTFLAG_PRINT; + + if (dwFlags != pWidget->GetFlags()) { + pWidget->SetFlags(dwFlags); + UpdateFormControl(m_pDocument, + pFormField->GetControl(m_nFormControlIndex), + TRUE, FALSE, TRUE); + } + } + } + } + } + } else { + CPDF_FormField* pFormField = FieldArray[0]; + CPDFSDK_Widget* pWidget = + pInterForm->GetWidget(GetSmartFieldControl(pFormField)); + if (!pWidget) + return FALSE; + + if (pWidget->GetFlags() & ANNOTFLAG_PRINT) + vp << true; + else + vp << false; + } + + return TRUE; +} + +FX_BOOL Field::radiosInUnison(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + } else { + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_RADIOSINUNISON) + vp << true; + else + vp << false; + } + + return TRUE; +} + +FX_BOOL Field::readonly(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + } else { + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldFlags() & FIELDFLAG_READONLY) + vp << true; + else + vp << false; + } + + return TRUE; +} + +FX_BOOL Field::rect(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Value Upper_Leftx(pRuntime); + CJS_Value Upper_Lefty(pRuntime); + CJS_Value Lower_Rightx(pRuntime); + CJS_Value Lower_Righty(pRuntime); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + if (!vp.IsArrayObject()) + return FALSE; + + CJS_Array rcArray(pRuntime); + vp >> rcArray; + rcArray.GetElement(0, Upper_Leftx); + rcArray.GetElement(1, Upper_Lefty); + rcArray.GetElement(2, Lower_Rightx); + rcArray.GetElement(3, Lower_Righty); + + FX_FLOAT pArray[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + pArray[0] = (FX_FLOAT)Upper_Leftx.ToInt(); + pArray[1] = (FX_FLOAT)Lower_Righty.ToInt(); + pArray[2] = (FX_FLOAT)Lower_Rightx.ToInt(); + pArray[3] = (FX_FLOAT)Upper_Lefty.ToInt(); + + CFX_FloatRect crRect(pArray); + if (m_bDelay) { + AddDelay_Rect(FP_RECT, crRect); + } else { + Field::SetRect(m_pDocument, m_FieldName, m_nFormControlIndex, crRect); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CPDFSDK_Widget* pWidget = + pInterForm->GetWidget(GetSmartFieldControl(pFormField)); + if (!pWidget) + return FALSE; + + CFX_FloatRect crRect = pWidget->GetRect(); + Upper_Leftx = (int32_t)crRect.left; + Upper_Lefty = (int32_t)crRect.top; + Lower_Rightx = (int32_t)crRect.right; + Lower_Righty = (int32_t)crRect.bottom; + + CJS_Array rcArray(pRuntime); + rcArray.SetElement(0, Upper_Leftx); + rcArray.SetElement(1, Upper_Lefty); + rcArray.SetElement(2, Lower_Rightx); + rcArray.SetElement(3, Lower_Righty); + vp << rcArray; + } + return TRUE; +} + +void Field::SetRect(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_FloatRect& rect) { + CPDFSDK_InterForm* pInterForm = (CPDFSDK_InterForm*)pDocument->GetInterForm(); + + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + for (CPDF_FormField* pFormField : FieldArray) { + if (nControlIndex < 0) { + FX_BOOL bSet = FALSE; + for (int i = 0, sz = pFormField->CountControls(); i < sz; ++i) { + CPDF_FormControl* pFormControl = pFormField->GetControl(i); + ASSERT(pFormControl); + + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + CFX_FloatRect crRect = rect; + + CPDF_Page* pPDFPage = pWidget->GetPDFPage(); + crRect.Intersect(pPDFPage->GetPageBBox()); + + if (!crRect.IsEmpty()) { + CFX_FloatRect rcOld = pWidget->GetRect(); + if (crRect.left != rcOld.left || crRect.right != rcOld.right || + crRect.top != rcOld.top || crRect.bottom != rcOld.bottom) { + pWidget->SetRect(crRect); + bSet = TRUE; + } + } + } + } + + if (bSet) + UpdateFormField(pDocument, pFormField, TRUE, TRUE, TRUE); + } else { + if (nControlIndex >= pFormField->CountControls()) + return; + if (CPDF_FormControl* pFormControl = + pFormField->GetControl(nControlIndex)) { + if (CPDFSDK_Widget* pWidget = pInterForm->GetWidget(pFormControl)) { + CFX_FloatRect crRect = rect; + + CPDF_Page* pPDFPage = pWidget->GetPDFPage(); + crRect.Intersect(pPDFPage->GetPageBBox()); + + if (!crRect.IsEmpty()) { + CFX_FloatRect rcOld = pWidget->GetRect(); + if (crRect.left != rcOld.left || crRect.right != rcOld.right || + crRect.top != rcOld.top || crRect.bottom != rcOld.bottom) { + pWidget->SetRect(crRect); + UpdateFormControl(pDocument, pFormControl, TRUE, TRUE, TRUE); + } + } + } + } + } + } +} + +FX_BOOL Field::required(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + } else { + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_REQUIRED) + vp << true; + else + vp << false; + } + + return TRUE; +} + +FX_BOOL Field::richText(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + bool bVP; + vp >> bVP; + + if (m_bDelay) { + AddDelay_Bool(FP_RICHTEXT, bVP); + } else { + Field::SetRichText(m_pDocument, m_FieldName, m_nFormControlIndex, bVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_TEXTFIELD) + return FALSE; + + if (pFormField->GetFieldFlags() & FIELDFLAG_RICHTEXT) + vp << true; + else + vp << false; + } + + return TRUE; +} + +void Field::SetRichText(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b) { + // Not supported. +} + +FX_BOOL Field::richValue(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +void Field::SetRichValue(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex) { + // Not supported. +} + +FX_BOOL Field::rotation(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_ROTATION, nVP); + } else { + Field::SetRotation(m_pDocument, m_FieldName, m_nFormControlIndex, nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + vp << (int32_t)pFormControl->GetRotation(); + } + + return TRUE; +} + +void Field::SetRotation(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::strokeColor(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array crArray(pRuntime); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + if (!vp.IsArrayObject()) + return FALSE; + + vp >> crArray; + + CPWL_Color color; + color::ConvertArrayToPWLColor(crArray, color); + + if (m_bDelay) { + AddDelay_Color(FP_STROKECOLOR, color); + } else { + Field::SetStrokeColor(m_pDocument, m_FieldName, m_nFormControlIndex, + color); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + int iColorType; + pFormControl->GetBorderColor(iColorType); + + CPWL_Color color; + if (iColorType == COLORTYPE_TRANSPARENT) { + color = CPWL_Color(COLORTYPE_TRANSPARENT); + } else if (iColorType == COLORTYPE_GRAY) { + color = + CPWL_Color(COLORTYPE_GRAY, pFormControl->GetOriginalBorderColor(0)); + } else if (iColorType == COLORTYPE_RGB) { + color = CPWL_Color(COLORTYPE_RGB, pFormControl->GetOriginalBorderColor(0), + pFormControl->GetOriginalBorderColor(1), + pFormControl->GetOriginalBorderColor(2)); + } else if (iColorType == COLORTYPE_CMYK) { + color = + CPWL_Color(COLORTYPE_CMYK, pFormControl->GetOriginalBorderColor(0), + pFormControl->GetOriginalBorderColor(1), + pFormControl->GetOriginalBorderColor(2), + pFormControl->GetOriginalBorderColor(3)); + } else { + return FALSE; + } + + color::ConvertPWLColorToArray(color, crArray); + vp << crArray; + } + return TRUE; +} + +void Field::SetStrokeColor(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CPWL_Color& color) { + // Not supported. +} + +FX_BOOL Field::style(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_ByteString csBCaption; + vp >> csBCaption; + + if (m_bDelay) { + AddDelay_String(FP_STYLE, csBCaption); + } else { + Field::SetStyle(m_pDocument, m_FieldName, m_nFormControlIndex, + csBCaption); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON && + pFormField->GetFieldType() != FIELDTYPE_CHECKBOX) { + return FALSE; + } + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CFX_WideString csWCaption = pFormControl->GetNormalCaption(); + CFX_ByteString csBCaption; + + switch (csWCaption[0]) { + case L'l': + csBCaption = "circle"; + break; + case L'8': + csBCaption = "cross"; + break; + case L'u': + csBCaption = "diamond"; + break; + case L'n': + csBCaption = "square"; + break; + case L'H': + csBCaption = "star"; + break; + default: // L'4' + csBCaption = "check"; + break; + } + vp << csBCaption; + } + + return TRUE; +} + +void Field::SetStyle(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string) { + // Not supported. +} + +FX_BOOL Field::submitName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::textColor(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array crArray(pRuntime); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + if (!vp.IsArrayObject()) + return FALSE; + + vp >> crArray; + + CPWL_Color color; + color::ConvertArrayToPWLColor(crArray, color); + + if (m_bDelay) { + AddDelay_Color(FP_TEXTCOLOR, color); + } else { + Field::SetTextColor(m_pDocument, m_FieldName, m_nFormControlIndex, color); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + int iColorType; + FX_ARGB color; + CPDF_DefaultAppearance FieldAppearance = + pFormControl->GetDefaultAppearance(); + FieldAppearance.GetColor(color, iColorType); + int32_t a, r, g, b; + ArgbDecode(color, a, r, g, b); + + CPWL_Color crRet = + CPWL_Color(COLORTYPE_RGB, r / 255.0f, g / 255.0f, b / 255.0f); + + if (iColorType == COLORTYPE_TRANSPARENT) + crRet = CPWL_Color(COLORTYPE_TRANSPARENT); + + color::ConvertPWLColorToArray(crRet, crArray); + vp << crArray; + } + return TRUE; +} + +void Field::SetTextColor(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CPWL_Color& color) { + // Not supported. +} + +FX_BOOL Field::textFont(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_ByteString csFontName; + vp >> csFontName; + if (csFontName.IsEmpty()) + return FALSE; + + if (m_bDelay) { + AddDelay_String(FP_TEXTFONT, csFontName); + } else { + Field::SetTextFont(m_pDocument, m_FieldName, m_nFormControlIndex, + csFontName); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + ASSERT(pFormField); + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + int nFieldType = pFormField->GetFieldType(); + + if (nFieldType == FIELDTYPE_PUSHBUTTON || + nFieldType == FIELDTYPE_COMBOBOX || nFieldType == FIELDTYPE_LISTBOX || + nFieldType == FIELDTYPE_TEXTFIELD) { + CPDF_Font* pFont = pFormControl->GetDefaultControlFont(); + if (!pFont) + return FALSE; + + vp << pFont->GetBaseFont(); + } else { + return FALSE; + } + } + + return TRUE; +} + +void Field::SetTextFont(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string) { + // Not supported. +} + +FX_BOOL Field::textSize(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + int nVP; + vp >> nVP; + + if (m_bDelay) { + AddDelay_Int(FP_TEXTSIZE, nVP); + } else { + Field::SetTextSize(m_pDocument, m_FieldName, m_nFormControlIndex, nVP); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + ASSERT(pFormField); + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CPDF_DefaultAppearance FieldAppearance = + pFormControl->GetDefaultAppearance(); + + CFX_ByteString csFontNameTag; + FX_FLOAT fFontSize; + FieldAppearance.GetFont(csFontNameTag, fFontSize); + + vp << (int)fFontSize; + } + + return TRUE; +} + +void Field::SetTextSize(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number) { + // Not supported. +} + +FX_BOOL Field::type(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + switch (pFormField->GetFieldType()) { + case FIELDTYPE_UNKNOWN: + vp << L"unknown"; + break; + case FIELDTYPE_PUSHBUTTON: + vp << L"button"; + break; + case FIELDTYPE_CHECKBOX: + vp << L"checkbox"; + break; + case FIELDTYPE_RADIOBUTTON: + vp << L"radiobutton"; + break; + case FIELDTYPE_COMBOBOX: + vp << L"combobox"; + break; + case FIELDTYPE_LISTBOX: + vp << L"listbox"; + break; + case FIELDTYPE_TEXTFIELD: + vp << L"text"; + break; + case FIELDTYPE_SIGNATURE: + vp << L"signature"; + break; + default: + vp << L"unknown"; + break; + } + + return TRUE; +} + +FX_BOOL Field::userName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CFX_WideString swName; + vp >> swName; + + if (m_bDelay) { + AddDelay_WideString(FP_USERNAME, swName); + } else { + Field::SetUserName(m_pDocument, m_FieldName, m_nFormControlIndex, swName); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + vp << (CFX_WideString)pFormField->GetAlternateName(); + } + + return TRUE; +} + +void Field::SetUserName(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_WideString& string) { + // Not supported. +} + +FX_BOOL Field::value(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + + if (vp.IsSetting()) { + if (!m_bCanSet) + return FALSE; + + CJS_WideStringArray strArray; + + if (vp.IsArrayObject()) { + CJS_Array ValueArray(pRuntime); + vp.ConvertToArray(ValueArray); + for (int i = 0, sz = ValueArray.GetLength(); i < sz; i++) { + CJS_Value ElementValue(pRuntime); + ValueArray.GetElement(i, ElementValue); + strArray.Add(ElementValue.ToCFXWideString()); + } + } else { + CFX_WideString swValue; + vp >> swValue; + strArray.Add(swValue); + } + + if (m_bDelay) { + AddDelay_WideStringArray(FP_VALUE, strArray); + } else { + Field::SetValue(m_pDocument, m_FieldName, m_nFormControlIndex, strArray); + } + } else { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + switch (pFormField->GetFieldType()) { + case FIELDTYPE_PUSHBUTTON: + return FALSE; + case FIELDTYPE_COMBOBOX: + case FIELDTYPE_TEXTFIELD: { + vp << pFormField->GetValue(); + } break; + case FIELDTYPE_LISTBOX: { + if (pFormField->CountSelectedItems() > 1) { + CJS_Array ValueArray(pRuntime); + CJS_Value ElementValue(pRuntime); + int iIndex; + for (int i = 0, sz = pFormField->CountSelectedItems(); i < sz; i++) { + iIndex = pFormField->GetSelectedIndex(i); + ElementValue = pFormField->GetOptionValue(iIndex).c_str(); + if (FXSYS_wcslen(ElementValue.ToCFXWideString().c_str()) == 0) + ElementValue = pFormField->GetOptionLabel(iIndex).c_str(); + ValueArray.SetElement(i, ElementValue); + } + vp << ValueArray; + } else { + vp << pFormField->GetValue(); + } + } break; + case FIELDTYPE_CHECKBOX: + case FIELDTYPE_RADIOBUTTON: { + bool bFind = false; + for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) { + if (pFormField->GetControl(i)->IsChecked()) { + vp << pFormField->GetControl(i)->GetExportValue(); + bFind = true; + break; + } + } + if (!bFind) + vp << L"Off"; + } break; + default: + vp << pFormField->GetValue(); + break; + } + } + vp.MaybeCoerceToNumber(); + return TRUE; +} + +void Field::SetValue(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CJS_WideStringArray& strArray) { + ASSERT(pDocument); + + if (strArray.GetSize() < 1) + return; + + std::vector<CPDF_FormField*> FieldArray = + GetFormFields(pDocument, swFieldName); + + for (CPDF_FormField* pFormField : FieldArray) { + if (pFormField->GetFullName().Compare(swFieldName) != 0) + continue; + + switch (pFormField->GetFieldType()) { + case FIELDTYPE_TEXTFIELD: + case FIELDTYPE_COMBOBOX: + if (pFormField->GetValue() != strArray.GetAt(0)) { + CFX_WideString WideString = strArray.GetAt(0); + pFormField->SetValue(strArray.GetAt(0), TRUE); + UpdateFormField(pDocument, pFormField, TRUE, FALSE, TRUE); + } + break; + case FIELDTYPE_CHECKBOX: // mantis: 0004493 + case FIELDTYPE_RADIOBUTTON: { + if (pFormField->GetValue() != strArray.GetAt(0)) { + pFormField->SetValue(strArray.GetAt(0), TRUE); + UpdateFormField(pDocument, pFormField, TRUE, FALSE, TRUE); + } + } break; + case FIELDTYPE_LISTBOX: { + FX_BOOL bModified = FALSE; + + for (int i = 0, sz = strArray.GetSize(); i < sz; i++) { + int iIndex = pFormField->FindOption(strArray.GetAt(i)); + + if (!pFormField->IsItemSelected(iIndex)) { + bModified = TRUE; + break; + } + } + + if (bModified) { + pFormField->ClearSelection(TRUE); + for (int i = 0, sz = strArray.GetSize(); i < sz; i++) { + int iIndex = pFormField->FindOption(strArray.GetAt(i)); + pFormField->SetItemSelection(iIndex, TRUE, TRUE); + } + + UpdateFormField(pDocument, pFormField, TRUE, FALSE, TRUE); + } + } break; + default: + break; + } + } +} + +FX_BOOL Field::valueAsString(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() == FIELDTYPE_PUSHBUTTON) + return FALSE; + + if (pFormField->GetFieldType() == FIELDTYPE_CHECKBOX) { + if (!pFormField->CountControls()) + return FALSE; + + if (pFormField->GetControl(0)->IsChecked()) + vp << L"Yes"; + else + vp << L"Off"; + } else if (pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON && + !(pFormField->GetFieldFlags() & FIELDFLAG_RADIOSINUNISON)) { + for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) { + if (pFormField->GetControl(i)->IsChecked()) { + vp << pFormField->GetControl(i)->GetExportValue().c_str(); + break; + } else { + vp << L"Off"; + } + } + } else if (pFormField->GetFieldType() == FIELDTYPE_LISTBOX && + (pFormField->CountSelectedItems() > 1)) { + vp << L""; + } else { + vp << pFormField->GetValue().c_str(); + } + + return TRUE; +} + +FX_BOOL Field::browseForFileToSubmit(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + CPDFDoc_Environment* pApp = m_pDocument->GetEnv(); + if ((pFormField->GetFieldFlags() & FIELDFLAG_FILESELECT) && + (pFormField->GetFieldType() == FIELDTYPE_TEXTFIELD)) { + CFX_WideString wsFileName = pApp->JS_fieldBrowse(); + if (!wsFileName.IsEmpty()) { + pFormField->SetValue(wsFileName); + UpdateFormField(m_pDocument, pFormField, TRUE, TRUE, TRUE); + } + return TRUE; + } + return FALSE; +} + +FX_BOOL Field::buttonGetCaption(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int nface = 0; + int iSize = params.size(); + if (iSize >= 1) + nface = params[0].ToInt(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + if (nface == 0) + vRet = pFormControl->GetNormalCaption().c_str(); + else if (nface == 1) + vRet = pFormControl->GetDownCaption().c_str(); + else if (nface == 2) + vRet = pFormControl->GetRolloverCaption().c_str(); + else + return FALSE; + + return TRUE; +} + +FX_BOOL Field::buttonGetIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int nface = 0; + int iSize = params.size(); + if (iSize >= 1) + nface = params[0].ToInt(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_PUSHBUTTON) + return FALSE; + + CPDF_FormControl* pFormControl = GetSmartFieldControl(pFormField); + if (!pFormControl) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Icon::g_nObjDefnID); + ASSERT(pObj.IsEmpty() == FALSE); + + CJS_Icon* pJS_Icon = (CJS_Icon*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj); + Icon* pIcon = (Icon*)pJS_Icon->GetEmbedObject(); + + CPDF_Stream* pIconStream = NULL; + if (nface == 0) + pIconStream = pFormControl->GetNormalIcon(); + else if (nface == 1) + pIconStream = pFormControl->GetDownIcon(); + else if (nface == 2) + pIconStream = pFormControl->GetRolloverIcon(); + else + return FALSE; + + pIcon->SetStream(pIconStream); + vRet = pJS_Icon; + + return TRUE; +} + +FX_BOOL Field::buttonImportIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::buttonSetCaption(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::buttonSetIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::checkThisBox(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + ASSERT(m_pDocument); + + if (!m_bCanSet) + return FALSE; + + int iSize = params.size(); + if (iSize < 1) + return FALSE; + + int nWidget = params[0].ToInt(); + + bool bCheckit = true; + if (iSize >= 2) + bCheckit = params[1].ToBool(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (pFormField->GetFieldType() != FIELDTYPE_CHECKBOX && + pFormField->GetFieldType() != FIELDTYPE_RADIOBUTTON) + return FALSE; + if (nWidget < 0 || nWidget >= pFormField->CountControls()) + return FALSE; + // TODO(weili): Check whether anything special needed for radio button, + // otherwise merge these branches. + if (pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON) + pFormField->CheckControl(nWidget, bCheckit, true); + else + pFormField->CheckControl(nWidget, bCheckit, true); + + UpdateFormField(m_pDocument, pFormField, TRUE, TRUE, TRUE); + return TRUE; +} + +FX_BOOL Field::clearItems(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::defaultIsChecked(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (!m_bCanSet) + return FALSE; + + int iSize = params.size(); + if (iSize < 1) + return FALSE; + + int nWidget = params[0].ToInt(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (nWidget < 0 || nWidget >= pFormField->CountControls()) { + vRet = FALSE; + return FALSE; + } + vRet = pFormField->GetFieldType() == FIELDTYPE_CHECKBOX || + pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON; + + return TRUE; +} + +FX_BOOL Field::deleteItemAt(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::getArray(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + std::vector<std::unique_ptr<CFX_WideString>> swSort; + for (CPDF_FormField* pFormField : FieldArray) { + swSort.push_back(std::unique_ptr<CFX_WideString>( + new CFX_WideString(pFormField->GetFullName()))); + } + + std::sort( + swSort.begin(), swSort.end(), + [](const std::unique_ptr<CFX_WideString>& p1, + const std::unique_ptr<CFX_WideString>& p2) { return *p1 < *p2; }); + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + CJS_Array FormFieldArray(pRuntime); + + int j = 0; + for (const auto& pStr : swSort) { + v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID); + ASSERT(!pObj.IsEmpty()); + + CJS_Field* pJSField = + static_cast<CJS_Field*>(FXJS_GetPrivate(pRuntime->GetIsolate(), pObj)); + Field* pField = static_cast<Field*>(pJSField->GetEmbedObject()); + pField->AttachField(m_pJSDoc, *pStr); + + CJS_Value FormFieldValue(pRuntime); + FormFieldValue = pJSField; + FormFieldArray.SetElement(j++, FormFieldValue); + } + + vRet = FormFieldArray; + return TRUE; +} + +FX_BOOL Field::getItemAt(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + + int nIdx = -1; + if (iSize >= 1) + nIdx = params[0].ToInt(); + + FX_BOOL bExport = TRUE; + if (iSize >= 2) + bExport = params[1].ToBool(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if ((pFormField->GetFieldType() == FIELDTYPE_LISTBOX) || + (pFormField->GetFieldType() == FIELDTYPE_COMBOBOX)) { + if (nIdx == -1 || nIdx > pFormField->CountOptions()) + nIdx = pFormField->CountOptions() - 1; + if (bExport) { + CFX_WideString strval = pFormField->GetOptionValue(nIdx); + if (strval.IsEmpty()) + vRet = pFormField->GetOptionLabel(nIdx).c_str(); + else + vRet = strval.c_str(); + } else { + vRet = pFormField->GetOptionLabel(nIdx).c_str(); + } + } else { + return FALSE; + } + + return TRUE; +} + +FX_BOOL Field::getLock(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::insertItemAt(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::isBoxChecked(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int nIndex = -1; + if (params.size() >= 1) + nIndex = params[0].ToInt(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (nIndex < 0 || nIndex >= pFormField->CountControls()) { + vRet = FALSE; + return FALSE; + } + + if ((pFormField->GetFieldType() == FIELDTYPE_CHECKBOX) || + (pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON)) { + if (pFormField->GetControl(nIndex)->IsChecked() != 0) + vRet = TRUE; + else + vRet = FALSE; + } else { + vRet = FALSE; + } + + return TRUE; +} + +FX_BOOL Field::isDefaultChecked(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int nIndex = -1; + if (params.size() >= 1) + nIndex = params[0].ToInt(); + + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + if (nIndex < 0 || nIndex >= pFormField->CountControls()) { + vRet = FALSE; + return FALSE; + } + if ((pFormField->GetFieldType() == FIELDTYPE_CHECKBOX) || + (pFormField->GetFieldType() == FIELDTYPE_RADIOBUTTON)) { + if (pFormField->GetControl(nIndex)->IsDefaultChecked() != 0) + vRet = TRUE; + else + vRet = FALSE; + } else { + vRet = FALSE; + } + + return TRUE; +} + +FX_BOOL Field::setAction(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::setFocus(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + std::vector<CPDF_FormField*> FieldArray = GetFormFields(m_FieldName); + if (FieldArray.empty()) + return FALSE; + + CPDF_FormField* pFormField = FieldArray[0]; + int32_t nCount = pFormField->CountControls(); + if (nCount < 1) + return FALSE; + + CPDFSDK_InterForm* pInterForm = + (CPDFSDK_InterForm*)m_pDocument->GetInterForm(); + CPDFSDK_Widget* pWidget = NULL; + if (nCount == 1) { + pWidget = pInterForm->GetWidget(pFormField->GetControl(0)); + } else { + CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); + UnderlyingPageType* pPage = UnderlyingFromFPDFPage( + pEnv->FFI_GetCurrentPage(m_pDocument->GetUnderlyingDocument())); + if (!pPage) + return FALSE; + if (CPDFSDK_PageView* pCurPageView = m_pDocument->GetPageView(pPage)) { + for (int32_t i = 0; i < nCount; i++) { + if (CPDFSDK_Widget* pTempWidget = + pInterForm->GetWidget(pFormField->GetControl(i))) { + if (pTempWidget->GetPDFPage() == pCurPageView->GetPDFPage()) { + pWidget = pTempWidget; + break; + } + } + } + } + } + + if (pWidget) { + m_pDocument->SetFocusAnnot(pWidget); + } + + return TRUE; +} + +FX_BOOL Field::setItems(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL Field::setLock(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::signatureGetModifications(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::signatureGetSeedValue(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::signatureInfo(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::signatureSetSeedValue(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::signatureSign(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::signatureValidate(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL Field::source(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp << (CJS_Object*)NULL; + } + + return TRUE; +} + +void Field::AddDelay_Int(enum FIELD_PROP prop, int32_t n) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + pNewData->num = n; + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_Bool(enum FIELD_PROP prop, bool b) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + pNewData->b = b; + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_String(enum FIELD_PROP prop, + const CFX_ByteString& string) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + pNewData->string = string; + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_WideString(enum FIELD_PROP prop, + const CFX_WideString& string) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + pNewData->widestring = string; + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_Rect(enum FIELD_PROP prop, const CFX_FloatRect& rect) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + pNewData->rect = rect; + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_Color(enum FIELD_PROP prop, const CPWL_Color& color) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + pNewData->color = color; + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_WordArray(enum FIELD_PROP prop, + const CFX_DWordArray& array) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + + for (int i = 0, sz = array.GetSize(); i < sz; i++) + pNewData->wordarray.Add(array.GetAt(i)); + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::AddDelay_WideStringArray(enum FIELD_PROP prop, + const CJS_WideStringArray& array) { + CJS_DelayData* pNewData = new CJS_DelayData; + pNewData->sFieldName = m_FieldName; + pNewData->nControlIndex = m_nFormControlIndex; + pNewData->eProp = prop; + for (int i = 0, sz = array.GetSize(); i < sz; i++) + pNewData->widestringarray.Add(array.GetAt(i)); + + m_pJSDoc->AddDelayData(pNewData); +} + +void Field::DoDelay(CPDFSDK_Document* pDocument, CJS_DelayData* pData) { + ASSERT(pDocument); + + switch (pData->eProp) { + case FP_ALIGNMENT: + Field::SetAlignment(pDocument, pData->sFieldName, pData->nControlIndex, + pData->string); + break; + case FP_BORDERSTYLE: + Field::SetBorderStyle(pDocument, pData->sFieldName, pData->nControlIndex, + pData->string); + break; + case FP_BUTTONALIGNX: + Field::SetButtonAlignX(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_BUTTONALIGNY: + Field::SetButtonAlignY(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_BUTTONFITBOUNDS: + Field::SetButtonFitBounds(pDocument, pData->sFieldName, + pData->nControlIndex, pData->b); + break; + case FP_BUTTONPOSITION: + Field::SetButtonPosition(pDocument, pData->sFieldName, + pData->nControlIndex, pData->num); + break; + case FP_BUTTONSCALEHOW: + Field::SetButtonScaleHow(pDocument, pData->sFieldName, + pData->nControlIndex, pData->num); + break; + case FP_BUTTONSCALEWHEN: + Field::SetButtonScaleWhen(pDocument, pData->sFieldName, + pData->nControlIndex, pData->num); + break; + case FP_CALCORDERINDEX: + Field::SetCalcOrderIndex(pDocument, pData->sFieldName, + pData->nControlIndex, pData->num); + break; + case FP_CHARLIMIT: + Field::SetCharLimit(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_COMB: + Field::SetComb(pDocument, pData->sFieldName, pData->nControlIndex, + pData->b); + break; + case FP_COMMITONSELCHANGE: + Field::SetCommitOnSelChange(pDocument, pData->sFieldName, + pData->nControlIndex, pData->b); + break; + case FP_CURRENTVALUEINDICES: + Field::SetCurrentValueIndices(pDocument, pData->sFieldName, + pData->nControlIndex, pData->wordarray); + break; + case FP_DEFAULTVALUE: + Field::SetDefaultValue(pDocument, pData->sFieldName, pData->nControlIndex, + pData->widestring); + break; + case FP_DONOTSCROLL: + Field::SetDoNotScroll(pDocument, pData->sFieldName, pData->nControlIndex, + pData->b); + break; + case FP_DISPLAY: + Field::SetDisplay(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_FILLCOLOR: + Field::SetFillColor(pDocument, pData->sFieldName, pData->nControlIndex, + pData->color); + break; + case FP_HIDDEN: + Field::SetHidden(pDocument, pData->sFieldName, pData->nControlIndex, + pData->b); + break; + case FP_HIGHLIGHT: + Field::SetHighlight(pDocument, pData->sFieldName, pData->nControlIndex, + pData->string); + break; + case FP_LINEWIDTH: + Field::SetLineWidth(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_MULTILINE: + Field::SetMultiline(pDocument, pData->sFieldName, pData->nControlIndex, + pData->b); + break; + case FP_MULTIPLESELECTION: + Field::SetMultipleSelection(pDocument, pData->sFieldName, + pData->nControlIndex, pData->b); + break; + case FP_PASSWORD: + Field::SetPassword(pDocument, pData->sFieldName, pData->nControlIndex, + pData->b); + break; + case FP_RECT: + Field::SetRect(pDocument, pData->sFieldName, pData->nControlIndex, + pData->rect); + break; + case FP_RICHTEXT: + Field::SetRichText(pDocument, pData->sFieldName, pData->nControlIndex, + pData->b); + break; + case FP_RICHVALUE: + break; + case FP_ROTATION: + Field::SetRotation(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_STROKECOLOR: + Field::SetStrokeColor(pDocument, pData->sFieldName, pData->nControlIndex, + pData->color); + break; + case FP_STYLE: + Field::SetStyle(pDocument, pData->sFieldName, pData->nControlIndex, + pData->string); + break; + case FP_TEXTCOLOR: + Field::SetTextColor(pDocument, pData->sFieldName, pData->nControlIndex, + pData->color); + break; + case FP_TEXTFONT: + Field::SetTextFont(pDocument, pData->sFieldName, pData->nControlIndex, + pData->string); + break; + case FP_TEXTSIZE: + Field::SetTextSize(pDocument, pData->sFieldName, pData->nControlIndex, + pData->num); + break; + case FP_USERNAME: + Field::SetUserName(pDocument, pData->sFieldName, pData->nControlIndex, + pData->widestring); + break; + case FP_VALUE: + Field::SetValue(pDocument, pData->sFieldName, pData->nControlIndex, + pData->widestringarray); + break; + } +} + +void Field::AddField(CPDFSDK_Document* pDocument, + int nPageIndex, + int nFieldType, + const CFX_WideString& sName, + const CFX_FloatRect& rcCoords) { + // Not supported. +} diff --git a/fpdfsdk/javascript/Field.h b/fpdfsdk/javascript/Field.h new file mode 100644 index 0000000000..171b081669 --- /dev/null +++ b/fpdfsdk/javascript/Field.h @@ -0,0 +1,585 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_FIELD_H_ +#define FPDFSDK_JAVASCRIPT_FIELD_H_ + +#include <string> +#include <vector> + +#include "fpdfsdk/include/pdfwindow/PWL_Wnd.h" // For CPWL_Color. +#include "fpdfsdk/javascript/JS_Define.h" + +class CPDFSDK_Widget; +class Document; + +enum FIELD_PROP { + FP_ALIGNMENT, + FP_BORDERSTYLE, + FP_BUTTONALIGNX, + FP_BUTTONALIGNY, + FP_BUTTONFITBOUNDS, + FP_BUTTONPOSITION, + FP_BUTTONSCALEHOW, + FP_BUTTONSCALEWHEN, + FP_CALCORDERINDEX, + FP_CHARLIMIT, + FP_COMB, + FP_COMMITONSELCHANGE, + FP_CURRENTVALUEINDICES, + FP_DEFAULTVALUE, + FP_DONOTSCROLL, + FP_DISPLAY, + FP_FILLCOLOR, + FP_HIDDEN, + FP_HIGHLIGHT, + FP_LINEWIDTH, + FP_MULTILINE, + FP_MULTIPLESELECTION, + FP_PASSWORD, + FP_RECT, + FP_RICHTEXT, + FP_RICHVALUE, + FP_ROTATION, + FP_STROKECOLOR, + FP_STYLE, + FP_TEXTCOLOR, + FP_TEXTFONT, + FP_TEXTSIZE, + FP_USERNAME, + FP_VALUE +}; + +class CJS_WideStringArray { + public: + CJS_WideStringArray() {} + virtual ~CJS_WideStringArray() { + for (int i = 0, sz = m_Data.GetSize(); i < sz; i++) + delete m_Data.GetAt(i); + m_Data.RemoveAll(); + } + + void Add(const CFX_WideString& string) { + m_Data.Add(new CFX_WideString(string)); + } + + int GetSize() const { return m_Data.GetSize(); } + + CFX_WideString GetAt(int i) const { return *m_Data.GetAt(i); } + + private: + CFX_ArrayTemplate<CFX_WideString*> m_Data; +}; + +struct CJS_DelayData { + CFX_WideString sFieldName; + int nControlIndex; + enum FIELD_PROP eProp; + int32_t num; + bool b; + CFX_ByteString string; + CFX_WideString widestring; + CFX_FloatRect rect; + CPWL_Color color; + CFX_DWordArray wordarray; + CJS_WideStringArray widestringarray; +}; + +class Field : public CJS_EmbedObj { + public: + explicit Field(CJS_Object* pJSObject); + ~Field() override; + + FX_BOOL alignment(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL borderStyle(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL buttonAlignX(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL buttonAlignY(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL buttonFitBounds(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL buttonPosition(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL buttonScaleHow(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL buttonScaleWhen(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL calcOrderIndex(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL charLimit(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL comb(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL commitOnSelChange(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL currentValueIndices(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL defaultStyle(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL defaultValue(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL doNotScroll(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL doNotSpellCheck(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL delay(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL display(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL doc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL editable(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL exportValues(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL fileSelect(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL fillColor(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL hidden(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL highlight(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL lineWidth(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL multiline(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL multipleSelection(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL numItems(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL page(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL password(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL print(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL radiosInUnison(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL readonly(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL rect(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL required(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL richText(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL richValue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL rotation(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL strokeColor(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL style(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL submitName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL textColor(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL textFont(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL textSize(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL userName(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL value(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL valueAsString(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL source(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + + FX_BOOL browseForFileToSubmit(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL buttonGetCaption(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL buttonGetIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL buttonImportIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL buttonSetCaption(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL buttonSetIcon(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL checkThisBox(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL clearItems(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL defaultIsChecked(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL deleteItemAt(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getArray(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getItemAt(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL getLock(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL insertItemAt(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL isBoxChecked(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL isDefaultChecked(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL setAction(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL setFocus(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL setItems(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL setLock(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL signatureGetModifications(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL signatureGetSeedValue(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL signatureInfo(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL signatureSetSeedValue(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL signatureSign(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL signatureValidate(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + + static void SetAlignment(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string); + static void SetBorderStyle(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string); + static void SetButtonAlignX(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetButtonAlignY(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetButtonFitBounds(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetButtonPosition(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetButtonScaleHow(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetButtonScaleWhen(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetCalcOrderIndex(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetCharLimit(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetComb(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetCommitOnSelChange(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetCurrentValueIndices(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_DWordArray& array); + static void SetDefaultStyle(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex); + static void SetDefaultValue(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_WideString& string); + static void SetDoNotScroll(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetDisplay(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetFillColor(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CPWL_Color& color); + static void SetHidden(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetHighlight(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string); + static void SetLineWidth(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetMultiline(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetMultipleSelection(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetPassword(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetRect(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_FloatRect& rect); + static void SetRichText(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + bool b); + static void SetRichValue(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex); + static void SetRotation(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetStrokeColor(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CPWL_Color& color); + static void SetStyle(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string); + static void SetTextColor(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CPWL_Color& color); + static void SetTextFont(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_ByteString& string); + static void SetTextSize(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + int number); + static void SetUserName(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CFX_WideString& string); + static void SetValue(CPDFSDK_Document* pDocument, + const CFX_WideString& swFieldName, + int nControlIndex, + const CJS_WideStringArray& strArray); + + static void AddField(CPDFSDK_Document* pDocument, + int nPageIndex, + int nFieldType, + const CFX_WideString& sName, + const CFX_FloatRect& rcCoords); + + static void UpdateFormField(CPDFSDK_Document* pDocument, + CPDF_FormField* pFormField, + FX_BOOL bChangeMark, + FX_BOOL bResetAP, + FX_BOOL bRefresh); + static void UpdateFormControl(CPDFSDK_Document* pDocument, + CPDF_FormControl* pFormControl, + FX_BOOL bChangeMark, + FX_BOOL bResetAP, + FX_BOOL bRefresh); + + static CPDFSDK_Widget* GetWidget(CPDFSDK_Document* pDocument, + CPDF_FormControl* pFormControl); + static std::vector<CPDF_FormField*> GetFormFields( + CPDFSDK_Document* pDocument, + const CFX_WideString& csFieldName); + + static void DoDelay(CPDFSDK_Document* pDocument, CJS_DelayData* pData); + + FX_BOOL AttachField(Document* pDocument, const CFX_WideString& csFieldName); + void SetDelay(FX_BOOL bDelay); + void SetIsolate(v8::Isolate* isolate) { m_isolate = isolate; } + + protected: + void ParseFieldName(const std::wstring& strFieldNameParsed, + std::wstring& strFieldName, + int& iControlNo); + std::vector<CPDF_FormField*> GetFormFields( + const CFX_WideString& csFieldName) const; + CPDF_FormControl* GetSmartFieldControl(CPDF_FormField* pFormField); + FX_BOOL ValueIsOccur(CPDF_FormField* pFormField, CFX_WideString csOptLabel); + + void AddDelay_Int(enum FIELD_PROP prop, int32_t n); + void AddDelay_Bool(enum FIELD_PROP prop, bool b); + void AddDelay_String(enum FIELD_PROP prop, const CFX_ByteString& string); + void AddDelay_WideString(enum FIELD_PROP prop, const CFX_WideString& string); + void AddDelay_Rect(enum FIELD_PROP prop, const CFX_FloatRect& rect); + void AddDelay_Color(enum FIELD_PROP prop, const CPWL_Color& color); + void AddDelay_WordArray(enum FIELD_PROP prop, const CFX_DWordArray& array); + void AddDelay_WideStringArray(enum FIELD_PROP prop, + const CJS_WideStringArray& array); + + void DoDelay(); + + public: + Document* m_pJSDoc; + CPDFSDK_Document* m_pDocument; + CFX_WideString m_FieldName; + int m_nFormControlIndex; + FX_BOOL m_bCanSet; + + FX_BOOL m_bDelay; + v8::Isolate* m_isolate; +}; + +class CJS_Field : public CJS_Object { + public: + explicit CJS_Field(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Field(void) override {} + + void InitInstance(IJS_Runtime* pIRuntime) override; + + DECLARE_JS_CLASS(); + JS_STATIC_PROP(alignment, Field); + JS_STATIC_PROP(borderStyle, Field); + JS_STATIC_PROP(buttonAlignX, Field); + JS_STATIC_PROP(buttonAlignY, Field); + JS_STATIC_PROP(buttonFitBounds, Field); + JS_STATIC_PROP(buttonPosition, Field); + JS_STATIC_PROP(buttonScaleHow, Field); + JS_STATIC_PROP(buttonScaleWhen, Field); + JS_STATIC_PROP(calcOrderIndex, Field); + JS_STATIC_PROP(charLimit, Field); + JS_STATIC_PROP(comb, Field); + JS_STATIC_PROP(commitOnSelChange, Field); + JS_STATIC_PROP(currentValueIndices, Field); + JS_STATIC_PROP(defaultStyle, Field); + JS_STATIC_PROP(defaultValue, Field); + JS_STATIC_PROP(doNotScroll, Field); + JS_STATIC_PROP(doNotSpellCheck, Field); + JS_STATIC_PROP(delay, Field); + JS_STATIC_PROP(display, Field); + JS_STATIC_PROP(doc, Field); + JS_STATIC_PROP(editable, Field); + JS_STATIC_PROP(exportValues, Field); + JS_STATIC_PROP(fileSelect, Field); + JS_STATIC_PROP(fillColor, Field); + JS_STATIC_PROP(hidden, Field); + JS_STATIC_PROP(highlight, Field); + JS_STATIC_PROP(lineWidth, Field); + JS_STATIC_PROP(multiline, Field); + JS_STATIC_PROP(multipleSelection, Field); + JS_STATIC_PROP(name, Field); + JS_STATIC_PROP(numItems, Field); + JS_STATIC_PROP(page, Field); + JS_STATIC_PROP(password, Field); + JS_STATIC_PROP(print, Field); + JS_STATIC_PROP(radiosInUnison, Field); + JS_STATIC_PROP(readonly, Field); + JS_STATIC_PROP(rect, Field); + JS_STATIC_PROP(required, Field); + JS_STATIC_PROP(richText, Field); + JS_STATIC_PROP(richValue, Field); + JS_STATIC_PROP(rotation, Field); + JS_STATIC_PROP(strokeColor, Field); + JS_STATIC_PROP(style, Field); + JS_STATIC_PROP(submitName, Field); + JS_STATIC_PROP(textColor, Field); + JS_STATIC_PROP(textFont, Field); + JS_STATIC_PROP(textSize, Field); + JS_STATIC_PROP(type, Field); + JS_STATIC_PROP(userName, Field); + JS_STATIC_PROP(value, Field); + JS_STATIC_PROP(valueAsString, Field); + JS_STATIC_PROP(source, Field); + + JS_STATIC_METHOD(browseForFileToSubmit, Field); + JS_STATIC_METHOD(buttonGetCaption, Field); + JS_STATIC_METHOD(buttonGetIcon, Field); + JS_STATIC_METHOD(buttonImportIcon, Field); + JS_STATIC_METHOD(buttonSetCaption, Field); + JS_STATIC_METHOD(buttonSetIcon, Field); + JS_STATIC_METHOD(checkThisBox, Field); + JS_STATIC_METHOD(clearItems, Field); + JS_STATIC_METHOD(defaultIsChecked, Field); + JS_STATIC_METHOD(deleteItemAt, Field); + JS_STATIC_METHOD(getArray, Field); + JS_STATIC_METHOD(getItemAt, Field); + JS_STATIC_METHOD(getLock, Field); + JS_STATIC_METHOD(insertItemAt, Field); + JS_STATIC_METHOD(isBoxChecked, Field); + JS_STATIC_METHOD(isDefaultChecked, Field); + JS_STATIC_METHOD(setAction, Field); + JS_STATIC_METHOD(setFocus, Field); + JS_STATIC_METHOD(setItems, Field); + JS_STATIC_METHOD(setLock, Field); + JS_STATIC_METHOD(signatureGetModifications, Field); + JS_STATIC_METHOD(signatureGetSeedValue, Field); + JS_STATIC_METHOD(signatureInfo, Field); + JS_STATIC_METHOD(signatureSetSeedValue, Field); + JS_STATIC_METHOD(signatureSign, Field); + JS_STATIC_METHOD(signatureValidate, Field); +}; + +#endif // FPDFSDK_JAVASCRIPT_FIELD_H_ diff --git a/fpdfsdk/javascript/Icon.cpp b/fpdfsdk/javascript/Icon.cpp new file mode 100644 index 0000000000..d3c2ba8039 --- /dev/null +++ b/fpdfsdk/javascript/Icon.cpp @@ -0,0 +1,56 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/Icon.h" + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" + +/* ---------------------- Icon ---------------------- */ + +BEGIN_JS_STATIC_CONST(CJS_Icon) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Icon) +JS_STATIC_PROP_ENTRY(name) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Icon) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Icon, Icon) + +Icon::Icon(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject), m_pIconStream(NULL), m_swIconName(L"") {} + +Icon::~Icon() {} + +void Icon::SetStream(CPDF_Stream* pIconStream) { + if (pIconStream) + m_pIconStream = pIconStream; +} + +CPDF_Stream* Icon::GetStream() { + return m_pIconStream; +} + +void Icon::SetIconName(CFX_WideString name) { + m_swIconName = name; +} + +CFX_WideString Icon::GetIconName() { + return m_swIconName; +} + +FX_BOOL Icon::name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + vp << m_swIconName; + return TRUE; +} diff --git a/fpdfsdk/javascript/Icon.h b/fpdfsdk/javascript/Icon.h new file mode 100644 index 0000000000..bd125d8299 --- /dev/null +++ b/fpdfsdk/javascript/Icon.h @@ -0,0 +1,37 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_ICON_H_ +#define FPDFSDK_JAVASCRIPT_ICON_H_ + +#include "fpdfsdk/javascript/JS_Define.h" + +class Icon : public CJS_EmbedObj { + public: + Icon(CJS_Object* pJSObject); + ~Icon() override; + + FX_BOOL name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + void SetStream(CPDF_Stream* pIconStream); + CPDF_Stream* GetStream(); + void SetIconName(CFX_WideString name); + CFX_WideString GetIconName(); + + private: + CPDF_Stream* m_pIconStream; + CFX_WideString m_swIconName; +}; + +class CJS_Icon : public CJS_Object { + public: + CJS_Icon(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Icon() override {} + + DECLARE_JS_CLASS(); + JS_STATIC_PROP(name, Icon); +}; + +#endif // FPDFSDK_JAVASCRIPT_ICON_H_ diff --git a/fpdfsdk/javascript/JS_Context.cpp b/fpdfsdk/javascript/JS_Context.cpp new file mode 100644 index 0000000000..c382b07b8b --- /dev/null +++ b/fpdfsdk/javascript/JS_Context.cpp @@ -0,0 +1,284 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/JS_Context.h" + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/resource.h" + +/* -------------------------- CJS_Context -------------------------- */ + +CJS_Context::CJS_Context(CJS_Runtime* pRuntime) + : m_pRuntime(pRuntime), m_bBusy(FALSE), m_bMsgBoxEnable(TRUE) { + m_pEventHandler = new CJS_EventHandler(this); +} + +CJS_Context::~CJS_Context() { + delete m_pEventHandler; +} + +CPDFSDK_Document* CJS_Context::GetReaderDocument() { + return m_pRuntime->GetReaderDocument(); +} + +CPDFDoc_Environment* CJS_Context::GetReaderApp() { + return m_pRuntime->GetReaderApp(); +} + +FX_BOOL CJS_Context::RunScript(const CFX_WideString& script, + CFX_WideString* info) { + v8::Isolate::Scope isolate_scope(m_pRuntime->GetIsolate()); +#ifdef PDF_ENABLE_XFA + v8::Locker locker(m_pRuntime->GetIsolate()); +#endif // PDF_ENABLE_XFA + v8::HandleScope handle_scope(m_pRuntime->GetIsolate()); + v8::Local<v8::Context> context = m_pRuntime->NewJSContext(); + v8::Context::Scope context_scope(context); + + if (m_bBusy) { + *info = JSGetStringFromID(this, IDS_STRING_JSBUSY); + return FALSE; + } + m_bBusy = TRUE; + + ASSERT(m_pEventHandler->IsValid()); + CJS_Runtime::FieldEvent event(m_pEventHandler->TargetName(), + m_pEventHandler->EventType()); + if (!m_pRuntime->AddEventToSet(event)) { + *info = JSGetStringFromID(this, IDS_STRING_JSEVENT); + return FALSE; + } + + CFX_WideString sErrorMessage; + int nRet = 0; + if (script.GetLength() > 0) { + nRet = m_pRuntime->Execute(this, script.c_str(), &sErrorMessage); + } + + if (nRet < 0) { + *info += sErrorMessage; + } else { + *info = JSGetStringFromID(this, IDS_STRING_RUN); + } + + m_pRuntime->RemoveEventFromSet(event); + m_pEventHandler->Destroy(); + m_bBusy = FALSE; + + return nRet >= 0; +} + +void CJS_Context::OnApp_Init() { + m_pEventHandler->OnApp_Init(); +} + +void CJS_Context::OnDoc_Open(CPDFSDK_Document* pDoc, + const CFX_WideString& strTargetName) { + m_pEventHandler->OnDoc_Open(pDoc, strTargetName); +} + +void CJS_Context::OnDoc_WillPrint(CPDFSDK_Document* pDoc) { + m_pEventHandler->OnDoc_WillPrint(pDoc); +} + +void CJS_Context::OnDoc_DidPrint(CPDFSDK_Document* pDoc) { + m_pEventHandler->OnDoc_DidPrint(pDoc); +} + +void CJS_Context::OnDoc_WillSave(CPDFSDK_Document* pDoc) { + m_pEventHandler->OnDoc_WillSave(pDoc); +} + +void CJS_Context::OnDoc_DidSave(CPDFSDK_Document* pDoc) { + m_pEventHandler->OnDoc_DidSave(pDoc); +} + +void CJS_Context::OnDoc_WillClose(CPDFSDK_Document* pDoc) { + m_pEventHandler->OnDoc_WillClose(pDoc); +} + +void CJS_Context::OnPage_Open(CPDFSDK_Document* pTarget) { + m_pEventHandler->OnPage_Open(pTarget); +} + +void CJS_Context::OnPage_Close(CPDFSDK_Document* pTarget) { + m_pEventHandler->OnPage_Close(pTarget); +} + +void CJS_Context::OnPage_InView(CPDFSDK_Document* pTarget) { + m_pEventHandler->OnPage_InView(pTarget); +} + +void CJS_Context::OnPage_OutView(CPDFSDK_Document* pTarget) { + m_pEventHandler->OnPage_OutView(pTarget); +} + +void CJS_Context::OnField_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + m_pEventHandler->OnField_MouseDown(bModifier, bShift, pTarget); +} + +void CJS_Context::OnField_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + m_pEventHandler->OnField_MouseEnter(bModifier, bShift, pTarget); +} + +void CJS_Context::OnField_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + m_pEventHandler->OnField_MouseExit(bModifier, bShift, pTarget); +} + +void CJS_Context::OnField_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + m_pEventHandler->OnField_MouseUp(bModifier, bShift, pTarget); +} + +void CJS_Context::OnField_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) { + m_pEventHandler->OnField_Focus(bModifier, bShift, pTarget, Value); +} + +void CJS_Context::OnField_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) { + m_pEventHandler->OnField_Blur(bModifier, bShift, pTarget, Value); +} + +void CJS_Context::OnField_Calculate(CPDF_FormField* pSource, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) { + m_pEventHandler->OnField_Calculate(pSource, pTarget, Value, bRc); +} + +void CJS_Context::OnField_Format(CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit) { + m_pEventHandler->OnField_Format(pTarget, Value, bWillCommit); +} + +void CJS_Context::OnField_Keystroke(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + int& nSelEnd, + int& nSelStart, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit, + FX_BOOL bFieldFull, + FX_BOOL& bRc) { + m_pEventHandler->OnField_Keystroke( + strChange, strChangeEx, bKeyDown, bModifier, nSelEnd, nSelStart, bShift, + pTarget, Value, bWillCommit, bFieldFull, bRc); +} + +void CJS_Context::OnField_Validate(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) { + m_pEventHandler->OnField_Validate(strChange, strChangeEx, bKeyDown, bModifier, + bShift, pTarget, Value, bRc); +} + +void CJS_Context::OnScreen_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_Focus(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_Blur(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_Open(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_Open(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_Close(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_Close(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_MouseDown(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_MouseUp(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_MouseEnter(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_MouseExit(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_InView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_InView(bModifier, bShift, pScreen); +} + +void CJS_Context::OnScreen_OutView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + m_pEventHandler->OnScreen_OutView(bModifier, bShift, pScreen); +} + +void CJS_Context::OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) { + m_pEventHandler->OnBookmark_MouseUp(pBookMark); +} + +void CJS_Context::OnLink_MouseUp(CPDFSDK_Document* pTarget) { + m_pEventHandler->OnLink_MouseUp(pTarget); +} + +void CJS_Context::OnConsole_Exec() { + m_pEventHandler->OnConsole_Exec(); +} + +void CJS_Context::OnExternal_Exec() { + m_pEventHandler->OnExternal_Exec(); +} + +void CJS_Context::OnBatchExec(CPDFSDK_Document* pTarget) { + m_pEventHandler->OnBatchExec(pTarget); +} + +void CJS_Context::OnMenu_Exec(CPDFSDK_Document* pTarget, + const CFX_WideString& strTargetName) { + m_pEventHandler->OnMenu_Exec(pTarget, strTargetName); +} diff --git a/fpdfsdk/javascript/JS_Context.h b/fpdfsdk/javascript/JS_Context.h new file mode 100644 index 0000000000..cd57187720 --- /dev/null +++ b/fpdfsdk/javascript/JS_Context.h @@ -0,0 +1,137 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_CONTEXT_H_ +#define FPDFSDK_JAVASCRIPT_JS_CONTEXT_H_ + +#include "core/include/fxcrt/fx_string.h" +#include "core/include/fxcrt/fx_system.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" + +class CJS_EventHandler; +class CJS_Runtime; + +class CJS_Context : public IJS_Context { + public: + explicit CJS_Context(CJS_Runtime* pRuntime); + ~CJS_Context() override; + + // IJS_Context + FX_BOOL RunScript(const CFX_WideString& script, + CFX_WideString* info) override; + void OnApp_Init() override; + void OnDoc_Open(CPDFSDK_Document* pDoc, + const CFX_WideString& strTargetName) override; + void OnDoc_WillPrint(CPDFSDK_Document* pDoc) override; + void OnDoc_DidPrint(CPDFSDK_Document* pDoc) override; + void OnDoc_WillSave(CPDFSDK_Document* pDoc) override; + void OnDoc_DidSave(CPDFSDK_Document* pDoc) override; + void OnDoc_WillClose(CPDFSDK_Document* pDoc) override; + void OnPage_Open(CPDFSDK_Document* pTarget) override; + void OnPage_Close(CPDFSDK_Document* pTarget) override; + void OnPage_InView(CPDFSDK_Document* pTarget) override; + void OnPage_OutView(CPDFSDK_Document* pTarget) override; + void OnField_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override; + void OnField_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override; + void OnField_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override; + void OnField_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override; + void OnField_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) override; + void OnField_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) override; + void OnField_Calculate(CPDF_FormField* pSource, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) override; + void OnField_Format(CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit) override; + void OnField_Keystroke(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + int& nSelEnd, + int& nSelStart, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit, + FX_BOOL bFieldFull, + FX_BOOL& bRc) override; + void OnField_Validate(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) override; + void OnScreen_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_Open(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_Close(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_InView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnScreen_OutView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override; + void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) override; + void OnLink_MouseUp(CPDFSDK_Document* pTarget) override; + void OnMenu_Exec(CPDFSDK_Document* pTarget, + const CFX_WideString& strTargetName) override; + void OnBatchExec(CPDFSDK_Document* pTarget) override; + void OnConsole_Exec() override; + void OnExternal_Exec() override; + void EnableMessageBox(FX_BOOL bEnable) override { m_bMsgBoxEnable = bEnable; } + + FX_BOOL IsMsgBoxEnabled() const { return m_bMsgBoxEnable; } + + CPDFDoc_Environment* GetReaderApp(); + CJS_Runtime* GetJSRuntime() const { return m_pRuntime; } + CJS_EventHandler* GetEventHandler() const { return m_pEventHandler; } + CPDFSDK_Document* GetReaderDocument(); + + private: + CJS_Runtime* m_pRuntime; + CJS_EventHandler* m_pEventHandler; + FX_BOOL m_bBusy; + FX_BOOL m_bMsgBoxEnable; +}; + +#endif // FPDFSDK_JAVASCRIPT_JS_CONTEXT_H_ diff --git a/fpdfsdk/javascript/JS_Define.h b/fpdfsdk/javascript/JS_Define.h new file mode 100644 index 0000000000..3c148cf358 --- /dev/null +++ b/fpdfsdk/javascript/JS_Define.h @@ -0,0 +1,493 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_DEFINE_H_ +#define FPDFSDK_JAVASCRIPT_JS_DEFINE_H_ + +#include <vector> + +#include "fpdfsdk/include/jsapi/fxjs_v8.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/resource.h" + +struct JSConstSpec { + const wchar_t* pName; + double number; + const wchar_t* string; // NOLINT + uint8_t t; // 0:double 1:str +}; + +struct JSPropertySpec { + const wchar_t* pName; + v8::AccessorGetterCallback pPropGet; + v8::AccessorSetterCallback pPropPut; +}; + +struct JSMethodSpec { + const wchar_t* pName; + v8::FunctionCallback pMethodCall; +}; + +#define JS_WIDESTRING(widestring) L## #widestring +#define BEGIN_JS_STATIC_CONST(js_class_name) \ + JSConstSpec js_class_name::JS_Class_Consts[] = { +#define JS_STATIC_CONST_ENTRY_NUMBER(const_name, pValue) \ + { const_name, pValue, L"", 0 } \ + , + +#define JS_STATIC_CONST_ENTRY_STRING(const_name, pValue) \ + { const_name, 0, pValue, 1 } \ + , + +#define END_JS_STATIC_CONST() \ + { 0, 0, 0, 0 } \ + } \ + ; // NOLINT + +#define BEGIN_JS_STATIC_PROP(js_class_name) \ + JSPropertySpec js_class_name::JS_Class_Properties[] = { +#define JS_STATIC_PROP_ENTRY(prop_name) \ + { \ + JS_WIDESTRING(prop_name), get_##prop_name##_static, \ + set_##prop_name##_static \ + } \ + , + +#define END_JS_STATIC_PROP() \ + { 0, 0, 0 } \ + } \ + ; // NOLINT + +#define BEGIN_JS_STATIC_METHOD(js_class_name) \ + JSMethodSpec js_class_name::JS_Class_Methods[] = { +#define JS_STATIC_METHOD_ENTRY(method_name) \ + { JS_WIDESTRING(method_name), method_name##_static } \ + , + +#define END_JS_STATIC_METHOD() \ + { 0, 0 } \ + } \ + ; // NOLINT + +template <class C, + FX_BOOL (C::*M)(IJS_Context*, CJS_PropValue&, CFX_WideString&)> +void JSPropGetter(const char* prop_name_string, + const char* class_name_string, + v8::Local<v8::String> property, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + CJS_Runtime* pRuntime = + static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder()); + C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject()); + CFX_WideString sError; + CJS_PropValue value(pRuntime); + value.StartGetting(); + if (!(pObj->*M)(pContext, value, sError)) { + FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string, + sError)); + return; + } + info.GetReturnValue().Set((v8::Local<v8::Value>)value); +} + +template <class C, + FX_BOOL (C::*M)(IJS_Context*, CJS_PropValue&, CFX_WideString&)> +void JSPropSetter(const char* prop_name_string, + const char* class_name_string, + v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<void>& info) { + v8::Isolate* isolate = info.GetIsolate(); + CJS_Runtime* pRuntime = + static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder()); + C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject()); + CFX_WideString sError; + CJS_PropValue propValue(CJS_Value(pRuntime, value, CJS_Value::VT_unknown)); + propValue.StartSetting(); + if (!(pObj->*M)(pContext, propValue, sError)) { + FXJS_Error(isolate, JSFormatErrorString(class_name_string, prop_name_string, + sError)); + } +} + +#define JS_STATIC_PROP(prop_name, class_name) \ + static void get_##prop_name##_static( \ + v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Value>& info) { \ + JSPropGetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \ + property, info); \ + } \ + static void set_##prop_name##_static( \ + v8::Local<v8::String> property, v8::Local<v8::Value> value, \ + const v8::PropertyCallbackInfo<void>& info) { \ + JSPropSetter<class_name, &class_name::prop_name>(#prop_name, #class_name, \ + property, value, info); \ + } + +template <class C, + FX_BOOL (C::*M)(IJS_Context*, + const std::vector<CJS_Value>&, + CJS_Value&, + CFX_WideString&)> +void JSMethod(const char* method_name_string, + const char* class_name_string, + const v8::FunctionCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + CJS_Runtime* pRuntime = + static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + std::vector<CJS_Value> parameters; + for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) { + parameters.push_back(CJS_Value(pRuntime, info[i], CJS_Value::VT_unknown)); + } + CJS_Value valueRes(pRuntime); + CJS_Object* pJSObj = (CJS_Object*)FXJS_GetPrivate(isolate, info.Holder()); + C* pObj = reinterpret_cast<C*>(pJSObj->GetEmbedObject()); + CFX_WideString sError; + if (!(pObj->*M)(pContext, parameters, valueRes, sError)) { + FXJS_Error(isolate, JSFormatErrorString(class_name_string, + method_name_string, sError)); + return; + } + info.GetReturnValue().Set(valueRes.ToV8Value()); +} + +#define JS_STATIC_METHOD(method_name, class_name) \ + static void method_name##_static( \ + const v8::FunctionCallbackInfo<v8::Value>& info) { \ + JSMethod<class_name, &class_name::method_name>(#method_name, #class_name, \ + info); \ + } + +#define JS_SPECIAL_STATIC_METHOD(method_name, class_alternate, class_name) \ + static void method_name##_static( \ + const v8::FunctionCallbackInfo<v8::Value>& info) { \ + JSMethod<class_alternate, &class_alternate::method_name>( \ + #method_name, #class_name, info); \ + } + +// All JS classes have a name, an object defintion ID, and the ability to +// register themselves with FXJS_V8. We never make a BASE class on its own +// because it can't really do anything. +#define DECLARE_JS_CLASS_BASE_PART() \ + static const wchar_t* g_pClassName; \ + static int g_nObjDefnID; \ + static void DefineJSObjects(v8::Isolate* pIsolate, FXJSOBJTYPE eObjType); + +#define IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ + const wchar_t* js_class_name::g_pClassName = JS_WIDESTRING(class_name); \ + int js_class_name::g_nObjDefnID = -1; + +// CONST classes provide constants, but not constructors, methods, or props. +#define DECLARE_JS_CLASS_CONST() \ + DECLARE_JS_CLASS_BASE_PART() \ + DECLARE_JS_CLASS_CONST_PART() + +#define IMPLEMENT_JS_CLASS_CONST(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ + void js_class_name::DefineJSObjects(v8::Isolate* pIsolate, \ + FXJSOBJTYPE eObjType) { \ + g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \ + eObjType, nullptr, nullptr); \ + DefineConsts(pIsolate); \ + } + +#define DECLARE_JS_CLASS_CONST_PART() \ + static JSConstSpec JS_Class_Consts[]; \ + static void DefineConsts(v8::Isolate* pIsolate); + +#define IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ + void js_class_name::DefineConsts(v8::Isolate* pIsolate) { \ + for (size_t i = 0; i < FX_ArraySize(JS_Class_Consts) - 1; ++i) { \ + FXJS_DefineObjConst( \ + pIsolate, g_nObjDefnID, JS_Class_Consts[i].pName, \ + JS_Class_Consts[i].t == 0 \ + ? FXJS_NewNumber(pIsolate, JS_Class_Consts[i].number) \ + : FXJS_NewString(pIsolate, JS_Class_Consts[i].string)); \ + } \ + } + +// Convenience macros for declaring classes without an alternate. +#define DECLARE_JS_CLASS() DECLARE_JS_CLASS_RICH() +#define IMPLEMENT_JS_CLASS(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_RICH(js_class_name, class_name, class_name) + +// Rich JS classes provide constants, methods, properties, and the ability +// to construct native object state. +#define DECLARE_JS_CLASS_RICH() \ + DECLARE_JS_CLASS_BASE_PART() \ + DECLARE_JS_CLASS_CONST_PART() \ + DECLARE_JS_CLASS_RICH_PART() + +#define IMPLEMENT_JS_CLASS_RICH(js_class_name, class_alternate, class_name) \ + IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name) \ + void js_class_name::DefineJSObjects(v8::Isolate* pIsolate, \ + FXJSOBJTYPE eObjType) { \ + g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \ + eObjType, JSConstructor, JSDestructor); \ + DefineConsts(pIsolate); \ + DefineProps(pIsolate); \ + DefineMethods(pIsolate); \ + } + +#define DECLARE_JS_CLASS_RICH_PART() \ + static void JSConstructor(IJS_Runtime* pRuntime, v8::Local<v8::Object> obj); \ + static void JSDestructor(v8::Local<v8::Object> obj); \ + static void DefineProps(v8::Isolate* pIsoalte); \ + static void DefineMethods(v8::Isolate* pIsoalte); \ + static JSPropertySpec JS_Class_Properties[]; \ + static JSMethodSpec JS_Class_Methods[]; + +#define IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, \ + class_name) \ + void js_class_name::JSConstructor(IJS_Runtime* pIRuntime, \ + v8::Local<v8::Object> obj) { \ + CJS_Object* pObj = new js_class_name(obj); \ + pObj->SetEmbedObject(new class_alternate(pObj)); \ + FXJS_SetPrivate(nullptr, obj, (void*)pObj); \ + pObj->InitInstance(pIRuntime); \ + } \ + void js_class_name::JSDestructor(v8::Local<v8::Object> obj) { \ + js_class_name* pObj = (js_class_name*)FXJS_GetPrivate(nullptr, obj); \ + pObj->ExitInstance(); \ + delete pObj; \ + } \ + void js_class_name::DefineProps(v8::Isolate* pIsolate) { \ + for (size_t i = 0; i < FX_ArraySize(JS_Class_Properties) - 1; ++i) { \ + FXJS_DefineObjProperty( \ + pIsolate, g_nObjDefnID, JS_Class_Properties[i].pName, \ + JS_Class_Properties[i].pPropGet, JS_Class_Properties[i].pPropPut); \ + } \ + } \ + void js_class_name::DefineMethods(v8::Isolate* pIsolate) { \ + for (size_t i = 0; i < FX_ArraySize(JS_Class_Methods) - 1; ++i) { \ + FXJS_DefineObjMethod(pIsolate, g_nObjDefnID, JS_Class_Methods[i].pName, \ + JS_Class_Methods[i].pMethodCall); \ + } \ + } + +// Special JS classes implement methods, props, and queries, but not consts. +#define DECLARE_SPECIAL_JS_CLASS() \ + DECLARE_JS_CLASS_BASE_PART() \ + DECLARE_JS_CLASS_CONST_PART() \ + DECLARE_JS_CLASS_RICH_PART() \ + DECLARE_SPECIAL_JS_CLASS_PART() + +#define IMPLEMENT_SPECIAL_JS_CLASS(js_class_name, class_alternate, class_name) \ + IMPLEMENT_JS_CLASS_BASE_PART(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_CONST_PART(js_class_name, class_name) \ + IMPLEMENT_JS_CLASS_RICH_PART(js_class_name, class_alternate, class_name) \ + IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, class_name) \ + void js_class_name::DefineJSObjects(v8::Isolate* pIsolate, \ + FXJSOBJTYPE eObjType) { \ + g_nObjDefnID = FXJS_DefineObj(pIsolate, js_class_name::g_pClassName, \ + eObjType, JSConstructor, JSDestructor); \ + DefineConsts(pIsolate); \ + DefineProps(pIsolate); \ + DefineMethods(pIsolate); \ + DefineAllProperties(pIsolate); \ + } + +#define DECLARE_SPECIAL_JS_CLASS_PART() \ + static void queryprop_static( \ + v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Integer>& info); \ + static void getprop_static(v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Value>& info); \ + static void putprop_static(v8::Local<v8::String> property, \ + v8::Local<v8::Value> value, \ + const v8::PropertyCallbackInfo<v8::Value>& info); \ + static void delprop_static( \ + v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Boolean>& info); \ + static void DefineAllProperties(v8::Isolate* pIsolate); + +#define IMPLEMENT_SPECIAL_JS_CLASS_PART(js_class_name, class_alternate, \ + class_name) \ + void js_class_name::queryprop_static( \ + v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Integer>& info) { \ + JSSpecialPropQuery<class_alternate>(#class_name, property, info); \ + } \ + void js_class_name::getprop_static( \ + v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Value>& info) { \ + JSSpecialPropGet<class_alternate>(#class_name, property, info); \ + } \ + void js_class_name::putprop_static( \ + v8::Local<v8::String> property, v8::Local<v8::Value> value, \ + const v8::PropertyCallbackInfo<v8::Value>& info) { \ + JSSpecialPropPut<class_alternate>(#class_name, property, value, info); \ + } \ + void js_class_name::delprop_static( \ + v8::Local<v8::String> property, \ + const v8::PropertyCallbackInfo<v8::Boolean>& info) { \ + JSSpecialPropDel<class_alternate>(#class_name, property, info); \ + } \ + void js_class_name::DefineAllProperties(v8::Isolate* pIsolate) { \ + FXJS_DefineObjAllProperties( \ + pIsolate, g_nObjDefnID, js_class_name::queryprop_static, \ + js_class_name::getprop_static, js_class_name::putprop_static, \ + js_class_name::delprop_static); \ + } + +template <class Alt> +void JSSpecialPropQuery(const char*, + v8::Local<v8::String> property, + const v8::PropertyCallbackInfo<v8::Integer>& info) { + v8::Isolate* isolate = info.GetIsolate(); + v8::String::Utf8Value utf8_value(property); + CFX_WideString propname = + CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); + CJS_Object* pJSObj = + reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); + Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); + FX_BOOL bRet = pObj->QueryProperty(propname.c_str()); + info.GetReturnValue().Set(bRet ? 4 : 0); +} + +template <class Alt> +void JSSpecialPropGet(const char* class_name, + v8::Local<v8::String> property, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + CJS_Runtime* pRuntime = + static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + CJS_Object* pJSObj = + reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); + Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); + v8::String::Utf8Value utf8_value(property); + CFX_WideString propname = + CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); + CFX_WideString sError; + CJS_PropValue value(pRuntime); + value.StartGetting(); + if (!pObj->DoProperty(pContext, propname.c_str(), value, sError)) { + FXJS_Error(isolate, JSFormatErrorString(class_name, "GetProperty", sError)); + return; + } + info.GetReturnValue().Set((v8::Local<v8::Value>)value); +} + +template <class Alt> +void JSSpecialPropPut(const char* class_name, + v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + CJS_Runtime* pRuntime = + static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(isolate)); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + CJS_Object* pJSObj = + reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); + Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); + v8::String::Utf8Value utf8_value(property); + CFX_WideString propname = + CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); + CFX_WideString sError; + CJS_PropValue PropValue(CJS_Value(pRuntime, value, CJS_Value::VT_unknown)); + PropValue.StartSetting(); + if (!pObj->DoProperty(pContext, propname.c_str(), PropValue, sError)) { + FXJS_Error(isolate, JSFormatErrorString(class_name, "PutProperty", sError)); + } +} + +template <class Alt> +void JSSpecialPropDel(const char* class_name, + v8::Local<v8::String> property, + const v8::PropertyCallbackInfo<v8::Boolean>& info) { + v8::Isolate* isolate = info.GetIsolate(); + IJS_Runtime* pRuntime = FXJS_GetRuntimeFromIsolate(isolate); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + CJS_Object* pJSObj = + reinterpret_cast<CJS_Object*>(FXJS_GetPrivate(isolate, info.Holder())); + Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject()); + v8::String::Utf8Value utf8_value(property); + CFX_WideString propname = + CFX_WideString::FromUTF8(*utf8_value, utf8_value.length()); + CFX_WideString sError; + if (!pObj->DelProperty(pContext, propname.c_str(), sError)) { + CFX_ByteString cbName; + cbName.Format("%s.%s", class_name, "DelProperty"); + // Probably a missing call to JSFX_Error(). + } +} + +template <FX_BOOL (*F)(IJS_Context*, + const std::vector<CJS_Value>&, + CJS_Value&, + CFX_WideString&)> +void JSGlobalFunc(const char* func_name_string, + const v8::FunctionCallbackInfo<v8::Value>& info) { + CJS_Runtime* pRuntime = + static_cast<CJS_Runtime*>(FXJS_GetRuntimeFromIsolate(info.GetIsolate())); + if (!pRuntime) + return; + IJS_Context* pContext = pRuntime->GetCurrentContext(); + std::vector<CJS_Value> parameters; + for (unsigned int i = 0; i < (unsigned int)info.Length(); i++) { + parameters.push_back(CJS_Value(pRuntime, info[i], CJS_Value::VT_unknown)); + } + CJS_Value valueRes(pRuntime); + CFX_WideString sError; + if (!(*F)(pContext, parameters, valueRes, sError)) { + FXJS_Error(pRuntime->GetIsolate(), + JSFormatErrorString(func_name_string, nullptr, sError)); + return; + } + info.GetReturnValue().Set(valueRes.ToV8Value()); +} + +#define JS_STATIC_GLOBAL_FUN(fun_name) \ + static void fun_name##_static( \ + const v8::FunctionCallbackInfo<v8::Value>& info) { \ + JSGlobalFunc<fun_name>(#fun_name, info); \ + } + +#define JS_STATIC_DECLARE_GLOBAL_FUN() \ + static JSMethodSpec global_methods[]; \ + static void DefineJSObjects(v8::Isolate* pIsolate) + +#define BEGIN_JS_STATIC_GLOBAL_FUN(js_class_name) \ + JSMethodSpec js_class_name::global_methods[] = { +#define JS_STATIC_GLOBAL_FUN_ENTRY(method_name) \ + JS_STATIC_METHOD_ENTRY(method_name) + +#define END_JS_STATIC_GLOBAL_FUN() END_JS_STATIC_METHOD() + +#define IMPLEMENT_JS_STATIC_GLOBAL_FUN(js_class_name) \ + void js_class_name::DefineJSObjects(v8::Isolate* pIsolate) { \ + for (size_t i = 0; i < FX_ArraySize(global_methods) - 1; ++i) { \ + FXJS_DefineGlobalMethod(pIsolate, \ + js_class_name::global_methods[i].pName, \ + js_class_name::global_methods[i].pMethodCall); \ + } \ + } + +CJS_Value::Type GET_VALUE_TYPE(v8::Local<v8::Value> p); + +#endif // FPDFSDK_JAVASCRIPT_JS_DEFINE_H_ diff --git a/fpdfsdk/javascript/JS_EventHandler.cpp b/fpdfsdk/javascript/JS_EventHandler.cpp new file mode 100644 index 0000000000..697cfeb208 --- /dev/null +++ b/fpdfsdk/javascript/JS_EventHandler.cpp @@ -0,0 +1,659 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/JS_EventHandler.h" + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Document.h" +#include "fpdfsdk/javascript/Field.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" + +/* ---------------------------- CJS_EventHandler ---------------------------- */ + +CJS_EventHandler::CJS_EventHandler(CJS_Context* pContext) + : m_pJSContext(pContext), + m_eEventType(JET_UNKNOWN), + m_bValid(FALSE), + m_pWideStrChange(NULL), + m_nCommitKey(-1), + m_bKeyDown(FALSE), + m_bModifier(FALSE), + m_bShift(FALSE), + m_pISelEnd(NULL), + m_nSelEndDu(0), + m_pISelStart(NULL), + m_nSelStartDu(0), + m_bWillCommit(FALSE), + m_pValue(NULL), + m_bFieldFull(FALSE), + m_pbRc(NULL), + m_bRcDu(FALSE), + m_pSourceDoc(NULL), + m_pTargetBookMark(NULL), + m_pTargetDoc(NULL), + m_pTargetAnnot(NULL) {} + +CJS_EventHandler::~CJS_EventHandler() {} + +void CJS_EventHandler::OnApp_Init() { + Initial(JET_APP_INIT); +} + +void CJS_EventHandler::OnDoc_Open(CPDFSDK_Document* pDoc, + const CFX_WideString& strTargetName) { + Initial(JET_DOC_OPEN); + + m_pTargetDoc = pDoc; + m_strTargetName = strTargetName; +} + +void CJS_EventHandler::OnDoc_WillPrint(CPDFSDK_Document* pDoc) { + Initial(JET_DOC_WILLPRINT); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnDoc_DidPrint(CPDFSDK_Document* pDoc) { + Initial(JET_DOC_DIDPRINT); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnDoc_WillSave(CPDFSDK_Document* pDoc) { + Initial(JET_DOC_WILLSAVE); + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnDoc_DidSave(CPDFSDK_Document* pDoc) { + Initial(JET_DOC_DIDSAVE); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnDoc_WillClose(CPDFSDK_Document* pDoc) { + Initial(JET_DOC_WILLCLOSE); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnPage_Open(CPDFSDK_Document* pDoc) { + Initial(JET_PAGE_OPEN); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnPage_Close(CPDFSDK_Document* pDoc) { + Initial(JET_PAGE_CLOSE); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnPage_InView(CPDFSDK_Document* pDoc) { + Initial(JET_PAGE_INVIEW); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnPage_OutView(CPDFSDK_Document* pDoc) { + Initial(JET_PAGE_OUTVIEW); + + m_pTargetDoc = pDoc; +} + +void CJS_EventHandler::OnField_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + Initial(JET_FIELD_MOUSEENTER); + + m_bModifier = bModifier; + m_bShift = bShift; + + m_strTargetName = pTarget->GetFullName(); +} + +void CJS_EventHandler::OnField_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + Initial(JET_FIELD_MOUSEEXIT); + + m_bModifier = bModifier; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); +} + +void CJS_EventHandler::OnField_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + Initial(JET_FIELD_MOUSEDOWN); + m_eEventType = JET_FIELD_MOUSEDOWN; + + m_bModifier = bModifier; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); +} + +void CJS_EventHandler::OnField_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) { + Initial(JET_FIELD_MOUSEUP); + + m_bModifier = bModifier; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); +} + +void CJS_EventHandler::OnField_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) { + Initial(JET_FIELD_FOCUS); + + m_bModifier = bModifier; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); + m_pValue = (CFX_WideString*)&Value; +} + +void CJS_EventHandler::OnField_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) { + Initial(JET_FIELD_BLUR); + + m_bModifier = bModifier; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); + m_pValue = (CFX_WideString*)&Value; +} + +void CJS_EventHandler::OnField_Keystroke(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL KeyDown, + FX_BOOL bModifier, + int& nSelEnd, + int& nSelStart, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit, + FX_BOOL bFieldFull, + FX_BOOL& bRc) { + Initial(JET_FIELD_KEYSTROKE); + + m_nCommitKey = 0; + m_pWideStrChange = &strChange; + m_WideStrChangeEx = strChangeEx; + m_bKeyDown = KeyDown; + m_bModifier = bModifier; + m_pISelEnd = &nSelEnd; + m_pISelStart = &nSelStart; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); + m_pValue = &Value; + m_bWillCommit = bWillCommit; + m_pbRc = &bRc; + m_bFieldFull = bFieldFull; +} + +void CJS_EventHandler::OnField_Validate(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) { + Initial(JET_FIELD_VALIDATE); + + m_pWideStrChange = &strChange; + m_WideStrChangeEx = strChangeEx; + m_bKeyDown = bKeyDown; + m_bModifier = bModifier; + m_bShift = bShift; + m_strTargetName = pTarget->GetFullName(); + m_pValue = &Value; + m_pbRc = &bRc; +} + +void CJS_EventHandler::OnField_Calculate(CPDF_FormField* pSource, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) { + Initial(JET_FIELD_CALCULATE); + + if (pSource) + m_strSourceName = pSource->GetFullName(); + m_strTargetName = pTarget->GetFullName(); + m_pValue = &Value; + m_pbRc = &bRc; +} + +void CJS_EventHandler::OnField_Format(CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit) { + Initial(JET_FIELD_FORMAT); + + m_nCommitKey = 0; + m_strTargetName = pTarget->GetFullName(); + m_pValue = &Value; + m_bWillCommit = bWillCommit; +} + +void CJS_EventHandler::OnScreen_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_FOCUS); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_BLUR); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_Open(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_OPEN); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_Close(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_CLOSE); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_MOUSEDOWN); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_MOUSEUP); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_MOUSEENTER); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_MOUSEEXIT); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_InView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_INVIEW); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnScreen_OutView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) { + Initial(JET_SCREEN_OUTVIEW); + + m_bModifier = bModifier; + m_bShift = bShift; + m_pTargetAnnot = pScreen; +} + +void CJS_EventHandler::OnLink_MouseUp(CPDFSDK_Document* pTarget) { + Initial(JET_LINK_MOUSEUP); + + m_pTargetDoc = pTarget; +} + +void CJS_EventHandler::OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) { + Initial(JET_BOOKMARK_MOUSEUP); + + m_pTargetBookMark = pBookMark; +} + +void CJS_EventHandler::OnMenu_Exec(CPDFSDK_Document* pTarget, + const CFX_WideString& strTargetName) { + Initial(JET_MENU_EXEC); + + m_pTargetDoc = pTarget; + m_strTargetName = strTargetName; +} + +void CJS_EventHandler::OnExternal_Exec() { + Initial(JET_EXTERNAL_EXEC); +} + +void CJS_EventHandler::OnBatchExec(CPDFSDK_Document* pTarget) { + Initial(JET_BATCH_EXEC); + + m_pTargetDoc = pTarget; +} + +void CJS_EventHandler::OnConsole_Exec() { + Initial(JET_CONSOLE_EXEC); +} + +void CJS_EventHandler::Initial(JS_EVENT_T type) { + m_eEventType = type; + + m_strTargetName = L""; + m_strSourceName = L""; + m_pWideStrChange = NULL; + m_WideStrChangeDu = L""; + m_WideStrChangeEx = L""; + m_nCommitKey = -1; + m_bKeyDown = FALSE; + m_bModifier = FALSE; + m_bShift = FALSE; + m_pISelEnd = NULL; + m_nSelEndDu = 0; + m_pISelStart = NULL; + m_nSelStartDu = 0; + m_bWillCommit = FALSE; + m_pValue = NULL; + m_bFieldFull = FALSE; + m_pbRc = NULL; + m_bRcDu = FALSE; + + m_pSourceDoc = NULL; + m_pTargetBookMark = NULL; + m_pTargetDoc = NULL; + m_pTargetAnnot = NULL; + + m_bValid = TRUE; +} + +void CJS_EventHandler::Destroy() { + m_bValid = FALSE; +} + +FX_BOOL CJS_EventHandler::IsValid() { + return m_bValid; +} + +CFX_WideString& CJS_EventHandler::Change() { + if (m_pWideStrChange) { + return *m_pWideStrChange; + } + return m_WideStrChangeDu; +} + +CFX_WideString CJS_EventHandler::ChangeEx() { + return m_WideStrChangeEx; +} + +int CJS_EventHandler::CommitKey() { + return m_nCommitKey; +} + +FX_BOOL CJS_EventHandler::FieldFull() { + return m_bFieldFull; +} + +FX_BOOL CJS_EventHandler::KeyDown() { + return m_bKeyDown; +} + +FX_BOOL CJS_EventHandler::Modifier() { + return m_bModifier; +} + +const FX_WCHAR* CJS_EventHandler::Name() { + switch (m_eEventType) { + case JET_APP_INIT: + return L"Init"; + case JET_BATCH_EXEC: + return L"Exec"; + case JET_BOOKMARK_MOUSEUP: + return L"Mouse Up"; + case JET_CONSOLE_EXEC: + return L"Exec"; + case JET_DOC_DIDPRINT: + return L"DidPrint"; + case JET_DOC_DIDSAVE: + return L"DidSave"; + case JET_DOC_OPEN: + return L"Open"; + case JET_DOC_WILLCLOSE: + return L"WillClose"; + case JET_DOC_WILLPRINT: + return L"WillPrint"; + case JET_DOC_WILLSAVE: + return L"WillSave"; + case JET_EXTERNAL_EXEC: + return L"Exec"; + case JET_FIELD_FOCUS: + case JET_SCREEN_FOCUS: + return L"Focus"; + case JET_FIELD_BLUR: + case JET_SCREEN_BLUR: + return L"Blur"; + case JET_FIELD_MOUSEDOWN: + case JET_SCREEN_MOUSEDOWN: + return L"Mouse Down"; + case JET_FIELD_MOUSEUP: + case JET_SCREEN_MOUSEUP: + return L"Mouse Up"; + case JET_FIELD_MOUSEENTER: + case JET_SCREEN_MOUSEENTER: + return L"Mouse Enter"; + case JET_FIELD_MOUSEEXIT: + case JET_SCREEN_MOUSEEXIT: + return L"Mouse Exit"; + case JET_FIELD_CALCULATE: + return L"Calculate"; + case JET_FIELD_FORMAT: + return L"Format"; + case JET_FIELD_KEYSTROKE: + return L"Keystroke"; + case JET_FIELD_VALIDATE: + return L"Validate"; + case JET_LINK_MOUSEUP: + return L"Mouse Up"; + case JET_MENU_EXEC: + return L"Exec"; + case JET_PAGE_OPEN: + case JET_SCREEN_OPEN: + return L"Open"; + case JET_PAGE_CLOSE: + case JET_SCREEN_CLOSE: + return L"Close"; + case JET_SCREEN_INVIEW: + case JET_PAGE_INVIEW: + return L"InView"; + case JET_PAGE_OUTVIEW: + case JET_SCREEN_OUTVIEW: + return L"OutView"; + default: + return L""; + } + + return L""; +} + +const FX_WCHAR* CJS_EventHandler::Type() { + switch (m_eEventType) { + case JET_APP_INIT: + return L"App"; + case JET_BATCH_EXEC: + return L"Batch"; + case JET_BOOKMARK_MOUSEUP: + return L"BookMark"; + case JET_CONSOLE_EXEC: + return L"Console"; + case JET_DOC_DIDPRINT: + case JET_DOC_DIDSAVE: + case JET_DOC_OPEN: + case JET_DOC_WILLCLOSE: + case JET_DOC_WILLPRINT: + case JET_DOC_WILLSAVE: + return L"Doc"; + case JET_EXTERNAL_EXEC: + return L"External"; + case JET_FIELD_BLUR: + case JET_FIELD_FOCUS: + case JET_FIELD_MOUSEDOWN: + case JET_FIELD_MOUSEENTER: + case JET_FIELD_MOUSEEXIT: + case JET_FIELD_MOUSEUP: + case JET_FIELD_CALCULATE: + case JET_FIELD_FORMAT: + case JET_FIELD_KEYSTROKE: + case JET_FIELD_VALIDATE: + return L"Field"; + case JET_SCREEN_FOCUS: + case JET_SCREEN_BLUR: + case JET_SCREEN_OPEN: + case JET_SCREEN_CLOSE: + case JET_SCREEN_MOUSEDOWN: + case JET_SCREEN_MOUSEUP: + case JET_SCREEN_MOUSEENTER: + case JET_SCREEN_MOUSEEXIT: + case JET_SCREEN_INVIEW: + case JET_SCREEN_OUTVIEW: + return L"Screen"; + case JET_LINK_MOUSEUP: + return L"Link"; + case JET_MENU_EXEC: + return L"Menu"; + case JET_PAGE_OPEN: + case JET_PAGE_CLOSE: + case JET_PAGE_INVIEW: + case JET_PAGE_OUTVIEW: + return L"Page"; + default: + return L""; + } + + return L""; +} + +FX_BOOL& CJS_EventHandler::Rc() { + if (m_pbRc) { + return *m_pbRc; + } + return m_bRcDu; +} + +int& CJS_EventHandler::SelEnd() { + if (m_pISelEnd) { + return *m_pISelEnd; + } + return m_nSelEndDu; +} + +int& CJS_EventHandler::SelStart() { + if (m_pISelStart) { + return *m_pISelStart; + } + return m_nSelStartDu; +} + +FX_BOOL CJS_EventHandler::Shift() { + return m_bShift; +} + +Field* CJS_EventHandler::Source() { + CJS_Runtime* pRuntime = m_pJSContext->GetJSRuntime(); + v8::Local<v8::Object> pDocObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Document::g_nObjDefnID); + ASSERT(!pDocObj.IsEmpty()); + + v8::Local<v8::Object> pFieldObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID); + ASSERT(!pFieldObj.IsEmpty()); + + CJS_Document* pJSDocument = + (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pDocObj); + Document* pDocument = (Document*)pJSDocument->GetEmbedObject(); + pDocument->AttachDoc(m_pTargetDoc ? m_pTargetDoc + : m_pJSContext->GetReaderDocument()); + + CJS_Field* pJSField = + (CJS_Field*)FXJS_GetPrivate(pRuntime->GetIsolate(), pFieldObj); + Field* pField = (Field*)pJSField->GetEmbedObject(); + pField->AttachField(pDocument, m_strSourceName); + return pField; +} + +Field* CJS_EventHandler::Target_Field() { + CJS_Runtime* pRuntime = m_pJSContext->GetJSRuntime(); + v8::Local<v8::Object> pDocObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Document::g_nObjDefnID); + ASSERT(!pDocObj.IsEmpty()); + + v8::Local<v8::Object> pFieldObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Field::g_nObjDefnID); + ASSERT(!pFieldObj.IsEmpty()); + + CJS_Document* pJSDocument = + (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pDocObj); + Document* pDocument = (Document*)pJSDocument->GetEmbedObject(); + pDocument->AttachDoc(m_pTargetDoc ? m_pTargetDoc + : m_pJSContext->GetReaderDocument()); + + CJS_Field* pJSField = + (CJS_Field*)FXJS_GetPrivate(pRuntime->GetIsolate(), pFieldObj); + Field* pField = (Field*)pJSField->GetEmbedObject(); + pField->AttachField(pDocument, m_strTargetName); + return pField; +} + +CFX_WideString& CJS_EventHandler::Value() { + return *m_pValue; +} + +FX_BOOL CJS_EventHandler::WillCommit() { + return m_bWillCommit; +} + +CFX_WideString CJS_EventHandler::TargetName() { + return m_strTargetName; +} diff --git a/fpdfsdk/javascript/JS_EventHandler.h b/fpdfsdk/javascript/JS_EventHandler.h new file mode 100644 index 0000000000..5a819749ef --- /dev/null +++ b/fpdfsdk/javascript/JS_EventHandler.h @@ -0,0 +1,220 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_ +#define FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_ + +#include "core/include/fxcrt/fx_string.h" +#include "core/include/fxcrt/fx_system.h" + +class CJS_Context; +class CPDFSDK_Annot; +class CPDFSDK_Document; +class CPDF_Bookmark; +class CPDF_FormField; +class Field; + +enum JS_EVENT_T { + JET_UNKNOWN, + JET_APP_INIT, + JET_DOC_OPEN, + JET_DOC_WILLPRINT, + JET_DOC_DIDPRINT, + JET_DOC_WILLSAVE, + JET_DOC_DIDSAVE, + JET_DOC_WILLCLOSE, + JET_PAGE_OPEN, + JET_PAGE_CLOSE, + JET_PAGE_INVIEW, + JET_PAGE_OUTVIEW, + JET_FIELD_MOUSEDOWN, + JET_FIELD_MOUSEUP, + JET_FIELD_MOUSEENTER, + JET_FIELD_MOUSEEXIT, + JET_FIELD_FOCUS, + JET_FIELD_BLUR, + JET_FIELD_KEYSTROKE, + JET_FIELD_VALIDATE, + JET_FIELD_CALCULATE, + JET_FIELD_FORMAT, + JET_SCREEN_FOCUS, + JET_SCREEN_BLUR, + JET_SCREEN_OPEN, + JET_SCREEN_CLOSE, + JET_SCREEN_MOUSEDOWN, + JET_SCREEN_MOUSEUP, + JET_SCREEN_MOUSEENTER, + JET_SCREEN_MOUSEEXIT, + JET_SCREEN_INVIEW, + JET_SCREEN_OUTVIEW, + JET_BATCH_EXEC, + JET_MENU_EXEC, + JET_CONSOLE_EXEC, + JET_EXTERNAL_EXEC, + JET_BOOKMARK_MOUSEUP, + JET_LINK_MOUSEUP +}; + +class CJS_EventHandler { + public: + CJS_EventHandler(CJS_Context* pContext); + virtual ~CJS_EventHandler(); + + void OnApp_Init(); + + void OnDoc_Open(CPDFSDK_Document* pDoc, const CFX_WideString& strTargetName); + void OnDoc_WillPrint(CPDFSDK_Document* pDoc); + void OnDoc_DidPrint(CPDFSDK_Document* pDoc); + void OnDoc_WillSave(CPDFSDK_Document* pDoc); + void OnDoc_DidSave(CPDFSDK_Document* pDoc); + void OnDoc_WillClose(CPDFSDK_Document* pDoc); + + void OnPage_Open(CPDFSDK_Document* pDoc); + void OnPage_Close(CPDFSDK_Document* pDoc); + void OnPage_InView(CPDFSDK_Document* pTarget); + void OnPage_OutView(CPDFSDK_Document* pTarget); + + void OnField_Calculate(CPDF_FormField* pSource, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc); + void OnField_Format(CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit); + void OnField_Keystroke(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL KeyDown, + FX_BOOL bModifier, + int& nSelEnd, + int& nSelStart, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit, + FX_BOOL bFieldFull, + FX_BOOL& bRc); + void OnField_Validate(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc); + + void OnField_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget); + void OnField_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget); + void OnField_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget); + void OnField_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget); + void OnField_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value); + void OnField_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value); + + void OnScreen_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_Blur(FX_BOOL bModifier, FX_BOOL bShift, CPDFSDK_Annot* pScreen); + void OnScreen_Open(FX_BOOL bModifier, FX_BOOL bShift, CPDFSDK_Annot* pScreen); + void OnScreen_Close(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_InView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + void OnScreen_OutView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen); + + void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark); + void OnLink_MouseUp(CPDFSDK_Document* pTarget); + + void OnMenu_Exec(CPDFSDK_Document* pTarget, + const CFX_WideString& strTargetName); + void OnBatchExec(CPDFSDK_Document* pTarget); + void OnConsole_Exec(); + void OnExternal_Exec(); + + public: + void Initial(JS_EVENT_T type); + void Destroy(); + FX_BOOL IsValid(); + + CFX_WideString& Change(); + CFX_WideString ChangeEx(); + int CommitKey(); + FX_BOOL FieldFull(); + FX_BOOL KeyDown(); + FX_BOOL Modifier(); + const FX_WCHAR* Name(); + const FX_WCHAR* Type(); + FX_BOOL& Rc(); + int& SelEnd(); + int& SelStart(); + FX_BOOL Shift(); + Field* Source(); + Field* Target_Field(); + CFX_WideString& Value(); + FX_BOOL WillCommit(); + CFX_WideString TargetName(); + + JS_EVENT_T EventType() { return m_eEventType; } + + public: + CJS_Context* m_pJSContext; + JS_EVENT_T m_eEventType; + FX_BOOL m_bValid; + + CFX_WideString m_strTargetName; + CFX_WideString m_strSourceName; + CFX_WideString* m_pWideStrChange; + CFX_WideString m_WideStrChangeDu; + CFX_WideString m_WideStrChangeEx; + int m_nCommitKey; + FX_BOOL m_bKeyDown; + FX_BOOL m_bModifier; + FX_BOOL m_bShift; + int* m_pISelEnd; + int m_nSelEndDu; + int* m_pISelStart; + int m_nSelStartDu; + FX_BOOL m_bWillCommit; + CFX_WideString* m_pValue; + FX_BOOL m_bFieldFull; + FX_BOOL* m_pbRc; + FX_BOOL m_bRcDu; + + CPDFSDK_Document* m_pSourceDoc; + CPDF_Bookmark* m_pTargetBookMark; + CPDFSDK_Document* m_pTargetDoc; + CPDFSDK_Annot* m_pTargetAnnot; +}; + +#endif // FPDFSDK_JAVASCRIPT_JS_EVENTHANDLER_H_ diff --git a/fpdfsdk/javascript/JS_GlobalData.cpp b/fpdfsdk/javascript/JS_GlobalData.cpp new file mode 100644 index 0000000000..1408dbe33d --- /dev/null +++ b/fpdfsdk/javascript/JS_GlobalData.cpp @@ -0,0 +1,490 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/JS_GlobalData.h" + +#include "core/include/fdrm/fx_crypt.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" + +#define JS_MAXGLOBALDATA (1024 * 4 - 8) + +/* --------------------- CJS_GlobalVariableArray --------------------- */ + +CJS_GlobalVariableArray::CJS_GlobalVariableArray() {} + +CJS_GlobalVariableArray::~CJS_GlobalVariableArray() { + Empty(); +} + +void CJS_GlobalVariableArray::Copy(const CJS_GlobalVariableArray& array) { + Empty(); + for (int i = 0, sz = array.Count(); i < sz; i++) { + CJS_KeyValue* pOldObjData = array.GetAt(i); + switch (pOldObjData->nType) { + case JS_GLOBALDATA_TYPE_NUMBER: { + CJS_KeyValue* pNewObjData = new CJS_KeyValue; + pNewObjData->sKey = pOldObjData->sKey; + pNewObjData->nType = pOldObjData->nType; + pNewObjData->dData = pOldObjData->dData; + Add(pNewObjData); + } break; + case JS_GLOBALDATA_TYPE_BOOLEAN: { + CJS_KeyValue* pNewObjData = new CJS_KeyValue; + pNewObjData->sKey = pOldObjData->sKey; + pNewObjData->nType = pOldObjData->nType; + pNewObjData->bData = pOldObjData->bData; + Add(pNewObjData); + } break; + case JS_GLOBALDATA_TYPE_STRING: { + CJS_KeyValue* pNewObjData = new CJS_KeyValue; + pNewObjData->sKey = pOldObjData->sKey; + pNewObjData->nType = pOldObjData->nType; + pNewObjData->sData = pOldObjData->sData; + Add(pNewObjData); + } break; + case JS_GLOBALDATA_TYPE_OBJECT: { + CJS_KeyValue* pNewObjData = new CJS_KeyValue; + pNewObjData->sKey = pOldObjData->sKey; + pNewObjData->nType = pOldObjData->nType; + pNewObjData->objData.Copy(pOldObjData->objData); + Add(pNewObjData); + } break; + case JS_GLOBALDATA_TYPE_NULL: { + CJS_KeyValue* pNewObjData = new CJS_KeyValue; + pNewObjData->sKey = pOldObjData->sKey; + pNewObjData->nType = pOldObjData->nType; + Add(pNewObjData); + } break; + } + } +} + +void CJS_GlobalVariableArray::Add(CJS_KeyValue* p) { + array.Add(p); +} + +int CJS_GlobalVariableArray::Count() const { + return array.GetSize(); +} + +CJS_KeyValue* CJS_GlobalVariableArray::GetAt(int index) const { + return array.GetAt(index); +} + +void CJS_GlobalVariableArray::Empty() { + for (int i = 0, sz = array.GetSize(); i < sz; i++) + delete array.GetAt(i); + array.RemoveAll(); +} + +/* -------------------------- CJS_GlobalData -------------------------- */ + +#define READER_JS_GLOBALDATA_FILENAME L"Reader_JsGlobal.Data" +#define PHANTOM_JS_GLOBALDATA_FILENAME L"Phantom_JsGlobal.Data" +#define SDK_JS_GLOBALDATA_FILENAME L"SDK_JsGlobal.Data" + +static const uint8_t JS_RC4KEY[] = { + 0x19, 0xa8, 0xe8, 0x01, 0xf6, 0xa8, 0xb6, 0x4d, 0x82, 0x04, 0x45, 0x6d, + 0xb4, 0xcf, 0xd7, 0x77, 0x67, 0xf9, 0x75, 0x9f, 0xf0, 0xe0, 0x1e, 0x51, + 0xee, 0x46, 0xfd, 0x0b, 0xc9, 0x93, 0x25, 0x55, 0x4a, 0xee, 0xe0, 0x16, + 0xd0, 0xdf, 0x8c, 0xfa, 0x2a, 0xa9, 0x49, 0xfd, 0x97, 0x1c, 0x0e, 0x22, + 0x13, 0x28, 0x7c, 0xaf, 0xc4, 0xfc, 0x9c, 0x12, 0x65, 0x8c, 0x4e, 0x5b, + 0x04, 0x75, 0x89, 0xc9, 0xb1, 0xed, 0x50, 0xca, 0x96, 0x6f, 0x1a, 0x7a, + 0xfe, 0x58, 0x5d, 0xec, 0x19, 0x4a, 0xf6, 0x35, 0x6a, 0x97, 0x14, 0x00, + 0x0e, 0xd0, 0x6b, 0xbb, 0xd5, 0x75, 0x55, 0x8b, 0x6e, 0x6b, 0x19, 0xa0, + 0xf8, 0x77, 0xd5, 0xa3}; + +CJS_GlobalData* CJS_GlobalData::g_Instance = nullptr; + +// static +CJS_GlobalData* CJS_GlobalData::GetRetainedInstance(CPDFDoc_Environment* pApp) { + if (!g_Instance) { + g_Instance = new CJS_GlobalData(); + } + ++g_Instance->m_RefCount; + return g_Instance; +} + +void CJS_GlobalData::Release() { + if (!--m_RefCount) { + delete g_Instance; + g_Instance = nullptr; + } +} + +CJS_GlobalData::CJS_GlobalData() : m_RefCount(0) { + m_sFilePath += SDK_JS_GLOBALDATA_FILENAME; + LoadGlobalPersistentVariables(); +} + +CJS_GlobalData::~CJS_GlobalData() { + SaveGlobalPersisitentVariables(); + for (int i = 0, sz = m_arrayGlobalData.GetSize(); i < sz; i++) + delete m_arrayGlobalData.GetAt(i); + + m_arrayGlobalData.RemoveAll(); +} + +int CJS_GlobalData::FindGlobalVariable(const FX_CHAR* propname) { + for (int i = 0, sz = m_arrayGlobalData.GetSize(); i < sz; i++) { + CJS_GlobalData_Element* pTemp = m_arrayGlobalData.GetAt(i); + if (pTemp->data.sKey[0] == *propname && pTemp->data.sKey == propname) + return i; + } + return -1; +} + +CJS_GlobalData_Element* CJS_GlobalData::GetGlobalVariable( + const FX_CHAR* propname) { + ASSERT(propname); + + int nFind = FindGlobalVariable(propname); + return nFind >= 0 ? m_arrayGlobalData.GetAt(nFind) : nullptr; +} + +void CJS_GlobalData::SetGlobalVariableNumber(const FX_CHAR* propname, + double dData) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + sPropName.TrimLeft(); + sPropName.TrimRight(); + if (sPropName.GetLength() == 0) + return; + + if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { + pData->data.nType = JS_GLOBALDATA_TYPE_NUMBER; + pData->data.dData = dData; + } else { + CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; + pNewData->data.sKey = sPropName; + pNewData->data.nType = JS_GLOBALDATA_TYPE_NUMBER; + pNewData->data.dData = dData; + m_arrayGlobalData.Add(pNewData); + } +} + +void CJS_GlobalData::SetGlobalVariableBoolean(const FX_CHAR* propname, + bool bData) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + + sPropName.TrimLeft(); + sPropName.TrimRight(); + + if (sPropName.GetLength() == 0) + return; + + if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { + pData->data.nType = JS_GLOBALDATA_TYPE_BOOLEAN; + pData->data.bData = bData; + } else { + CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; + pNewData->data.sKey = sPropName; + pNewData->data.nType = JS_GLOBALDATA_TYPE_BOOLEAN; + pNewData->data.bData = bData; + + m_arrayGlobalData.Add(pNewData); + } +} + +void CJS_GlobalData::SetGlobalVariableString(const FX_CHAR* propname, + const CFX_ByteString& sData) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + + sPropName.TrimLeft(); + sPropName.TrimRight(); + + if (sPropName.GetLength() == 0) + return; + + if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { + pData->data.nType = JS_GLOBALDATA_TYPE_STRING; + pData->data.sData = sData; + } else { + CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; + pNewData->data.sKey = sPropName; + pNewData->data.nType = JS_GLOBALDATA_TYPE_STRING; + pNewData->data.sData = sData; + + m_arrayGlobalData.Add(pNewData); + } +} + +void CJS_GlobalData::SetGlobalVariableObject( + const FX_CHAR* propname, + const CJS_GlobalVariableArray& array) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + + sPropName.TrimLeft(); + sPropName.TrimRight(); + + if (sPropName.GetLength() == 0) + return; + + if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { + pData->data.nType = JS_GLOBALDATA_TYPE_OBJECT; + pData->data.objData.Copy(array); + } else { + CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; + pNewData->data.sKey = sPropName; + pNewData->data.nType = JS_GLOBALDATA_TYPE_OBJECT; + pNewData->data.objData.Copy(array); + + m_arrayGlobalData.Add(pNewData); + } +} + +void CJS_GlobalData::SetGlobalVariableNull(const FX_CHAR* propname) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + + sPropName.TrimLeft(); + sPropName.TrimRight(); + + if (sPropName.GetLength() == 0) + return; + + if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { + pData->data.nType = JS_GLOBALDATA_TYPE_NULL; + } else { + CJS_GlobalData_Element* pNewData = new CJS_GlobalData_Element; + pNewData->data.sKey = sPropName; + pNewData->data.nType = JS_GLOBALDATA_TYPE_NULL; + + m_arrayGlobalData.Add(pNewData); + } +} + +FX_BOOL CJS_GlobalData::SetGlobalVariablePersistent(const FX_CHAR* propname, + FX_BOOL bPersistent) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + + sPropName.TrimLeft(); + sPropName.TrimRight(); + + if (sPropName.GetLength() == 0) + return FALSE; + + if (CJS_GlobalData_Element* pData = GetGlobalVariable(sPropName)) { + pData->bPersistent = bPersistent; + return TRUE; + } + + return FALSE; +} + +FX_BOOL CJS_GlobalData::DeleteGlobalVariable(const FX_CHAR* propname) { + ASSERT(propname); + CFX_ByteString sPropName = propname; + + sPropName.TrimLeft(); + sPropName.TrimRight(); + + if (sPropName.GetLength() == 0) + return FALSE; + + int nFind = FindGlobalVariable(sPropName); + + if (nFind >= 0) { + delete m_arrayGlobalData.GetAt(nFind); + m_arrayGlobalData.RemoveAt(nFind); + return TRUE; + } + + return FALSE; +} + +int32_t CJS_GlobalData::GetSize() const { + return m_arrayGlobalData.GetSize(); +} + +CJS_GlobalData_Element* CJS_GlobalData::GetAt(int index) const { + return m_arrayGlobalData.GetAt(index); +} + +void CJS_GlobalData::LoadGlobalPersistentVariables() { + uint8_t* pBuffer = NULL; + int32_t nLength = 0; + + LoadFileBuffer(m_sFilePath.c_str(), pBuffer, nLength); + CRYPT_ArcFourCryptBlock(pBuffer, nLength, JS_RC4KEY, sizeof(JS_RC4KEY)); + + if (pBuffer) { + uint8_t* p = pBuffer; + FX_WORD wType = *((FX_WORD*)p); + p += sizeof(FX_WORD); + + // FX_WORD wTemp = (FX_WORD)(('X' << 8) | 'F'); + + if (wType == (FX_WORD)(('X' << 8) | 'F')) { + FX_WORD wVersion = *((FX_WORD*)p); + p += sizeof(FX_WORD); + + ASSERT(wVersion <= 2); + + FX_DWORD dwCount = *((FX_DWORD*)p); + p += sizeof(FX_DWORD); + + FX_DWORD dwSize = *((FX_DWORD*)p); + p += sizeof(FX_DWORD); + + if (dwSize == nLength - sizeof(FX_WORD) * 2 - sizeof(FX_DWORD) * 2) { + for (int32_t i = 0, sz = dwCount; i < sz; i++) { + if (p > pBuffer + nLength) + break; + + FX_DWORD dwNameLen = *((FX_DWORD*)p); + p += sizeof(FX_DWORD); + + if (p + dwNameLen > pBuffer + nLength) + break; + + CFX_ByteString sEntry = CFX_ByteString(p, dwNameLen); + p += sizeof(char) * dwNameLen; + + FX_WORD wDataType = *((FX_WORD*)p); + p += sizeof(FX_WORD); + + switch (wDataType) { + case JS_GLOBALDATA_TYPE_NUMBER: { + double dData = 0; + switch (wVersion) { + case 1: { + FX_DWORD dwData = *((FX_DWORD*)p); + p += sizeof(FX_DWORD); + dData = dwData; + } break; + case 2: { + dData = *((double*)p); + p += sizeof(double); + } break; + } + SetGlobalVariableNumber(sEntry, dData); + SetGlobalVariablePersistent(sEntry, TRUE); + } break; + case JS_GLOBALDATA_TYPE_BOOLEAN: { + FX_WORD wData = *((FX_WORD*)p); + p += sizeof(FX_WORD); + SetGlobalVariableBoolean(sEntry, (bool)(wData == 1)); + SetGlobalVariablePersistent(sEntry, TRUE); + } break; + case JS_GLOBALDATA_TYPE_STRING: { + FX_DWORD dwLength = *((FX_DWORD*)p); + p += sizeof(FX_DWORD); + + if (p + dwLength > pBuffer + nLength) + break; + + SetGlobalVariableString(sEntry, CFX_ByteString(p, dwLength)); + SetGlobalVariablePersistent(sEntry, TRUE); + p += sizeof(char) * dwLength; + } break; + case JS_GLOBALDATA_TYPE_NULL: { + SetGlobalVariableNull(sEntry); + SetGlobalVariablePersistent(sEntry, TRUE); + } + } + } + } + } + FX_Free(pBuffer); + } +} + +void CJS_GlobalData::SaveGlobalPersisitentVariables() { + FX_DWORD nCount = 0; + CFX_BinaryBuf sData; + + for (int i = 0, sz = m_arrayGlobalData.GetSize(); i < sz; i++) { + CJS_GlobalData_Element* pElement = m_arrayGlobalData.GetAt(i); + if (pElement->bPersistent) { + CFX_BinaryBuf sElement; + MakeByteString(pElement->data.sKey, &pElement->data, sElement); + + if (sData.GetSize() + sElement.GetSize() > JS_MAXGLOBALDATA) + break; + + sData.AppendBlock(sElement.GetBuffer(), sElement.GetSize()); + nCount++; + } + } + + CFX_BinaryBuf sFile; + + FX_WORD wType = (FX_WORD)(('X' << 8) | 'F'); + sFile.AppendBlock(&wType, sizeof(FX_WORD)); + FX_WORD wVersion = 2; + sFile.AppendBlock(&wVersion, sizeof(FX_WORD)); + sFile.AppendBlock(&nCount, sizeof(FX_DWORD)); + FX_DWORD dwSize = sData.GetSize(); + sFile.AppendBlock(&dwSize, sizeof(FX_DWORD)); + + sFile.AppendBlock(sData.GetBuffer(), sData.GetSize()); + + CRYPT_ArcFourCryptBlock(sFile.GetBuffer(), sFile.GetSize(), JS_RC4KEY, + sizeof(JS_RC4KEY)); + WriteFileBuffer(m_sFilePath.c_str(), (const FX_CHAR*)sFile.GetBuffer(), + sFile.GetSize()); +} + +void CJS_GlobalData::LoadFileBuffer(const FX_WCHAR* sFilePath, + uint8_t*& pBuffer, + int32_t& nLength) { + // UnSupport. +} + +void CJS_GlobalData::WriteFileBuffer(const FX_WCHAR* sFilePath, + const FX_CHAR* pBuffer, + int32_t nLength) { + // UnSupport. +} + +void CJS_GlobalData::MakeByteString(const CFX_ByteString& name, + CJS_KeyValue* pData, + CFX_BinaryBuf& sData) { + FX_WORD wType = (FX_WORD)pData->nType; + switch (wType) { + case JS_GLOBALDATA_TYPE_NUMBER: { + FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); + sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); + sData.AppendString(name); + sData.AppendBlock(&wType, sizeof(FX_WORD)); + + double dData = pData->dData; + sData.AppendBlock(&dData, sizeof(double)); + } break; + case JS_GLOBALDATA_TYPE_BOOLEAN: { + FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); + sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); + sData.AppendString(name); + sData.AppendBlock(&wType, sizeof(FX_WORD)); + + FX_WORD wData = (FX_WORD)pData->bData; + sData.AppendBlock(&wData, sizeof(FX_WORD)); + } break; + case JS_GLOBALDATA_TYPE_STRING: { + FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); + sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); + sData.AppendString(name); + sData.AppendBlock(&wType, sizeof(FX_WORD)); + + FX_DWORD dwDataLen = (FX_DWORD)pData->sData.GetLength(); + sData.AppendBlock(&dwDataLen, sizeof(FX_DWORD)); + sData.AppendString(pData->sData); + } break; + case JS_GLOBALDATA_TYPE_NULL: { + FX_DWORD dwNameLen = (FX_DWORD)name.GetLength(); + sData.AppendBlock(&dwNameLen, sizeof(FX_DWORD)); + sData.AppendString(name); + sData.AppendBlock(&wType, sizeof(FX_DWORD)); + } break; + default: + break; + } +} diff --git a/fpdfsdk/javascript/JS_GlobalData.h b/fpdfsdk/javascript/JS_GlobalData.h new file mode 100644 index 0000000000..28833d8c12 --- /dev/null +++ b/fpdfsdk/javascript/JS_GlobalData.h @@ -0,0 +1,106 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_GLOBALDATA_H_ +#define FPDFSDK_JAVASCRIPT_JS_GLOBALDATA_H_ + +#include "core/include/fxcrt/fx_basic.h" + +#define JS_GLOBALDATA_TYPE_NUMBER 0 +#define JS_GLOBALDATA_TYPE_BOOLEAN 1 +#define JS_GLOBALDATA_TYPE_STRING 2 +#define JS_GLOBALDATA_TYPE_OBJECT 3 +#define JS_GLOBALDATA_TYPE_NULL 4 + +class CJS_KeyValue; +class CPDFDoc_Environment; + +class CJS_GlobalVariableArray { + public: + CJS_GlobalVariableArray(); + virtual ~CJS_GlobalVariableArray(); + + void Add(CJS_KeyValue* p); + int Count() const; + CJS_KeyValue* GetAt(int index) const; + void Copy(const CJS_GlobalVariableArray& array); + + void Empty(); + + private: + CFX_ArrayTemplate<CJS_KeyValue*> array; +}; + +class CJS_KeyValue { + public: + CJS_KeyValue() {} + virtual ~CJS_KeyValue() {} + + CFX_ByteString sKey; + int nType; // 0:int 1:bool 2:string 3:obj + double dData; + bool bData; + CFX_ByteString sData; + CJS_GlobalVariableArray objData; +}; + +class CJS_GlobalData_Element { + public: + CJS_GlobalData_Element() {} + virtual ~CJS_GlobalData_Element() {} + + CJS_KeyValue data; + FX_BOOL bPersistent; +}; + +class CJS_GlobalData { + public: + static CJS_GlobalData* GetRetainedInstance(CPDFDoc_Environment* pApp); + void Release(); + + void SetGlobalVariableNumber(const FX_CHAR* propname, double dData); + void SetGlobalVariableBoolean(const FX_CHAR* propname, bool bData); + void SetGlobalVariableString(const FX_CHAR* propname, + const CFX_ByteString& sData); + void SetGlobalVariableObject(const FX_CHAR* propname, + const CJS_GlobalVariableArray& array); + void SetGlobalVariableNull(const FX_CHAR* propname); + + FX_BOOL SetGlobalVariablePersistent(const FX_CHAR* propname, + FX_BOOL bPersistent); + FX_BOOL DeleteGlobalVariable(const FX_CHAR* propname); + + int32_t GetSize() const; + CJS_GlobalData_Element* GetAt(int index) const; + + private: + static CJS_GlobalData* g_Instance; + + CJS_GlobalData(); + ~CJS_GlobalData(); + + void LoadGlobalPersistentVariables(); + void SaveGlobalPersisitentVariables(); + + CJS_GlobalData_Element* GetGlobalVariable(const FX_CHAR* propname); + int FindGlobalVariable(const FX_CHAR* propname); + + void LoadFileBuffer(const FX_WCHAR* sFilePath, + uint8_t*& pBuffer, + int32_t& nLength); + void WriteFileBuffer(const FX_WCHAR* sFilePath, + const FX_CHAR* pBuffer, + int32_t nLength); + void MakeByteString(const CFX_ByteString& name, + CJS_KeyValue* pData, + CFX_BinaryBuf& sData); + + size_t m_RefCount; + CFX_ArrayTemplate<CJS_GlobalData_Element*> m_arrayGlobalData; + CFX_WideString m_sFilePath; +}; + +#endif // FPDFSDK_JAVASCRIPT_JS_GLOBALDATA_H_ diff --git a/fpdfsdk/javascript/JS_Object.cpp b/fpdfsdk/javascript/JS_Object.cpp new file mode 100644 index 0000000000..e6af576339 --- /dev/null +++ b/fpdfsdk/javascript/JS_Object.cpp @@ -0,0 +1,158 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/JS_Object.h" + +#include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" + +namespace { + +int FXJS_MsgBox(CPDFDoc_Environment* pApp, + const FX_WCHAR* swMsg, + const FX_WCHAR* swTitle, + FX_UINT nType, + FX_UINT nIcon) { + if (!pApp) + return 0; + + if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument()) + pDoc->KillFocusAnnot(); + + return pApp->JS_appAlert(swMsg, swTitle, nType, nIcon); +} + +} // namespace + +CJS_EmbedObj::CJS_EmbedObj(CJS_Object* pJSObject) : m_pJSObject(pJSObject) {} + +CJS_EmbedObj::~CJS_EmbedObj() { + m_pJSObject = NULL; +} + +int CJS_EmbedObj::MsgBox(CPDFDoc_Environment* pApp, + const FX_WCHAR* swMsg, + const FX_WCHAR* swTitle, + FX_UINT nType, + FX_UINT nIcon) { + return FXJS_MsgBox(pApp, swMsg, swTitle, nType, nIcon); +} + +void CJS_EmbedObj::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) { + CJS_Object::Alert(pContext, swMsg); +} + +void FreeObject(const v8::WeakCallbackInfo<CJS_Object>& data) { + CJS_Object* pJSObj = data.GetParameter(); + pJSObj->ExitInstance(); + delete pJSObj; + FXJS_FreePrivate(data.GetInternalField(0)); +} + +void DisposeObject(const v8::WeakCallbackInfo<CJS_Object>& data) { + CJS_Object* pJSObj = data.GetParameter(); + pJSObj->Dispose(); + data.SetSecondPassCallback(FreeObject); +} + +CJS_Object::CJS_Object(v8::Local<v8::Object> pObject) { + m_pIsolate = pObject->GetIsolate(); + m_pV8Object.Reset(m_pIsolate, pObject); +} + +CJS_Object::~CJS_Object() {} + +void CJS_Object::MakeWeak() { + m_pV8Object.SetWeak(this, DisposeObject, + v8::WeakCallbackType::kInternalFields); +} + +void CJS_Object::Dispose() { + m_pV8Object.Reset(); +} + +int CJS_Object::MsgBox(CPDFDoc_Environment* pApp, + const FX_WCHAR* swMsg, + const FX_WCHAR* swTitle, + FX_UINT nType, + FX_UINT nIcon) { + return FXJS_MsgBox(pApp, swMsg, swTitle, nType, nIcon); +} + +void CJS_Object::Alert(CJS_Context* pContext, const FX_WCHAR* swMsg) { + if (pContext->IsMsgBoxEnabled()) { + CPDFDoc_Environment* pApp = pContext->GetReaderApp(); + if (pApp) + pApp->JS_appAlert(swMsg, NULL, 0, 3); + } +} + +CJS_Timer::CJS_Timer(CJS_EmbedObj* pObj, + CPDFDoc_Environment* pApp, + CJS_Runtime* pRuntime, + int nType, + const CFX_WideString& script, + FX_DWORD dwElapse, + FX_DWORD dwTimeOut) + : m_nTimerID(0), + m_pEmbedObj(pObj), + m_bProcessing(false), + m_bValid(true), + m_nType(nType), + m_dwTimeOut(dwTimeOut), + m_swJScript(script), + m_pRuntime(pRuntime), + m_pApp(pApp) { + IFX_SystemHandler* pHandler = m_pApp->GetSysHandler(); + m_nTimerID = pHandler->SetTimer(dwElapse, TimerProc); + (*GetGlobalTimerMap())[m_nTimerID] = this; + m_pRuntime->AddObserver(this); +} + +CJS_Timer::~CJS_Timer() { + CJS_Runtime* pRuntime = GetRuntime(); + if (pRuntime) + pRuntime->RemoveObserver(this); + KillJSTimer(); +} + +void CJS_Timer::KillJSTimer() { + if (m_nTimerID) { + if (m_bValid) { + IFX_SystemHandler* pHandler = m_pApp->GetSysHandler(); + pHandler->KillTimer(m_nTimerID); + } + GetGlobalTimerMap()->erase(m_nTimerID); + m_nTimerID = 0; + } +} + +// static +void CJS_Timer::TimerProc(int idEvent) { + const auto it = GetGlobalTimerMap()->find(idEvent); + if (it != GetGlobalTimerMap()->end()) { + CJS_Timer* pTimer = it->second; + if (!pTimer->m_bProcessing) { + CFX_AutoRestorer<bool> scoped_processing(&pTimer->m_bProcessing); + pTimer->m_bProcessing = true; + if (pTimer->m_pEmbedObj) + pTimer->m_pEmbedObj->TimerProc(pTimer); + } + } +} + +// static +CJS_Timer::TimerMap* CJS_Timer::GetGlobalTimerMap() { + // Leak the timer array at shutdown. + static auto* s_TimerMap = new TimerMap; + return s_TimerMap; +} + +void CJS_Timer::OnDestroyed() { + m_bValid = false; +} diff --git a/fpdfsdk/javascript/JS_Object.h b/fpdfsdk/javascript/JS_Object.h new file mode 100644 index 0000000000..983b713744 --- /dev/null +++ b/fpdfsdk/javascript/JS_Object.h @@ -0,0 +1,116 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_OBJECT_H_ +#define FPDFSDK_JAVASCRIPT_JS_OBJECT_H_ + +#include <map> +#include <memory> + +#include "fpdfsdk/include/fsdk_define.h" // For FX_UINT +#include "fpdfsdk/include/jsapi/fxjs_v8.h" +#include "fpdfsdk/javascript/JS_Runtime.h" + +class CJS_Context; +class CJS_Object; +class CJS_Timer; +class CPDFDoc_Environment; +class CJS_EmbedObj { + public: + explicit CJS_EmbedObj(CJS_Object* pJSObject); + virtual ~CJS_EmbedObj(); + + virtual void TimerProc(CJS_Timer* pTimer) {} + + CJS_Object* GetJSObject() const { return m_pJSObject; } + + int MsgBox(CPDFDoc_Environment* pApp, + const FX_WCHAR* swMsg, + const FX_WCHAR* swTitle, + FX_UINT nType, + FX_UINT nIcon); + void Alert(CJS_Context* pContext, const FX_WCHAR* swMsg); + + protected: + CJS_Object* m_pJSObject; +}; + +class CJS_Object { + public: + explicit CJS_Object(v8::Local<v8::Object> pObject); + virtual ~CJS_Object(); + + void MakeWeak(); + void Dispose(); + + virtual FX_BOOL IsType(const FX_CHAR* sClassName) { return TRUE; } + virtual CFX_ByteString GetClassName() { return ""; } + + virtual void InitInstance(IJS_Runtime* pIRuntime) {} + virtual void ExitInstance() {} + + v8::Local<v8::Object> ToV8Object() { return m_pV8Object.Get(m_pIsolate); } + + // Takes ownership of |pObj|. + void SetEmbedObject(CJS_EmbedObj* pObj) { m_pEmbedObj.reset(pObj); } + CJS_EmbedObj* GetEmbedObject() const { return m_pEmbedObj.get(); } + + static int MsgBox(CPDFDoc_Environment* pApp, + const FX_WCHAR* swMsg, + const FX_WCHAR* swTitle, + FX_UINT nType, + FX_UINT nIcon); + static void Alert(CJS_Context* pContext, const FX_WCHAR* swMsg); + + v8::Isolate* GetIsolate() { return m_pIsolate; } + + protected: + std::unique_ptr<CJS_EmbedObj> m_pEmbedObj; + v8::Global<v8::Object> m_pV8Object; + v8::Isolate* m_pIsolate; +}; + +class CJS_Timer : public CJS_Runtime::Observer { + public: + CJS_Timer(CJS_EmbedObj* pObj, + CPDFDoc_Environment* pApp, + CJS_Runtime* pRuntime, + int nType, + const CFX_WideString& script, + FX_DWORD dwElapse, + FX_DWORD dwTimeOut); + ~CJS_Timer() override; + + void KillJSTimer(); + + int GetType() const { return m_nType; } + FX_DWORD GetTimeOut() const { return m_dwTimeOut; } + CJS_Runtime* GetRuntime() const { return m_bValid ? m_pRuntime : nullptr; } + CFX_WideString GetJScript() const { return m_swJScript; } + + static void TimerProc(int idEvent); + + private: + using TimerMap = std::map<FX_UINT, CJS_Timer*>; + static TimerMap* GetGlobalTimerMap(); + + // CJS_Runtime::Observer + void OnDestroyed() override; + + FX_DWORD m_nTimerID; + CJS_EmbedObj* const m_pEmbedObj; + bool m_bProcessing; + bool m_bValid; + + // data + const int m_nType; // 0:Interval; 1:TimeOut + const FX_DWORD m_dwTimeOut; + const CFX_WideString m_swJScript; + CJS_Runtime* const m_pRuntime; + CPDFDoc_Environment* const m_pApp; +}; + +#endif // FPDFSDK_JAVASCRIPT_JS_OBJECT_H_ diff --git a/fpdfsdk/javascript/JS_Runtime.cpp b/fpdfsdk/javascript/JS_Runtime.cpp new file mode 100644 index 0000000000..d56a8aca39 --- /dev/null +++ b/fpdfsdk/javascript/JS_Runtime.cpp @@ -0,0 +1,345 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/JS_Runtime.h" + +#include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Consts.h" +#include "fpdfsdk/javascript/Document.h" +#include "fpdfsdk/javascript/Field.h" +#include "fpdfsdk/javascript/Icon.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_GlobalData.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/PublicMethods.h" +#include "fpdfsdk/javascript/app.h" +#include "fpdfsdk/javascript/color.h" +#include "fpdfsdk/javascript/console.h" +#include "fpdfsdk/javascript/event.h" +#include "fpdfsdk/javascript/global.h" +#include "fpdfsdk/javascript/report.h" +#include "fpdfsdk/javascript/util.h" +#include "third_party/base/stl_util.h" + +#ifdef PDF_ENABLE_XFA +#include "fpdfsdk/include/fpdfxfa/fpdfxfa_app.h" +#include "xfa/src/fxjse/value.h" +#endif // PDF_ENABLE_XFA + +// static +void IJS_Runtime::Initialize(unsigned int slot, void* isolate) { + FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate)); +} + +// static +IJS_Runtime* IJS_Runtime::Create(CPDFDoc_Environment* pEnv) { + return new CJS_Runtime(pEnv); +} + +// static +CJS_Runtime* CJS_Runtime::FromContext(const IJS_Context* cc) { + const CJS_Context* pContext = static_cast<const CJS_Context*>(cc); + return pContext->GetJSRuntime(); +} + +CJS_Runtime::CJS_Runtime(CPDFDoc_Environment* pApp) + : m_pApp(pApp), + m_pDocument(NULL), + m_bBlocking(FALSE), + m_isolate(NULL), + m_isolateManaged(false) { +#ifndef PDF_ENABLE_XFA + IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform; + if (pPlatform->version <= 2) { + unsigned int embedderDataSlot = 0; + v8::Isolate* pExternalIsolate = nullptr; + if (pPlatform->version == 2) { + pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate); + embedderDataSlot = pPlatform->m_v8EmbedderSlot; +#else + if (CPDFXFA_App::GetInstance()->GetJSERuntime()) { + // TODO(tsepez): CPDFXFA_App should also use the embedder provided isolate. + m_isolate = (v8::Isolate*)CPDFXFA_App::GetInstance()->GetJSERuntime(); + } else { + IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform; + if (pPlatform->version <= 2) { + unsigned int embedderDataSlot = 0; + v8::Isolate* pExternalIsolate = nullptr; + if (pPlatform->version == 2) { + pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate); + embedderDataSlot = pPlatform->m_v8EmbedderSlot; + } + FXJS_Initialize(embedderDataSlot, pExternalIsolate); +#endif + } +#ifndef PDF_ENABLE_XFA + FXJS_Initialize(embedderDataSlot, pExternalIsolate); +#else + m_isolateManaged = FXJS_GetIsolate(&m_isolate); + } + + v8::Isolate* isolate = m_isolate; + v8::Isolate::Scope isolate_scope(isolate); + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + if (CPDFXFA_App::GetInstance()->IsJavaScriptInitialized()) { + CJS_Context* pContext = (CJS_Context*)NewContext(); + FXJS_InitializeRuntime(GetIsolate(), this, &m_context, &m_StaticObjects); + ReleaseContext(pContext); + return; +#endif + } +#ifndef PDF_ENABLE_XFA + m_isolateManaged = FXJS_GetIsolate(&m_isolate); +#else + +#endif + if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0) + DefineJSObjects(); + +#ifdef PDF_ENABLE_XFA + CPDFXFA_App::GetInstance()->SetJavaScriptInitialized(TRUE); + +#endif + CJS_Context* pContext = (CJS_Context*)NewContext(); + FXJS_InitializeRuntime(GetIsolate(), this, &m_context, &m_StaticObjects); + ReleaseContext(pContext); +} + +CJS_Runtime::~CJS_Runtime() { + for (auto* obs : m_observers) + obs->OnDestroyed(); + + for (int i = 0, sz = m_ContextArray.GetSize(); i < sz; i++) + delete m_ContextArray.GetAt(i); + + m_ContextArray.RemoveAll(); + m_ConstArrays.clear(); + FXJS_ReleaseRuntime(GetIsolate(), &m_context, &m_StaticObjects); + + m_pApp = NULL; + m_pDocument = NULL; + m_context.Reset(); + + if (m_isolateManaged) + m_isolate->Dispose(); +} + +void CJS_Runtime::DefineJSObjects() { + v8::Isolate::Scope isolate_scope(GetIsolate()); +#ifdef PDF_ENABLE_XFA + v8::Locker locker(GetIsolate()); +#endif + v8::HandleScope handle_scope(GetIsolate()); + v8::Local<v8::Context> context = v8::Context::New(GetIsolate()); + v8::Context::Scope context_scope(context); + + // The call order determines the "ObjDefID" assigned to each class. + // ObjDefIDs 0 - 2 + CJS_Border::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Display::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Font::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + + // ObjDefIDs 3 - 5 + CJS_Highlight::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Position::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_ScaleHow::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + + // ObjDefIDs 6 - 8 + CJS_ScaleWhen::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Style::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Zoomtype::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + + // ObjDefIDs 9 - 11 + CJS_App::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Color::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Console::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + + // ObjDefIDs 12 - 14 + CJS_Document::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_GLOBAL); + CJS_Event::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Field::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); + + // ObjDefIDs 15 - 17 + CJS_Global::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + CJS_Icon::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); + CJS_Util::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC); + + // ObjDefIDs 18 - 20 (these can't fail, return void). + CJS_PublicMethods::DefineJSObjects(GetIsolate()); + CJS_GlobalConsts::DefineJSObjects(this); + CJS_GlobalArrays::DefineJSObjects(this); + + // ObjDefIDs 21 - 22. + CJS_TimerObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); + CJS_PrintParamsObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC); +} + +IJS_Context* CJS_Runtime::NewContext() { + CJS_Context* p = new CJS_Context(this); + m_ContextArray.Add(p); + return p; +} + +void CJS_Runtime::ReleaseContext(IJS_Context* pContext) { + CJS_Context* pJSContext = (CJS_Context*)pContext; + + for (int i = 0, sz = m_ContextArray.GetSize(); i < sz; i++) { + if (pJSContext == m_ContextArray.GetAt(i)) { + delete pJSContext; + m_ContextArray.RemoveAt(i); + break; + } + } +} + +IJS_Context* CJS_Runtime::GetCurrentContext() { + if (!m_ContextArray.GetSize()) + return NULL; + return m_ContextArray.GetAt(m_ContextArray.GetSize() - 1); +} + +void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc) { + if (m_pDocument != pReaderDoc) { + v8::Isolate::Scope isolate_scope(m_isolate); +#ifdef PDF_ENABLE_XFA + v8::Locker locker(m_isolate); +#endif + v8::HandleScope handle_scope(m_isolate); + v8::Local<v8::Context> context = + v8::Local<v8::Context>::New(m_isolate, m_context); + v8::Context::Scope context_scope(context); + + m_pDocument = pReaderDoc; + if (pReaderDoc) { + v8::Local<v8::Object> pThis = FXJS_GetThisObj(GetIsolate()); + if (!pThis.IsEmpty()) { + if (FXJS_GetObjDefnID(pThis) == CJS_Document::g_nObjDefnID) { + if (CJS_Document* pJSDocument = + (CJS_Document*)FXJS_GetPrivate(GetIsolate(), pThis)) { + if (Document* pDocument = (Document*)pJSDocument->GetEmbedObject()) + pDocument->AttachDoc(pReaderDoc); + } + } + } + } + } +} + +int CJS_Runtime::Execute(IJS_Context* cc, + const wchar_t* script, + CFX_WideString* info) { + FXJSErr error = {}; + int nRet = FXJS_Execute(m_isolate, cc, script, &error); + if (nRet < 0) { + info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline, + error.message); + } + return nRet; +} + +bool CJS_Runtime::AddEventToSet(const FieldEvent& event) { + return m_FieldEventSet.insert(event).second; +} + +void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) { + m_FieldEventSet.erase(event); +} + +v8::Local<v8::Context> CJS_Runtime::NewJSContext() { + return v8::Local<v8::Context>::New(m_isolate, m_context); +} + +void CJS_Runtime::SetConstArray(const CFX_WideString& name, + v8::Local<v8::Array> array) { + m_ConstArrays[name] = v8::Global<v8::Array>(m_isolate, array); +} + +v8::Local<v8::Array> CJS_Runtime::GetConstArray(const CFX_WideString& name) { + return v8::Local<v8::Array>::New(m_isolate, m_ConstArrays[name]); +} + +#ifdef PDF_ENABLE_XFA +CFX_WideString ChangeObjName(const CFX_WideString& str) { + CFX_WideString sRet = str; + sRet.Replace(L"_", L"."); + return sRet; +} +FX_BOOL CJS_Runtime::GetHValueByName(const CFX_ByteStringC& utf8Name, + FXJSE_HVALUE hValue) { +#ifdef PDF_ENABLE_XFA + const FX_CHAR* name = utf8Name.GetCStr(); + + v8::Locker lock(GetIsolate()); + v8::Isolate::Scope isolate_scope(GetIsolate()); + v8::HandleScope handle_scope(GetIsolate()); + v8::Local<v8::Context> old_context = GetIsolate()->GetCurrentContext(); + v8::Local<v8::Context> context = + v8::Local<v8::Context>::New(GetIsolate(), m_context); + v8::Context::Scope context_scope(context); + + // Caution: We're about to hand to XFA an object that in order to invoke + // methods will require that the current v8::Context always has a pointer + // to a CJS_Runtime in its embedder data slot. Unfortunately, XFA creates + // its own v8::Context which has not initialized the embedder data slot. + // Do so now. + // TODO(tsepez): redesign PDF-side objects to not rely on v8::Context's + // embedder data slots, and/or to always use the right context. + FXJS_SetRuntimeForV8Context(old_context, this); + + v8::Local<v8::Value> propvalue = + context->Global()->Get(v8::String::NewFromUtf8( + GetIsolate(), name, v8::String::kNormalString, utf8Name.GetLength())); + + if (propvalue.IsEmpty()) { + FXJSE_Value_SetUndefined(hValue); + return FALSE; + } + ((CFXJSE_Value*)hValue)->ForceSetValue(propvalue); +#endif + + return TRUE; +} +FX_BOOL CJS_Runtime::SetHValueByName(const CFX_ByteStringC& utf8Name, + FXJSE_HVALUE hValue) { +#ifdef PDF_ENABLE_XFA + if (utf8Name.IsEmpty() || hValue == NULL) + return FALSE; + const FX_CHAR* name = utf8Name.GetCStr(); + v8::Isolate* pIsolate = GetIsolate(); + v8::Locker lock(pIsolate); + v8::Isolate::Scope isolate_scope(pIsolate); + v8::HandleScope handle_scope(pIsolate); + v8::Local<v8::Context> context = + v8::Local<v8::Context>::New(pIsolate, m_context); + v8::Context::Scope context_scope(context); + + // v8::Local<v8::Context> tmpCotext = + // v8::Local<v8::Context>::New(GetIsolate(), m_context); + v8::Local<v8::Value> propvalue = v8::Local<v8::Value>::New( + GetIsolate(), ((CFXJSE_Value*)hValue)->DirectGetValue()); + context->Global()->Set( + v8::String::NewFromUtf8(pIsolate, name, v8::String::kNormalString, + utf8Name.GetLength()), + propvalue); +#endif + return TRUE; +} + +#endif +void CJS_Runtime::AddObserver(Observer* observer) { + ASSERT(!pdfium::ContainsKey(m_observers, observer)); + m_observers.insert(observer); +} + +void CJS_Runtime::RemoveObserver(Observer* observer) { + ASSERT(pdfium::ContainsKey(m_observers, observer)); + m_observers.erase(observer); +} diff --git a/fpdfsdk/javascript/JS_Runtime.h b/fpdfsdk/javascript/JS_Runtime.h new file mode 100644 index 0000000000..377916416f --- /dev/null +++ b/fpdfsdk/javascript/JS_Runtime.h @@ -0,0 +1,91 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_RUNTIME_H_ +#define FPDFSDK_JAVASCRIPT_JS_RUNTIME_H_ + +#include <map> +#include <set> +#include <utility> +#include <vector> + +#include "core/include/fxcrt/fx_basic.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/include/jsapi/fxjs_v8.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" + +class CJS_Context; + +class CJS_Runtime : public IJS_Runtime { + public: + class Observer { + public: + virtual void OnDestroyed() = 0; + + protected: + virtual ~Observer() {} + }; + + using FieldEvent = std::pair<CFX_WideString, JS_EVENT_T>; + + static CJS_Runtime* FromContext(const IJS_Context* cc); + + explicit CJS_Runtime(CPDFDoc_Environment* pApp); + ~CJS_Runtime() override; + + // IJS_Runtime + IJS_Context* NewContext() override; + void ReleaseContext(IJS_Context* pContext) override; + IJS_Context* GetCurrentContext() override; + void SetReaderDocument(CPDFSDK_Document* pReaderDoc) override; + CPDFSDK_Document* GetReaderDocument() override { return m_pDocument; } + int Execute(IJS_Context* cc, + const wchar_t* script, + CFX_WideString* info) override; + + CPDFDoc_Environment* GetReaderApp() const { return m_pApp; } + + // Returns true if the event isn't already found in the set. + bool AddEventToSet(const FieldEvent& event); + void RemoveEventFromSet(const FieldEvent& event); + + void BeginBlock() { m_bBlocking = TRUE; } + void EndBlock() { m_bBlocking = FALSE; } + FX_BOOL IsBlocking() const { return m_bBlocking; } + + v8::Isolate* GetIsolate() const { return m_isolate; } + v8::Local<v8::Context> NewJSContext(); + + void SetConstArray(const CFX_WideString& name, v8::Local<v8::Array> array); + v8::Local<v8::Array> GetConstArray(const CFX_WideString& name); + +#ifdef PDF_ENABLE_XFA + FX_BOOL GetHValueByName(const CFX_ByteStringC& utf8Name, + FXJSE_HVALUE hValue) override; + FX_BOOL SetHValueByName(const CFX_ByteStringC& utf8Name, + FXJSE_HVALUE hValue) override; +#endif // PDF_ENABLE_XFA + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + private: + void DefineJSObjects(); + + CFX_ArrayTemplate<CJS_Context*> m_ContextArray; + CPDFDoc_Environment* m_pApp; + CPDFSDK_Document* m_pDocument; + FX_BOOL m_bBlocking; + std::set<FieldEvent> m_FieldEventSet; + v8::Isolate* m_isolate; + bool m_isolateManaged; + v8::Global<v8::Context> m_context; + std::vector<v8::Global<v8::Object>*> m_StaticObjects; + std::map<CFX_WideString, v8::Global<v8::Array>> m_ConstArrays; + std::set<Observer*> m_observers; +}; + +#endif // FPDFSDK_JAVASCRIPT_JS_RUNTIME_H_ diff --git a/fpdfsdk/javascript/JS_Runtime_Stub.cpp b/fpdfsdk/javascript/JS_Runtime_Stub.cpp new file mode 100644 index 0000000000..d7962807c9 --- /dev/null +++ b/fpdfsdk/javascript/JS_Runtime_Stub.cpp @@ -0,0 +1,167 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include <memory> + +#include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. +#include "fpdfsdk/include/javascript/IJavaScript.h" + +class CJS_ContextStub final : public IJS_Context { + public: + CJS_ContextStub() {} + ~CJS_ContextStub() override {} + + // IJS_Context: + FX_BOOL RunScript(const CFX_WideString& script, + CFX_WideString* info) override { + return FALSE; + } + + void OnApp_Init() override {} + void OnDoc_Open(CPDFSDK_Document* pDoc, + const CFX_WideString& strTargetName) override {} + void OnDoc_WillPrint(CPDFSDK_Document* pDoc) override {} + void OnDoc_DidPrint(CPDFSDK_Document* pDoc) override {} + void OnDoc_WillSave(CPDFSDK_Document* pDoc) override {} + void OnDoc_DidSave(CPDFSDK_Document* pDoc) override {} + void OnDoc_WillClose(CPDFSDK_Document* pDoc) override {} + void OnPage_Open(CPDFSDK_Document* pTarget) override {} + void OnPage_Close(CPDFSDK_Document* pTarget) override {} + void OnPage_InView(CPDFSDK_Document* pTarget) override {} + void OnPage_OutView(CPDFSDK_Document* pTarget) override {} + void OnField_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override {} + void OnField_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override {} + void OnField_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override {} + void OnField_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget) override {} + void OnField_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) override {} + void OnField_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + const CFX_WideString& Value) override {} + void OnField_Calculate(CPDF_FormField* pSource, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) override {} + void OnField_Format(CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit) override {} + void OnField_Keystroke(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL KeyDown, + FX_BOOL bModifier, + int& nSelEnd, + int& nSelStart, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL bWillCommit, + FX_BOOL bFieldFull, + FX_BOOL& bRc) override {} + void OnField_Validate(CFX_WideString& strChange, + const CFX_WideString& strChangeEx, + FX_BOOL bKeyDown, + FX_BOOL bModifier, + FX_BOOL bShift, + CPDF_FormField* pTarget, + CFX_WideString& Value, + FX_BOOL& bRc) override {} + void OnScreen_Focus(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_Blur(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_Open(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_Close(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_MouseDown(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_MouseUp(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_MouseEnter(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_MouseExit(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_InView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnScreen_OutView(FX_BOOL bModifier, + FX_BOOL bShift, + CPDFSDK_Annot* pScreen) override {} + void OnBookmark_MouseUp(CPDF_Bookmark* pBookMark) override {} + void OnLink_MouseUp(CPDFSDK_Document* pTarget) override {} + void OnMenu_Exec(CPDFSDK_Document* pTarget, const CFX_WideString&) override {} + void OnBatchExec(CPDFSDK_Document* pTarget) override {} + void OnConsole_Exec() override {} + void OnExternal_Exec() override {} + void EnableMessageBox(FX_BOOL bEnable) override {} +}; + +class CJS_RuntimeStub final : public IJS_Runtime { + public: + CJS_RuntimeStub() : m_pDoc(nullptr) {} + ~CJS_RuntimeStub() override {} + + IJS_Context* NewContext() override { + if (!m_pContext) + m_pContext.reset(new CJS_ContextStub()); + return GetCurrentContext(); + } + + IJS_Context* GetCurrentContext() override { return m_pContext.get(); } + void ReleaseContext(IJS_Context* pContext) override {} + + void SetReaderDocument(CPDFSDK_Document* pReaderDoc) override { + m_pDoc = pReaderDoc; + } + CPDFSDK_Document* GetReaderDocument() override { return m_pDoc; } + +#ifdef PDF_ENABLE_XFA + FX_BOOL GetHValueByName(const CFX_ByteStringC&, FXJSE_HVALUE) override { + return FALSE; + } + + FX_BOOL SetHValueByName(const CFX_ByteStringC&, FXJSE_HVALUE) override { + return FALSE; + } +#endif // PDF_ENABLE_XFA + + int Execute(IJS_Context* cc, + const wchar_t* script, + CFX_WideString* info) override { + return 0; + } + + protected: + CPDFSDK_Document* m_pDoc; + std::unique_ptr<CJS_ContextStub> m_pContext; +}; + +// static +void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {} + +// static +IJS_Runtime* IJS_Runtime::Create(CPDFDoc_Environment* pEnv) { + return new CJS_RuntimeStub; +} diff --git a/fpdfsdk/javascript/JS_Value.cpp b/fpdfsdk/javascript/JS_Value.cpp new file mode 100644 index 0000000000..8e5e463e61 --- /dev/null +++ b/fpdfsdk/javascript/JS_Value.cpp @@ -0,0 +1,906 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/JS_Value.h" + +#include <time.h> + +#include <algorithm> +#include <cmath> +#include <limits> +#include <vector> + +#include "fpdfsdk/javascript/Document.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_Object.h" + +static const FX_DWORD g_nan[2] = {0, 0x7FF80000}; +static double GetNan() { + return *(double*)g_nan; +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime) + : m_eType(VT_unknown), m_pJSRuntime(pRuntime) {} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Value> pValue, Type t) + : m_eType(t), m_pValue(pValue), m_pJSRuntime(pRuntime) {} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const int& iValue) + : m_pJSRuntime(pRuntime) { + operator=(iValue); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const bool& bValue) + : m_pJSRuntime(pRuntime) { + operator=(bValue); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const float& fValue) + : m_pJSRuntime(pRuntime) { + operator=(fValue); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const double& dValue) + : m_pJSRuntime(pRuntime) { + operator=(dValue); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Object> pJsObj) + : m_pJSRuntime(pRuntime) { + operator=(pJsObj); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Object* pJsObj) + : m_pJSRuntime(pRuntime) { + operator=(pJsObj); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Document* pJsDoc) + : m_pJSRuntime(pRuntime) { + m_eType = VT_object; + if (pJsDoc) + m_pValue = pJsDoc->ToV8Object(); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr) + : m_pJSRuntime(pRuntime) { + operator=(pWstr); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr) + : m_pJSRuntime(pRuntime) { + operator=(pStr); +} + +CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Array& array) + : m_pJSRuntime(pRuntime) { + operator=(array); +} + +CJS_Value::~CJS_Value() {} + +void CJS_Value::Attach(v8::Local<v8::Value> pValue, Type t) { + m_pValue = pValue; + m_eType = t; +} + +void CJS_Value::Attach(CJS_Value* pValue) { + if (pValue) + Attach(pValue->ToV8Value(), pValue->GetType()); +} + +void CJS_Value::Detach() { + m_pValue = v8::Local<v8::Value>(); + m_eType = VT_unknown; +} + +int CJS_Value::ToInt() const { + return FXJS_ToInt32(m_pJSRuntime->GetIsolate(), m_pValue); +} + +bool CJS_Value::ToBool() const { + return FXJS_ToBoolean(m_pJSRuntime->GetIsolate(), m_pValue); +} + +double CJS_Value::ToDouble() const { + return FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pValue); +} + +float CJS_Value::ToFloat() const { + return (float)ToDouble(); +} + +CJS_Object* CJS_Value::ToCJSObject() const { + v8::Local<v8::Object> pObj = + FXJS_ToObject(m_pJSRuntime->GetIsolate(), m_pValue); + return (CJS_Object*)FXJS_GetPrivate(m_pJSRuntime->GetIsolate(), pObj); +} + +v8::Local<v8::Object> CJS_Value::ToV8Object() const { + return FXJS_ToObject(m_pJSRuntime->GetIsolate(), m_pValue); +} + +CFX_WideString CJS_Value::ToCFXWideString() const { + return FXJS_ToString(m_pJSRuntime->GetIsolate(), m_pValue); +} + +CFX_ByteString CJS_Value::ToCFXByteString() const { + return CFX_ByteString::FromUnicode(ToCFXWideString()); +} + +v8::Local<v8::Value> CJS_Value::ToV8Value() const { + return m_pValue; +} + +v8::Local<v8::Array> CJS_Value::ToV8Array() const { + if (IsArrayObject()) + return v8::Local<v8::Array>::Cast( + FXJS_ToObject(m_pJSRuntime->GetIsolate(), m_pValue)); + return v8::Local<v8::Array>(); +} + +void CJS_Value::MaybeCoerceToNumber() { + bool bAllowNaN = false; + if (m_eType == VT_string) { + CFX_ByteString bstr = ToCFXByteString(); + if (bstr.GetLength() == 0) + return; + if (bstr == "NaN") + bAllowNaN = true; + } + v8::TryCatch(m_pJSRuntime->GetIsolate()); + v8::MaybeLocal<v8::Number> maybeNum = + m_pValue->ToNumber(m_pJSRuntime->GetIsolate()->GetCurrentContext()); + if (maybeNum.IsEmpty()) + return; + v8::Local<v8::Number> num = maybeNum.ToLocalChecked(); + if (std::isnan(num->Value()) && !bAllowNaN) + return; + m_pValue = num; + m_eType = VT_number; +} + +void CJS_Value::operator=(int iValue) { + m_pValue = FXJS_NewNumber(m_pJSRuntime->GetIsolate(), iValue); + m_eType = VT_number; +} + +void CJS_Value::operator=(bool bValue) { + m_pValue = FXJS_NewBoolean(m_pJSRuntime->GetIsolate(), bValue); + m_eType = VT_boolean; +} + +void CJS_Value::operator=(double dValue) { + m_pValue = FXJS_NewNumber(m_pJSRuntime->GetIsolate(), dValue); + m_eType = VT_number; +} + +void CJS_Value::operator=(float fValue) { + m_pValue = FXJS_NewNumber(m_pJSRuntime->GetIsolate(), fValue); + m_eType = VT_number; +} + +void CJS_Value::operator=(v8::Local<v8::Object> pObj) { + m_pValue = FXJS_NewObject(m_pJSRuntime->GetIsolate(), pObj); + m_eType = VT_fxobject; +} + +void CJS_Value::operator=(CJS_Object* pObj) { + if (pObj) + operator=(pObj->ToV8Object()); +} + +void CJS_Value::operator=(CJS_Document* pJsDoc) { + m_eType = VT_object; + if (pJsDoc) { + m_pValue = pJsDoc->ToV8Object(); + } +} + +void CJS_Value::operator=(const FX_WCHAR* pWstr) { + m_pValue = FXJS_NewString(m_pJSRuntime->GetIsolate(), (wchar_t*)pWstr); + m_eType = VT_string; +} + +void CJS_Value::SetNull() { + m_pValue = FXJS_NewNull(); + m_eType = VT_null; +} + +void CJS_Value::operator=(const FX_CHAR* pStr) { + operator=(CFX_WideString::FromLocal(pStr).c_str()); +} + +void CJS_Value::operator=(CJS_Array& array) { + m_pValue = + FXJS_NewObject2(m_pJSRuntime->GetIsolate(), (v8::Local<v8::Array>)array); + m_eType = VT_object; +} + +void CJS_Value::operator=(CJS_Date& date) { + m_pValue = FXJS_NewDate(m_pJSRuntime->GetIsolate(), (double)date); + m_eType = VT_date; +} + +void CJS_Value::operator=(CJS_Value value) { + m_pValue = value.ToV8Value(); + m_eType = value.m_eType; + m_pJSRuntime = value.m_pJSRuntime; +} + +CJS_Value::Type CJS_Value::GetType() const { + if (m_pValue.IsEmpty()) + return VT_unknown; + if (m_pValue->IsString()) + return VT_string; + if (m_pValue->IsNumber()) + return VT_number; + if (m_pValue->IsBoolean()) + return VT_boolean; + if (m_pValue->IsDate()) + return VT_date; + if (m_pValue->IsObject()) + return VT_object; + if (m_pValue->IsNull()) + return VT_null; + if (m_pValue->IsUndefined()) + return VT_undefined; + return VT_unknown; +} + +FX_BOOL CJS_Value::IsArrayObject() const { + if (m_pValue.IsEmpty()) + return FALSE; + return m_pValue->IsArray(); +} + +FX_BOOL CJS_Value::IsDateObject() const { + if (m_pValue.IsEmpty()) + return FALSE; + return m_pValue->IsDate(); +} + +// CJS_Value::operator CJS_Array() +FX_BOOL CJS_Value::ConvertToArray(CJS_Array& array) const { + if (IsArrayObject()) { + array.Attach(FXJS_ToArray(m_pJSRuntime->GetIsolate(), m_pValue)); + return TRUE; + } + + return FALSE; +} + +FX_BOOL CJS_Value::ConvertToDate(CJS_Date& date) const { + if (IsDateObject()) { + date.Attach(m_pValue); + return TRUE; + } + + return FALSE; +} + +/* ---------------------------- CJS_PropValue ---------------------------- */ + +CJS_PropValue::CJS_PropValue(const CJS_Value& value) + : CJS_Value(value), m_bIsSetting(0) {} + +CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime) + : CJS_Value(pRuntime), m_bIsSetting(0) {} + +CJS_PropValue::~CJS_PropValue() {} + +void CJS_PropValue::operator<<(int iValue) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(iValue); +} + +void CJS_PropValue::operator>>(int& iValue) const { + ASSERT(m_bIsSetting); + iValue = CJS_Value::ToInt(); +} + +void CJS_PropValue::operator<<(bool bValue) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(bValue); +} + +void CJS_PropValue::operator>>(bool& bValue) const { + ASSERT(m_bIsSetting); + bValue = CJS_Value::ToBool(); +} + +void CJS_PropValue::operator<<(double dValue) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(dValue); +} + +void CJS_PropValue::operator>>(double& dValue) const { + ASSERT(m_bIsSetting); + dValue = CJS_Value::ToDouble(); +} + +void CJS_PropValue::operator<<(CJS_Object* pObj) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(pObj); +} + +void CJS_PropValue::operator>>(CJS_Object*& ppObj) const { + ASSERT(m_bIsSetting); + ppObj = CJS_Value::ToCJSObject(); +} + +void CJS_PropValue::operator<<(CJS_Document* pJsDoc) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(pJsDoc); +} + +void CJS_PropValue::operator>>(CJS_Document*& ppJsDoc) const { + ASSERT(m_bIsSetting); + ppJsDoc = static_cast<CJS_Document*>(CJS_Value::ToCJSObject()); +} + +void CJS_PropValue::operator<<(v8::Local<v8::Object> pObj) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(pObj); +} + +void CJS_PropValue::operator>>(v8::Local<v8::Object>& ppObj) const { + ASSERT(m_bIsSetting); + ppObj = CJS_Value::ToV8Object(); +} + +void CJS_PropValue::StartSetting() { + m_bIsSetting = 1; +} + +void CJS_PropValue::StartGetting() { + m_bIsSetting = 0; +} +void CJS_PropValue::operator<<(CFX_ByteString str) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(str.c_str()); +} + +void CJS_PropValue::operator>>(CFX_ByteString& str) const { + ASSERT(m_bIsSetting); + str = CJS_Value::ToCFXByteString(); +} + +void CJS_PropValue::operator<<(const FX_WCHAR* c_string) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(c_string); +} + +void CJS_PropValue::operator>>(CFX_WideString& wide_string) const { + ASSERT(m_bIsSetting); + wide_string = CJS_Value::ToCFXWideString(); +} + +void CJS_PropValue::operator<<(CFX_WideString wide_string) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(wide_string.c_str()); +} + +void CJS_PropValue::operator>>(CJS_Array& array) const { + ASSERT(m_bIsSetting); + ConvertToArray(array); +} + +void CJS_PropValue::operator<<(CJS_Array& array) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(array); +} + +void CJS_PropValue::operator>>(CJS_Date& date) const { + ASSERT(m_bIsSetting); + ConvertToDate(date); +} + +void CJS_PropValue::operator<<(CJS_Date& date) { + ASSERT(!m_bIsSetting); + CJS_Value::operator=(date); +} + +CJS_PropValue::operator v8::Local<v8::Value>() const { + return m_pValue; +} + +CJS_Array::CJS_Array(CJS_Runtime* pRuntime) : m_pJSRuntime(pRuntime) {} + +CJS_Array::~CJS_Array() {} + +void CJS_Array::Attach(v8::Local<v8::Array> pArray) { + m_pArray = pArray; +} + +FX_BOOL CJS_Array::IsAttached() { + return FALSE; +} + +void CJS_Array::GetElement(unsigned index, CJS_Value& value) { + if (m_pArray.IsEmpty()) + return; + v8::Local<v8::Value> p = + FXJS_GetArrayElement(m_pJSRuntime->GetIsolate(), m_pArray, index); + value.Attach(p, CJS_Value::VT_object); +} + +void CJS_Array::SetElement(unsigned index, CJS_Value value) { + if (m_pArray.IsEmpty()) + m_pArray = FXJS_NewArray(m_pJSRuntime->GetIsolate()); + + FXJS_PutArrayElement(m_pJSRuntime->GetIsolate(), m_pArray, index, + value.ToV8Value()); +} + +int CJS_Array::GetLength() { + if (m_pArray.IsEmpty()) + return 0; + return FXJS_GetArrayLength(m_pArray); +} + +CJS_Array::operator v8::Local<v8::Array>() { + if (m_pArray.IsEmpty()) + m_pArray = FXJS_NewArray(m_pJSRuntime->GetIsolate()); + + return m_pArray; +} + +CJS_Date::CJS_Date(CJS_Runtime* pRuntime) : m_pJSRuntime(pRuntime) {} + +CJS_Date::CJS_Date(CJS_Runtime* pRuntime, double dMsecTime) + : m_pJSRuntime(pRuntime) { + m_pDate = FXJS_NewDate(pRuntime->GetIsolate(), dMsecTime); +} + +CJS_Date::CJS_Date(CJS_Runtime* pRuntime, + int year, + int mon, + int day, + int hour, + int min, + int sec) + : m_pJSRuntime(pRuntime) { + m_pDate = FXJS_NewDate(pRuntime->GetIsolate(), + MakeDate(year, mon, day, hour, min, sec, 0)); +} + +double CJS_Date::MakeDate(int year, + int mon, + int day, + int hour, + int min, + int sec, + int ms) { + return JS_MakeDate(JS_MakeDay(year, mon, day), + JS_MakeTime(hour, min, sec, ms)); +} + +CJS_Date::~CJS_Date() {} + +FX_BOOL CJS_Date::IsValidDate() { + if (m_pDate.IsEmpty()) + return FALSE; + return !JS_PortIsNan(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate)); +} + +void CJS_Date::Attach(v8::Local<v8::Value> pDate) { + m_pDate = pDate; +} + +int CJS_Date::GetYear() { + if (IsValidDate()) + return JS_GetYearFromTime( + JS_LocalTime(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate))); + + return 0; +} + +void CJS_Date::SetYear(int iYear) { + double date = MakeDate(iYear, GetMonth(), GetDay(), GetHours(), GetMinutes(), + GetSeconds(), 0); + FXJS_ValueCopy(m_pDate, FXJS_NewDate(m_pJSRuntime->GetIsolate(), date)); +} + +int CJS_Date::GetMonth() { + if (IsValidDate()) + return JS_GetMonthFromTime( + JS_LocalTime(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate))); + + return 0; +} + +void CJS_Date::SetMonth(int iMonth) { + double date = MakeDate(GetYear(), iMonth, GetDay(), GetHours(), GetMinutes(), + GetSeconds(), 0); + FXJS_ValueCopy(m_pDate, FXJS_NewDate(m_pJSRuntime->GetIsolate(), date)); +} + +int CJS_Date::GetDay() { + if (IsValidDate()) + return JS_GetDayFromTime( + JS_LocalTime(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate))); + + return 0; +} + +void CJS_Date::SetDay(int iDay) { + double date = MakeDate(GetYear(), GetMonth(), iDay, GetHours(), GetMinutes(), + GetSeconds(), 0); + FXJS_ValueCopy(m_pDate, FXJS_NewDate(m_pJSRuntime->GetIsolate(), date)); +} + +int CJS_Date::GetHours() { + if (IsValidDate()) + return JS_GetHourFromTime( + JS_LocalTime(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate))); + + return 0; +} + +void CJS_Date::SetHours(int iHours) { + double date = MakeDate(GetYear(), GetMonth(), GetDay(), iHours, GetMinutes(), + GetSeconds(), 0); + FXJS_ValueCopy(m_pDate, FXJS_NewDate(m_pJSRuntime->GetIsolate(), date)); +} + +int CJS_Date::GetMinutes() { + if (IsValidDate()) + return JS_GetMinFromTime( + JS_LocalTime(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate))); + + return 0; +} + +void CJS_Date::SetMinutes(int minutes) { + double date = MakeDate(GetYear(), GetMonth(), GetDay(), GetHours(), minutes, + GetSeconds(), 0); + FXJS_ValueCopy(m_pDate, FXJS_NewDate(m_pJSRuntime->GetIsolate(), date)); +} + +int CJS_Date::GetSeconds() { + if (IsValidDate()) + return JS_GetSecFromTime( + JS_LocalTime(FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate))); + + return 0; +} + +void CJS_Date::SetSeconds(int seconds) { + double date = MakeDate(GetYear(), GetMonth(), GetDay(), GetHours(), + GetMinutes(), seconds, 0); + FXJS_ValueCopy(m_pDate, FXJS_NewDate(m_pJSRuntime->GetIsolate(), date)); +} + +CJS_Date::operator v8::Local<v8::Value>() { + return m_pDate; +} + +CJS_Date::operator double() const { + if (m_pDate.IsEmpty()) + return 0.0; + return FXJS_ToNumber(m_pJSRuntime->GetIsolate(), m_pDate); +} + +CFX_WideString CJS_Date::ToString() const { + if (m_pDate.IsEmpty()) + return L""; + return FXJS_ToString(m_pJSRuntime->GetIsolate(), m_pDate); +} + +double _getLocalTZA() { + if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) + return 0; + time_t t = 0; + time(&t); + localtime(&t); +#if _MSC_VER >= 1900 + // In gcc and in Visual Studio prior to VS 2015 'timezone' is a global + // variable declared in time.h. That variable was deprecated and in VS 2015 + // is removed, with _get_timezone replacing it. + long timezone = 0; + _get_timezone(&timezone); +#endif + return (double)(-(timezone * 1000)); +} + +int _getDaylightSavingTA(double d) { + if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) + return 0; + time_t t = (time_t)(d / 1000); + struct tm* tmp = localtime(&t); + if (!tmp) + return 0; + if (tmp->tm_isdst > 0) + // One hour. + return (int)60 * 60 * 1000; + return 0; +} + +double _Mod(double x, double y) { + double r = fmod(x, y); + if (r < 0) + r += y; + return r; +} + +int _isfinite(double v) { +#if _MSC_VER + return ::_finite(v); +#else + return std::fabs(v) < std::numeric_limits<double>::max(); +#endif +} + +double _toInteger(double n) { + return (n >= 0) ? FXSYS_floor(n) : -FXSYS_floor(-n); +} + +bool _isLeapYear(int year) { + return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 != 0)); +} + +int _DayFromYear(int y) { + return (int)(365 * (y - 1970.0) + FXSYS_floor((y - 1969.0) / 4) - + FXSYS_floor((y - 1901.0) / 100) + + FXSYS_floor((y - 1601.0) / 400)); +} + +double _TimeFromYear(int y) { + return 86400000.0 * _DayFromYear(y); +} + +double _TimeFromYearMonth(int y, int m) { + static int daysMonth[12] = {0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334}; + static int leapDaysMonth[12] = {0, 31, 60, 91, 121, 152, + 182, 213, 244, 274, 305, 335}; + int* pMonth = daysMonth; + if (_isLeapYear(y)) + pMonth = leapDaysMonth; + return _TimeFromYear(y) + ((double)pMonth[m]) * 86400000; +} + +int _Day(double t) { + return (int)FXSYS_floor(t / 86400000); +} + +int _YearFromTime(double t) { + // estimate the time. + int y = 1970 + static_cast<int>(t / (365.2425 * 86400000)); + if (_TimeFromYear(y) <= t) { + while (_TimeFromYear(y + 1) <= t) + y++; + } else { + while (_TimeFromYear(y) > t) + y--; + } + return y; +} + +int _DayWithinYear(double t) { + int year = _YearFromTime(t); + int day = _Day(t); + return day - _DayFromYear(year); +} + +int _MonthFromTime(double t) { + int day = _DayWithinYear(t); + int year = _YearFromTime(t); + if (0 <= day && day < 31) + return 0; + if (31 <= day && day < 59 + _isLeapYear(year)) + return 1; + if ((59 + _isLeapYear(year)) <= day && day < (90 + _isLeapYear(year))) + return 2; + if ((90 + _isLeapYear(year)) <= day && day < (120 + _isLeapYear(year))) + return 3; + if ((120 + _isLeapYear(year)) <= day && day < (151 + _isLeapYear(year))) + return 4; + if ((151 + _isLeapYear(year)) <= day && day < (181 + _isLeapYear(year))) + return 5; + if ((181 + _isLeapYear(year)) <= day && day < (212 + _isLeapYear(year))) + return 6; + if ((212 + _isLeapYear(year)) <= day && day < (243 + _isLeapYear(year))) + return 7; + if ((243 + _isLeapYear(year)) <= day && day < (273 + _isLeapYear(year))) + return 8; + if ((273 + _isLeapYear(year)) <= day && day < (304 + _isLeapYear(year))) + return 9; + if ((304 + _isLeapYear(year)) <= day && day < (334 + _isLeapYear(year))) + return 10; + if ((334 + _isLeapYear(year)) <= day && day < (365 + _isLeapYear(year))) + return 11; + + return -1; +} + +int _DateFromTime(double t) { + int day = _DayWithinYear(t); + int year = _YearFromTime(t); + bool leap = _isLeapYear(year); + int month = _MonthFromTime(t); + switch (month) { + case 0: + return day + 1; + case 1: + return day - 30; + case 2: + return day - 58 - leap; + case 3: + return day - 89 - leap; + case 4: + return day - 119 - leap; + case 5: + return day - 150 - leap; + case 6: + return day - 180 - leap; + case 7: + return day - 211 - leap; + case 8: + return day - 242 - leap; + case 9: + return day - 272 - leap; + case 10: + return day - 303 - leap; + case 11: + return day - 333 - leap; + default: + return 0; + } +} + +double JS_GetDateTime() { + if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) + return 0; + time_t t = time(NULL); + struct tm* pTm = localtime(&t); + + int year = pTm->tm_year + 1900; + double t1 = _TimeFromYear(year); + + return t1 + pTm->tm_yday * 86400000.0 + pTm->tm_hour * 3600000.0 + + pTm->tm_min * 60000.0 + pTm->tm_sec * 1000.0; +} + +int JS_GetYearFromTime(double dt) { + return _YearFromTime(dt); +} + +int JS_GetMonthFromTime(double dt) { + return _MonthFromTime(dt); +} + +int JS_GetDayFromTime(double dt) { + return _DateFromTime(dt); +} + +int JS_GetHourFromTime(double dt) { + return (int)_Mod(FXSYS_floor((double)(dt / (60 * 60 * 1000))), 24); +} + +int JS_GetMinFromTime(double dt) { + return (int)_Mod(FXSYS_floor((double)(dt / (60 * 1000))), 60); +} + +int JS_GetSecFromTime(double dt) { + return (int)_Mod(FXSYS_floor((double)(dt / 1000)), 60); +} + +double JS_DateParse(const wchar_t* str) { + v8::Isolate* pIsolate = v8::Isolate::GetCurrent(); + v8::Isolate::Scope isolate_scope(pIsolate); + v8::HandleScope scope(pIsolate); + + v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); + + // Use the built-in object method. + v8::Local<v8::Value> v = + context->Global() + ->Get(context, v8::String::NewFromUtf8(pIsolate, "Date", + v8::NewStringType::kNormal) + .ToLocalChecked()) + .ToLocalChecked(); + if (v->IsObject()) { + v8::Local<v8::Object> o = v->ToObject(context).ToLocalChecked(); + v = o->Get(context, v8::String::NewFromUtf8(pIsolate, "parse", + v8::NewStringType::kNormal) + .ToLocalChecked()) + .ToLocalChecked(); + if (v->IsFunction()) { + v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v); + + const int argc = 1; + v8::Local<v8::String> timeStr = FXJS_WSToJSString(pIsolate, str); + v8::Local<v8::Value> argv[argc] = {timeStr}; + v = funC->Call(context, context->Global(), argc, argv).ToLocalChecked(); + if (v->IsNumber()) { + double date = v->ToNumber(context).ToLocalChecked()->Value(); + if (!_isfinite(date)) + return date; + return date + _getLocalTZA() + _getDaylightSavingTA(date); + } + } + } + return 0; +} + +double JS_MakeDay(int nYear, int nMonth, int nDate) { + if (!_isfinite(nYear) || !_isfinite(nMonth) || !_isfinite(nDate)) + return GetNan(); + double y = _toInteger(nYear); + double m = _toInteger(nMonth); + double dt = _toInteger(nDate); + double ym = y + FXSYS_floor((double)m / 12); + double mn = _Mod(m, 12); + + double t = _TimeFromYearMonth((int)ym, (int)mn); + + if (_YearFromTime(t) != ym || _MonthFromTime(t) != mn || + _DateFromTime(t) != 1) + return GetNan(); + return _Day(t) + dt - 1; +} + +double JS_MakeTime(int nHour, int nMin, int nSec, int nMs) { + if (!_isfinite(nHour) || !_isfinite(nMin) || !_isfinite(nSec) || + !_isfinite(nMs)) + return GetNan(); + + double h = _toInteger(nHour); + double m = _toInteger(nMin); + double s = _toInteger(nSec); + double milli = _toInteger(nMs); + + return h * 3600000 + m * 60000 + s * 1000 + milli; +} + +double JS_MakeDate(double day, double time) { + if (!_isfinite(day) || !_isfinite(time)) + return GetNan(); + + return day * 86400000 + time; +} + +bool JS_PortIsNan(double d) { + return d != d; +} + +double JS_LocalTime(double d) { + return JS_GetDateTime() + _getDaylightSavingTA(d); +} + +std::vector<CJS_Value> JS_ExpandKeywordParams( + CJS_Runtime* pRuntime, + const std::vector<CJS_Value>& originals, + size_t nKeywords, + ...) { + ASSERT(nKeywords); + + std::vector<CJS_Value> result(nKeywords, CJS_Value(pRuntime)); + size_t size = std::min(originals.size(), nKeywords); + for (size_t i = 0; i < size; ++i) + result[i] = originals[i]; + + if (originals.size() != 1 || originals[0].GetType() != CJS_Value::VT_object || + originals[0].IsArrayObject()) { + return result; + } + v8::Local<v8::Object> pObj = originals[0].ToV8Object(); + result[0] = CJS_Value(pRuntime); // Make unknown. + + va_list ap; + va_start(ap, nKeywords); + for (int i = 0; i < nKeywords; ++i) { + const wchar_t* property = va_arg(ap, const wchar_t*); + v8::Local<v8::Value> v8Value = + FXJS_GetObjectElement(pRuntime->GetIsolate(), pObj, property); + if (!v8Value->IsUndefined()) + result[i] = CJS_Value(pRuntime, v8Value, CJS_Value::VT_unknown); + } + va_end(ap); + return result; +} diff --git a/fpdfsdk/javascript/JS_Value.h b/fpdfsdk/javascript/JS_Value.h new file mode 100644 index 0000000000..70f76cef87 --- /dev/null +++ b/fpdfsdk/javascript/JS_Value.h @@ -0,0 +1,230 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_JS_VALUE_H_ +#define FPDFSDK_JAVASCRIPT_JS_VALUE_H_ + +#include <vector> + +#include "core/include/fxcrt/fx_basic.h" +#include "fpdfsdk/include/jsapi/fxjs_v8.h" + +class CJS_Array; +class CJS_Date; +class CJS_Document; +class CJS_Object; +class CJS_Runtime; + +class CJS_Value { + public: + enum Type { + VT_unknown, + VT_string, + VT_number, + VT_boolean, + VT_date, + VT_object, + VT_fxobject, + VT_null, + VT_undefined + }; + + CJS_Value(CJS_Runtime* pRuntime); + CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Value> pValue, Type t); + CJS_Value(CJS_Runtime* pRuntime, const int& iValue); + CJS_Value(CJS_Runtime* pRuntime, const double& dValue); + CJS_Value(CJS_Runtime* pRuntime, const float& fValue); + CJS_Value(CJS_Runtime* pRuntime, const bool& bValue); + CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Object>); + CJS_Value(CJS_Runtime* pRuntime, CJS_Object*); + CJS_Value(CJS_Runtime* pRuntime, CJS_Document*); + CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr); + CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr); + CJS_Value(CJS_Runtime* pRuntime, CJS_Array& array); + + ~CJS_Value(); + + void SetNull(); + void Attach(v8::Local<v8::Value> pValue, Type t); + void Attach(CJS_Value* pValue); + void Detach(); + + Type GetType() const; + int ToInt() const; + bool ToBool() const; + double ToDouble() const; + float ToFloat() const; + CJS_Object* ToCJSObject() const; + CFX_WideString ToCFXWideString() const; + CFX_ByteString ToCFXByteString() const; + v8::Local<v8::Object> ToV8Object() const; + v8::Local<v8::Array> ToV8Array() const; + v8::Local<v8::Value> ToV8Value() const; + + // Replace the current |m_pValue| with a v8::Number if possible + // to make one from the current |m_pValue|, updating |m_eType| + // as appropriate to indicate the result. + void MaybeCoerceToNumber(); + + void operator=(int iValue); + void operator=(bool bValue); + void operator=(double val); + void operator=(float val); + void operator=(CJS_Object* val); + void operator=(CJS_Document* val); + void operator=(v8::Local<v8::Object> val); + void operator=(CJS_Array& val); + void operator=(CJS_Date& val); + void operator=(const FX_WCHAR* pWstr); + void operator=(const FX_CHAR* pStr); + void operator=(CJS_Value value); + + FX_BOOL IsArrayObject() const; + FX_BOOL IsDateObject() const; + FX_BOOL ConvertToArray(CJS_Array&) const; + FX_BOOL ConvertToDate(CJS_Date&) const; + + CJS_Runtime* GetJSRuntime() const { return m_pJSRuntime; } + + protected: + Type m_eType; + v8::Local<v8::Value> m_pValue; + CJS_Runtime* m_pJSRuntime; +}; + +class CJS_PropValue : public CJS_Value { + public: + CJS_PropValue(const CJS_Value&); + CJS_PropValue(CJS_Runtime* pRuntime); + ~CJS_PropValue(); + + FX_BOOL IsSetting() const { return m_bIsSetting; } + FX_BOOL IsGetting() const { return !m_bIsSetting; } + + void operator<<(int val); + void operator>>(int&) const; + void operator<<(bool val); + void operator>>(bool&) const; + void operator<<(double val); + void operator>>(double&) const; + void operator<<(CJS_Object* pObj); + void operator>>(CJS_Object*& ppObj) const; + void operator<<(CJS_Document* pJsDoc); + void operator>>(CJS_Document*& ppJsDoc) const; + void operator<<(CFX_ByteString); + void operator>>(CFX_ByteString&) const; + void operator<<(CFX_WideString); + void operator>>(CFX_WideString&) const; + void operator<<(const FX_WCHAR* c_string); + void operator<<(v8::Local<v8::Object>); + void operator>>(v8::Local<v8::Object>&) const; + void operator>>(CJS_Array& array) const; + void operator<<(CJS_Array& array); + void operator<<(CJS_Date& date); + void operator>>(CJS_Date& date) const; + operator v8::Local<v8::Value>() const; + void StartSetting(); + void StartGetting(); + + private: + FX_BOOL m_bIsSetting; +}; + +class CJS_Array { + public: + CJS_Array(CJS_Runtime* pRuntime); + virtual ~CJS_Array(); + + void Attach(v8::Local<v8::Array> pArray); + void GetElement(unsigned index, CJS_Value& value); + void SetElement(unsigned index, CJS_Value value); + int GetLength(); + FX_BOOL IsAttached(); + operator v8::Local<v8::Array>(); + + CJS_Runtime* GetJSRuntime() const { return m_pJSRuntime; } + + private: + v8::Local<v8::Array> m_pArray; + CJS_Runtime* m_pJSRuntime; +}; + +class CJS_Date { + friend class CJS_Value; + + public: + CJS_Date(CJS_Runtime* pRuntime); + CJS_Date(CJS_Runtime* pRuntime, double dMsec_time); + CJS_Date(CJS_Runtime* pRuntime, + int year, + int mon, + int day, + int hour, + int min, + int sec); + virtual ~CJS_Date(); + void Attach(v8::Local<v8::Value> pDate); + + int GetYear(); + void SetYear(int iYear); + + int GetMonth(); + void SetMonth(int iMonth); + + int GetDay(); + void SetDay(int iDay); + + int GetHours(); + void SetHours(int iHours); + + int GetMinutes(); + void SetMinutes(int minutes); + + int GetSeconds(); + void SetSeconds(int seconds); + + operator v8::Local<v8::Value>(); + operator double() const; + + CFX_WideString ToString() const; + + static double + MakeDate(int year, int mon, int mday, int hour, int min, int sec, int ms); + + FX_BOOL IsValidDate(); + + protected: + v8::Local<v8::Value> m_pDate; + CJS_Runtime* m_pJSRuntime; +}; + +double JS_GetDateTime(); +int JS_GetYearFromTime(double dt); +int JS_GetMonthFromTime(double dt); +int JS_GetDayFromTime(double dt); +int JS_GetHourFromTime(double dt); +int JS_GetMinFromTime(double dt); +int JS_GetSecFromTime(double dt); +double JS_DateParse(const wchar_t* str); +double JS_MakeDay(int nYear, int nMonth, int nDay); +double JS_MakeTime(int nHour, int nMin, int nSec, int nMs); +double JS_MakeDate(double day, double time); +bool JS_PortIsNan(double d); +double JS_LocalTime(double d); + +// Some JS methods have the bizarre convention that they may also be called +// with a single argument which is an object containing the actual arguments +// as its properties. The varying arguments to this method are the property +// names as wchar_t string literals corresponding to each positional argument. +// The result will always contain |nKeywords| value, with unspecified ones +// being set to type VT_unknown. +std::vector<CJS_Value> JS_ExpandKeywordParams( + CJS_Runtime* pRuntime, + const std::vector<CJS_Value>& originals, + size_t nKeywords, + ...); + +#endif // FPDFSDK_JAVASCRIPT_JS_VALUE_H_ diff --git a/fpdfsdk/javascript/PublicMethods.cpp b/fpdfsdk/javascript/PublicMethods.cpp new file mode 100644 index 0000000000..d154fc1766 --- /dev/null +++ b/fpdfsdk/javascript/PublicMethods.cpp @@ -0,0 +1,1899 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/PublicMethods.h" + +#include <algorithm> +#include <string> +#include <vector> + +#include "core/include/fxcrt/fx_ext.h" +#include "fpdfsdk/include/fsdk_mgr.h" // For CPDFDoc_Environment. +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Field.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/color.h" +#include "fpdfsdk/javascript/resource.h" +#include "fpdfsdk/javascript/util.h" + +#define DOUBLE_CORRECT 0.000000000000001 + +BEGIN_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods) +JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Format) +JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Keystroke) +JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Format) +JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Keystroke) +JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_FormatEx) +JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_KeystrokeEx) +JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Format) +JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Keystroke) +JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_FormatEx) +JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_KeystrokeEx) +JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Format) +JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Keystroke) +JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Format) +JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Keystroke) +JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_KeystrokeEx) +JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple) +JS_STATIC_GLOBAL_FUN_ENTRY(AFMakeNumber) +JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple_Calculate) +JS_STATIC_GLOBAL_FUN_ENTRY(AFRange_Validate) +JS_STATIC_GLOBAL_FUN_ENTRY(AFMergeChange) +JS_STATIC_GLOBAL_FUN_ENTRY(AFParseDateEx) +JS_STATIC_GLOBAL_FUN_ENTRY(AFExtractNums) +END_JS_STATIC_GLOBAL_FUN() + +IMPLEMENT_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods) + +static const FX_WCHAR* const months[] = {L"Jan", L"Feb", L"Mar", L"Apr", + L"May", L"Jun", L"Jul", L"Aug", + L"Sep", L"Oct", L"Nov", L"Dec"}; + +static const FX_WCHAR* const fullmonths[] = { + L"January", L"February", L"March", L"April", + L"May", L"June", L"July", L"August", + L"September", L"October", L"November", L"December"}; + +FX_BOOL CJS_PublicMethods::IsNumber(const FX_WCHAR* str) { + CFX_WideString sTrim = StrTrim(str); + const FX_WCHAR* pTrim = sTrim.c_str(); + const FX_WCHAR* p = pTrim; + + FX_BOOL bDot = FALSE; + FX_BOOL bKXJS = FALSE; + + wchar_t c; + while ((c = *p)) { + if (c == '.' || c == ',') { + if (bDot) + return FALSE; + bDot = TRUE; + } else if (c == '-' || c == '+') { + if (p != pTrim) + return FALSE; + } else if (c == 'e' || c == 'E') { + if (bKXJS) + return FALSE; + + p++; + c = *p; + if (c == '+' || c == '-') { + bKXJS = TRUE; + } else { + return FALSE; + } + } else if (!FXSYS_iswdigit(c)) { + return FALSE; + } + p++; + } + + return TRUE; +} + +FX_BOOL CJS_PublicMethods::maskSatisfied(wchar_t c_Change, wchar_t c_Mask) { + switch (c_Mask) { + case L'9': + return FXSYS_iswdigit(c_Change); + case L'A': + return FXSYS_iswalpha(c_Change); + case L'O': + return FXSYS_iswalnum(c_Change); + case L'X': + return TRUE; + default: + return (c_Change == c_Mask); + } +} + +FX_BOOL CJS_PublicMethods::isReservedMaskChar(wchar_t ch) { + return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X'; +} + +double CJS_PublicMethods::AF_Simple(const FX_WCHAR* sFuction, + double dValue1, + double dValue2) { + if (FXSYS_wcsicmp(sFuction, L"AVG") == 0 || + FXSYS_wcsicmp(sFuction, L"SUM") == 0) { + return dValue1 + dValue2; + } + if (FXSYS_wcsicmp(sFuction, L"PRD") == 0) { + return dValue1 * dValue2; + } + if (FXSYS_wcsicmp(sFuction, L"MIN") == 0) { + return std::min(dValue1, dValue2); + } + if (FXSYS_wcsicmp(sFuction, L"MAX") == 0) { + return std::max(dValue1, dValue2); + } + return dValue1; +} + +CFX_WideString CJS_PublicMethods::StrLTrim(const FX_WCHAR* pStr) { + while (*pStr && *pStr == L' ') + pStr++; + + return pStr; +} + +CFX_WideString CJS_PublicMethods::StrRTrim(const FX_WCHAR* pStr) { + const FX_WCHAR* p = pStr; + while (*p) + p++; + while (p > pStr && *(p - 1) == L' ') + p--; + + return CFX_WideString(pStr, p - pStr); +} + +CFX_WideString CJS_PublicMethods::StrTrim(const FX_WCHAR* pStr) { + return StrRTrim(StrLTrim(pStr).c_str()); +} + +CFX_ByteString CJS_PublicMethods::StrLTrim(const FX_CHAR* pStr) { + while (*pStr && *pStr == ' ') + pStr++; + + return pStr; +} + +CFX_ByteString CJS_PublicMethods::StrRTrim(const FX_CHAR* pStr) { + const FX_CHAR* p = pStr; + while (*p) + p++; + while (p > pStr && *(p - 1) == L' ') + p--; + + return CFX_ByteString(pStr, p - pStr); +} + +CFX_ByteString CJS_PublicMethods::StrTrim(const FX_CHAR* pStr) { + return StrRTrim(StrLTrim(pStr)); +} + +CJS_Array CJS_PublicMethods::AF_MakeArrayFromList(CJS_Runtime* pRuntime, + CJS_Value val) { + CJS_Array StrArray(pRuntime); + if (val.IsArrayObject()) { + val.ConvertToArray(StrArray); + return StrArray; + } + CFX_WideString wsStr = val.ToCFXWideString(); + CFX_ByteString t = CFX_ByteString::FromUnicode(wsStr); + const char* p = (const char*)t; + + int ch = ','; + int nIndex = 0; + + while (*p) { + const char* pTemp = strchr(p, ch); + if (!pTemp) { + StrArray.SetElement(nIndex, CJS_Value(pRuntime, StrTrim(p).c_str())); + break; + } + + char* pSub = new char[pTemp - p + 1]; + strncpy(pSub, p, pTemp - p); + *(pSub + (pTemp - p)) = '\0'; + + StrArray.SetElement(nIndex, CJS_Value(pRuntime, StrTrim(pSub).c_str())); + delete[] pSub; + + nIndex++; + p = ++pTemp; + } + return StrArray; +} + +int CJS_PublicMethods::ParseStringInteger(const CFX_WideString& str, + int nStart, + int& nSkip, + int nMaxStep) { + int nRet = 0; + nSkip = 0; + for (int i = nStart, sz = str.GetLength(); i < sz; i++) { + if (i - nStart > 10) + break; + + FX_WCHAR c = str.GetAt(i); + if (!FXSYS_iswdigit(c)) + break; + + nRet = nRet * 10 + FXSYS_toDecimalDigit(c); + nSkip = i - nStart + 1; + if (nSkip >= nMaxStep) + break; + } + + return nRet; +} + +CFX_WideString CJS_PublicMethods::ParseStringString(const CFX_WideString& str, + int nStart, + int& nSkip) { + CFX_WideString swRet; + nSkip = 0; + for (int i = nStart, sz = str.GetLength(); i < sz; i++) { + FX_WCHAR c = str.GetAt(i); + if (!FXSYS_iswdigit(c)) + break; + + swRet += c; + nSkip = i - nStart + 1; + } + + return swRet; +} + +double CJS_PublicMethods::ParseNormalDate(const CFX_WideString& value, + bool* bWrongFormat) { + double dt = JS_GetDateTime(); + + int nYear = JS_GetYearFromTime(dt); + int nMonth = JS_GetMonthFromTime(dt) + 1; + int nDay = JS_GetDayFromTime(dt); + int nHour = JS_GetHourFromTime(dt); + int nMin = JS_GetMinFromTime(dt); + int nSec = JS_GetSecFromTime(dt); + + int number[3]; + + int nSkip = 0; + int nLen = value.GetLength(); + int nIndex = 0; + int i = 0; + while (i < nLen) { + if (nIndex > 2) + break; + + FX_WCHAR c = value.GetAt(i); + if (FXSYS_iswdigit(c)) { + number[nIndex++] = ParseStringInteger(value, i, nSkip, 4); + i += nSkip; + } else { + i++; + } + } + + if (nIndex == 2) { + // case2: month/day + // case3: day/month + if ((number[0] >= 1 && number[0] <= 12) && + (number[1] >= 1 && number[1] <= 31)) { + nMonth = number[0]; + nDay = number[1]; + } else if ((number[0] >= 1 && number[0] <= 31) && + (number[1] >= 1 && number[1] <= 12)) { + nDay = number[0]; + nMonth = number[1]; + } + + if (bWrongFormat) + *bWrongFormat = false; + } else if (nIndex == 3) { + // case1: year/month/day + // case2: month/day/year + // case3: day/month/year + + if (number[0] > 12 && (number[1] >= 1 && number[1] <= 12) && + (number[2] >= 1 && number[2] <= 31)) { + nYear = number[0]; + nMonth = number[1]; + nDay = number[2]; + } else if ((number[0] >= 1 && number[0] <= 12) && + (number[1] >= 1 && number[1] <= 31) && number[2] > 31) { + nMonth = number[0]; + nDay = number[1]; + nYear = number[2]; + } else if ((number[0] >= 1 && number[0] <= 31) && + (number[1] >= 1 && number[1] <= 12) && number[2] > 31) { + nDay = number[0]; + nMonth = number[1]; + nYear = number[2]; + } + + if (bWrongFormat) + *bWrongFormat = false; + } else { + if (bWrongFormat) + *bWrongFormat = true; + return dt; + } + + CFX_WideString swTemp; + swTemp.Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear, nHour, nMin, nSec); + return JS_DateParse(swTemp.c_str()); +} + +double CJS_PublicMethods::MakeRegularDate(const CFX_WideString& value, + const CFX_WideString& format, + bool* bWrongFormat) { + double dt = JS_GetDateTime(); + + if (format.IsEmpty() || value.IsEmpty()) + return dt; + + int nYear = JS_GetYearFromTime(dt); + int nMonth = JS_GetMonthFromTime(dt) + 1; + int nDay = JS_GetDayFromTime(dt); + int nHour = JS_GetHourFromTime(dt); + int nMin = JS_GetMinFromTime(dt); + int nSec = JS_GetSecFromTime(dt); + + int nYearSub = 99; // nYear - 2000; + + FX_BOOL bPm = FALSE; + FX_BOOL bExit = FALSE; + bool bBadFormat = false; + + int i = 0; + int j = 0; + + while (i < format.GetLength()) { + if (bExit) + break; + + FX_WCHAR c = format.GetAt(i); + switch (c) { + case ':': + case '.': + case '-': + case '\\': + case '/': + i++; + j++; + break; + + case 'y': + case 'm': + case 'd': + case 'H': + case 'h': + case 'M': + case 's': + case 't': { + int oldj = j; + int nSkip = 0; + int remaining = format.GetLength() - i - 1; + + if (remaining == 0 || format.GetAt(i + 1) != c) { + switch (c) { + case 'y': + i++; + j++; + break; + case 'm': + nMonth = ParseStringInteger(value, j, nSkip, 2); + i++; + j += nSkip; + break; + case 'd': + nDay = ParseStringInteger(value, j, nSkip, 2); + i++; + j += nSkip; + break; + case 'H': + nHour = ParseStringInteger(value, j, nSkip, 2); + i++; + j += nSkip; + break; + case 'h': + nHour = ParseStringInteger(value, j, nSkip, 2); + i++; + j += nSkip; + break; + case 'M': + nMin = ParseStringInteger(value, j, nSkip, 2); + i++; + j += nSkip; + break; + case 's': + nSec = ParseStringInteger(value, j, nSkip, 2); + i++; + j += nSkip; + break; + case 't': + bPm = (j < value.GetLength() && value.GetAt(j) == 'p'); + i++; + j++; + break; + } + } else if (remaining == 1 || format.GetAt(i + 2) != c) { + switch (c) { + case 'y': + nYear = ParseStringInteger(value, j, nSkip, 4); + i += 2; + j += nSkip; + break; + case 'm': + nMonth = ParseStringInteger(value, j, nSkip, 2); + i += 2; + j += nSkip; + break; + case 'd': + nDay = ParseStringInteger(value, j, nSkip, 2); + i += 2; + j += nSkip; + break; + case 'H': + nHour = ParseStringInteger(value, j, nSkip, 2); + i += 2; + j += nSkip; + break; + case 'h': + nHour = ParseStringInteger(value, j, nSkip, 2); + i += 2; + j += nSkip; + break; + case 'M': + nMin = ParseStringInteger(value, j, nSkip, 2); + i += 2; + j += nSkip; + break; + case 's': + nSec = ParseStringInteger(value, j, nSkip, 2); + i += 2; + j += nSkip; + break; + case 't': + bPm = (j + 1 < value.GetLength() && value.GetAt(j) == 'p' && + value.GetAt(j + 1) == 'm'); + i += 2; + j += 2; + break; + } + } else if (remaining == 2 || format.GetAt(i + 3) != c) { + switch (c) { + case 'm': { + CFX_WideString sMonth = ParseStringString(value, j, nSkip); + FX_BOOL bFind = FALSE; + for (int m = 0; m < 12; m++) { + if (sMonth.CompareNoCase(months[m]) == 0) { + nMonth = m + 1; + i += 3; + j += nSkip; + bFind = TRUE; + break; + } + } + + if (!bFind) { + nMonth = ParseStringInteger(value, j, nSkip, 3); + i += 3; + j += nSkip; + } + } break; + case 'y': + break; + default: + i += 3; + j += 3; + break; + } + } else if (remaining == 3 || format.GetAt(i + 4) != c) { + switch (c) { + case 'y': + nYear = ParseStringInteger(value, j, nSkip, 4); + j += nSkip; + i += 4; + break; + case 'm': { + FX_BOOL bFind = FALSE; + + CFX_WideString sMonth = ParseStringString(value, j, nSkip); + sMonth.MakeLower(); + + for (int m = 0; m < 12; m++) { + CFX_WideString sFullMonths = fullmonths[m]; + sFullMonths.MakeLower(); + + if (sFullMonths.Find(sMonth.c_str(), 0) != -1) { + nMonth = m + 1; + i += 4; + j += nSkip; + bFind = TRUE; + break; + } + } + + if (!bFind) { + nMonth = ParseStringInteger(value, j, nSkip, 4); + i += 4; + j += nSkip; + } + } break; + default: + i += 4; + j += 4; + break; + } + } else { + if (j >= value.GetLength() || format.GetAt(i) != value.GetAt(j)) { + bBadFormat = true; + bExit = TRUE; + } + i++; + j++; + } + + if (oldj == j) { + bBadFormat = true; + bExit = TRUE; + } + } + + break; + default: + if (value.GetLength() <= j) { + bExit = TRUE; + } else if (format.GetAt(i) != value.GetAt(j)) { + bBadFormat = true; + bExit = TRUE; + } + + i++; + j++; + break; + } + } + + if (bPm) + nHour += 12; + + if (nYear >= 0 && nYear <= nYearSub) + nYear += 2000; + + if (nMonth < 1 || nMonth > 12) + bBadFormat = true; + + if (nDay < 1 || nDay > 31) + bBadFormat = true; + + if (nHour < 0 || nHour > 24) + bBadFormat = true; + + if (nMin < 0 || nMin > 60) + bBadFormat = true; + + if (nSec < 0 || nSec > 60) + bBadFormat = true; + + double dRet = 0; + + if (bBadFormat) { + dRet = ParseNormalDate(value, &bBadFormat); + } else { + dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay), + JS_MakeTime(nHour, nMin, nSec, 0)); + + if (JS_PortIsNan(dRet)) { + dRet = JS_DateParse(value.c_str()); + } + } + + if (JS_PortIsNan(dRet)) { + dRet = ParseNormalDate(value, &bBadFormat); + } + + if (bWrongFormat) + *bWrongFormat = bBadFormat; + return dRet; +} + +CFX_WideString CJS_PublicMethods::MakeFormatDate(double dDate, + const CFX_WideString& format) { + CFX_WideString sRet = L"", sPart = L""; + + int nYear = JS_GetYearFromTime(dDate); + int nMonth = JS_GetMonthFromTime(dDate) + 1; + int nDay = JS_GetDayFromTime(dDate); + int nHour = JS_GetHourFromTime(dDate); + int nMin = JS_GetMinFromTime(dDate); + int nSec = JS_GetSecFromTime(dDate); + + int i = 0; + while (i < format.GetLength()) { + FX_WCHAR c = format.GetAt(i); + int remaining = format.GetLength() - i - 1; + sPart = L""; + switch (c) { + case 'y': + case 'm': + case 'd': + case 'H': + case 'h': + case 'M': + case 's': + case 't': + if (remaining == 0 || format.GetAt(i + 1) != c) { + switch (c) { + case 'y': + sPart += c; + break; + case 'm': + sPart.Format(L"%d", nMonth); + break; + case 'd': + sPart.Format(L"%d", nDay); + break; + case 'H': + sPart.Format(L"%d", nHour); + break; + case 'h': + sPart.Format(L"%d", nHour > 12 ? nHour - 12 : nHour); + break; + case 'M': + sPart.Format(L"%d", nMin); + break; + case 's': + sPart.Format(L"%d", nSec); + break; + case 't': + sPart += nHour > 12 ? 'p' : 'a'; + break; + } + i++; + } else if (remaining == 1 || format.GetAt(i + 2) != c) { + switch (c) { + case 'y': + sPart.Format(L"%02d", nYear - (nYear / 100) * 100); + break; + case 'm': + sPart.Format(L"%02d", nMonth); + break; + case 'd': + sPart.Format(L"%02d", nDay); + break; + case 'H': + sPart.Format(L"%02d", nHour); + break; + case 'h': + sPart.Format(L"%02d", nHour > 12 ? nHour - 12 : nHour); + break; + case 'M': + sPart.Format(L"%02d", nMin); + break; + case 's': + sPart.Format(L"%02d", nSec); + break; + case 't': + sPart = nHour > 12 ? L"pm" : L"am"; + break; + } + i += 2; + } else if (remaining == 2 || format.GetAt(i + 3) != c) { + switch (c) { + case 'm': + i += 3; + if (nMonth > 0 && nMonth <= 12) + sPart += months[nMonth - 1]; + break; + default: + i += 3; + sPart += c; + sPart += c; + sPart += c; + break; + } + } else if (remaining == 3 || format.GetAt(i + 4) != c) { + switch (c) { + case 'y': + sPart.Format(L"%04d", nYear); + i += 4; + break; + case 'm': + i += 4; + if (nMonth > 0 && nMonth <= 12) + sPart += fullmonths[nMonth - 1]; + break; + default: + i += 4; + sPart += c; + sPart += c; + sPart += c; + sPart += c; + break; + } + } else { + i++; + sPart += c; + } + break; + default: + i++; + sPart += c; + break; + } + + sRet += sPart; + } + + return sRet; +} + +/* -------------------------------------------------------------------------- */ + +// function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency, +// bCurrencyPrepend) +FX_BOOL CJS_PublicMethods::AFNumber_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { +#if _FX_OS_ != _FX_ANDROID_ + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 6) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + if (!pEvent->m_pValue) + return FALSE; + + CFX_WideString& Value = pEvent->Value(); + CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value)); + if (strValue.IsEmpty()) + return TRUE; + + int iDec = params[0].ToInt(); + int iSepStyle = params[1].ToInt(); + int iNegStyle = params[2].ToInt(); + // params[3] is iCurrStyle, it's not used. + std::wstring wstrCurrency(params[4].ToCFXWideString().c_str()); + FX_BOOL bCurrencyPrepend = params[5].ToBool(); + + if (iDec < 0) + iDec = -iDec; + + if (iSepStyle < 0 || iSepStyle > 3) + iSepStyle = 0; + + if (iNegStyle < 0 || iNegStyle > 3) + iNegStyle = 0; + + ////////////////////////////////////////////////////// + // for processing decimal places + strValue.Replace(",", "."); + double dValue = atof(strValue); + if (iDec > 0) + dValue += DOUBLE_CORRECT; + + int iDec2; + int iNegative = 0; + + strValue = fcvt(dValue, iDec, &iDec2, &iNegative); + if (strValue.IsEmpty()) { + dValue = 0; + strValue = fcvt(dValue, iDec, &iDec2, &iNegative); + if (strValue.IsEmpty()) { + strValue = "0"; + iDec2 = 1; + } + } + + if (iDec2 < 0) { + for (int iNum = 0; iNum < abs(iDec2); iNum++) { + strValue = "0" + strValue; + } + iDec2 = 0; + } + int iMax = strValue.GetLength(); + if (iDec2 > iMax) { + for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) { + strValue += "0"; + } + iMax = iDec2 + 1; + } + /////////////////////////////////////////////////////// + // for processing seperator style + if (iDec2 < iMax) { + if (iSepStyle == 0 || iSepStyle == 1) { + strValue.Insert(iDec2, '.'); + iMax++; + } else if (iSepStyle == 2 || iSepStyle == 3) { + strValue.Insert(iDec2, ','); + iMax++; + } + + if (iDec2 == 0) + strValue.Insert(iDec2, '0'); + } + if (iSepStyle == 0 || iSepStyle == 2) { + char cSeperator; + if (iSepStyle == 0) + cSeperator = ','; + else + cSeperator = '.'; + + for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) { + strValue.Insert(iDecPositive, cSeperator); + iMax++; + } + } + + ////////////////////////////////////////////////////////////////////// + // for processing currency string + + Value = CFX_WideString::FromLocal(strValue); + std::wstring strValue2 = Value.c_str(); + + if (bCurrencyPrepend) + strValue2 = wstrCurrency + strValue2; + else + strValue2 = strValue2 + wstrCurrency; + + ///////////////////////////////////////////////////////////////////////// + // for processing negative style + if (iNegative) { + if (iNegStyle == 0) { + strValue2.insert(0, L"-"); + } + if (iNegStyle == 2 || iNegStyle == 3) { + strValue2.insert(0, L"("); + strValue2.insert(strValue2.length(), L")"); + } + if (iNegStyle == 1 || iNegStyle == 3) { + if (Field* fTarget = pEvent->Target_Field()) { + CJS_Array arColor(pRuntime); + CJS_Value vColElm(pRuntime); + vColElm = L"RGB"; + arColor.SetElement(0, vColElm); + vColElm = 1; + arColor.SetElement(1, vColElm); + vColElm = 0; + arColor.SetElement(2, vColElm); + + arColor.SetElement(3, vColElm); + + CJS_PropValue vProp(pRuntime); + vProp.StartGetting(); + vProp << arColor; + vProp.StartSetting(); + fTarget->textColor(cc, vProp, sError); // red + } + } + } else { + if (iNegStyle == 1 || iNegStyle == 3) { + if (Field* fTarget = pEvent->Target_Field()) { + CJS_Array arColor(pRuntime); + CJS_Value vColElm(pRuntime); + vColElm = L"RGB"; + arColor.SetElement(0, vColElm); + vColElm = 0; + arColor.SetElement(1, vColElm); + arColor.SetElement(2, vColElm); + arColor.SetElement(3, vColElm); + + CJS_PropValue vProp(pRuntime); + vProp.StartGetting(); + fTarget->textColor(cc, vProp, sError); + + CJS_Array aProp(pRuntime); + vProp.ConvertToArray(aProp); + + CPWL_Color crProp; + CPWL_Color crColor; + color::ConvertArrayToPWLColor(aProp, crProp); + color::ConvertArrayToPWLColor(arColor, crColor); + + if (crColor != crProp) { + CJS_PropValue vProp2(pRuntime); + vProp2.StartGetting(); + vProp2 << arColor; + vProp2.StartSetting(); + fTarget->textColor(cc, vProp2, sError); + } + } + } + } + Value = strValue2.c_str(); +#endif + return TRUE; +} + +// function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency, +// bCurrencyPrepend) +FX_BOOL CJS_PublicMethods::AFNumber_Keystroke( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (params.size() < 2) + return FALSE; + int iSepStyle = params[1].ToInt(); + + if (iSepStyle < 0 || iSepStyle > 3) + iSepStyle = 0; + if (!pEvent->m_pValue) + return FALSE; + CFX_WideString& val = pEvent->Value(); + CFX_WideString& w_strChange = pEvent->Change(); + CFX_WideString w_strValue = val; + + if (pEvent->WillCommit()) { + CFX_WideString wstrChange = w_strChange; + CFX_WideString wstrValue = StrLTrim(w_strValue.c_str()); + if (wstrValue.IsEmpty()) + return TRUE; + + CFX_WideString swTemp = wstrValue; + swTemp.Replace(L",", L"."); + if (!IsNumber(swTemp.c_str())) { + pEvent->Rc() = FALSE; + sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE); + Alert(pContext, sError.c_str()); + return TRUE; + } + return TRUE; // it happens after the last keystroke and before validating, + } + + std::wstring w_strValue2 = w_strValue.c_str(); + std::wstring w_strChange2 = w_strChange.c_str(); + std::wstring w_strSelected; + if (-1 != pEvent->SelStart()) + w_strSelected = w_strValue2.substr(pEvent->SelStart(), + (pEvent->SelEnd() - pEvent->SelStart())); + bool bHasSign = (w_strValue2.find('-') != std::wstring::npos) && + (w_strSelected.find('-') == std::wstring::npos); + if (bHasSign) { + // can't insert "change" in front to sign postion. + if (pEvent->SelStart() == 0) { + FX_BOOL& bRc = pEvent->Rc(); + bRc = FALSE; + return TRUE; + } + } + + char cSep = L'.'; + + switch (iSepStyle) { + case 0: + case 1: + cSep = L'.'; + break; + case 2: + case 3: + cSep = L','; + break; + } + + bool bHasSep = (w_strValue2.find(cSep) != std::wstring::npos); + for (std::wstring::iterator it = w_strChange2.begin(); + it != w_strChange2.end(); it++) { + if (*it == cSep) { + if (bHasSep) { + FX_BOOL& bRc = pEvent->Rc(); + bRc = FALSE; + return TRUE; + } + bHasSep = TRUE; + continue; + } + if (*it == L'-') { + if (bHasSign) { + FX_BOOL& bRc = pEvent->Rc(); + bRc = FALSE; + return TRUE; + } + // sign's position is not correct + if (it != w_strChange2.begin()) { + FX_BOOL& bRc = pEvent->Rc(); + bRc = FALSE; + return TRUE; + } + if (pEvent->SelStart() != 0) { + FX_BOOL& bRc = pEvent->Rc(); + bRc = FALSE; + return TRUE; + } + bHasSign = TRUE; + continue; + } + + if (!FXSYS_iswdigit(*it)) { + FX_BOOL& bRc = pEvent->Rc(); + bRc = FALSE; + return TRUE; + } + } + + std::wstring w_prefix = w_strValue2.substr(0, pEvent->SelStart()); + std::wstring w_postfix; + if (pEvent->SelEnd() < (int)w_strValue2.length()) + w_postfix = w_strValue2.substr(pEvent->SelEnd()); + w_strValue2 = w_prefix + w_strChange2 + w_postfix; + w_strValue = w_strValue2.c_str(); + val = w_strValue; + return TRUE; +} + +// function AFPercent_Format(nDec, sepStyle) +FX_BOOL CJS_PublicMethods::AFPercent_Format( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { +#if _FX_OS_ != _FX_ANDROID_ + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (params.size() != 2) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + if (!pEvent->m_pValue) + return FALSE; + + CFX_WideString& Value = pEvent->Value(); + CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value)); + if (strValue.IsEmpty()) + return TRUE; + + int iDec = params[0].ToInt(); + if (iDec < 0) + iDec = -iDec; + + int iSepStyle = params[1].ToInt(); + if (iSepStyle < 0 || iSepStyle > 3) + iSepStyle = 0; + + ////////////////////////////////////////////////////// + // for processing decimal places + double dValue = atof(strValue); + dValue *= 100; + if (iDec > 0) + dValue += DOUBLE_CORRECT; + + int iDec2; + int iNegative = 0; + strValue = fcvt(dValue, iDec, &iDec2, &iNegative); + if (strValue.IsEmpty()) { + dValue = 0; + strValue = fcvt(dValue, iDec, &iDec2, &iNegative); + } + + if (iDec2 < 0) { + for (int iNum = 0; iNum < abs(iDec2); iNum++) { + strValue = "0" + strValue; + } + iDec2 = 0; + } + int iMax = strValue.GetLength(); + if (iDec2 > iMax) { + for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) { + strValue += "0"; + } + iMax = iDec2 + 1; + } + /////////////////////////////////////////////////////// + // for processing seperator style + if (iDec2 < iMax) { + if (iSepStyle == 0 || iSepStyle == 1) { + strValue.Insert(iDec2, '.'); + iMax++; + } else if (iSepStyle == 2 || iSepStyle == 3) { + strValue.Insert(iDec2, ','); + iMax++; + } + + if (iDec2 == 0) + strValue.Insert(iDec2, '0'); + } + if (iSepStyle == 0 || iSepStyle == 2) { + char cSeperator; + if (iSepStyle == 0) + cSeperator = ','; + else + cSeperator = '.'; + + for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) { + strValue.Insert(iDecPositive, cSeperator); + iMax++; + } + } + //////////////////////////////////////////////////////////////////// + // negative mark + if (iNegative) + strValue = "-" + strValue; + strValue += "%"; + Value = CFX_WideString::FromLocal(strValue); +#endif + return TRUE; +} +// AFPercent_Keystroke(nDec, sepStyle) +FX_BOOL CJS_PublicMethods::AFPercent_Keystroke( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return AFNumber_Keystroke(cc, params, vRet, sError); +} + +// function AFDate_FormatEx(cFormat) +FX_BOOL CJS_PublicMethods::AFDate_FormatEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + if (!pEvent->m_pValue) + return FALSE; + + CFX_WideString& val = pEvent->Value(); + CFX_WideString strValue = val; + if (strValue.IsEmpty()) + return TRUE; + + CFX_WideString sFormat = params[0].ToCFXWideString(); + double dDate = 0.0f; + + if (strValue.Find(L"GMT") != -1) { + // for GMT format time + // such as "Tue Aug 11 14:24:16 GMT+08002009" + dDate = MakeInterDate(strValue); + } else { + dDate = MakeRegularDate(strValue, sFormat, nullptr); + } + + if (JS_PortIsNan(dDate)) { + CFX_WideString swMsg; + swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(), + sFormat.c_str()); + Alert(pContext, swMsg.c_str()); + return FALSE; + } + + val = MakeFormatDate(dDate, sFormat); + return TRUE; +} + +double CJS_PublicMethods::MakeInterDate(CFX_WideString strValue) { + std::vector<CFX_WideString> wsArray; + CFX_WideString sTemp = L""; + for (int i = 0; i < strValue.GetLength(); ++i) { + FX_WCHAR c = strValue.GetAt(i); + if (c == L' ' || c == L':') { + wsArray.push_back(sTemp); + sTemp = L""; + continue; + } + sTemp += c; + } + wsArray.push_back(sTemp); + if (wsArray.size() != 8) + return 0; + + int nMonth = 1; + sTemp = wsArray[1]; + if (sTemp.Compare(L"Jan") == 0) + nMonth = 1; + else if (sTemp.Compare(L"Feb") == 0) + nMonth = 2; + else if (sTemp.Compare(L"Mar") == 0) + nMonth = 3; + else if (sTemp.Compare(L"Apr") == 0) + nMonth = 4; + else if (sTemp.Compare(L"May") == 0) + nMonth = 5; + else if (sTemp.Compare(L"Jun") == 0) + nMonth = 6; + else if (sTemp.Compare(L"Jul") == 0) + nMonth = 7; + else if (sTemp.Compare(L"Aug") == 0) + nMonth = 8; + else if (sTemp.Compare(L"Sep") == 0) + nMonth = 9; + else if (sTemp.Compare(L"Oct") == 0) + nMonth = 10; + else if (sTemp.Compare(L"Nov") == 0) + nMonth = 11; + else if (sTemp.Compare(L"Dec") == 0) + nMonth = 12; + + int nDay = FX_atof(wsArray[2]); + int nHour = FX_atof(wsArray[3]); + int nMin = FX_atof(wsArray[4]); + int nSec = FX_atof(wsArray[5]); + int nYear = FX_atof(wsArray[7]); + double dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay), + JS_MakeTime(nHour, nMin, nSec, 0)); + if (JS_PortIsNan(dRet)) + dRet = JS_DateParse(strValue.c_str()); + + return dRet; +} + +// AFDate_KeystrokeEx(cFormat) +FX_BOOL CJS_PublicMethods::AFDate_KeystrokeEx( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (params.size() != 1) { + sError = L"AFDate_KeystrokeEx's parameters' size r not correct"; + return FALSE; + } + + if (pEvent->WillCommit()) { + if (!pEvent->m_pValue) + return FALSE; + CFX_WideString strValue = pEvent->Value(); + if (strValue.IsEmpty()) + return TRUE; + + CFX_WideString sFormat = params[0].ToCFXWideString(); + bool bWrongFormat = FALSE; + double dRet = MakeRegularDate(strValue, sFormat, &bWrongFormat); + if (bWrongFormat || JS_PortIsNan(dRet)) { + CFX_WideString swMsg; + swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(), + sFormat.c_str()); + Alert(pContext, swMsg.c_str()); + pEvent->Rc() = FALSE; + return TRUE; + } + } + return TRUE; +} + +FX_BOOL CJS_PublicMethods::AFDate_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + int iIndex = params[0].ToInt(); + const FX_WCHAR* cFormats[] = {L"m/d", + L"m/d/yy", + L"mm/dd/yy", + L"mm/yy", + L"d-mmm", + L"d-mmm-yy", + L"dd-mmm-yy", + L"yy-mm-dd", + L"mmm-yy", + L"mmmm-yy", + L"mmm d, yyyy", + L"mmmm d, yyyy", + L"m/d/yy h:MM tt", + L"m/d/yy HH:MM"}; + + if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) + iIndex = 0; + + std::vector<CJS_Value> newParams; + newParams.push_back( + CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); + return AFDate_FormatEx(cc, newParams, vRet, sError); +} + +// AFDate_KeystrokeEx(cFormat) +FX_BOOL CJS_PublicMethods::AFDate_Keystroke( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + int iIndex = params[0].ToInt(); + const FX_WCHAR* cFormats[] = {L"m/d", + L"m/d/yy", + L"mm/dd/yy", + L"mm/yy", + L"d-mmm", + L"d-mmm-yy", + L"dd-mmm-yy", + L"yy-mm-dd", + L"mmm-yy", + L"mmmm-yy", + L"mmm d, yyyy", + L"mmmm d, yyyy", + L"m/d/yy h:MM tt", + L"m/d/yy HH:MM"}; + + if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) + iIndex = 0; + + std::vector<CJS_Value> newParams; + newParams.push_back( + CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); + return AFDate_KeystrokeEx(cc, newParams, vRet, sError); +} + +// function AFTime_Format(ptf) +FX_BOOL CJS_PublicMethods::AFTime_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + int iIndex = params[0].ToInt(); + const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss", + L"h:MM:ss tt"}; + + if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) + iIndex = 0; + + std::vector<CJS_Value> newParams; + newParams.push_back( + CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); + return AFDate_FormatEx(cc, newParams, vRet, sError); +} + +FX_BOOL CJS_PublicMethods::AFTime_Keystroke( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + int iIndex = params[0].ToInt(); + const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss", + L"h:MM:ss tt"}; + + if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats))) + iIndex = 0; + + std::vector<CJS_Value> newParams; + newParams.push_back( + CJS_Value(CJS_Runtime::FromContext(cc), cFormats[iIndex])); + return AFDate_KeystrokeEx(cc, newParams, vRet, sError); +} + +FX_BOOL CJS_PublicMethods::AFTime_FormatEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return AFDate_FormatEx(cc, params, vRet, sError); +} + +FX_BOOL CJS_PublicMethods::AFTime_KeystrokeEx( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return AFDate_KeystrokeEx(cc, params, vRet, sError); +} + +// function AFSpecial_Format(psf) +FX_BOOL CJS_PublicMethods::AFSpecial_Format( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + std::string cFormat; + int iIndex = params[0].ToInt(); + + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + if (!pEvent->m_pValue) + return FALSE; + CFX_WideString& Value = pEvent->Value(); + std::string strSrc = CFX_ByteString::FromUnicode(Value).c_str(); + + switch (iIndex) { + case 0: + cFormat = "99999"; + break; + case 1: + cFormat = "99999-9999"; + break; + case 2: { + std::string NumberStr; + util::printx("9999999999", strSrc, NumberStr); + if (NumberStr.length() >= 10) + cFormat = "(999) 999-9999"; + else + cFormat = "999-9999"; + break; + } + case 3: + cFormat = "999-99-9999"; + break; + } + + std::string strDes; + util::printx(cFormat, strSrc, strDes); + Value = CFX_WideString::FromLocal(strDes.c_str()); + return TRUE; +} + +// function AFSpecial_KeystrokeEx(mask) +FX_BOOL CJS_PublicMethods::AFSpecial_KeystrokeEx( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (params.size() < 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + if (!pEvent->m_pValue) + return FALSE; + CFX_WideString& valEvent = pEvent->Value(); + + CFX_WideString wstrMask = params[0].ToCFXWideString(); + if (wstrMask.IsEmpty()) + return TRUE; + + const size_t wstrMaskLen = wstrMask.GetLength(); + const std::wstring wstrValue = valEvent.c_str(); + + if (pEvent->WillCommit()) { + if (wstrValue.empty()) + return TRUE; + size_t iIndexMask = 0; + for (const auto& w_Value : wstrValue) { + if (!maskSatisfied(w_Value, wstrMask[iIndexMask])) + break; + iIndexMask++; + } + + if (iIndexMask != wstrMaskLen || + (iIndexMask != wstrValue.size() && wstrMaskLen != 0)) { + Alert( + pContext, + JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE).c_str()); + pEvent->Rc() = FALSE; + } + return TRUE; + } + + CFX_WideString& wideChange = pEvent->Change(); + std::wstring wChange = wideChange.c_str(); + if (wChange.empty()) + return TRUE; + + int iIndexMask = pEvent->SelStart(); + + size_t combined_len = wstrValue.length() + wChange.length() - + (pEvent->SelEnd() - pEvent->SelStart()); + if (combined_len > wstrMaskLen) { + Alert(pContext, + JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str()); + pEvent->Rc() = FALSE; + return TRUE; + } + + if (iIndexMask >= wstrMaskLen && (!wChange.empty())) { + Alert(pContext, + JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str()); + pEvent->Rc() = FALSE; + return TRUE; + } + + for (std::wstring::iterator it = wChange.begin(); it != wChange.end(); it++) { + if (iIndexMask >= wstrMaskLen) { + Alert(pContext, + JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str()); + pEvent->Rc() = FALSE; + return TRUE; + } + wchar_t w_Mask = wstrMask[iIndexMask]; + if (!isReservedMaskChar(w_Mask)) { + *it = w_Mask; + } + wchar_t w_Change = *it; + if (!maskSatisfied(w_Change, w_Mask)) { + pEvent->Rc() = FALSE; + return TRUE; + } + iIndexMask++; + } + + wideChange = wChange.c_str(); + return TRUE; +} + +// function AFSpecial_Keystroke(psf) +FX_BOOL CJS_PublicMethods::AFSpecial_Keystroke( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + if (!pEvent->m_pValue) + return FALSE; + + std::string cFormat; + int iIndex = params[0].ToInt(); + CFX_WideString& val = pEvent->Value(); + std::string strSrc = CFX_ByteString::FromUnicode(val).c_str(); + std::wstring wstrChange = pEvent->Change().c_str(); + + switch (iIndex) { + case 0: + cFormat = "99999"; + break; + case 1: + // cFormat = "99999-9999"; + cFormat = "999999999"; + break; + case 2: { + std::string NumberStr; + util::printx("9999999999", strSrc, NumberStr); + if (strSrc.length() + wstrChange.length() > 7) + // cFormat = "(999) 999-9999"; + cFormat = "9999999999"; + else + // cFormat = "999-9999"; + cFormat = "9999999"; + break; + } + case 3: + // cFormat = "999-99-9999"; + cFormat = "999999999"; + break; + } + + std::vector<CJS_Value> params2; + params2.push_back(CJS_Value(CJS_Runtime::FromContext(cc), cFormat.c_str())); + return AFSpecial_KeystrokeEx(cc, params2, vRet, sError); +} + +FX_BOOL CJS_PublicMethods::AFMergeChange(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEventHandler = pContext->GetEventHandler(); + + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CFX_WideString swValue; + if (pEventHandler->m_pValue) + swValue = pEventHandler->Value(); + + if (pEventHandler->WillCommit()) { + vRet = swValue.c_str(); + return TRUE; + } + + CFX_WideString prefix, postfix; + + if (pEventHandler->SelStart() >= 0) + prefix = swValue.Mid(0, pEventHandler->SelStart()); + else + prefix = L""; + + if (pEventHandler->SelEnd() >= 0 && + pEventHandler->SelEnd() <= swValue.GetLength()) + postfix = swValue.Mid(pEventHandler->SelEnd(), + swValue.GetLength() - pEventHandler->SelEnd()); + else + postfix = L""; + + vRet = (prefix + pEventHandler->Change() + postfix).c_str(); + + return TRUE; +} + +FX_BOOL CJS_PublicMethods::AFParseDateEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + ASSERT(pContext); + + if (params.size() != 2) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CFX_WideString sValue = params[0].ToCFXWideString(); + CFX_WideString sFormat = params[1].ToCFXWideString(); + + double dDate = MakeRegularDate(sValue, sFormat, nullptr); + + if (JS_PortIsNan(dDate)) { + CFX_WideString swMsg; + swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(), + sFormat.c_str()); + Alert((CJS_Context*)cc, swMsg.c_str()); + return FALSE; + } + + vRet = dDate; + return TRUE; +} + +FX_BOOL CJS_PublicMethods::AFSimple(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (params.size() != 3) { + CJS_Context* pContext = (CJS_Context*)cc; + ASSERT(pContext); + + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + vRet = (double)AF_Simple(params[0].ToCFXWideString().c_str(), + params[1].ToDouble(), params[2].ToDouble()); + return TRUE; +} + +FX_BOOL CJS_PublicMethods::AFMakeNumber(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + CFX_WideString ws = params[0].ToCFXWideString(); + ws.Replace(L",", L"."); + vRet = ws; + vRet.MaybeCoerceToNumber(); + if (vRet.GetType() != CJS_Value::VT_number) + vRet = 0; + return TRUE; +} + +FX_BOOL CJS_PublicMethods::AFSimple_Calculate( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 2) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CJS_Value params1 = params[1]; + if (!params1.IsArrayObject() && params1.GetType() != CJS_Value::VT_string) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CPDFSDK_Document* pReaderDoc = pContext->GetReaderDocument(); + CPDFSDK_InterForm* pReaderInterForm = pReaderDoc->GetInterForm(); + CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm(); + + CFX_WideString sFunction = params[0].ToCFXWideString(); + double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0; + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array FieldNameArray = AF_MakeArrayFromList(pRuntime, params1); + int nFieldsCount = 0; + + for (int i = 0, isz = FieldNameArray.GetLength(); i < isz; i++) { + CJS_Value jsValue(pRuntime); + FieldNameArray.GetElement(i, jsValue); + CFX_WideString wsFieldName = jsValue.ToCFXWideString(); + + for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) { + if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) { + double dTemp = 0.0; + switch (pFormField->GetFieldType()) { + case FIELDTYPE_TEXTFIELD: + case FIELDTYPE_COMBOBOX: { + CFX_WideString trimmed = pFormField->GetValue(); + trimmed.TrimRight(); + trimmed.TrimLeft(); + dTemp = FX_atof(trimmed); + } break; + case FIELDTYPE_PUSHBUTTON: { + dTemp = 0.0; + } break; + case FIELDTYPE_CHECKBOX: + case FIELDTYPE_RADIOBUTTON: { + dTemp = 0.0; + for (int c = 0, csz = pFormField->CountControls(); c < csz; c++) { + if (CPDF_FormControl* pFormCtrl = pFormField->GetControl(c)) { + if (pFormCtrl->IsChecked()) { + CFX_WideString trimmed = pFormCtrl->GetExportValue(); + trimmed.TrimRight(); + trimmed.TrimLeft(); + dTemp = FX_atof(trimmed); + break; + } + } + } + } break; + case FIELDTYPE_LISTBOX: { + if (pFormField->CountSelectedItems() <= 1) { + CFX_WideString trimmed = pFormField->GetValue(); + trimmed.TrimRight(); + trimmed.TrimLeft(); + dTemp = FX_atof(trimmed); + } + } break; + default: + break; + } + + if (i == 0 && j == 0 && (wcscmp(sFunction.c_str(), L"MIN") == 0 || + wcscmp(sFunction.c_str(), L"MAX") == 0)) + dValue = dTemp; + + dValue = AF_Simple(sFunction.c_str(), dValue, dTemp); + + nFieldsCount++; + } + } + } + + if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0) + dValue /= nFieldsCount; + + dValue = (double)floor(dValue * FXSYS_pow((double)10, (double)6) + 0.49) / + FXSYS_pow((double)10, (double)6); + CJS_Value jsValue(pRuntime, dValue); + if (pContext->GetEventHandler()->m_pValue) + pContext->GetEventHandler()->Value() = jsValue.ToCFXWideString(); + + return TRUE; +} + +/* This function validates the current event to ensure that its value is +** within the specified range. */ + +FX_BOOL CJS_PublicMethods::AFRange_Validate( + IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (params.size() != 4) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + if (!pEvent->m_pValue) + return FALSE; + if (pEvent->Value().IsEmpty()) + return TRUE; + double dEentValue = atof(CFX_ByteString::FromUnicode(pEvent->Value())); + FX_BOOL bGreaterThan = params[0].ToBool(); + double dGreaterThan = params[1].ToDouble(); + FX_BOOL bLessThan = params[2].ToBool(); + double dLessThan = params[3].ToDouble(); + CFX_WideString swMsg; + + if (bGreaterThan && bLessThan) { + if (dEentValue < dGreaterThan || dEentValue > dLessThan) + swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE1).c_str(), + params[1].ToCFXWideString().c_str(), + params[3].ToCFXWideString().c_str()); + } else if (bGreaterThan) { + if (dEentValue < dGreaterThan) + swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE2).c_str(), + params[1].ToCFXWideString().c_str()); + } else if (bLessThan) { + if (dEentValue > dLessThan) + swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE3).c_str(), + params[3].ToCFXWideString().c_str()); + } + + if (!swMsg.IsEmpty()) { + Alert(pContext, swMsg.c_str()); + pEvent->Rc() = FALSE; + } + return TRUE; +} + +FX_BOOL CJS_PublicMethods::AFExtractNums(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array nums(pRuntime); + + CFX_WideString str = params[0].ToCFXWideString(); + CFX_WideString sPart; + + if (str.GetAt(0) == L'.' || str.GetAt(0) == L',') + str = L"0" + str; + + int nIndex = 0; + for (int i = 0, sz = str.GetLength(); i < sz; i++) { + FX_WCHAR wc = str.GetAt(i); + if (FXSYS_iswdigit(wc)) { + sPart += wc; + } else { + if (sPart.GetLength() > 0) { + nums.SetElement(nIndex, CJS_Value(pRuntime, sPart.c_str())); + sPart = L""; + nIndex++; + } + } + } + + if (sPart.GetLength() > 0) { + nums.SetElement(nIndex, CJS_Value(pRuntime, sPart.c_str())); + } + + if (nums.GetLength() > 0) + vRet = nums; + else + vRet.SetNull(); + + return TRUE; +} diff --git a/fpdfsdk/javascript/PublicMethods.h b/fpdfsdk/javascript/PublicMethods.h new file mode 100644 index 0000000000..8961c5abc8 --- /dev/null +++ b/fpdfsdk/javascript/PublicMethods.h @@ -0,0 +1,175 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_PUBLICMETHODS_H_ +#define FPDFSDK_JAVASCRIPT_PUBLICMETHODS_H_ + +#include <string> +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class CJS_PublicMethods : public CJS_Object { + public: + explicit CJS_PublicMethods(v8::Local<v8::Object> pObject) + : CJS_Object(pObject) {} + ~CJS_PublicMethods() override {} + + public: + static FX_BOOL AFNumber_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFNumber_Keystroke(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFPercent_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFPercent_Keystroke(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFDate_FormatEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFDate_KeystrokeEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFDate_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFDate_Keystroke(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFTime_FormatEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); // + static FX_BOOL AFTime_KeystrokeEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFTime_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFTime_Keystroke(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFSpecial_Format(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFSpecial_Keystroke(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFSpecial_KeystrokeEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); // + static FX_BOOL AFSimple(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFMakeNumber(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFSimple_Calculate(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFRange_Validate(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFMergeChange(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFParseDateEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + static FX_BOOL AFExtractNums(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + + public: + JS_STATIC_GLOBAL_FUN(AFNumber_Format); + JS_STATIC_GLOBAL_FUN(AFNumber_Keystroke); + JS_STATIC_GLOBAL_FUN(AFPercent_Format); + JS_STATIC_GLOBAL_FUN(AFPercent_Keystroke); + JS_STATIC_GLOBAL_FUN(AFDate_FormatEx); + JS_STATIC_GLOBAL_FUN(AFDate_KeystrokeEx); + JS_STATIC_GLOBAL_FUN(AFDate_Format); + JS_STATIC_GLOBAL_FUN(AFDate_Keystroke); + JS_STATIC_GLOBAL_FUN(AFTime_FormatEx); + JS_STATIC_GLOBAL_FUN(AFTime_KeystrokeEx); + JS_STATIC_GLOBAL_FUN(AFTime_Format); + JS_STATIC_GLOBAL_FUN(AFTime_Keystroke); + JS_STATIC_GLOBAL_FUN(AFSpecial_Format); + JS_STATIC_GLOBAL_FUN(AFSpecial_Keystroke); + JS_STATIC_GLOBAL_FUN(AFSpecial_KeystrokeEx); + JS_STATIC_GLOBAL_FUN(AFSimple); + JS_STATIC_GLOBAL_FUN(AFMakeNumber); + JS_STATIC_GLOBAL_FUN(AFSimple_Calculate); + JS_STATIC_GLOBAL_FUN(AFRange_Validate); + JS_STATIC_GLOBAL_FUN(AFMergeChange); + JS_STATIC_GLOBAL_FUN(AFParseDateEx); + JS_STATIC_GLOBAL_FUN(AFExtractNums); + + JS_STATIC_DECLARE_GLOBAL_FUN(); + + public: + static int ParseStringInteger(const CFX_WideString& string, + int nStart, + int& nSkip, + int nMaxStep); + static CFX_WideString ParseStringString(const CFX_WideString& string, + int nStart, + int& nSkip); + static double MakeRegularDate(const CFX_WideString& value, + const CFX_WideString& format, + bool* bWrongFormat); + static CFX_WideString MakeFormatDate(double dDate, + const CFX_WideString& format); + static double ParseNormalDate(const CFX_WideString& value, + bool* bWrongFormat); + static double MakeInterDate(CFX_WideString strValue); + + public: + static CFX_WideString StrLTrim(const FX_WCHAR* pStr); + static CFX_WideString StrRTrim(const FX_WCHAR* pStr); + static CFX_WideString StrTrim(const FX_WCHAR* pStr); + + static CFX_ByteString StrLTrim(const FX_CHAR* pStr); + static CFX_ByteString StrRTrim(const FX_CHAR* pStr); + static CFX_ByteString StrTrim(const FX_CHAR* pStr); + + static FX_BOOL IsNumber(const FX_CHAR* string); + static FX_BOOL IsNumber(const FX_WCHAR* string); + + static FX_BOOL maskSatisfied(wchar_t c_Change, wchar_t c_Mask); + static FX_BOOL isReservedMaskChar(wchar_t ch); + + static double AF_Simple(const FX_WCHAR* sFuction, + double dValue1, + double dValue2); + static CJS_Array AF_MakeArrayFromList(CJS_Runtime* pRuntime, CJS_Value val); +}; + +#endif // FPDFSDK_JAVASCRIPT_PUBLICMETHODS_H_ diff --git a/fpdfsdk/javascript/app.cpp b/fpdfsdk/javascript/app.cpp new file mode 100644 index 0000000000..2f81791dc7 --- /dev/null +++ b/fpdfsdk/javascript/app.cpp @@ -0,0 +1,750 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/app.h" + +#include <memory> +#include <vector> + +#include "fpdfsdk/include/fsdk_mgr.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Document.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/resource.h" + +BEGIN_JS_STATIC_CONST(CJS_TimerObj) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_TimerObj) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_TimerObj) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_TimerObj, TimerObj) + +TimerObj::TimerObj(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject), m_pTimer(NULL) {} + +TimerObj::~TimerObj() {} + +void TimerObj::SetTimer(CJS_Timer* pTimer) { + m_pTimer = pTimer; +} + +CJS_Timer* TimerObj::GetTimer() const { + return m_pTimer; +} + +#define JS_STR_VIEWERTYPE L"pdfium" +#define JS_STR_VIEWERVARIATION L"Full" +#define JS_STR_PLATFORM L"WIN" +#define JS_STR_LANGUANGE L"ENU" +#define JS_NUM_VIEWERVERSION 8 +#ifdef PDF_ENABLE_XFA +#define JS_NUM_VIEWERVERSION_XFA 11 +#endif // PDF_ENABLE_XFA +#define JS_NUM_FORMSVERSION 7 + +BEGIN_JS_STATIC_CONST(CJS_App) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_App) +JS_STATIC_PROP_ENTRY(activeDocs) +JS_STATIC_PROP_ENTRY(calculate) +JS_STATIC_PROP_ENTRY(formsVersion) +JS_STATIC_PROP_ENTRY(fs) +JS_STATIC_PROP_ENTRY(fullscreen) +JS_STATIC_PROP_ENTRY(language) +JS_STATIC_PROP_ENTRY(media) +JS_STATIC_PROP_ENTRY(platform) +JS_STATIC_PROP_ENTRY(runtimeHighlight) +JS_STATIC_PROP_ENTRY(viewerType) +JS_STATIC_PROP_ENTRY(viewerVariation) +JS_STATIC_PROP_ENTRY(viewerVersion) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_App) +JS_STATIC_METHOD_ENTRY(alert) +JS_STATIC_METHOD_ENTRY(beep) +JS_STATIC_METHOD_ENTRY(browseForDoc) +JS_STATIC_METHOD_ENTRY(clearInterval) +JS_STATIC_METHOD_ENTRY(clearTimeOut) +JS_STATIC_METHOD_ENTRY(execDialog) +JS_STATIC_METHOD_ENTRY(execMenuItem) +JS_STATIC_METHOD_ENTRY(findComponent) +JS_STATIC_METHOD_ENTRY(goBack) +JS_STATIC_METHOD_ENTRY(goForward) +JS_STATIC_METHOD_ENTRY(launchURL) +JS_STATIC_METHOD_ENTRY(mailMsg) +JS_STATIC_METHOD_ENTRY(newFDF) +JS_STATIC_METHOD_ENTRY(newDoc) +JS_STATIC_METHOD_ENTRY(openDoc) +JS_STATIC_METHOD_ENTRY(openFDF) +JS_STATIC_METHOD_ENTRY(popUpMenuEx) +JS_STATIC_METHOD_ENTRY(popUpMenu) +JS_STATIC_METHOD_ENTRY(response) +JS_STATIC_METHOD_ENTRY(setInterval) +JS_STATIC_METHOD_ENTRY(setTimeOut) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_App, app) + +app::app(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject), m_bCalculate(true), m_bRuntimeHighLight(false) {} + +app::~app() { + for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) + delete m_aTimer[i]; + + m_aTimer.RemoveAll(); +} + +FX_BOOL app::activeDocs(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CPDFDoc_Environment* pApp = pContext->GetReaderApp(); + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + CPDFSDK_Document* pCurDoc = pContext->GetReaderDocument(); + CJS_Array aDocs(pRuntime); + if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument()) { + CJS_Document* pJSDocument = NULL; + if (pDoc == pCurDoc) { + v8::Local<v8::Object> pObj = FXJS_GetThisObj(pRuntime->GetIsolate()); + if (FXJS_GetObjDefnID(pObj) == CJS_Document::g_nObjDefnID) + pJSDocument = + (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj); + } else { + v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_Document::g_nObjDefnID); + pJSDocument = + (CJS_Document*)FXJS_GetPrivate(pRuntime->GetIsolate(), pObj); + ASSERT(pJSDocument); + } + aDocs.SetElement(0, CJS_Value(pRuntime, pJSDocument)); + } + if (aDocs.GetLength() > 0) + vp << aDocs; + else + vp.SetNull(); + + return TRUE; +} + +FX_BOOL app::calculate(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + bool bVP; + vp >> bVP; + m_bCalculate = (FX_BOOL)bVP; + + CJS_Context* pContext = (CJS_Context*)cc; + CPDFDoc_Environment* pApp = pContext->GetReaderApp(); + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + CJS_Array aDocs(pRuntime); + if (CPDFSDK_Document* pDoc = pApp->GetSDKDocument()) + pDoc->GetInterForm()->EnableCalculate((FX_BOOL)m_bCalculate); + } else { + vp << (bool)m_bCalculate; + } + return TRUE; +} + +FX_BOOL app::formsVersion(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp << JS_NUM_FORMSVERSION; + return TRUE; + } + + return FALSE; +} + +FX_BOOL app::viewerType(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp << JS_STR_VIEWERTYPE; + return TRUE; + } + + return FALSE; +} + +FX_BOOL app::viewerVariation(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsGetting()) { + vp << JS_STR_VIEWERVARIATION; + return TRUE; + } + + return FALSE; +} + +FX_BOOL app::viewerVersion(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; +#ifdef PDF_ENABLE_XFA + CJS_Context* pContext = (CJS_Context*)cc; + CPDFSDK_Document* pCurDoc = pContext->GetReaderDocument(); + CPDFXFA_Document* pDoc = pCurDoc->GetXFADocument(); + if (pDoc->GetDocType() == 1 || pDoc->GetDocType() == 2) { + vp << JS_NUM_VIEWERVERSION_XFA; + return TRUE; + } +#endif // PDF_ENABLE_XFA + vp << JS_NUM_VIEWERVERSION; + return TRUE; +} + +FX_BOOL app::platform(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; +#ifdef PDF_ENABLE_XFA + CPDFDoc_Environment* pEnv = + static_cast<CJS_Context*>(cc)->GetJSRuntime()->GetReaderApp(); + if (!pEnv) + return FALSE; + CFX_WideString platfrom = pEnv->FFI_GetPlatform(); + if (!platfrom.IsEmpty()) { + vp << platfrom; + return TRUE; + } +#endif + vp << JS_STR_PLATFORM; + return TRUE; +} + +FX_BOOL app::language(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; +#ifdef PDF_ENABLE_XFA + CPDFDoc_Environment* pEnv = + static_cast<CJS_Context*>(cc)->GetJSRuntime()->GetReaderApp(); + if (!pEnv) + return FALSE; + CFX_WideString language = pEnv->FFI_GetLanguage(); + if (!language.IsEmpty()) { + vp << language; + return TRUE; + } +#endif + vp << JS_STR_LANGUANGE; + return TRUE; +} + +// creates a new fdf object that contains no data +// comment: need reader support +// note: +// CFDF_Document * CPDFDoc_Environment::NewFDF(); +FX_BOOL app::newFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} +// opens a specified pdf document and returns its document object +// comment:need reader support +// note: as defined in js reference, the proto of this function's fourth +// parmeters, how old an fdf document while do not show it. +// CFDF_Document * CPDFDoc_Environment::OpenFDF(string strPath,bool bUserConv); + +FX_BOOL app::openFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL app::alert(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + std::vector<CJS_Value> newParams = JS_ExpandKeywordParams( + pRuntime, params, 4, L"cMsg", L"nIcon", L"nType", L"cTitle"); + + if (newParams[0].GetType() == CJS_Value::VT_unknown) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CFX_WideString swMsg; + if (newParams[0].GetType() == CJS_Value::VT_object) { + CJS_Array carray(pRuntime); + if (newParams[0].ConvertToArray(carray)) { + swMsg = L"["; + CJS_Value element(pRuntime); + for (int i = 0; i < carray.GetLength(); ++i) { + if (i) + swMsg += L", "; + carray.GetElement(i, element); + swMsg += element.ToCFXWideString(); + } + swMsg += L"]"; + } else { + swMsg = newParams[0].ToCFXWideString(); + } + } else { + swMsg = newParams[0].ToCFXWideString(); + } + + int iIcon = 0; + if (newParams[1].GetType() != CJS_Value::VT_unknown) + iIcon = newParams[1].ToInt(); + + int iType = 0; + if (newParams[2].GetType() != CJS_Value::VT_unknown) + iType = newParams[2].ToInt(); + + CFX_WideString swTitle; + if (newParams[3].GetType() != CJS_Value::VT_unknown) + swTitle = newParams[3].ToCFXWideString(); + else + swTitle = JSGetStringFromID(pContext, IDS_STRING_JSALERT); + + pRuntime->BeginBlock(); + vRet = MsgBox(pRuntime->GetReaderApp(), swMsg.c_str(), swTitle.c_str(), iType, + iIcon); + pRuntime->EndBlock(); + return TRUE; +} + +FX_BOOL app::beep(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (params.size() == 1) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + CPDFDoc_Environment* pEnv = pRuntime->GetReaderApp(); + pEnv->JS_appBeep(params[0].ToInt()); + return TRUE; + } + + sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR); + return FALSE; +} + +FX_BOOL app::findComponent(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL app::popUpMenuEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::fs(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::setInterval(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() > 2 || params.size() == 0) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CFX_WideString script = params.size() > 0 ? params[0].ToCFXWideString() : L""; + if (script.IsEmpty()) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE); + return TRUE; + } + + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + FX_DWORD dwInterval = params.size() > 1 ? params[1].ToInt() : 1000; + + CPDFDoc_Environment* pApp = pRuntime->GetReaderApp(); + ASSERT(pApp); + CJS_Timer* pTimer = + new CJS_Timer(this, pApp, pRuntime, 0, script, dwInterval, 0); + m_aTimer.Add(pTimer); + + v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_TimerObj::g_nObjDefnID); + CJS_TimerObj* pJS_TimerObj = + (CJS_TimerObj*)FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj); + TimerObj* pTimerObj = (TimerObj*)pJS_TimerObj->GetEmbedObject(); + pTimerObj->SetTimer(pTimer); + + vRet = pRetObj; + return TRUE; +} + +FX_BOOL app::setTimeOut(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (params.size() > 2 || params.size() == 0) { + sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + + CFX_WideString script = params.size() > 0 ? params[0].ToCFXWideString() : L""; + if (script.IsEmpty()) { + sError = + JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSAFNUMBER_KEYSTROKE); + return TRUE; + } + + FX_DWORD dwTimeOut = params.size() > 1 ? params[1].ToInt() : 1000; + + CPDFDoc_Environment* pApp = pRuntime->GetReaderApp(); + ASSERT(pApp); + + CJS_Timer* pTimer = + new CJS_Timer(this, pApp, pRuntime, 1, script, dwTimeOut, dwTimeOut); + m_aTimer.Add(pTimer); + + v8::Local<v8::Object> pRetObj = FXJS_NewFxDynamicObj( + pRuntime->GetIsolate(), pRuntime, CJS_TimerObj::g_nObjDefnID); + CJS_TimerObj* pJS_TimerObj = + (CJS_TimerObj*)FXJS_GetPrivate(pRuntime->GetIsolate(), pRetObj); + TimerObj* pTimerObj = (TimerObj*)pJS_TimerObj->GetEmbedObject(); + pTimerObj->SetTimer(pTimer); + + vRet = pRetObj; + return TRUE; +} + +FX_BOOL app::clearTimeOut(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + if (params[0].GetType() == CJS_Value::VT_fxobject) { + v8::Local<v8::Object> pObj = params[0].ToV8Object(); + if (FXJS_GetObjDefnID(pObj) == CJS_TimerObj::g_nObjDefnID) { + if (CJS_Object* pJSObj = params[0].ToCJSObject()) { + if (TimerObj* pTimerObj = (TimerObj*)pJSObj->GetEmbedObject()) { + if (CJS_Timer* pTimer = pTimerObj->GetTimer()) { + pTimer->KillJSTimer(); + + for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) { + if (m_aTimer[i] == pTimer) { + m_aTimer.RemoveAt(i); + break; + } + } + + delete pTimer; + pTimerObj->SetTimer(NULL); + } + } + } + } + } + + return TRUE; +} + +FX_BOOL app::clearInterval(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + if (params.size() != 1) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + if (params[0].GetType() == CJS_Value::VT_fxobject) { + v8::Local<v8::Object> pObj = params[0].ToV8Object(); + if (FXJS_GetObjDefnID(pObj) == CJS_TimerObj::g_nObjDefnID) { + if (CJS_Object* pJSObj = params[0].ToCJSObject()) { + if (TimerObj* pTimerObj = (TimerObj*)pJSObj->GetEmbedObject()) { + if (CJS_Timer* pTimer = pTimerObj->GetTimer()) { + pTimer->KillJSTimer(); + + for (int i = 0, sz = m_aTimer.GetSize(); i < sz; i++) { + if (m_aTimer[i] == pTimer) { + m_aTimer.RemoveAt(i); + break; + } + } + + delete pTimer; + pTimerObj->SetTimer(NULL); + } + } + } + } + } + + return TRUE; +} + +FX_BOOL app::execMenuItem(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +void app::TimerProc(CJS_Timer* pTimer) { + CJS_Runtime* pRuntime = pTimer->GetRuntime(); + + switch (pTimer->GetType()) { + case 0: // interval + if (pRuntime) + RunJsScript(pRuntime, pTimer->GetJScript()); + break; + case 1: + if (pTimer->GetTimeOut() > 0) { + if (pRuntime) + RunJsScript(pRuntime, pTimer->GetJScript()); + pTimer->KillJSTimer(); + } + break; + } +} + +void app::RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript) { + if (!pRuntime->IsBlocking()) { + IJS_Context* pContext = pRuntime->NewContext(); + pContext->OnExternal_Exec(); + CFX_WideString wtInfo; + pContext->RunScript(wsScript, &wtInfo); + pRuntime->ReleaseContext(pContext); + } +} + +FX_BOOL app::goBack(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Not supported. + return TRUE; +} + +FX_BOOL app::goForward(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Not supported. + return TRUE; +} + +FX_BOOL app::mailMsg(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + CJS_Runtime* pRuntime = pContext->GetJSRuntime(); + std::vector<CJS_Value> newParams = + JS_ExpandKeywordParams(pRuntime, params, 6, L"bUI", L"cTo", L"cCc", + L"cBcc", L"cSubject", L"cMsg"); + + if (newParams[0].GetType() == CJS_Value::VT_unknown) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + bool bUI = newParams[0].ToBool(); + + CFX_WideString cTo; + if (newParams[1].GetType() != CJS_Value::VT_unknown) { + cTo = newParams[1].ToCFXWideString(); + } else { + if (!bUI) { + // cTo parameter required when UI not invoked. + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + } + + CFX_WideString cCc; + if (newParams[2].GetType() != CJS_Value::VT_unknown) + cCc = newParams[2].ToCFXWideString(); + + CFX_WideString cBcc; + if (newParams[3].GetType() != CJS_Value::VT_unknown) + cBcc = newParams[3].ToCFXWideString(); + + CFX_WideString cSubject; + if (newParams[4].GetType() != CJS_Value::VT_unknown) + cSubject = newParams[4].ToCFXWideString(); + + CFX_WideString cMsg; + if (newParams[5].GetType() != CJS_Value::VT_unknown) + cMsg = newParams[5].ToCFXWideString(); + + pRuntime->BeginBlock(); + pContext->GetReaderApp()->JS_docmailForm(nullptr, 0, bUI, cTo.c_str(), + cSubject.c_str(), cCc.c_str(), + cBcc.c_str(), cMsg.c_str()); + pRuntime->EndBlock(); + return TRUE; +} + +FX_BOOL app::launchURL(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL app::runtimeHighlight(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + vp >> m_bRuntimeHighLight; + } else { + vp << m_bRuntimeHighLight; + } + return TRUE; +} + +FX_BOOL app::fullscreen(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::popUpMenu(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::browseForDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +CFX_WideString app::SysPathToPDFPath(const CFX_WideString& sOldPath) { + CFX_WideString sRet = L"/"; + + for (int i = 0, sz = sOldPath.GetLength(); i < sz; i++) { + wchar_t c = sOldPath.GetAt(i); + if (c == L':') { + } else { + if (c == L'\\') { + sRet += L"/"; + } else { + sRet += c; + } + } + } + + return sRet; +} + +FX_BOOL app::newDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::openDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::response(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + std::vector<CJS_Value> newParams = + JS_ExpandKeywordParams(pRuntime, params, 5, L"cQuestion", L"cTitle", + L"cDefault", L"bPassword", L"cLabel"); + + if (newParams[0].GetType() == CJS_Value::VT_unknown) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + CFX_WideString swQuestion = newParams[0].ToCFXWideString(); + + CFX_WideString swTitle = L"PDF"; + if (newParams[1].GetType() != CJS_Value::VT_unknown) + swTitle = newParams[1].ToCFXWideString(); + + CFX_WideString swDefault; + if (newParams[2].GetType() != CJS_Value::VT_unknown) + swDefault = newParams[2].ToCFXWideString(); + + bool bPassword = false; + if (newParams[3].GetType() != CJS_Value::VT_unknown) + bPassword = newParams[3].ToBool(); + + CFX_WideString swLabel; + if (newParams[4].GetType() != CJS_Value::VT_unknown) + swLabel = newParams[4].ToCFXWideString(); + + const int MAX_INPUT_BYTES = 2048; + std::unique_ptr<char[]> pBuff(new char[MAX_INPUT_BYTES + 2]); + memset(pBuff.get(), 0, MAX_INPUT_BYTES + 2); + + int nLengthBytes = pContext->GetReaderApp()->JS_appResponse( + swQuestion.c_str(), swTitle.c_str(), swDefault.c_str(), swLabel.c_str(), + bPassword, pBuff.get(), MAX_INPUT_BYTES); + + if (nLengthBytes < 0 || nLengthBytes > MAX_INPUT_BYTES) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG); + return FALSE; + } + + vRet = CFX_WideString::FromUTF16LE(reinterpret_cast<uint16_t*>(pBuff.get()), + nLengthBytes / sizeof(uint16_t)) + .c_str(); + return TRUE; +} + +FX_BOOL app::media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) { + return FALSE; +} + +FX_BOOL app::execDialog(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} diff --git a/fpdfsdk/javascript/app.h b/fpdfsdk/javascript/app.h new file mode 100644 index 0000000000..764f73b2f7 --- /dev/null +++ b/fpdfsdk/javascript/app.h @@ -0,0 +1,211 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_APP_H_ +#define FPDFSDK_JAVASCRIPT_APP_H_ + +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class CJS_Runtime; +class CJS_Timer; + +class TimerObj : public CJS_EmbedObj { + public: + TimerObj(CJS_Object* pJSObject); + ~TimerObj() override; + + public: + void SetTimer(CJS_Timer* pTimer); + CJS_Timer* GetTimer() const; + + private: + CJS_Timer* m_pTimer; +}; + +class CJS_TimerObj : public CJS_Object { + public: + CJS_TimerObj(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_TimerObj() override {} + + DECLARE_JS_CLASS(); +}; + +class app : public CJS_EmbedObj { + public: + app(CJS_Object* pJSObject); + ~app() override; + + public: + FX_BOOL activeDocs(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL calculate(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL formsVersion(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL fs(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL fullscreen(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL language(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL media(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL platform(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL runtimeHighlight(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL viewerType(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL viewerVariation(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL viewerVersion(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + + FX_BOOL alert(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL beep(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL browseForDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL clearInterval(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL clearTimeOut(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL execDialog(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL execMenuItem(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL findComponent(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL goBack(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL goForward(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL launchURL(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL mailMsg(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL newFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL newDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL openDoc(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL openFDF(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL popUpMenuEx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL popUpMenu(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL response(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL setInterval(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL setTimeOut(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + + static CFX_WideString SysPathToPDFPath(const CFX_WideString& sOldPath); + + private: + // CJS_EmbedObj + void TimerProc(CJS_Timer* pTimer) override; + void RunJsScript(CJS_Runtime* pRuntime, const CFX_WideString& wsScript); + + bool m_bCalculate; + bool m_bRuntimeHighLight; + CFX_ArrayTemplate<CJS_Timer*> m_aTimer; +}; + +class CJS_App : public CJS_Object { + public: + explicit CJS_App(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_App() override {} + + DECLARE_JS_CLASS(); + + JS_STATIC_PROP(activeDocs, app); + JS_STATIC_PROP(calculate, app); + JS_STATIC_PROP(formsVersion, app); + JS_STATIC_PROP(fs, app); + JS_STATIC_PROP(fullscreen, app); + JS_STATIC_PROP(language, app); + JS_STATIC_PROP(media, app); + JS_STATIC_PROP(platform, app); + JS_STATIC_PROP(runtimeHighlight, app); + JS_STATIC_PROP(viewerType, app); + JS_STATIC_PROP(viewerVariation, app); + JS_STATIC_PROP(viewerVersion, app); + + JS_STATIC_METHOD(alert, app); + JS_STATIC_METHOD(beep, app); + JS_STATIC_METHOD(browseForDoc, app); + JS_STATIC_METHOD(clearInterval, app); + JS_STATIC_METHOD(clearTimeOut, app); + JS_STATIC_METHOD(execDialog, app); + JS_STATIC_METHOD(execMenuItem, app); + JS_STATIC_METHOD(findComponent, app); + JS_STATIC_METHOD(goBack, app); + JS_STATIC_METHOD(goForward, app); + JS_STATIC_METHOD(launchURL, app); + JS_STATIC_METHOD(mailMsg, app); + JS_STATIC_METHOD(newFDF, app); + JS_STATIC_METHOD(newDoc, app); + JS_STATIC_METHOD(openDoc, app); + JS_STATIC_METHOD(openFDF, app); + JS_STATIC_METHOD(popUpMenuEx, app); + JS_STATIC_METHOD(popUpMenu, app); + JS_STATIC_METHOD(response, app); + JS_STATIC_METHOD(setInterval, app); + JS_STATIC_METHOD(setTimeOut, app); +}; + +#endif // FPDFSDK_JAVASCRIPT_APP_H_ diff --git a/fpdfsdk/javascript/color.cpp b/fpdfsdk/javascript/color.cpp new file mode 100644 index 0000000000..2681a8693e --- /dev/null +++ b/fpdfsdk/javascript/color.cpp @@ -0,0 +1,223 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/color.h" + +#include <vector> + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" + +/* -------------------------- color -------------------------- */ + +BEGIN_JS_STATIC_CONST(CJS_Color) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Color) +JS_STATIC_PROP_ENTRY(black) +JS_STATIC_PROP_ENTRY(blue) +JS_STATIC_PROP_ENTRY(cyan) +JS_STATIC_PROP_ENTRY(dkGray) +JS_STATIC_PROP_ENTRY(gray) +JS_STATIC_PROP_ENTRY(green) +JS_STATIC_PROP_ENTRY(ltGray) +JS_STATIC_PROP_ENTRY(magenta) +JS_STATIC_PROP_ENTRY(red) +JS_STATIC_PROP_ENTRY(transparent) +JS_STATIC_PROP_ENTRY(white) +JS_STATIC_PROP_ENTRY(yellow) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Color) +JS_STATIC_METHOD_ENTRY(convert) +JS_STATIC_METHOD_ENTRY(equal) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Color, color) + +color::color(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) { + m_crTransparent = CPWL_Color(COLORTYPE_TRANSPARENT); + m_crBlack = CPWL_Color(COLORTYPE_GRAY, 0); + m_crWhite = CPWL_Color(COLORTYPE_GRAY, 1); + m_crRed = CPWL_Color(COLORTYPE_RGB, 1, 0, 0); + m_crGreen = CPWL_Color(COLORTYPE_RGB, 0, 1, 0); + m_crBlue = CPWL_Color(COLORTYPE_RGB, 0, 0, 1); + m_crCyan = CPWL_Color(COLORTYPE_CMYK, 1, 0, 0, 0); + m_crMagenta = CPWL_Color(COLORTYPE_CMYK, 0, 1, 0, 0); + m_crYellow = CPWL_Color(COLORTYPE_CMYK, 0, 0, 1, 0); + m_crDKGray = CPWL_Color(COLORTYPE_GRAY, 0.25); + m_crGray = CPWL_Color(COLORTYPE_GRAY, 0.5); + m_crLTGray = CPWL_Color(COLORTYPE_GRAY, 0.75); +} + +color::~color() {} + +void color::ConvertPWLColorToArray(const CPWL_Color& color, CJS_Array& array) { + switch (color.nColorType) { + case COLORTYPE_TRANSPARENT: + array.SetElement(0, CJS_Value(array.GetJSRuntime(), "T")); + break; + case COLORTYPE_GRAY: + array.SetElement(0, CJS_Value(array.GetJSRuntime(), "G")); + array.SetElement(1, CJS_Value(array.GetJSRuntime(), color.fColor1)); + break; + case COLORTYPE_RGB: + array.SetElement(0, CJS_Value(array.GetJSRuntime(), "RGB")); + array.SetElement(1, CJS_Value(array.GetJSRuntime(), color.fColor1)); + array.SetElement(2, CJS_Value(array.GetJSRuntime(), color.fColor2)); + array.SetElement(3, CJS_Value(array.GetJSRuntime(), color.fColor3)); + break; + case COLORTYPE_CMYK: + array.SetElement(0, CJS_Value(array.GetJSRuntime(), "CMYK")); + array.SetElement(1, CJS_Value(array.GetJSRuntime(), color.fColor1)); + array.SetElement(2, CJS_Value(array.GetJSRuntime(), color.fColor2)); + array.SetElement(3, CJS_Value(array.GetJSRuntime(), color.fColor3)); + array.SetElement(4, CJS_Value(array.GetJSRuntime(), color.fColor4)); + break; + } +} + +void color::ConvertArrayToPWLColor(CJS_Array& array, CPWL_Color& color) { + int nArrayLen = array.GetLength(); + if (nArrayLen < 1) + return; + + CJS_Value value(array.GetJSRuntime()); + array.GetElement(0, value); + CFX_ByteString sSpace = value.ToCFXByteString(); + + double d1 = 0; + double d2 = 0; + double d3 = 0; + double d4 = 0; + + if (nArrayLen > 1) { + array.GetElement(1, value); + d1 = value.ToDouble(); + } + + if (nArrayLen > 2) { + array.GetElement(2, value); + d2 = value.ToDouble(); + } + + if (nArrayLen > 3) { + array.GetElement(3, value); + d3 = value.ToDouble(); + } + + if (nArrayLen > 4) { + array.GetElement(4, value); + d4 = value.ToDouble(); + } + + if (sSpace == "T") { + color = CPWL_Color(COLORTYPE_TRANSPARENT); + } else if (sSpace == "G") { + color = CPWL_Color(COLORTYPE_GRAY, (FX_FLOAT)d1); + } else if (sSpace == "RGB") { + color = CPWL_Color(COLORTYPE_RGB, (FX_FLOAT)d1, (FX_FLOAT)d2, (FX_FLOAT)d3); + } else if (sSpace == "CMYK") { + color = CPWL_Color(COLORTYPE_CMYK, (FX_FLOAT)d1, (FX_FLOAT)d2, (FX_FLOAT)d3, + (FX_FLOAT)d4); + } +} + +#define JS_IMPLEMENT_COLORPROP(prop, var) \ + FX_BOOL color::prop(IJS_Context* cc, CJS_PropValue& vp, \ + CFX_WideString& sError) { \ + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); \ + CJS_Array array(pRuntime); \ + if (vp.IsGetting()) { \ + ConvertPWLColorToArray(var, array); \ + vp << array; \ + } else { \ + if (!vp.ConvertToArray(array)) \ + return FALSE; \ + ConvertArrayToPWLColor(array, var); \ + } \ + return TRUE; \ + } + +JS_IMPLEMENT_COLORPROP(transparent, m_crTransparent) +JS_IMPLEMENT_COLORPROP(black, m_crBlack) +JS_IMPLEMENT_COLORPROP(white, m_crWhite) +JS_IMPLEMENT_COLORPROP(red, m_crRed) +JS_IMPLEMENT_COLORPROP(green, m_crGreen) +JS_IMPLEMENT_COLORPROP(blue, m_crBlue) +JS_IMPLEMENT_COLORPROP(cyan, m_crCyan) +JS_IMPLEMENT_COLORPROP(magenta, m_crMagenta) +JS_IMPLEMENT_COLORPROP(yellow, m_crYellow) +JS_IMPLEMENT_COLORPROP(dkGray, m_crDKGray) +JS_IMPLEMENT_COLORPROP(gray, m_crGray) +JS_IMPLEMENT_COLORPROP(ltGray, m_crLTGray) + +FX_BOOL color::convert(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + if (iSize < 2) + return FALSE; + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array aSource(pRuntime); + if (!params[0].ConvertToArray(aSource)) + return FALSE; + + CPWL_Color crSource; + ConvertArrayToPWLColor(aSource, crSource); + + CFX_ByteString sDestSpace = params[1].ToCFXByteString(); + int nColorType = COLORTYPE_TRANSPARENT; + + if (sDestSpace == "T") { + nColorType = COLORTYPE_TRANSPARENT; + } else if (sDestSpace == "G") { + nColorType = COLORTYPE_GRAY; + } else if (sDestSpace == "RGB") { + nColorType = COLORTYPE_RGB; + } else if (sDestSpace == "CMYK") { + nColorType = COLORTYPE_CMYK; + } + + CJS_Array aDest(pRuntime); + CPWL_Color crDest = crSource; + crDest.ConvertColorType(nColorType); + ConvertPWLColorToArray(crDest, aDest); + vRet = aDest; + + return TRUE; +} + +FX_BOOL color::equal(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (params.size() < 2) + return FALSE; + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Array array1(pRuntime); + CJS_Array array2(pRuntime); + if (!params[0].ConvertToArray(array1)) + return FALSE; + if (!params[1].ConvertToArray(array2)) + return FALSE; + + CPWL_Color color1; + CPWL_Color color2; + ConvertArrayToPWLColor(array1, color1); + ConvertArrayToPWLColor(array2, color2); + color1.ConvertColorType(color2.nColorType); + vRet = color1 == color2; + return TRUE; +} diff --git a/fpdfsdk/javascript/color.h b/fpdfsdk/javascript/color.h new file mode 100644 index 0000000000..cb5e59dd6a --- /dev/null +++ b/fpdfsdk/javascript/color.h @@ -0,0 +1,87 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_COLOR_H_ +#define FPDFSDK_JAVASCRIPT_COLOR_H_ + +#include <vector> + +#include "fpdfsdk/include/pdfwindow/PWL_Wnd.h" +#include "fpdfsdk/javascript/JS_Define.h" + +class color : public CJS_EmbedObj { + public: + color(CJS_Object* pJSObject); + ~color() override; + + FX_BOOL black(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL blue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL cyan(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL dkGray(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL gray(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL green(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL ltGray(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL magenta(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL red(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL transparent(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL white(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL yellow(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + + FX_BOOL convert(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL equal(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + + public: + static void ConvertPWLColorToArray(const CPWL_Color& color, CJS_Array& array); + static void ConvertArrayToPWLColor(CJS_Array& array, CPWL_Color& color); + + private: + CPWL_Color m_crTransparent; + CPWL_Color m_crBlack; + CPWL_Color m_crWhite; + CPWL_Color m_crRed; + CPWL_Color m_crGreen; + CPWL_Color m_crBlue; + CPWL_Color m_crCyan; + CPWL_Color m_crMagenta; + CPWL_Color m_crYellow; + CPWL_Color m_crDKGray; + CPWL_Color m_crGray; + CPWL_Color m_crLTGray; +}; + +class CJS_Color : public CJS_Object { + public: + CJS_Color(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Color() override {} + + DECLARE_JS_CLASS(); + + JS_STATIC_PROP(black, color); + JS_STATIC_PROP(blue, color); + JS_STATIC_PROP(cyan, color); + JS_STATIC_PROP(dkGray, color); + JS_STATIC_PROP(gray, color); + JS_STATIC_PROP(green, color); + JS_STATIC_PROP(ltGray, color); + JS_STATIC_PROP(magenta, color); + JS_STATIC_PROP(red, color); + JS_STATIC_PROP(transparent, color); + JS_STATIC_PROP(white, color); + JS_STATIC_PROP(yellow, color); + + JS_STATIC_METHOD(convert, color); + JS_STATIC_METHOD(equal, color); +}; + +#endif // FPDFSDK_JAVASCRIPT_COLOR_H_ diff --git a/fpdfsdk/javascript/console.cpp b/fpdfsdk/javascript/console.cpp new file mode 100644 index 0000000000..4cce32d54a --- /dev/null +++ b/fpdfsdk/javascript/console.cpp @@ -0,0 +1,68 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/console.h" + +#include <vector> + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" + +/* ------------------------ console ------------------------ */ + +BEGIN_JS_STATIC_CONST(CJS_Console) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Console) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Console) +JS_STATIC_METHOD_ENTRY(clear) +JS_STATIC_METHOD_ENTRY(hide) +JS_STATIC_METHOD_ENTRY(println) +JS_STATIC_METHOD_ENTRY(show) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Console, console) + +console::console(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {} + +console::~console() {} + +FX_BOOL console::clear(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL console::hide(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL console::println(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + if (params.size() < 1) { + return FALSE; + } + return TRUE; +} + +FX_BOOL console::show(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + return TRUE; +} diff --git a/fpdfsdk/javascript/console.h b/fpdfsdk/javascript/console.h new file mode 100644 index 0000000000..589dbc8914 --- /dev/null +++ b/fpdfsdk/javascript/console.h @@ -0,0 +1,51 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_CONSOLE_H_ +#define FPDFSDK_JAVASCRIPT_CONSOLE_H_ + +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class console : public CJS_EmbedObj { + public: + console(CJS_Object* pJSObject); + ~console() override; + + public: + FX_BOOL clear(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL hide(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL println(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL show(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); +}; + +class CJS_Console : public CJS_Object { + public: + CJS_Console(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Console() override {} + + DECLARE_JS_CLASS(); + + JS_STATIC_METHOD(clear, console); + JS_STATIC_METHOD(hide, console); + JS_STATIC_METHOD(println, console); + JS_STATIC_METHOD(show, console); +}; + +#endif // FPDFSDK_JAVASCRIPT_CONSOLE_H_ diff --git a/fpdfsdk/javascript/event.cpp b/fpdfsdk/javascript/event.cpp new file mode 100644 index 0000000000..7549451e6c --- /dev/null +++ b/fpdfsdk/javascript/event.cpp @@ -0,0 +1,326 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/event.h" + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/Field.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" + +/* -------------------------- event -------------------------- */ + +BEGIN_JS_STATIC_CONST(CJS_Event) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Event) +JS_STATIC_PROP_ENTRY(change) +JS_STATIC_PROP_ENTRY(changeEx) +JS_STATIC_PROP_ENTRY(commitKey) +JS_STATIC_PROP_ENTRY(fieldFull) +JS_STATIC_PROP_ENTRY(keyDown) +JS_STATIC_PROP_ENTRY(modifier) +JS_STATIC_PROP_ENTRY(name) +JS_STATIC_PROP_ENTRY(rc) +JS_STATIC_PROP_ENTRY(richChange) +JS_STATIC_PROP_ENTRY(richChangeEx) +JS_STATIC_PROP_ENTRY(richValue) +JS_STATIC_PROP_ENTRY(selEnd) +JS_STATIC_PROP_ENTRY(selStart) +JS_STATIC_PROP_ENTRY(shift) +JS_STATIC_PROP_ENTRY(source) +JS_STATIC_PROP_ENTRY(target) +JS_STATIC_PROP_ENTRY(targetName) +JS_STATIC_PROP_ENTRY(type) +JS_STATIC_PROP_ENTRY(value) +JS_STATIC_PROP_ENTRY(willCommit) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Event) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Event, event) + +event::event(CJS_Object* pJsObject) : CJS_EmbedObj(pJsObject) {} + +event::~event() {} + +FX_BOOL event::change(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + CFX_WideString& wChange = pEvent->Change(); + if (vp.IsSetting()) { + if (vp.GetType() == CJS_Value::VT_string) + vp >> wChange; + } else { + vp << wChange; + } + return TRUE; +} + +FX_BOOL event::changeEx(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->ChangeEx(); + return TRUE; +} + +FX_BOOL event::commitKey(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->CommitKey(); + return TRUE; +} + +FX_BOOL event::fieldFull(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (!vp.IsGetting() && + wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0) + return FALSE; + + if (pEvent->FieldFull()) + vp << TRUE; + else + vp << FALSE; + return TRUE; +} + +FX_BOOL event::keyDown(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (pEvent->KeyDown()) + vp << TRUE; + else + vp << FALSE; + return TRUE; +} + +FX_BOOL event::modifier(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (pEvent->Modifier()) + vp << TRUE; + else + vp << FALSE; + return TRUE; +} + +FX_BOOL event::name(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->Name(); + return TRUE; +} + +FX_BOOL event::rc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + FX_BOOL& bRc = pEvent->Rc(); + if (vp.IsSetting()) { + vp >> bRc; + } else { + vp << bRc; + } + return TRUE; +} + +FX_BOOL event::richChange(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL event::richChangeEx(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL event::richValue(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + return TRUE; +} + +FX_BOOL event::selEnd(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0) { + return TRUE; + } + + int& iSelEnd = pEvent->SelEnd(); + if (vp.IsSetting()) { + vp >> iSelEnd; + } else { + vp << iSelEnd; + } + return TRUE; +} + +FX_BOOL event::selStart(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (wcscmp((const wchar_t*)pEvent->Name(), L"Keystroke") != 0) { + return TRUE; + } + int& iSelStart = pEvent->SelStart(); + if (vp.IsSetting()) { + vp >> iSelStart; + } else { + vp << iSelStart; + } + return TRUE; +} + +FX_BOOL event::shift(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (pEvent->Shift()) + vp << TRUE; + else + vp << FALSE; + return TRUE; +} + +FX_BOOL event::source(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->Source()->GetJSObject(); + return TRUE; +} + +FX_BOOL event::target(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->Target_Field()->GetJSObject(); + return TRUE; +} + +FX_BOOL event::targetName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->TargetName(); + return TRUE; +} + +FX_BOOL event::type(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + vp << pEvent->Type(); + return TRUE; +} + +FX_BOOL event::value(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (wcscmp((const wchar_t*)pEvent->Type(), L"Field") != 0) + return FALSE; + if (!pEvent->m_pValue) + return FALSE; + CFX_WideString& val = pEvent->Value(); + if (vp.IsSetting()) { + vp >> val; + } else { + vp << val; + } + return TRUE; +} + +FX_BOOL event::willCommit(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (!vp.IsGetting()) + return FALSE; + + CJS_Context* pContext = (CJS_Context*)cc; + CJS_EventHandler* pEvent = pContext->GetEventHandler(); + + if (pEvent->WillCommit()) + vp << TRUE; + else + vp << FALSE; + return TRUE; +} diff --git a/fpdfsdk/javascript/event.h b/fpdfsdk/javascript/event.h new file mode 100644 index 0000000000..57b3416bf9 --- /dev/null +++ b/fpdfsdk/javascript/event.h @@ -0,0 +1,76 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_EVENT_H_ +#define FPDFSDK_JAVASCRIPT_EVENT_H_ + +#include "fpdfsdk/javascript/JS_Define.h" + +class event : public CJS_EmbedObj { + public: + event(CJS_Object* pJSObject); + ~event() override; + + public: + FX_BOOL change(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL changeEx(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL commitKey(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL fieldFull(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL keyDown(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL modifier(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL name(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL rc(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL richChange(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL richChangeEx(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL richValue(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL selEnd(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL selStart(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL shift(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL source(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL target(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL targetName(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL type(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL value(IJS_Context* cc, CJS_PropValue& vp, CFX_WideString& sError); + FX_BOOL willCommit(IJS_Context* cc, + CJS_PropValue& vp, + CFX_WideString& sError); +}; + +class CJS_Event : public CJS_Object { + public: + CJS_Event(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Event() override {} + + DECLARE_JS_CLASS(); + JS_STATIC_PROP(change, event); + JS_STATIC_PROP(changeEx, event); + JS_STATIC_PROP(commitKey, event); + JS_STATIC_PROP(fieldFull, event); + JS_STATIC_PROP(keyDown, event); + JS_STATIC_PROP(modifier, event); + JS_STATIC_PROP(name, event); + JS_STATIC_PROP(rc, event); + JS_STATIC_PROP(richChange, event); + JS_STATIC_PROP(richChangeEx, event); + JS_STATIC_PROP(richValue, event); + JS_STATIC_PROP(selEnd, event); + JS_STATIC_PROP(selStart, event); + JS_STATIC_PROP(shift, event); + JS_STATIC_PROP(source, event); + JS_STATIC_PROP(target, event); + JS_STATIC_PROP(targetName, event); + JS_STATIC_PROP(type, event); + JS_STATIC_PROP(value, event); + JS_STATIC_PROP(willCommit, event); +}; + +#endif // FPDFSDK_JAVASCRIPT_EVENT_H_ diff --git a/fpdfsdk/javascript/global.cpp b/fpdfsdk/javascript/global.cpp new file mode 100644 index 0000000000..c22c05d1db --- /dev/null +++ b/fpdfsdk/javascript/global.cpp @@ -0,0 +1,516 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/global.h" + +#include <vector> + +#include "core/include/fxcrt/fx_ext.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_GlobalData.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/resource.h" + +/* ---------------------------- global ---------------------------- */ + +// Helper class for compile-time calculation of hash values in order to +// avoid having global object initializers. +template <unsigned ACC, wchar_t... Ns> +struct CHash; + +// Only needed to hash single-character strings. +template <wchar_t N> +struct CHash<N> { + static const unsigned value = N; +}; + +template <unsigned ACC, wchar_t N> +struct CHash<ACC, N> { + static const unsigned value = (ACC * 1313LLU + N) & 0xFFFFFFFF; +}; + +template <unsigned ACC, wchar_t N, wchar_t... Ns> +struct CHash<ACC, N, Ns...> { + static const unsigned value = CHash<CHash<ACC, N>::value, Ns...>::value; +}; + +const unsigned int JSCONST_nStringHash = + CHash<'s', 't', 'r', 'i', 'n', 'g'>::value; +const unsigned int JSCONST_nNumberHash = + CHash<'n', 'u', 'm', 'b', 'e', 'r'>::value; +const unsigned int JSCONST_nBoolHash = + CHash<'b', 'o', 'o', 'l', 'e', 'a', 'n'>::value; +const unsigned int JSCONST_nDateHash = CHash<'d', 'a', 't', 'e'>::value; +const unsigned int JSCONST_nObjectHash = + CHash<'o', 'b', 'j', 'e', 'c', 't'>::value; +const unsigned int JSCONST_nFXobjHash = CHash<'f', 'x', 'o', 'b', 'j'>::value; +const unsigned int JSCONST_nNullHash = CHash<'n', 'u', 'l', 'l'>::value; +const unsigned int JSCONST_nUndefHash = + CHash<'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd'>::value; + +static unsigned JS_CalcHash(const wchar_t* main) { + return (unsigned)FX_HashCode_String_GetW(main, FXSYS_wcslen(main)); +} + +#ifndef NDEBUG +class HashVerify { + public: + HashVerify(); +} g_hashVerify; + +HashVerify::HashVerify() { + ASSERT(JSCONST_nStringHash == JS_CalcHash(kFXJSValueNameString)); + ASSERT(JSCONST_nNumberHash == JS_CalcHash(kFXJSValueNameNumber)); + ASSERT(JSCONST_nBoolHash == JS_CalcHash(kFXJSValueNameBoolean)); + ASSERT(JSCONST_nDateHash == JS_CalcHash(kFXJSValueNameDate)); + ASSERT(JSCONST_nObjectHash == JS_CalcHash(kFXJSValueNameObject)); + ASSERT(JSCONST_nFXobjHash == JS_CalcHash(kFXJSValueNameFxobj)); + ASSERT(JSCONST_nNullHash == JS_CalcHash(kFXJSValueNameNull)); + ASSERT(JSCONST_nUndefHash == JS_CalcHash(kFXJSValueNameUndefined)); +} +#endif + +BEGIN_JS_STATIC_CONST(CJS_Global) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Global) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Global) +JS_STATIC_METHOD_ENTRY(setPersistent) +END_JS_STATIC_METHOD() + +IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, JSGlobalAlternate, global); + +void CJS_Global::InitInstance(IJS_Runtime* pIRuntime) { + CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime); + JSGlobalAlternate* pGlobal = + static_cast<JSGlobalAlternate*>(GetEmbedObject()); + pGlobal->Initial(pRuntime->GetReaderApp()); +} + +JSGlobalAlternate::JSGlobalAlternate(CJS_Object* pJSObject) + : CJS_EmbedObj(pJSObject), m_pApp(NULL) {} + +JSGlobalAlternate::~JSGlobalAlternate() { + DestroyGlobalPersisitentVariables(); + m_pGlobalData->Release(); +} + +void JSGlobalAlternate::Initial(CPDFDoc_Environment* pApp) { + m_pApp = pApp; + m_pGlobalData = CJS_GlobalData::GetRetainedInstance(pApp); + UpdateGlobalPersistentVariables(); +} + +FX_BOOL JSGlobalAlternate::QueryProperty(const FX_WCHAR* propname) { + return CFX_WideString(propname) != L"setPersistent"; +} + +FX_BOOL JSGlobalAlternate::DelProperty(IJS_Context* cc, + const FX_WCHAR* propname, + CFX_WideString& sError) { + auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname)); + if (it == m_mapGlobal.end()) + return FALSE; + + it->second->bDeleted = TRUE; + return TRUE; +} + +FX_BOOL JSGlobalAlternate::DoProperty(IJS_Context* cc, + const FX_WCHAR* propname, + CJS_PropValue& vp, + CFX_WideString& sError) { + if (vp.IsSetting()) { + CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname); + switch (vp.GetType()) { + case CJS_Value::VT_number: { + double dData; + vp >> dData; + return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NUMBER, dData, + false, "", v8::Local<v8::Object>(), FALSE); + } + case CJS_Value::VT_boolean: { + bool bData; + vp >> bData; + return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_BOOLEAN, 0, + bData, "", v8::Local<v8::Object>(), FALSE); + } + case CJS_Value::VT_string: { + CFX_ByteString sData; + vp >> sData; + return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_STRING, 0, + false, sData, v8::Local<v8::Object>(), FALSE); + } + case CJS_Value::VT_object: { + v8::Local<v8::Object> pData; + vp >> pData; + return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, + false, "", pData, FALSE); + } + case CJS_Value::VT_null: { + return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NULL, 0, false, + "", v8::Local<v8::Object>(), FALSE); + } + case CJS_Value::VT_undefined: { + DelProperty(cc, propname, sError); + return TRUE; + } + default: + break; + } + } else { + auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname)); + if (it == m_mapGlobal.end()) { + vp.SetNull(); + return TRUE; + } + JSGlobalData* pData = it->second; + if (pData->bDeleted) { + vp.SetNull(); + return TRUE; + } + switch (pData->nType) { + case JS_GLOBALDATA_TYPE_NUMBER: + vp << pData->dData; + return TRUE; + case JS_GLOBALDATA_TYPE_BOOLEAN: + vp << pData->bData; + return TRUE; + case JS_GLOBALDATA_TYPE_STRING: + vp << pData->sData; + return TRUE; + case JS_GLOBALDATA_TYPE_OBJECT: { + v8::Local<v8::Object> obj = v8::Local<v8::Object>::New( + vp.GetJSRuntime()->GetIsolate(), pData->pData); + vp << obj; + return TRUE; + } + case JS_GLOBALDATA_TYPE_NULL: + vp.SetNull(); + return TRUE; + default: + break; + } + } + return FALSE; +} + +FX_BOOL JSGlobalAlternate::setPersistent(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + CJS_Context* pContext = static_cast<CJS_Context*>(cc); + if (params.size() != 2) { + sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR); + return FALSE; + } + + auto it = m_mapGlobal.find(params[0].ToCFXByteString()); + if (it != m_mapGlobal.end()) { + JSGlobalData* pData = it->second; + if (!pData->bDeleted) { + pData->bPersistent = params[1].ToBool(); + return TRUE; + } + } + + sError = JSGetStringFromID(pContext, IDS_STRING_JSNOGLOBAL); + return FALSE; +} + +void JSGlobalAlternate::UpdateGlobalPersistentVariables() { + for (int i = 0, sz = m_pGlobalData->GetSize(); i < sz; i++) { + CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i); + switch (pData->data.nType) { + case JS_GLOBALDATA_TYPE_NUMBER: + SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NUMBER, + pData->data.dData, false, "", + v8::Local<v8::Object>(), pData->bPersistent == 1); + FXJS_PutObjectNumber(NULL, m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode().c_str(), + pData->data.dData); + break; + case JS_GLOBALDATA_TYPE_BOOLEAN: + SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_BOOLEAN, 0, + (bool)(pData->data.bData == 1), "", + v8::Local<v8::Object>(), pData->bPersistent == 1); + FXJS_PutObjectBoolean(NULL, m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode().c_str(), + (bool)(pData->data.bData == 1)); + break; + case JS_GLOBALDATA_TYPE_STRING: + SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_STRING, 0, + false, pData->data.sData, v8::Local<v8::Object>(), + pData->bPersistent == 1); + FXJS_PutObjectString(NULL, m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode().c_str(), + pData->data.sData.UTF8Decode().c_str()); + break; + case JS_GLOBALDATA_TYPE_OBJECT: { + v8::Isolate* pRuntime = m_pJSObject->ToV8Object()->GetIsolate(); + v8::Local<v8::Object> pObj = FXJS_NewFxDynamicObj(pRuntime, NULL, -1); + + PutObjectProperty(pObj, &pData->data); + + SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_OBJECT, 0, + false, "", pObj, pData->bPersistent == 1); + FXJS_PutObjectObject(NULL, m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode().c_str(), pObj); + } break; + case JS_GLOBALDATA_TYPE_NULL: + SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NULL, 0, false, + "", v8::Local<v8::Object>(), + pData->bPersistent == 1); + FXJS_PutObjectNull(NULL, m_pJSObject->ToV8Object(), + pData->data.sKey.UTF8Decode().c_str()); + break; + } + } +} + +void JSGlobalAlternate::CommitGlobalPersisitentVariables(IJS_Context* cc) { + for (auto it = m_mapGlobal.begin(); it != m_mapGlobal.end(); ++it) { + CFX_ByteString name = it->first; + JSGlobalData* pData = it->second; + if (pData->bDeleted) { + m_pGlobalData->DeleteGlobalVariable(name); + } else { + switch (pData->nType) { + case JS_GLOBALDATA_TYPE_NUMBER: + m_pGlobalData->SetGlobalVariableNumber(name, pData->dData); + m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); + break; + case JS_GLOBALDATA_TYPE_BOOLEAN: + m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData); + m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); + break; + case JS_GLOBALDATA_TYPE_STRING: + m_pGlobalData->SetGlobalVariableString(name, pData->sData); + m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); + break; + case JS_GLOBALDATA_TYPE_OBJECT: { + CJS_GlobalVariableArray array; + v8::Local<v8::Object> obj = v8::Local<v8::Object>::New( + GetJSObject()->GetIsolate(), pData->pData); + ObjectToArray(cc, obj, array); + m_pGlobalData->SetGlobalVariableObject(name, array); + m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); + } break; + case JS_GLOBALDATA_TYPE_NULL: + m_pGlobalData->SetGlobalVariableNull(name); + m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); + break; + } + } + } +} + +void JSGlobalAlternate::ObjectToArray(IJS_Context* cc, + v8::Local<v8::Object> pObj, + CJS_GlobalVariableArray& array) { + v8::Isolate* isolate = pObj->GetIsolate(); + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + + v8::Local<v8::Array> pKeyList = FXJS_GetObjectElementNames(isolate, pObj); + int nObjElements = pKeyList->Length(); + for (int i = 0; i < nObjElements; i++) { + CFX_WideString ws = + FXJS_ToString(isolate, FXJS_GetArrayElement(isolate, pKeyList, i)); + CFX_ByteString sKey = ws.UTF8Encode(); + + v8::Local<v8::Value> v = FXJS_GetObjectElement(isolate, pObj, ws.c_str()); + switch (GET_VALUE_TYPE(v)) { + case CJS_Value::VT_number: { + CJS_KeyValue* pObjElement = new CJS_KeyValue; + pObjElement->nType = JS_GLOBALDATA_TYPE_NUMBER; + pObjElement->sKey = sKey; + pObjElement->dData = FXJS_ToNumber(isolate, v); + array.Add(pObjElement); + } break; + case CJS_Value::VT_boolean: { + CJS_KeyValue* pObjElement = new CJS_KeyValue; + pObjElement->nType = JS_GLOBALDATA_TYPE_BOOLEAN; + pObjElement->sKey = sKey; + pObjElement->dData = FXJS_ToBoolean(isolate, v); + array.Add(pObjElement); + } break; + case CJS_Value::VT_string: { + CFX_ByteString sValue = + CJS_Value(pRuntime, v, CJS_Value::VT_string).ToCFXByteString(); + CJS_KeyValue* pObjElement = new CJS_KeyValue; + pObjElement->nType = JS_GLOBALDATA_TYPE_STRING; + pObjElement->sKey = sKey; + pObjElement->sData = sValue; + array.Add(pObjElement); + } break; + case CJS_Value::VT_object: { + CJS_KeyValue* pObjElement = new CJS_KeyValue; + pObjElement->nType = JS_GLOBALDATA_TYPE_OBJECT; + pObjElement->sKey = sKey; + ObjectToArray(cc, FXJS_ToObject(isolate, v), pObjElement->objData); + array.Add(pObjElement); + } break; + case CJS_Value::VT_null: { + CJS_KeyValue* pObjElement = new CJS_KeyValue; + pObjElement->nType = JS_GLOBALDATA_TYPE_NULL; + pObjElement->sKey = sKey; + array.Add(pObjElement); + } break; + default: + break; + } + } +} + +void JSGlobalAlternate::PutObjectProperty(v8::Local<v8::Object> pObj, + CJS_KeyValue* pData) { + for (int i = 0, sz = pData->objData.Count(); i < sz; i++) { + CJS_KeyValue* pObjData = pData->objData.GetAt(i); + switch (pObjData->nType) { + case JS_GLOBALDATA_TYPE_NUMBER: + FXJS_PutObjectNumber(NULL, pObj, pObjData->sKey.UTF8Decode().c_str(), + pObjData->dData); + break; + case JS_GLOBALDATA_TYPE_BOOLEAN: + FXJS_PutObjectBoolean(NULL, pObj, pObjData->sKey.UTF8Decode().c_str(), + pObjData->bData == 1); + break; + case JS_GLOBALDATA_TYPE_STRING: + FXJS_PutObjectString(NULL, pObj, pObjData->sKey.UTF8Decode().c_str(), + pObjData->sData.UTF8Decode().c_str()); + break; + case JS_GLOBALDATA_TYPE_OBJECT: { + v8::Isolate* pRuntime = m_pJSObject->ToV8Object()->GetIsolate(); + v8::Local<v8::Object> pNewObj = + FXJS_NewFxDynamicObj(pRuntime, NULL, -1); + PutObjectProperty(pNewObj, pObjData); + FXJS_PutObjectObject(NULL, pObj, pObjData->sKey.UTF8Decode().c_str(), + pNewObj); + } break; + case JS_GLOBALDATA_TYPE_NULL: + FXJS_PutObjectNull(NULL, pObj, pObjData->sKey.UTF8Decode().c_str()); + break; + } + } +} + +void JSGlobalAlternate::DestroyGlobalPersisitentVariables() { + for (const auto& pair : m_mapGlobal) { + delete pair.second; + } + m_mapGlobal.clear(); +} + +FX_BOOL JSGlobalAlternate::SetGlobalVariables(const FX_CHAR* propname, + int nType, + double dData, + bool bData, + const CFX_ByteString& sData, + v8::Local<v8::Object> pData, + bool bDefaultPersistent) { + if (!propname) + return FALSE; + + auto it = m_mapGlobal.find(propname); + if (it != m_mapGlobal.end()) { + JSGlobalData* pTemp = it->second; + if (pTemp->bDeleted || pTemp->nType != nType) { + pTemp->dData = 0; + pTemp->bData = 0; + pTemp->sData = ""; + pTemp->nType = nType; + } + + pTemp->bDeleted = FALSE; + switch (nType) { + case JS_GLOBALDATA_TYPE_NUMBER: { + pTemp->dData = dData; + } break; + case JS_GLOBALDATA_TYPE_BOOLEAN: { + pTemp->bData = bData; + } break; + case JS_GLOBALDATA_TYPE_STRING: { + pTemp->sData = sData; + } break; + case JS_GLOBALDATA_TYPE_OBJECT: { + pTemp->pData.Reset(pData->GetIsolate(), pData); + } break; + case JS_GLOBALDATA_TYPE_NULL: + break; + default: + return FALSE; + } + return TRUE; + } + + JSGlobalData* pNewData = NULL; + + switch (nType) { + case JS_GLOBALDATA_TYPE_NUMBER: { + pNewData = new JSGlobalData; + pNewData->nType = JS_GLOBALDATA_TYPE_NUMBER; + pNewData->dData = dData; + pNewData->bPersistent = bDefaultPersistent; + } break; + case JS_GLOBALDATA_TYPE_BOOLEAN: { + pNewData = new JSGlobalData; + pNewData->nType = JS_GLOBALDATA_TYPE_BOOLEAN; + pNewData->bData = bData; + pNewData->bPersistent = bDefaultPersistent; + } break; + case JS_GLOBALDATA_TYPE_STRING: { + pNewData = new JSGlobalData; + pNewData->nType = JS_GLOBALDATA_TYPE_STRING; + pNewData->sData = sData; + pNewData->bPersistent = bDefaultPersistent; + } break; + case JS_GLOBALDATA_TYPE_OBJECT: { + pNewData = new JSGlobalData; + pNewData->nType = JS_GLOBALDATA_TYPE_OBJECT; + pNewData->pData.Reset(pData->GetIsolate(), pData); + pNewData->bPersistent = bDefaultPersistent; + } break; + case JS_GLOBALDATA_TYPE_NULL: { + pNewData = new JSGlobalData; + pNewData->nType = JS_GLOBALDATA_TYPE_NULL; + pNewData->bPersistent = bDefaultPersistent; + } break; + default: + return FALSE; + } + + m_mapGlobal[propname] = pNewData; + return TRUE; +} + +CJS_Value::Type GET_VALUE_TYPE(v8::Local<v8::Value> p) { + const unsigned int nHash = JS_CalcHash(FXJS_GetTypeof(p)); + + if (nHash == JSCONST_nUndefHash) + return CJS_Value::VT_undefined; + if (nHash == JSCONST_nNullHash) + return CJS_Value::VT_null; + if (nHash == JSCONST_nStringHash) + return CJS_Value::VT_string; + if (nHash == JSCONST_nNumberHash) + return CJS_Value::VT_number; + if (nHash == JSCONST_nBoolHash) + return CJS_Value::VT_boolean; + if (nHash == JSCONST_nDateHash) + return CJS_Value::VT_date; + if (nHash == JSCONST_nObjectHash) + return CJS_Value::VT_object; + if (nHash == JSCONST_nFXobjHash) + return CJS_Value::VT_fxobject; + + return CJS_Value::VT_unknown; +} diff --git a/fpdfsdk/javascript/global.h b/fpdfsdk/javascript/global.h new file mode 100644 index 0000000000..335b540271 --- /dev/null +++ b/fpdfsdk/javascript/global.h @@ -0,0 +1,92 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_GLOBAL_H_ +#define FPDFSDK_JAVASCRIPT_GLOBAL_H_ + +#include <map> +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class CJS_GlobalData; +class CJS_GlobalVariableArray; +class CJS_KeyValue; + +struct JSGlobalData { + JSGlobalData() { + nType = 0; + dData = 0; + bData = FALSE; + sData = ""; + bPersistent = FALSE; + bDeleted = FALSE; + } + + ~JSGlobalData() { pData.Reset(); } + int nType; // 0:int 1:bool 2:string 3:obj + double dData; + bool bData; + CFX_ByteString sData; + v8::Global<v8::Object> pData; + bool bPersistent; + bool bDeleted; +}; + +class JSGlobalAlternate : public CJS_EmbedObj { + public: + JSGlobalAlternate(CJS_Object* pJSObject); + ~JSGlobalAlternate() override; + + FX_BOOL setPersistent(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL QueryProperty(const FX_WCHAR* propname); + FX_BOOL DoProperty(IJS_Context* cc, + const FX_WCHAR* propname, + CJS_PropValue& vp, + CFX_WideString& sError); + FX_BOOL DelProperty(IJS_Context* cc, + const FX_WCHAR* propname, + CFX_WideString& sError); + void Initial(CPDFDoc_Environment* pApp); + + private: + void UpdateGlobalPersistentVariables(); + void CommitGlobalPersisitentVariables(IJS_Context* cc); + void DestroyGlobalPersisitentVariables(); + FX_BOOL SetGlobalVariables(const FX_CHAR* propname, + int nType, + double dData, + bool bData, + const CFX_ByteString& sData, + v8::Local<v8::Object> pData, + bool bDefaultPersistent); + void ObjectToArray(IJS_Context* cc, + v8::Local<v8::Object> pObj, + CJS_GlobalVariableArray& array); + void PutObjectProperty(v8::Local<v8::Object> obj, CJS_KeyValue* pData); + + std::map<CFX_ByteString, JSGlobalData*> m_mapGlobal; + CFX_WideString m_sFilePath; + CJS_GlobalData* m_pGlobalData; + CPDFDoc_Environment* m_pApp; +}; + +class CJS_Global : public CJS_Object { + public: + explicit CJS_Global(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Global() override {} + + // CJS_Object + void InitInstance(IJS_Runtime* pIRuntime) override; + + DECLARE_SPECIAL_JS_CLASS(); + JS_SPECIAL_STATIC_METHOD(setPersistent, JSGlobalAlternate, global); +}; + +#endif // FPDFSDK_JAVASCRIPT_GLOBAL_H_ diff --git a/fpdfsdk/javascript/public_methods_embeddertest.cpp b/fpdfsdk/javascript/public_methods_embeddertest.cpp new file mode 100644 index 0000000000..a298cfc2c8 --- /dev/null +++ b/fpdfsdk/javascript/public_methods_embeddertest.cpp @@ -0,0 +1,168 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <cmath> + +#include "core/include/fxcrt/fx_string.h" +#include "fpdfsdk/javascript/PublicMethods.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/js_embedder_test.h" + +namespace { + +double RoundDownDate(double date) { + return date - fmod(date, 86400000); +} + +} // namespace + +class PublicMethodsEmbedderTest : public JSEmbedderTest {}; + +TEST_F(PublicMethodsEmbedderTest, MakeRegularDate) { + v8::Isolate::Scope isolate_scope(isolate()); +#ifdef PDF_ENABLE_XFA + v8::Locker locker(isolate()); +#endif // PDF_ENABLE_XFA + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + bool bWrongFormat; + double date; + + // 1968 + bWrongFormat = false; + date = CJS_PublicMethods::MakeRegularDate(L"06/25/1968", L"mm/dd/yyyy", + &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(-47865600000, date); + EXPECT_FALSE(bWrongFormat); + + // 1968 + bWrongFormat = false; + date = CJS_PublicMethods::MakeRegularDate(L"25061968", L"ddmmyyyy", + &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(-47865600000, date); + EXPECT_FALSE(bWrongFormat); + + // 1968 + bWrongFormat = false; + date = CJS_PublicMethods::MakeRegularDate(L"19680625", L"yyyymmdd", + &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(-47865600000, date); + EXPECT_FALSE(bWrongFormat); + + // 1985 + bWrongFormat = false; + date = CJS_PublicMethods::MakeRegularDate(L"31121985", L"ddmmyyyy", + &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(504835200000.0, date); + EXPECT_FALSE(bWrongFormat); + + // 2085, the other '85. + bWrongFormat = false; + date = + CJS_PublicMethods::MakeRegularDate(L"311285", L"ddmmyy", &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(3660595200000.0, date); + EXPECT_FALSE(bWrongFormat); + + // 1995 + bWrongFormat = false; + date = CJS_PublicMethods::MakeRegularDate(L"01021995", L"ddmmyyyy", + &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(791596800000.0, date); + EXPECT_FALSE(bWrongFormat); + + // 2095, the other '95. + bWrongFormat = false; + date = + CJS_PublicMethods::MakeRegularDate(L"010295", L"ddmmyy", &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(3947356800000.0, date); + EXPECT_FALSE(bWrongFormat); + + // 2005 + bWrongFormat = false; + date = CJS_PublicMethods::MakeRegularDate(L"01022005", L"ddmmyyyy", + &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(1107216000000.0, date); + EXPECT_FALSE(bWrongFormat); + + // 2005 + bWrongFormat = false; + date = + CJS_PublicMethods::MakeRegularDate(L"010205", L"ddmmyy", &bWrongFormat); + date = RoundDownDate(date); + EXPECT_DOUBLE_EQ(1107216000000.0, date); + EXPECT_FALSE(bWrongFormat); +} + +TEST_F(PublicMethodsEmbedderTest, MakeFormatDate) { + v8::Isolate::Scope isolate_scope(isolate()); +#ifdef PDF_ENABLE_XFA + v8::Locker locker(isolate()); +#endif // PDF_ENABLE_XFA + v8::HandleScope handle_scope(isolate()); + v8::Context::Scope context_scope(GetV8Context()); + CFX_WideString formatted_date; + + // 1968-06-25 + formatted_date = CJS_PublicMethods::MakeFormatDate(-47952000000, L"ddmmyy"); + EXPECT_STREQ(L"250668", formatted_date); + formatted_date = CJS_PublicMethods::MakeFormatDate(-47952000000, L"yy/mm/dd"); + EXPECT_STREQ(L"68/06/25", formatted_date); + + // 1969-12-31 + formatted_date = CJS_PublicMethods::MakeFormatDate(-0.0001, L"ddmmyy"); + EXPECT_STREQ(L"311269", formatted_date); + formatted_date = CJS_PublicMethods::MakeFormatDate(-0.0001, L"yy!mmdd"); + EXPECT_STREQ(L"69!1231", formatted_date); + + // 1970-01-01 + formatted_date = CJS_PublicMethods::MakeFormatDate(0, L"ddmmyy"); + EXPECT_STREQ(L"010170", formatted_date); + formatted_date = CJS_PublicMethods::MakeFormatDate(0, L"mm-yyyy-dd"); + EXPECT_STREQ(L"01-1970-01", formatted_date); + + // 1985-12-31 + formatted_date = CJS_PublicMethods::MakeFormatDate(504835200000.0, L"ddmmyy"); + EXPECT_STREQ(L"311285", formatted_date); + formatted_date = CJS_PublicMethods::MakeFormatDate(504835200000.0, L"yymmdd"); + EXPECT_STREQ(L"851231", formatted_date); + + // 1995-02-01 + formatted_date = CJS_PublicMethods::MakeFormatDate(791596800000.0, L"ddmmyy"); + EXPECT_STREQ(L"010295", formatted_date); + formatted_date = + CJS_PublicMethods::MakeFormatDate(791596800000.0, L"yyyymmdd"); + EXPECT_STREQ(L"19950201", formatted_date); + + // 2005-02-01 + formatted_date = + CJS_PublicMethods::MakeFormatDate(1107216000000.0, L"ddmmyy"); + EXPECT_STREQ(L"010205", formatted_date); + formatted_date = + CJS_PublicMethods::MakeFormatDate(1107216000000.0, L"yyyyddmm"); + EXPECT_STREQ(L"20050102", formatted_date); + + // 2085-12-31 + formatted_date = + CJS_PublicMethods::MakeFormatDate(3660595200000.0, L"ddmmyy"); + EXPECT_STREQ(L"311285", formatted_date); + formatted_date = + CJS_PublicMethods::MakeFormatDate(3660595200000.0, L"yyyydd"); + EXPECT_STREQ(L"208531", formatted_date); + + // 2095-02-01 + formatted_date = + CJS_PublicMethods::MakeFormatDate(3947356800000.0, L"ddmmyy"); + EXPECT_STREQ(L"010295", formatted_date); + formatted_date = + CJS_PublicMethods::MakeFormatDate(3947356800000.0, L"mmddyyyy"); + EXPECT_STREQ(L"02012095", formatted_date); +} diff --git a/fpdfsdk/javascript/report.cpp b/fpdfsdk/javascript/report.cpp new file mode 100644 index 0000000000..ca7e199b0f --- /dev/null +++ b/fpdfsdk/javascript/report.cpp @@ -0,0 +1,49 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/report.h" + +#include <vector> + +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Value.h" + +/* ---------------------- report ---------------------- */ + +BEGIN_JS_STATIC_CONST(CJS_Report) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Report) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Report) +JS_STATIC_METHOD_ENTRY(save) +JS_STATIC_METHOD_ENTRY(writeText) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Report, Report) + +Report::Report(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {} + +Report::~Report() {} + +FX_BOOL Report::writeText(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} + +FX_BOOL Report::save(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + // Unsafe, not supported. + return TRUE; +} diff --git a/fpdfsdk/javascript/report.h b/fpdfsdk/javascript/report.h new file mode 100644 index 0000000000..3cd3b3b02c --- /dev/null +++ b/fpdfsdk/javascript/report.h @@ -0,0 +1,41 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_REPORT_H_ +#define FPDFSDK_JAVASCRIPT_REPORT_H_ + +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class Report : public CJS_EmbedObj { + public: + Report(CJS_Object* pJSObject); + ~Report() override; + + public: + FX_BOOL save(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL writeText(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); +}; + +class CJS_Report : public CJS_Object { + public: + CJS_Report(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Report() override {} + + DECLARE_JS_CLASS(); + + JS_STATIC_METHOD(save, Report) + JS_STATIC_METHOD(writeText, Report); +}; + +#endif // FPDFSDK_JAVASCRIPT_REPORT_H_ diff --git a/fpdfsdk/javascript/resource.cpp b/fpdfsdk/javascript/resource.cpp new file mode 100644 index 0000000000..88721efd2c --- /dev/null +++ b/fpdfsdk/javascript/resource.cpp @@ -0,0 +1,64 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/resource.h" + +CFX_WideString JSGetStringFromID(CJS_Context* pContext, FX_UINT id) { + switch (id) { + case IDS_STRING_JSALERT: + return L"Alert"; + case IDS_STRING_JSPARAMERROR: + return L"Incorrect number of parameters passed to function."; + case IDS_STRING_JSAFNUMBER_KEYSTROKE: + return L"The input value is invalid."; + case IDS_STRING_JSPARAM_TOOLONG: + return L"The input value is too long."; + case IDS_STRING_JSPARSEDATE: + return L"The input value can't be parsed as a valid date/time (%s)."; + case IDS_STRING_JSRANGE1: + return L"The input value must be greater than or equal to %s" + L" and less than or equal to %s."; + case IDS_STRING_JSRANGE2: + return L"The input value must be greater than or equal to %s."; + case IDS_STRING_JSRANGE3: + return L"The input value must be less than or equal to %s."; + case IDS_STRING_NOTSUPPORT: + return L"Operation not supported."; + case IDS_STRING_JSBUSY: + return L"System is busy."; + case IDS_STRING_JSEVENT: + return L"Duplicate formfield event found."; + case IDS_STRING_RUN: + return L"Script ran successfully."; + case IDS_STRING_JSPRINT1: + return L"The second parameter can't be converted to a Date."; + case IDS_STRING_JSPRINT2: + return L"The second parameter is an invalid Date!"; + case IDS_STRING_JSNOGLOBAL: + return L"Global value not found."; + case IDS_STRING_JSREADONLY: + return L"Cannot assign to readonly property."; + case IDS_STRING_JSTYPEERROR: + return L"Incorrect parameter type."; + case IDS_STRING_JSVALUEERROR: + return L"Incorrect parameter value."; + default: + return L""; + } +} + +CFX_WideString JSFormatErrorString(const char* class_name, + const char* property_name, + const CFX_WideString& details) { + CFX_WideString result = CFX_WideString::FromLocal(class_name); + if (property_name) { + result += L"."; + result += CFX_WideString::FromLocal(property_name); + } + result += L": "; + result += details; + return result; +} diff --git a/fpdfsdk/javascript/resource.h b/fpdfsdk/javascript/resource.h new file mode 100644 index 0000000000..4f35f276bc --- /dev/null +++ b/fpdfsdk/javascript/resource.h @@ -0,0 +1,39 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_RESOURCE_H_ +#define FPDFSDK_JAVASCRIPT_RESOURCE_H_ + +#include "core/include/fxcrt/fx_string.h" // For CFX_WideString. +#include "fpdfsdk/include/fsdk_define.h" // For FX_UINT. + +class CJS_Context; + +#define IDS_STRING_JSALERT 25613 +#define IDS_STRING_JSPARAMERROR 25614 +#define IDS_STRING_JSAFNUMBER_KEYSTROKE 25615 +#define IDS_STRING_JSPARAM_TOOLONG 25617 +#define IDS_STRING_JSPARSEDATE 25618 +#define IDS_STRING_JSRANGE1 25619 +#define IDS_STRING_JSRANGE2 25620 +#define IDS_STRING_JSRANGE3 25621 +#define IDS_STRING_NOTSUPPORT 25627 +#define IDS_STRING_JSBUSY 25628 +#define IDS_STRING_JSEVENT 25629 +#define IDS_STRING_RUN 25630 +#define IDS_STRING_JSPRINT1 25632 +#define IDS_STRING_JSPRINT2 25633 +#define IDS_STRING_JSNOGLOBAL 25635 +#define IDS_STRING_JSREADONLY 25636 +#define IDS_STRING_JSTYPEERROR 25637 +#define IDS_STRING_JSVALUEERROR 25638 + +CFX_WideString JSGetStringFromID(CJS_Context* pContext, FX_UINT id); +CFX_WideString JSFormatErrorString(const char* class_name, + const char* property_name, + const CFX_WideString& details); + +#endif // FPDFSDK_JAVASCRIPT_RESOURCE_H_ diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp new file mode 100644 index 0000000000..d488cb23da --- /dev/null +++ b/fpdfsdk/javascript/util.cpp @@ -0,0 +1,530 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "fpdfsdk/javascript/util.h" + +#include <time.h> + +#include <string> +#include <vector> + +#include "core/include/fxcrt/fx_ext.h" +#include "fpdfsdk/include/javascript/IJavaScript.h" +#include "fpdfsdk/javascript/JS_Context.h" +#include "fpdfsdk/javascript/JS_Define.h" +#include "fpdfsdk/javascript/JS_EventHandler.h" +#include "fpdfsdk/javascript/JS_Object.h" +#include "fpdfsdk/javascript/JS_Runtime.h" +#include "fpdfsdk/javascript/JS_Value.h" +#include "fpdfsdk/javascript/PublicMethods.h" +#include "fpdfsdk/javascript/resource.h" + +#if _FX_OS_ == _FX_ANDROID_ +#include <ctype.h> +#endif + +BEGIN_JS_STATIC_CONST(CJS_Util) +END_JS_STATIC_CONST() + +BEGIN_JS_STATIC_PROP(CJS_Util) +END_JS_STATIC_PROP() + +BEGIN_JS_STATIC_METHOD(CJS_Util) +JS_STATIC_METHOD_ENTRY(printd) +JS_STATIC_METHOD_ENTRY(printf) +JS_STATIC_METHOD_ENTRY(printx) +JS_STATIC_METHOD_ENTRY(scand) +JS_STATIC_METHOD_ENTRY(byteToChar) +END_JS_STATIC_METHOD() + +IMPLEMENT_JS_CLASS(CJS_Util, util) + +util::util(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {} + +util::~util() {} + +struct stru_TbConvert { + const FX_WCHAR* lpszJSMark; + const FX_WCHAR* lpszCppMark; +}; + +const stru_TbConvert fcTable[] = { + {L"mmmm", L"%B"}, + {L"mmm", L"%b"}, + {L"mm", L"%m"}, + // "m" + {L"dddd", L"%A"}, + {L"ddd", L"%a"}, + {L"dd", L"%d"}, + // "d", "%w", + {L"yyyy", L"%Y"}, + {L"yy", L"%y"}, + {L"HH", L"%H"}, + // "H" + {L"hh", L"%I"}, + // "h" + {L"MM", L"%M"}, + // "M" + {L"ss", L"%S"}, + // "s + {L"TT", L"%p"}, +// "t" +#if defined(_WIN32) + {L"tt", L"%p"}, + {L"h", L"%#I"}, +#else + {L"tt", L"%P"}, + {L"h", L"%l"}, +#endif +}; + +#define UTIL_INT 0 +#define UTIL_DOUBLE 1 +#define UTIL_STRING 2 + +int util::ParstDataType(std::wstring* sFormat) { + bool bPercent = FALSE; + for (size_t i = 0; i < sFormat->length(); ++i) { + wchar_t c = (*sFormat)[i]; + if (c == L'%') { + bPercent = true; + continue; + } + + if (bPercent) { + if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' || + c == L'u' || c == L'x' || c == L'X') { + return UTIL_INT; + } + if (c == L'e' || c == L'E' || c == L'f' || c == L'g' || c == L'G') { + return UTIL_DOUBLE; + } + if (c == L's' || c == L'S') { + // Map s to S since we always deal internally + // with wchar_t strings. + (*sFormat)[i] = L'S'; + return UTIL_STRING; + } + if (c == L'.' || c == L'+' || c == L'-' || c == L'#' || c == L' ' || + FXSYS_iswdigit(c)) { + continue; + } + break; + } + } + + return -1; +} + +FX_BOOL util::printf(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + if (iSize < 1) + return FALSE; + std::wstring c_ConvChar(params[0].ToCFXWideString().c_str()); + std::vector<std::wstring> c_strConvers; + int iOffset = 0; + int iOffend = 0; + c_ConvChar.insert(c_ConvChar.begin(), L'S'); + while (iOffset != -1) { + iOffend = c_ConvChar.find(L"%", iOffset + 1); + std::wstring strSub; + if (iOffend == -1) + strSub = c_ConvChar.substr(iOffset); + else + strSub = c_ConvChar.substr(iOffset, iOffend - iOffset); + c_strConvers.push_back(strSub); + iOffset = iOffend; + } + + std::wstring c_strResult; + + // for(int iIndex = 1;iIndex < params.size();iIndex++) + std::wstring c_strFormat; + for (int iIndex = 0; iIndex < (int)c_strConvers.size(); iIndex++) { + c_strFormat = c_strConvers[iIndex]; + if (iIndex == 0) { + c_strResult = c_strFormat; + continue; + } + + CFX_WideString strSegment; + if (iIndex >= iSize) { + c_strResult += c_strFormat; + continue; + } + + switch (ParstDataType(&c_strFormat)) { + case UTIL_INT: + strSegment.Format(c_strFormat.c_str(), params[iIndex].ToInt()); + break; + case UTIL_DOUBLE: + strSegment.Format(c_strFormat.c_str(), params[iIndex].ToDouble()); + break; + case UTIL_STRING: + strSegment.Format(c_strFormat.c_str(), + params[iIndex].ToCFXWideString().c_str()); + break; + default: + strSegment.Format(L"%S", c_strFormat.c_str()); + break; + } + c_strResult += strSegment.GetBuffer(strSegment.GetLength() + 1); + } + + c_strResult.erase(c_strResult.begin()); + vRet = c_strResult.c_str(); + return TRUE; +} + +FX_BOOL util::printd(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + if (iSize < 2) + return FALSE; + + CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc); + CJS_Value p1(pRuntime); + p1 = params[0]; + + CJS_Value p2 = params[1]; + CJS_Date jsDate(pRuntime); + if (!p2.ConvertToDate(jsDate)) { + sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT1); + return FALSE; + } + + if (!jsDate.IsValidDate()) { + sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT2); + return FALSE; + } + + if (p1.GetType() == CJS_Value::VT_number) { + int nFormat = p1.ToInt(); + CFX_WideString swResult; + + switch (nFormat) { + case 0: + swResult.Format(L"D:%04d%02d%02d%02d%02d%02d", jsDate.GetYear(), + jsDate.GetMonth() + 1, jsDate.GetDay(), + jsDate.GetHours(), jsDate.GetMinutes(), + jsDate.GetSeconds()); + break; + case 1: + swResult.Format(L"%04d.%02d.%02d %02d:%02d:%02d", jsDate.GetYear(), + jsDate.GetMonth() + 1, jsDate.GetDay(), + jsDate.GetHours(), jsDate.GetMinutes(), + jsDate.GetSeconds()); + break; + case 2: + swResult.Format(L"%04d/%02d/%02d %02d:%02d:%02d", jsDate.GetYear(), + jsDate.GetMonth() + 1, jsDate.GetDay(), + jsDate.GetHours(), jsDate.GetMinutes(), + jsDate.GetSeconds()); + break; + default: + return FALSE; + } + + vRet = swResult.c_str(); + return TRUE; + } + if (p1.GetType() == CJS_Value::VT_string) { + std::basic_string<wchar_t> cFormat = p1.ToCFXWideString().c_str(); + + bool bXFAPicture = false; + if (iSize > 2) { + bXFAPicture = params[2].ToBool(); + } + + if (bXFAPicture) { + return FALSE; // currently, it doesn't support XFAPicture. + } + + for (size_t i = 0; i < sizeof(fcTable) / sizeof(stru_TbConvert); ++i) { + int iStart = 0; + int iEnd; + while ((iEnd = cFormat.find(fcTable[i].lpszJSMark, iStart)) != -1) { + cFormat.replace(iEnd, FXSYS_wcslen(fcTable[i].lpszJSMark), + fcTable[i].lpszCppMark); + iStart = iEnd; + } + } + + int iYear, iMonth, iDay, iHour, iMin, iSec; + iYear = jsDate.GetYear(); + iMonth = jsDate.GetMonth(); + iDay = jsDate.GetDay(); + iHour = jsDate.GetHours(); + iMin = jsDate.GetMinutes(); + iSec = jsDate.GetSeconds(); + + struct tm time = {}; + time.tm_year = iYear - 1900; + time.tm_mon = iMonth; + time.tm_mday = iDay; + time.tm_hour = iHour; + time.tm_min = iMin; + time.tm_sec = iSec; + + struct stru_TbConvertAd { + const FX_WCHAR* lpszJSMark; + int iValue; + }; + + stru_TbConvertAd cTableAd[] = { + {L"m", iMonth + 1}, {L"d", iDay}, + {L"H", iHour}, {L"h", iHour > 12 ? iHour - 12 : iHour}, + {L"M", iMin}, {L"s", iSec}, + }; + + for (size_t i = 0; i < sizeof(cTableAd) / sizeof(stru_TbConvertAd); ++i) { + wchar_t tszValue[10]; + CFX_WideString sValue; + sValue.Format(L"%d", cTableAd[i].iValue); + memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1), + (sValue.GetLength() + 1) * sizeof(wchar_t)); + + int iStart = 0; + int iEnd; + while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) { + if (iEnd > 0) { + if (cFormat[iEnd - 1] == L'%') { + iStart = iEnd + 1; + continue; + } + } + cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue); + iStart = iEnd; + } + } + + CFX_WideString strFormat; + wchar_t buf[64] = {}; + strFormat = wcsftime(buf, 64, cFormat.c_str(), &time); + cFormat = buf; + vRet = cFormat.c_str(); + return TRUE; + } + return FALSE; +} + +void util::printd(const std::wstring& cFormat2, + CJS_Date jsDate, + bool bXFAPicture, + std::wstring& cPurpose) { + std::wstring cFormat = cFormat2; + + if (bXFAPicture) { + return; // currently, it doesn't support XFAPicture. + } + + for (size_t i = 0; i < sizeof(fcTable) / sizeof(stru_TbConvert); ++i) { + int iStart = 0; + int iEnd; + while ((iEnd = cFormat.find(fcTable[i].lpszJSMark, iStart)) != -1) { + cFormat.replace(iEnd, FXSYS_wcslen(fcTable[i].lpszJSMark), + fcTable[i].lpszCppMark); + iStart = iEnd; + } + } + + int iYear, iMonth, iDay, iHour, iMin, iSec; + iYear = jsDate.GetYear(); + iMonth = jsDate.GetMonth(); + iDay = jsDate.GetDay(); + iHour = jsDate.GetHours(); + iMin = jsDate.GetMinutes(); + iSec = jsDate.GetSeconds(); + + struct tm time = {}; + time.tm_year = iYear - 1900; + time.tm_mon = iMonth; + time.tm_mday = iDay; + time.tm_hour = iHour; + time.tm_min = iMin; + time.tm_sec = iSec; + // COleDateTime cppTm(iYear,iMonth+1,iDay,iHour,iMin,iSec); + // CString strFormat = cppTm.Format(cFormat.c_str()); + + struct stru_TbConvertAd { + const FX_WCHAR* lpszJSMark; + int iValue; + }; + + stru_TbConvertAd cTableAd[] = { + {L"m", iMonth + 1}, {L"d", iDay}, + {L"H", iHour}, {L"h", iHour > 12 ? iHour - 12 : iHour}, + {L"M", iMin}, {L"s", iSec}, + }; + + // cFormat = strFormat.GetBuffer(strFormat.GetLength()+1); + for (size_t i = 0; i < sizeof(cTableAd) / sizeof(stru_TbConvertAd); ++i) { + wchar_t tszValue[10]; + CFX_WideString sValue; + sValue.Format(L"%d", cTableAd[i].iValue); + memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1), + sValue.GetLength() * sizeof(wchar_t)); + + int iStart = 0; + int iEnd; + while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) { + if (iEnd > 0) { + if (cFormat[iEnd - 1] == L'%') { + iStart = iEnd + 1; + continue; + } + } + cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue); + iStart = iEnd; + } + } + + CFX_WideString strFormat; + wchar_t buf[64] = {}; + strFormat = wcsftime(buf, 64, cFormat.c_str(), &time); + cFormat = buf; + cPurpose = cFormat; +} + +FX_BOOL util::printx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + if (iSize < 2) + return FALSE; + CFX_WideString sFormat = params[0].ToCFXWideString(); + CFX_WideString sSource = params[1].ToCFXWideString(); + std::string cFormat = CFX_ByteString::FromUnicode(sFormat).c_str(); + std::string cSource = CFX_ByteString::FromUnicode(sSource).c_str(); + std::string cDest; + printx(cFormat, cSource, cDest); + vRet = cDest.c_str(); + return TRUE; +} + +void util::printx(const std::string& cFormat, + const std::string& cSource2, + std::string& cPurpose) { + std::string cSource(cSource2); + if (!cPurpose.empty()) + // cPurpose.clear(); + cPurpose.erase(); + int itSource = 0; + int iSize = cSource.size(); + for (int iIndex = 0; iIndex < (int)cFormat.size() && itSource < iSize; + iIndex++) { + char letter = cFormat[iIndex]; + switch (letter) { + case '?': + cPurpose += cSource[itSource]; + itSource++; + break; + case 'X': { + while (itSource < iSize) { + if (std::isdigit(cSource[itSource]) || + (cSource[itSource] >= 'a' && cSource[itSource] <= 'z') || + (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) { + cPurpose += cSource[itSource]; + itSource++; + break; + } + itSource++; + } + break; + } break; + case 'A': { + while (itSource < iSize) { + if ((cSource[itSource] >= 'a' && cSource[itSource] <= 'z') || + (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) { + cPurpose += cSource[itSource]; + itSource++; + break; + } + itSource++; + } + break; + } break; + case '9': { + while (itSource < iSize) { + if (std::isdigit(cSource[itSource])) { + cPurpose += cSource[itSource]; + itSource++; + break; + } + itSource++; + } + break; + } + case '*': { + cPurpose.append(cSource, itSource, iSize - itSource); + itSource = iSize - 1; + break; + } + case '\\': + break; + case '>': { + for (char& c : cSource) + c = toupper(c); + break; + } + case '<': { + for (char& c : cSource) + c = tolower(c); + break; + } + case '=': + break; + default: + cPurpose += letter; + break; + } + } +} + +FX_BOOL util::scand(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + if (iSize < 2) + return FALSE; + + CFX_WideString sFormat = params[0].ToCFXWideString(); + CFX_WideString sDate = params[1].ToCFXWideString(); + double dDate = JS_GetDateTime(); + if (sDate.GetLength() > 0) { + dDate = CJS_PublicMethods::MakeRegularDate(sDate, sFormat, nullptr); + } + + if (!JS_PortIsNan(dDate)) { + vRet = CJS_Date(CJS_Runtime::FromContext(cc), dDate); + } else { + vRet.SetNull(); + } + + return TRUE; +} + +FX_BOOL util::byteToChar(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError) { + int iSize = params.size(); + if (iSize == 0) + return FALSE; + int nByte = params[0].ToInt(); + unsigned char cByte = (unsigned char)nByte; + CFX_WideString csValue; + csValue.Format(L"%c", cByte); + vRet = csValue.c_str(); + return TRUE; +} diff --git a/fpdfsdk/javascript/util.h b/fpdfsdk/javascript/util.h new file mode 100644 index 0000000000..50fa31ad27 --- /dev/null +++ b/fpdfsdk/javascript/util.h @@ -0,0 +1,67 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef FPDFSDK_JAVASCRIPT_UTIL_H_ +#define FPDFSDK_JAVASCRIPT_UTIL_H_ + +#include <string> +#include <vector> + +#include "fpdfsdk/javascript/JS_Define.h" + +class util : public CJS_EmbedObj { + public: + util(CJS_Object* pJSObject); + ~util() override; + + public: + FX_BOOL printd(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL printf(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL printx(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL scand(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + FX_BOOL byteToChar(IJS_Context* cc, + const std::vector<CJS_Value>& params, + CJS_Value& vRet, + CFX_WideString& sError); + + public: + static void printd(const std::wstring& cFormat, + CJS_Date Date, + bool bXFAPicture, + std::wstring& cPurpose); + static void printx(const std::string& cFormat, + const std::string& cSource, + std::string& cPurpose); + static int ParstDataType(std::wstring* sFormat); +}; + +class CJS_Util : public CJS_Object { + public: + CJS_Util(v8::Local<v8::Object> pObject) : CJS_Object(pObject) {} + ~CJS_Util() override {} + + DECLARE_JS_CLASS(); + + JS_STATIC_METHOD(printd, util); + JS_STATIC_METHOD(printf, util); + JS_STATIC_METHOD(printx, util); + JS_STATIC_METHOD(scand, util); + JS_STATIC_METHOD(byteToChar, util); +}; + +#endif // FPDFSDK_JAVASCRIPT_UTIL_H_ |