Add signatures to FXJS_V8.

BUG=chromium:529012
R=jochen@chromium.org, krasin@google.com

Review URL: https://codereview.chromium.org/1353193004 .
diff --git a/fpdfsdk/src/jsapi/fxjs_v8.cpp b/fpdfsdk/src/jsapi/fxjs_v8.cpp
index 7b93a2a..a626bce 100644
--- a/fpdfsdk/src/jsapi/fxjs_v8.cpp
+++ b/fpdfsdk/src/jsapi/fxjs_v8.cpp
@@ -24,6 +24,8 @@
 //   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 @@
         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 @@
   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 @@
                           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 @@
                             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 @@
                                  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 @@
                          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 @@
                              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 @@
                             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 @@
                             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 @@
                  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 @@
   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 @@
 
   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 0000000..1342c1a
--- /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 0000000..750676f
--- /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