Home | History | Annotate | Download | only in fxjs
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "fxjs/cjs_global.h"
      8 
      9 #include <map>
     10 #include <memory>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "core/fxcrt/fx_extension.h"
     15 #include "fxjs/JS_Define.h"
     16 #include "fxjs/cjs_event_context.h"
     17 #include "fxjs/cjs_eventhandler.h"
     18 #include "fxjs/cjs_globaldata.h"
     19 #include "fxjs/cjs_keyvalue.h"
     20 #include "fxjs/cjs_object.h"
     21 #include "fxjs/js_resources.h"
     22 
     23 namespace {
     24 
     25 WideString PropFromV8Prop(v8::Isolate* pIsolate,
     26                           v8::Local<v8::String> property) {
     27   v8::String::Utf8Value utf8_value(pIsolate, property);
     28   return WideString::FromUTF8(ByteStringView(*utf8_value, utf8_value.length()));
     29 }
     30 
     31 template <class Alt>
     32 void JSSpecialPropQuery(const char*,
     33                         v8::Local<v8::String> property,
     34                         const v8::PropertyCallbackInfo<v8::Integer>& info) {
     35   CJS_Runtime* pRuntime =
     36       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
     37   if (!pRuntime)
     38     return;
     39 
     40   CJS_Object* pJSObj =
     41       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
     42   if (!pJSObj)
     43     return;
     44 
     45   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
     46   CJS_Return result =
     47       pObj->QueryProperty(PropFromV8Prop(info.GetIsolate(), property).c_str());
     48   info.GetReturnValue().Set(!result.HasError() ? 4 : 0);
     49 }
     50 
     51 template <class Alt>
     52 void JSSpecialPropGet(const char* class_name,
     53                       v8::Local<v8::String> property,
     54                       const v8::PropertyCallbackInfo<v8::Value>& info) {
     55   CJS_Runtime* pRuntime =
     56       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
     57   if (!pRuntime)
     58     return;
     59 
     60   CJS_Object* pJSObj =
     61       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
     62   if (!pJSObj)
     63     return;
     64 
     65   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
     66   CJS_Return result = pObj->GetProperty(
     67       pRuntime, PropFromV8Prop(info.GetIsolate(), property).c_str());
     68   if (result.HasError()) {
     69     pRuntime->Error(
     70         JSFormatErrorString(class_name, "GetProperty", result.Error()));
     71     return;
     72   }
     73 
     74   if (result.HasReturn())
     75     info.GetReturnValue().Set(result.Return());
     76 }
     77 
     78 template <class Alt>
     79 void JSSpecialPropPut(const char* class_name,
     80                       v8::Local<v8::String> property,
     81                       v8::Local<v8::Value> value,
     82                       const v8::PropertyCallbackInfo<v8::Value>& info) {
     83   CJS_Runtime* pRuntime =
     84       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
     85   if (!pRuntime)
     86     return;
     87 
     88   CJS_Object* pJSObj =
     89       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
     90   if (!pJSObj)
     91     return;
     92 
     93   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
     94   CJS_Return result = pObj->SetProperty(
     95       pRuntime, PropFromV8Prop(info.GetIsolate(), property).c_str(), value);
     96   if (result.HasError()) {
     97     pRuntime->Error(
     98         JSFormatErrorString(class_name, "PutProperty", result.Error()));
     99   }
    100 }
    101 
    102 template <class Alt>
    103 void JSSpecialPropDel(const char* class_name,
    104                       v8::Local<v8::String> property,
    105                       const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    106   CJS_Runtime* pRuntime =
    107       CJS_Runtime::CurrentRuntimeFromIsolate(info.GetIsolate());
    108   if (!pRuntime)
    109     return;
    110 
    111   CJS_Object* pJSObj =
    112       static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(info.Holder()));
    113   if (!pJSObj)
    114     return;
    115 
    116   Alt* pObj = reinterpret_cast<Alt*>(pJSObj->GetEmbedObject());
    117   CJS_Return result = pObj->DelProperty(
    118       pRuntime, PropFromV8Prop(info.GetIsolate(), property).c_str());
    119   if (result.HasError()) {
    120     // TODO(dsinclair): Should this set the pRuntime->Error result?
    121     // ByteString cbName =
    122     //     ByteString::Format("%s.%s", class_name, "DelProperty");
    123   }
    124 }
    125 
    126 struct JSGlobalData {
    127   JSGlobalData();
    128   ~JSGlobalData();
    129 
    130   JS_GlobalDataType nType;
    131   double dData;
    132   bool bData;
    133   ByteString sData;
    134   v8::Global<v8::Object> pData;
    135   bool bPersistent;
    136   bool bDeleted;
    137 };
    138 
    139 class JSGlobalAlternate : public CJS_EmbedObj {
    140  public:
    141   explicit JSGlobalAlternate(CJS_Object* pJSObject);
    142   ~JSGlobalAlternate() override;
    143 
    144   CJS_Return setPersistent(CJS_Runtime* pRuntime,
    145                            const std::vector<v8::Local<v8::Value>>& params);
    146   CJS_Return QueryProperty(const wchar_t* propname);
    147   CJS_Return GetProperty(CJS_Runtime* pRuntime, const wchar_t* propname);
    148   CJS_Return SetProperty(CJS_Runtime* pRuntime,
    149                          const wchar_t* propname,
    150                          v8::Local<v8::Value> vp);
    151   CJS_Return DelProperty(CJS_Runtime* pRuntime, const wchar_t* propname);
    152   void Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv);
    153 
    154  private:
    155   void UpdateGlobalPersistentVariables();
    156   void CommitGlobalPersisitentVariables(CJS_Runtime* pRuntime);
    157   void DestroyGlobalPersisitentVariables();
    158   CJS_Return SetGlobalVariables(const ByteString& propname,
    159                                 JS_GlobalDataType nType,
    160                                 double dData,
    161                                 bool bData,
    162                                 const ByteString& sData,
    163                                 v8::Local<v8::Object> pData,
    164                                 bool bDefaultPersistent);
    165   void ObjectToArray(CJS_Runtime* pRuntime,
    166                      v8::Local<v8::Object> pObj,
    167                      CJS_GlobalVariableArray& array);
    168   void PutObjectProperty(v8::Local<v8::Object> obj, CJS_KeyValue* pData);
    169 
    170   std::map<ByteString, std::unique_ptr<JSGlobalData>> m_MapGlobal;
    171   WideString m_sFilePath;
    172   CJS_GlobalData* m_pGlobalData;
    173   CPDFSDK_FormFillEnvironment::ObservedPtr m_pFormFillEnv;
    174 };
    175 
    176 }  // namespace
    177 
    178 const JSMethodSpec CJS_Global::MethodSpecs[] = {
    179     {"setPersistent", setPersistent_static}};
    180 
    181 int CJS_Global::ObjDefnID = -1;
    182 
    183 // static
    184 void CJS_Global::setPersistent_static(
    185     const v8::FunctionCallbackInfo<v8::Value>& info) {
    186   JSMethod<JSGlobalAlternate, &JSGlobalAlternate::setPersistent>(
    187       "setPersistent", "global", info);
    188 }
    189 
    190 // static
    191 void CJS_Global::queryprop_static(
    192     v8::Local<v8::String> property,
    193     const v8::PropertyCallbackInfo<v8::Integer>& info) {
    194   JSSpecialPropQuery<JSGlobalAlternate>("global", property, info);
    195 }
    196 
    197 // static
    198 void CJS_Global::getprop_static(
    199     v8::Local<v8::String> property,
    200     const v8::PropertyCallbackInfo<v8::Value>& info) {
    201   JSSpecialPropGet<JSGlobalAlternate>("global", property, info);
    202 }
    203 
    204 // static
    205 void CJS_Global::putprop_static(
    206     v8::Local<v8::String> property,
    207     v8::Local<v8::Value> value,
    208     const v8::PropertyCallbackInfo<v8::Value>& info) {
    209   JSSpecialPropPut<JSGlobalAlternate>("global", property, value, info);
    210 }
    211 
    212 // static
    213 void CJS_Global::delprop_static(
    214     v8::Local<v8::String> property,
    215     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    216   JSSpecialPropDel<JSGlobalAlternate>("global", property, info);
    217 }
    218 
    219 // static
    220 void CJS_Global::DefineAllProperties(CFXJS_Engine* pEngine) {
    221   pEngine->DefineObjAllProperties(
    222       ObjDefnID, CJS_Global::queryprop_static, CJS_Global::getprop_static,
    223       CJS_Global::putprop_static, CJS_Global::delprop_static);
    224 }
    225 
    226 // static
    227 void CJS_Global::DefineJSObjects(CFXJS_Engine* pEngine) {
    228   ObjDefnID = pEngine->DefineObj("global", FXJSOBJTYPE_STATIC,
    229                                  JSConstructor<CJS_Global, JSGlobalAlternate>,
    230                                  JSDestructor<CJS_Global>);
    231   DefineMethods(pEngine, ObjDefnID, MethodSpecs, FX_ArraySize(MethodSpecs));
    232   DefineAllProperties(pEngine);
    233 }
    234 
    235 void CJS_Global::InitInstance(IJS_Runtime* pIRuntime) {
    236   CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime);
    237   JSGlobalAlternate* pGlobal =
    238       static_cast<JSGlobalAlternate*>(GetEmbedObject());
    239   pGlobal->Initial(pRuntime->GetFormFillEnv());
    240 }
    241 
    242 JSGlobalData::JSGlobalData()
    243     : nType(JS_GlobalDataType::NUMBER),
    244       dData(0),
    245       bData(false),
    246       sData(""),
    247       bPersistent(false),
    248       bDeleted(false) {}
    249 
    250 JSGlobalData::~JSGlobalData() {
    251   pData.Reset();
    252 }
    253 
    254 JSGlobalAlternate::JSGlobalAlternate(CJS_Object* pJSObject)
    255     : CJS_EmbedObj(pJSObject), m_pFormFillEnv(nullptr) {}
    256 
    257 JSGlobalAlternate::~JSGlobalAlternate() {
    258   DestroyGlobalPersisitentVariables();
    259   m_pGlobalData->Release();
    260 }
    261 
    262 void JSGlobalAlternate::Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv) {
    263   m_pFormFillEnv.Reset(pFormFillEnv);
    264   m_pGlobalData = CJS_GlobalData::GetRetainedInstance(pFormFillEnv);
    265   UpdateGlobalPersistentVariables();
    266 }
    267 
    268 CJS_Return JSGlobalAlternate::QueryProperty(const wchar_t* propname) {
    269   return CJS_Return(WideString(propname) != L"setPersistent");
    270 }
    271 
    272 CJS_Return JSGlobalAlternate::DelProperty(CJS_Runtime* pRuntime,
    273                                           const wchar_t* propname) {
    274   auto it = m_MapGlobal.find(ByteString::FromUnicode(propname));
    275   if (it == m_MapGlobal.end())
    276     return CJS_Return(false);
    277 
    278   it->second->bDeleted = true;
    279   return CJS_Return(true);
    280 }
    281 
    282 CJS_Return JSGlobalAlternate::GetProperty(CJS_Runtime* pRuntime,
    283                                           const wchar_t* propname) {
    284   auto it = m_MapGlobal.find(ByteString::FromUnicode(propname));
    285   if (it == m_MapGlobal.end())
    286     return CJS_Return(true);
    287 
    288   JSGlobalData* pData = it->second.get();
    289   if (pData->bDeleted)
    290     return CJS_Return(true);
    291 
    292   switch (pData->nType) {
    293     case JS_GlobalDataType::NUMBER:
    294       return CJS_Return(pRuntime->NewNumber(pData->dData));
    295     case JS_GlobalDataType::BOOLEAN:
    296       return CJS_Return(pRuntime->NewBoolean(pData->bData));
    297     case JS_GlobalDataType::STRING:
    298       return CJS_Return(pRuntime->NewString(
    299           WideString::FromLocal(pData->sData.c_str()).c_str()));
    300     case JS_GlobalDataType::OBJECT:
    301       return CJS_Return(
    302           v8::Local<v8::Object>::New(pRuntime->GetIsolate(), pData->pData));
    303     case JS_GlobalDataType::NULLOBJ:
    304       return CJS_Return(pRuntime->NewNull());
    305     default:
    306       break;
    307   }
    308   return CJS_Return(false);
    309 }
    310 
    311 CJS_Return JSGlobalAlternate::SetProperty(CJS_Runtime* pRuntime,
    312                                           const wchar_t* propname,
    313                                           v8::Local<v8::Value> vp) {
    314   ByteString sPropName = ByteString::FromUnicode(propname);
    315   if (vp->IsNumber()) {
    316     return SetGlobalVariables(sPropName, JS_GlobalDataType::NUMBER,
    317                               pRuntime->ToDouble(vp), false, "",
    318                               v8::Local<v8::Object>(), false);
    319   }
    320   if (vp->IsBoolean()) {
    321     return SetGlobalVariables(sPropName, JS_GlobalDataType::BOOLEAN, 0,
    322                               pRuntime->ToBoolean(vp), "",
    323                               v8::Local<v8::Object>(), false);
    324   }
    325   if (vp->IsString()) {
    326     return SetGlobalVariables(
    327         sPropName, JS_GlobalDataType::STRING, 0, false,
    328         ByteString::FromUnicode(pRuntime->ToWideString(vp)),
    329         v8::Local<v8::Object>(), false);
    330   }
    331   if (vp->IsObject()) {
    332     return SetGlobalVariables(sPropName, JS_GlobalDataType::OBJECT, 0, false,
    333                               "", pRuntime->ToObject(vp), false);
    334   }
    335   if (vp->IsNull()) {
    336     return SetGlobalVariables(sPropName, JS_GlobalDataType::NULLOBJ, 0, false,
    337                               "", v8::Local<v8::Object>(), false);
    338   }
    339   if (vp->IsUndefined()) {
    340     DelProperty(pRuntime, propname);
    341     return CJS_Return(true);
    342   }
    343   return CJS_Return(false);
    344 }
    345 
    346 CJS_Return JSGlobalAlternate::setPersistent(
    347     CJS_Runtime* pRuntime,
    348     const std::vector<v8::Local<v8::Value>>& params) {
    349   if (params.size() != 2)
    350     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
    351 
    352   auto it = m_MapGlobal.find(
    353       ByteString::FromUnicode(pRuntime->ToWideString(params[0])));
    354   if (it == m_MapGlobal.end() || it->second->bDeleted)
    355     return CJS_Return(JSGetStringFromID(JSMessage::kGlobalNotFoundError));
    356 
    357   it->second->bPersistent = pRuntime->ToBoolean(params[1]);
    358   return CJS_Return(true);
    359 }
    360 
    361 void JSGlobalAlternate::UpdateGlobalPersistentVariables() {
    362   CJS_Runtime* pRuntime =
    363       static_cast<CJS_Runtime*>(CFXJS_Engine::CurrentEngineFromIsolate(
    364           m_pJSObject->ToV8Object()->GetIsolate()));
    365 
    366   for (int i = 0, sz = m_pGlobalData->GetSize(); i < sz; i++) {
    367     CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i);
    368     switch (pData->data.nType) {
    369       case JS_GlobalDataType::NUMBER:
    370         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NUMBER,
    371                            pData->data.dData, false, "",
    372                            v8::Local<v8::Object>(), pData->bPersistent == 1);
    373         pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(),
    374                                     pData->data.sKey.UTF8Decode(),
    375                                     pRuntime->NewNumber(pData->data.dData));
    376         break;
    377       case JS_GlobalDataType::BOOLEAN:
    378         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::BOOLEAN, 0,
    379                            pData->data.bData == 1, "", v8::Local<v8::Object>(),
    380                            pData->bPersistent == 1);
    381         pRuntime->PutObjectProperty(
    382             m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(),
    383             pRuntime->NewBoolean(pData->data.bData == 1));
    384         break;
    385       case JS_GlobalDataType::STRING:
    386         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::STRING, 0,
    387                            false, pData->data.sData, v8::Local<v8::Object>(),
    388                            pData->bPersistent == 1);
    389         pRuntime->PutObjectProperty(
    390             m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(),
    391             pRuntime->NewString(pData->data.sData.UTF8Decode().AsStringView()));
    392         break;
    393       case JS_GlobalDataType::OBJECT: {
    394         v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1);
    395         if (!pObj.IsEmpty()) {
    396           PutObjectProperty(pObj, &pData->data);
    397           SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::OBJECT, 0,
    398                              false, "", pObj, pData->bPersistent == 1);
    399           pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(),
    400                                       pData->data.sKey.UTF8Decode(), pObj);
    401         }
    402       } break;
    403       case JS_GlobalDataType::NULLOBJ:
    404         SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NULLOBJ, 0,
    405                            false, "", v8::Local<v8::Object>(),
    406                            pData->bPersistent == 1);
    407         pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(),
    408                                     pData->data.sKey.UTF8Decode(),
    409                                     pRuntime->NewNull());
    410         break;
    411     }
    412   }
    413 }
    414 
    415 void JSGlobalAlternate::CommitGlobalPersisitentVariables(
    416     CJS_Runtime* pRuntime) {
    417   for (const auto& iter : m_MapGlobal) {
    418     ByteString name = iter.first;
    419     JSGlobalData* pData = iter.second.get();
    420     if (pData->bDeleted) {
    421       m_pGlobalData->DeleteGlobalVariable(name);
    422       continue;
    423     }
    424     switch (pData->nType) {
    425       case JS_GlobalDataType::NUMBER:
    426         m_pGlobalData->SetGlobalVariableNumber(name, pData->dData);
    427         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
    428         break;
    429       case JS_GlobalDataType::BOOLEAN:
    430         m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData);
    431         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
    432         break;
    433       case JS_GlobalDataType::STRING:
    434         m_pGlobalData->SetGlobalVariableString(name, pData->sData);
    435         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
    436         break;
    437       case JS_GlobalDataType::OBJECT: {
    438         CJS_GlobalVariableArray array;
    439         v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(
    440             GetJSObject()->GetIsolate(), pData->pData);
    441         ObjectToArray(pRuntime, obj, array);
    442         m_pGlobalData->SetGlobalVariableObject(name, array);
    443         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
    444       } break;
    445       case JS_GlobalDataType::NULLOBJ:
    446         m_pGlobalData->SetGlobalVariableNull(name);
    447         m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent);
    448         break;
    449     }
    450   }
    451 }
    452 
    453 void JSGlobalAlternate::ObjectToArray(CJS_Runtime* pRuntime,
    454                                       v8::Local<v8::Object> pObj,
    455                                       CJS_GlobalVariableArray& array) {
    456   std::vector<WideString> pKeyList = pRuntime->GetObjectPropertyNames(pObj);
    457   for (const auto& ws : pKeyList) {
    458     ByteString sKey = ws.UTF8Encode();
    459     v8::Local<v8::Value> v = pRuntime->GetObjectProperty(pObj, ws);
    460     if (v->IsNumber()) {
    461       CJS_KeyValue* pObjElement = new CJS_KeyValue;
    462       pObjElement->nType = JS_GlobalDataType::NUMBER;
    463       pObjElement->sKey = sKey;
    464       pObjElement->dData = pRuntime->ToDouble(v);
    465       array.Add(pObjElement);
    466       continue;
    467     }
    468     if (v->IsBoolean()) {
    469       CJS_KeyValue* pObjElement = new CJS_KeyValue;
    470       pObjElement->nType = JS_GlobalDataType::BOOLEAN;
    471       pObjElement->sKey = sKey;
    472       pObjElement->dData = pRuntime->ToBoolean(v);
    473       array.Add(pObjElement);
    474       continue;
    475     }
    476     if (v->IsString()) {
    477       ByteString sValue = ByteString::FromUnicode(pRuntime->ToWideString(v));
    478       CJS_KeyValue* pObjElement = new CJS_KeyValue;
    479       pObjElement->nType = JS_GlobalDataType::STRING;
    480       pObjElement->sKey = sKey;
    481       pObjElement->sData = sValue;
    482       array.Add(pObjElement);
    483       continue;
    484     }
    485     if (v->IsObject()) {
    486       CJS_KeyValue* pObjElement = new CJS_KeyValue;
    487       pObjElement->nType = JS_GlobalDataType::OBJECT;
    488       pObjElement->sKey = sKey;
    489       ObjectToArray(pRuntime, pRuntime->ToObject(v), pObjElement->objData);
    490       array.Add(pObjElement);
    491       continue;
    492     }
    493     if (v->IsNull()) {
    494       CJS_KeyValue* pObjElement = new CJS_KeyValue;
    495       pObjElement->nType = JS_GlobalDataType::NULLOBJ;
    496       pObjElement->sKey = sKey;
    497       array.Add(pObjElement);
    498     }
    499   }
    500 }
    501 
    502 void JSGlobalAlternate::PutObjectProperty(v8::Local<v8::Object> pObj,
    503                                           CJS_KeyValue* pData) {
    504   CJS_Runtime* pRuntime = CJS_Runtime::CurrentRuntimeFromIsolate(
    505       m_pJSObject->ToV8Object()->GetIsolate());
    506 
    507   for (int i = 0, sz = pData->objData.Count(); i < sz; i++) {
    508     CJS_KeyValue* pObjData = pData->objData.GetAt(i);
    509     switch (pObjData->nType) {
    510       case JS_GlobalDataType::NUMBER:
    511         pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
    512                                     pRuntime->NewNumber(pObjData->dData));
    513         break;
    514       case JS_GlobalDataType::BOOLEAN:
    515         pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
    516                                     pRuntime->NewBoolean(pObjData->bData == 1));
    517         break;
    518       case JS_GlobalDataType::STRING:
    519         pRuntime->PutObjectProperty(
    520             pObj, pObjData->sKey.UTF8Decode(),
    521             pRuntime->NewString(pObjData->sData.UTF8Decode().AsStringView()));
    522         break;
    523       case JS_GlobalDataType::OBJECT: {
    524         v8::Local<v8::Object> pNewObj = pRuntime->NewFxDynamicObj(-1);
    525         if (!pNewObj.IsEmpty()) {
    526           PutObjectProperty(pNewObj, pObjData);
    527           pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
    528                                       pNewObj);
    529         }
    530       } break;
    531       case JS_GlobalDataType::NULLOBJ:
    532         pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(),
    533                                     pRuntime->NewNull());
    534         break;
    535     }
    536   }
    537 }
    538 
    539 void JSGlobalAlternate::DestroyGlobalPersisitentVariables() {
    540   m_MapGlobal.clear();
    541 }
    542 
    543 CJS_Return JSGlobalAlternate::SetGlobalVariables(const ByteString& propname,
    544                                                  JS_GlobalDataType nType,
    545                                                  double dData,
    546                                                  bool bData,
    547                                                  const ByteString& sData,
    548                                                  v8::Local<v8::Object> pData,
    549                                                  bool bDefaultPersistent) {
    550   if (propname.IsEmpty())
    551     return CJS_Return(false);
    552 
    553   auto it = m_MapGlobal.find(propname);
    554   if (it != m_MapGlobal.end()) {
    555     JSGlobalData* pTemp = it->second.get();
    556     if (pTemp->bDeleted || pTemp->nType != nType) {
    557       pTemp->dData = 0;
    558       pTemp->bData = 0;
    559       pTemp->sData.clear();
    560       pTemp->nType = nType;
    561     }
    562     pTemp->bDeleted = false;
    563     switch (nType) {
    564       case JS_GlobalDataType::NUMBER:
    565         pTemp->dData = dData;
    566         break;
    567       case JS_GlobalDataType::BOOLEAN:
    568         pTemp->bData = bData;
    569         break;
    570       case JS_GlobalDataType::STRING:
    571         pTemp->sData = sData;
    572         break;
    573       case JS_GlobalDataType::OBJECT:
    574         pTemp->pData.Reset(pData->GetIsolate(), pData);
    575         break;
    576       case JS_GlobalDataType::NULLOBJ:
    577         break;
    578       default:
    579         return CJS_Return(false);
    580     }
    581     return CJS_Return(true);
    582   }
    583 
    584   auto pNewData = pdfium::MakeUnique<JSGlobalData>();
    585   switch (nType) {
    586     case JS_GlobalDataType::NUMBER:
    587       pNewData->nType = JS_GlobalDataType::NUMBER;
    588       pNewData->dData = dData;
    589       pNewData->bPersistent = bDefaultPersistent;
    590       break;
    591     case JS_GlobalDataType::BOOLEAN:
    592       pNewData->nType = JS_GlobalDataType::BOOLEAN;
    593       pNewData->bData = bData;
    594       pNewData->bPersistent = bDefaultPersistent;
    595       break;
    596     case JS_GlobalDataType::STRING:
    597       pNewData->nType = JS_GlobalDataType::STRING;
    598       pNewData->sData = sData;
    599       pNewData->bPersistent = bDefaultPersistent;
    600       break;
    601     case JS_GlobalDataType::OBJECT:
    602       pNewData->nType = JS_GlobalDataType::OBJECT;
    603       pNewData->pData.Reset(pData->GetIsolate(), pData);
    604       pNewData->bPersistent = bDefaultPersistent;
    605       break;
    606     case JS_GlobalDataType::NULLOBJ:
    607       pNewData->nType = JS_GlobalDataType::NULLOBJ;
    608       pNewData->bPersistent = bDefaultPersistent;
    609       break;
    610     default:
    611       return CJS_Return(false);
    612   }
    613   m_MapGlobal[propname] = std::move(pNewData);
    614   return CJS_Return(true);
    615 }
    616