diff options
-rw-r--r-- | fpdfsdk/src/jsapi/fxjs_v8.cpp | 171 | ||||
-rw-r--r-- | testing/resources/javascript/apply.in | 75 | ||||
-rw-r--r-- | testing/resources/javascript/apply_expected.txt | 8 |
3 files changed, 154 insertions, 100 deletions
diff --git a/fpdfsdk/src/jsapi/fxjs_v8.cpp b/fpdfsdk/src/jsapi/fxjs_v8.cpp index 7b93a2ad26..a626bce345 100644 --- a/fpdfsdk/src/jsapi/fxjs_v8.cpp +++ b/fpdfsdk/src/jsapi/fxjs_v8.cpp @@ -24,6 +24,8 @@ static unsigned int g_embedderDataSlot = 1u; // kPerContextDataStartIndex + kEmbedderPDFium, which is 3. static const unsigned int kPerContextDataIndex = 3u; +static v8::Global<v8::ObjectTemplate> g_DefaultGlobalObjectTemplate; + class CFXJS_PrivateData { public: CFXJS_PrivateData(int nObjDefID) : ObjDefID(nObjDefID), pPrivate(NULL) {} @@ -52,35 +54,70 @@ class CFXJS_ObjDefinition { objType(eObjType), m_pConstructor(pConstructor), m_pDestructor(pDestructor), - m_bSetAsGlobalObject(FALSE) { + m_bSetAsGlobalObject(FALSE), + m_pIsolate(isolate) { v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); - v8::Local<v8::ObjectTemplate> objTemplate = - v8::ObjectTemplate::New(isolate); - objTemplate->SetInternalFieldCount(2); - m_objTemplate.Reset(isolate, objTemplate); + v8::Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); + fun->InstanceTemplate()->SetInternalFieldCount(2); + m_FunctionTemplate.Reset(isolate, fun); + + v8::Local<v8::Signature> sig = v8::Signature::New(isolate, fun); + m_Signature.Reset(isolate, sig); // Document as the global object. if (FXSYS_wcscmp(sObjName, L"Document") == 0) { m_bSetAsGlobalObject = TRUE; } } - ~CFXJS_ObjDefinition() { - m_objTemplate.Reset(); - m_StaticObj.Reset(); + + int AssignID() { + FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(m_pIsolate); + pData->m_ObjectDefnArray.Add(this); + return pData->m_ObjectDefnArray.GetSize() - 1; + } + + v8::Local<v8::ObjectTemplate> GetInstanceTemplate() { + v8::EscapableHandleScope scope(m_pIsolate); + v8::Local<v8::FunctionTemplate> function = + m_FunctionTemplate.Get(m_pIsolate); + return scope.Escape(function->InstanceTemplate()); + } + + v8::Local<v8::Signature> GetSignature() { + v8::EscapableHandleScope scope(m_pIsolate); + return scope.Escape(m_Signature.Get(m_pIsolate)); } const wchar_t* objName; - FXJSOBJTYPE objType; - FXJS_CONSTRUCTOR m_pConstructor; - FXJS_DESTRUCTOR m_pDestructor; + const FXJSOBJTYPE objType; + const FXJS_CONSTRUCTOR m_pConstructor; + const FXJS_DESTRUCTOR m_pDestructor; FX_BOOL m_bSetAsGlobalObject; - v8::Global<v8::ObjectTemplate> m_objTemplate; + v8::Isolate* m_pIsolate; + v8::Global<v8::FunctionTemplate> m_FunctionTemplate; + v8::Global<v8::Signature> m_Signature; v8::Global<v8::Object> m_StaticObj; }; +static v8::Local<v8::ObjectTemplate> GetGlobalObjectTemplate( + v8::Isolate* pIsolate) { + int maxID = CFXJS_ObjDefinition::MaxID(pIsolate); + for (int i = 0; i < maxID; ++i) { + CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i); + if (pObjDef->m_bSetAsGlobalObject) + return pObjDef->GetInstanceTemplate(); + } + + if (g_DefaultGlobalObjectTemplate.IsEmpty()) + g_DefaultGlobalObjectTemplate.Reset(pIsolate, + v8::ObjectTemplate::New(pIsolate)); + + return g_DefaultGlobalObjectTemplate.Get(pIsolate); +} + void* FXJS_ArrayBufferAllocator::Allocate(size_t length) { return calloc(1, length); } @@ -121,10 +158,9 @@ int FXJS_DefineObj(v8::Isolate* pIsolate, v8::HandleScope handle_scope(pIsolate); FXJS_PerIsolateData::SetUp(pIsolate); - FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); - pData->m_ObjectDefnArray.Add(new CFXJS_ObjDefinition( - pIsolate, sObjName, eObjType, pConstructor, pDestructor)); - return pData->m_ObjectDefnArray.GetSize() - 1; + CFXJS_ObjDefinition* pObjDef = new CFXJS_ObjDefinition( + pIsolate, sObjName, eObjType, pConstructor, pDestructor); + return pObjDef->AssignID(); } void FXJS_DefineObjMethod(v8::Isolate* pIsolate, @@ -133,18 +169,15 @@ void FXJS_DefineObjMethod(v8::Isolate* pIsolate, v8::FunctionCallback pMethodCall) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode(); CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); - v8::Local<v8::ObjectTemplate> objTemp = - v8::Local<v8::ObjectTemplate>::New(pIsolate, pObjDef->m_objTemplate); - - objTemp->Set( + pObjDef->GetInstanceTemplate()->Set( v8::String::NewFromUtf8(pIsolate, bsMethodName.c_str(), v8::NewStringType::kNormal).ToLocalChecked(), - v8::FunctionTemplate::New(pIsolate, pMethodCall), v8::ReadOnly); - pObjDef->m_objTemplate.Reset(pIsolate, objTemp); + v8::FunctionTemplate::New(pIsolate, pMethodCall, v8::Local<v8::Value>(), + pObjDef->GetSignature()), + v8::ReadOnly); } void FXJS_DefineObjProperty(v8::Isolate* pIsolate, @@ -154,17 +187,13 @@ void FXJS_DefineObjProperty(v8::Isolate* pIsolate, v8::AccessorSetterCallback pPropPut) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - CFX_ByteString bsPropertyName = CFX_WideString(sPropName).UTF8Encode(); CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); - v8::Local<v8::ObjectTemplate> objTemp = - v8::Local<v8::ObjectTemplate>::New(pIsolate, pObjDef->m_objTemplate); - objTemp->SetAccessor( + pObjDef->GetInstanceTemplate()->SetAccessor( v8::String::NewFromUtf8(pIsolate, bsPropertyName.c_str(), v8::NewStringType::kNormal).ToLocalChecked(), pPropGet, pPropPut); - pObjDef->m_objTemplate.Reset(pIsolate, objTemp); } void FXJS_DefineObjAllProperties(v8::Isolate* pIsolate, @@ -175,13 +204,10 @@ void FXJS_DefineObjAllProperties(v8::Isolate* pIsolate, v8::NamedPropertyDeleterCallback pPropDel) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); - v8::Local<v8::ObjectTemplate> objTemp = - v8::Local<v8::ObjectTemplate>::New(pIsolate, pObjDef->m_objTemplate); - objTemp->SetNamedPropertyHandler(pPropGet, pPropPut, pPropQurey, pPropDel); - pObjDef->m_objTemplate.Reset(pIsolate, objTemp); + pObjDef->GetInstanceTemplate()->SetNamedPropertyHandler(pPropGet, pPropPut, + pPropQurey, pPropDel); } void FXJS_DefineObjConst(v8::Isolate* pIsolate, @@ -190,29 +216,10 @@ void FXJS_DefineObjConst(v8::Isolate* pIsolate, v8::Local<v8::Value> pDefault) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - CFX_ByteString bsConstName = CFX_WideString(sConstName).UTF8Encode(); CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); - v8::Local<v8::ObjectTemplate> objTemp = - v8::Local<v8::ObjectTemplate>::New(pIsolate, pObjDef->m_objTemplate); - objTemp->Set(pIsolate, bsConstName.c_str(), pDefault); - pObjDef->m_objTemplate.Reset(pIsolate, objTemp); -} - -static v8::Global<v8::ObjectTemplate>& _getGlobalObjectTemplate( - v8::Isolate* pIsolate) { - v8::Isolate::Scope isolate_scope(pIsolate); - v8::HandleScope handle_scope(pIsolate); - - int maxID = CFXJS_ObjDefinition::MaxID(pIsolate); - for (int i = 0; i < maxID; ++i) { - CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, i); - if (pObjDef->m_bSetAsGlobalObject) - return pObjDef->m_objTemplate; - } - static v8::Global<v8::ObjectTemplate> gloabalObjectTemplate; - return gloabalObjectTemplate; + pObjDef->GetInstanceTemplate()->Set(pIsolate, bsConstName.c_str(), pDefault); } void FXJS_DefineGlobalMethod(v8::Isolate* pIsolate, @@ -220,24 +227,11 @@ void FXJS_DefineGlobalMethod(v8::Isolate* pIsolate, v8::FunctionCallback pMethodCall) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - CFX_ByteString bsMethodName = CFX_WideString(sMethodName).UTF8Encode(); - v8::Local<v8::FunctionTemplate> funTempl = - v8::FunctionTemplate::New(pIsolate, pMethodCall); - v8::Local<v8::ObjectTemplate> objTemp; - - v8::Global<v8::ObjectTemplate>& globalObjTemp = - _getGlobalObjectTemplate(pIsolate); - if (globalObjTemp.IsEmpty()) - objTemp = v8::ObjectTemplate::New(pIsolate); - else - objTemp = v8::Local<v8::ObjectTemplate>::New(pIsolate, globalObjTemp); - objTemp->Set( + GetGlobalObjectTemplate(pIsolate)->Set( v8::String::NewFromUtf8(pIsolate, bsMethodName.c_str(), v8::NewStringType::kNormal).ToLocalChecked(), - funTempl, v8::ReadOnly); - - globalObjTemp.Reset(pIsolate, objTemp); + v8::FunctionTemplate::New(pIsolate, pMethodCall), v8::ReadOnly); } void FXJS_DefineGlobalConst(v8::Isolate* pIsolate, @@ -245,24 +239,11 @@ void FXJS_DefineGlobalConst(v8::Isolate* pIsolate, v8::Local<v8::Value> pDefault) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - - CFX_WideString ws = CFX_WideString(sConstName); - CFX_ByteString bsConst = ws.UTF8Encode(); - - v8::Local<v8::ObjectTemplate> objTemp; - - v8::Global<v8::ObjectTemplate>& globalObjTemp = - _getGlobalObjectTemplate(pIsolate); - if (globalObjTemp.IsEmpty()) - objTemp = v8::ObjectTemplate::New(pIsolate); - else - objTemp = v8::Local<v8::ObjectTemplate>::New(pIsolate, globalObjTemp); - objTemp->Set( + CFX_ByteString bsConst = CFX_WideString(sConstName).UTF8Encode(); + GetGlobalObjectTemplate(pIsolate)->Set( v8::String::NewFromUtf8(pIsolate, bsConst.c_str(), v8::NewStringType::kNormal).ToLocalChecked(), pDefault, v8::ReadOnly); - - globalObjTemp.Reset(pIsolate, objTemp); } void FXJS_InitializeRuntime(v8::Isolate* pIsolate, @@ -271,12 +252,8 @@ void FXJS_InitializeRuntime(v8::Isolate* pIsolate, v8::Global<v8::Context>& v8PersistentContext) { v8::Isolate::Scope isolate_scope(pIsolate); v8::HandleScope handle_scope(pIsolate); - - v8::Global<v8::ObjectTemplate>& globalObjTemp = - _getGlobalObjectTemplate(pIsolate); - v8::Local<v8::Context> v8Context = v8::Context::New( - pIsolate, NULL, - v8::Local<v8::ObjectTemplate>::New(pIsolate, globalObjTemp)); + v8::Local<v8::Context> v8Context = + v8::Context::New(pIsolate, NULL, GetGlobalObjectTemplate(pIsolate)); v8::Context::Scope context_scope(v8Context); FXJS_PerIsolateData::SetUp(pIsolate); @@ -362,10 +339,7 @@ int FXJS_Execute(v8::Isolate* pIsolate, FXJSErr* pError) { v8::Isolate::Scope isolate_scope(pIsolate); v8::TryCatch try_catch(pIsolate); - - CFX_WideString wsScript(script); - CFX_ByteString bsScript = wsScript.UTF8Encode(); - + CFX_ByteString bsScript = CFX_WideString(script).UTF8Encode(); v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); v8::Local<v8::Script> compiled_script; if (!v8::Script::Compile( @@ -395,9 +369,9 @@ v8::Local<v8::Object> FXJS_NewFxDynamicObj(v8::Isolate* pIsolate, if (nObjDefnID == -1) { v8::Local<v8::ObjectTemplate> objTempl = v8::ObjectTemplate::New(pIsolate); v8::Local<v8::Object> obj; - if (objTempl->NewInstance(context).ToLocal(&obj)) - return obj; - return v8::Local<v8::Object>(); + if (!objTempl->NewInstance(context).ToLocal(&obj)) + return v8::Local<v8::Object>(); + return obj; } FXJS_PerIsolateData* pData = FXJS_PerIsolateData::Get(pIsolate); @@ -409,11 +383,8 @@ v8::Local<v8::Object> FXJS_NewFxDynamicObj(v8::Isolate* pIsolate, CFXJS_ObjDefinition* pObjDef = CFXJS_ObjDefinition::ForID(pIsolate, nObjDefnID); - - v8::Local<v8::ObjectTemplate> objTemp = - v8::Local<v8::ObjectTemplate>::New(pIsolate, pObjDef->m_objTemplate); v8::Local<v8::Object> obj; - if (!objTemp->NewInstance(context).ToLocal(&obj)) + if (!pObjDef->GetInstanceTemplate()->NewInstance(context).ToLocal(&obj)) return v8::Local<v8::Object>(); obj->SetAlignedPointerInInternalField(0, new CFXJS_PrivateData(nObjDefnID)); diff --git a/testing/resources/javascript/apply.in b/testing/resources/javascript/apply.in new file mode 100644 index 0000000000..1342c1af4e --- /dev/null +++ b/testing/resources/javascript/apply.in @@ -0,0 +1,75 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R + /OpenAction 10 0 R +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [ + 3 0 R + ] +>> +endobj +% Page number 0. +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Resources << + /Font <</F1 15 0 R>> + >> + /Contents [21 0 R] + /MediaBox [0 0 612 792] +>> +% OpenAction action +{{object 10 0}} << + /Type /Action + /S /JavaScript + /JS 11 0 R +>> +endobj +% JS program to exexute +{{object 11 0}} << +>> +stream +app.alert('Applying to util itself - should succeed'); +try { + app.alert(util.byteToChar.apply(util, [65])); +} +catch (e) { + app.alert('Caught: ' + e); +} + +app.alert('Applying to array - should throw'); +try { + app.alert(util.byteToChar.apply([], [65])); +} +catch (e) { + app.alert('Caught: ' + e); +} + +app.alert('Applying to number - should throw'); +try { + app.alert(util.byteToChar.apply(7, [65])); +} +catch (e) { + app.alert('Caught: ' + e); +} + +app.alert('Applying to wrong native obj - should throw'); +try { + app.alert(util.byteToChar.apply(app, [65])); +} +catch (e) { + app.alert('Caught: ' + e); +} +endstream +endobj +{{xref}} +trailer << + /Root 1 0 R +>> +{{startxref}} +%%EOF diff --git a/testing/resources/javascript/apply_expected.txt b/testing/resources/javascript/apply_expected.txt new file mode 100644 index 0000000000..750676f235 --- /dev/null +++ b/testing/resources/javascript/apply_expected.txt @@ -0,0 +1,8 @@ +Alert: Applying to util itself - should succeed +Alert: A +Alert: Applying to array - should throw +Alert: Caught: TypeError: Illegal invocation +Alert: Applying to number - should throw +Alert: Caught: TypeError: Illegal invocation +Alert: Applying to wrong native obj - should throw +Alert: Caught: TypeError: Illegal invocation |