global.cpp revision 5ae9d0c6fd838a2967cca72aa5751b51dadc2769
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 "fpdfsdk/javascript/global.h" 8 9#include <vector> 10 11#include "core/fxcrt/fx_ext.h" 12#include "fpdfsdk/javascript/JS_Define.h" 13#include "fpdfsdk/javascript/JS_EventHandler.h" 14#include "fpdfsdk/javascript/JS_GlobalData.h" 15#include "fpdfsdk/javascript/JS_Object.h" 16#include "fpdfsdk/javascript/JS_Value.h" 17#include "fpdfsdk/javascript/cjs_event_context.h" 18#include "fpdfsdk/javascript/resource.h" 19 20JSConstSpec CJS_Global::ConstSpecs[] = {{0, JSConstSpec::Number, 0, 0}}; 21 22JSPropertySpec CJS_Global::PropertySpecs[] = {{0, 0, 0}}; 23 24JSMethodSpec CJS_Global::MethodSpecs[] = { 25 {"setPersistent", setPersistent_static}, 26 {0, 0}}; 27 28IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, JSGlobalAlternate, global); 29 30void CJS_Global::InitInstance(IJS_Runtime* pIRuntime) { 31 CJS_Runtime* pRuntime = static_cast<CJS_Runtime*>(pIRuntime); 32 JSGlobalAlternate* pGlobal = 33 static_cast<JSGlobalAlternate*>(GetEmbedObject()); 34 pGlobal->Initial(pRuntime->GetFormFillEnv()); 35} 36 37JSGlobalData::JSGlobalData() 38 : nType(JS_GlobalDataType::NUMBER), 39 dData(0), 40 bData(false), 41 sData(""), 42 bPersistent(false), 43 bDeleted(false) {} 44 45JSGlobalData::~JSGlobalData() { 46 pData.Reset(); 47} 48 49JSGlobalAlternate::JSGlobalAlternate(CJS_Object* pJSObject) 50 : CJS_EmbedObj(pJSObject), m_pFormFillEnv(nullptr) {} 51 52JSGlobalAlternate::~JSGlobalAlternate() { 53 DestroyGlobalPersisitentVariables(); 54 m_pGlobalData->Release(); 55} 56 57void JSGlobalAlternate::Initial(CPDFSDK_FormFillEnvironment* pFormFillEnv) { 58 m_pFormFillEnv.Reset(pFormFillEnv); 59 m_pGlobalData = CJS_GlobalData::GetRetainedInstance(pFormFillEnv); 60 UpdateGlobalPersistentVariables(); 61} 62 63bool JSGlobalAlternate::QueryProperty(const FX_WCHAR* propname) { 64 return CFX_WideString(propname) != L"setPersistent"; 65} 66 67bool JSGlobalAlternate::DelProperty(CJS_Runtime* pRuntime, 68 const FX_WCHAR* propname, 69 CFX_WideString& sError) { 70 auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname)); 71 if (it == m_mapGlobal.end()) 72 return false; 73 74 it->second->bDeleted = true; 75 return true; 76} 77 78bool JSGlobalAlternate::DoProperty(CJS_Runtime* pRuntime, 79 const FX_WCHAR* propname, 80 CJS_PropValue& vp, 81 CFX_WideString& sError) { 82 if (vp.IsSetting()) { 83 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname); 84 switch (vp.GetJSValue()->GetType()) { 85 case CJS_Value::VT_number: { 86 double dData; 87 vp >> dData; 88 return SetGlobalVariables(sPropName, JS_GlobalDataType::NUMBER, dData, 89 false, "", v8::Local<v8::Object>(), false); 90 } 91 case CJS_Value::VT_boolean: { 92 bool bData; 93 vp >> bData; 94 return SetGlobalVariables(sPropName, JS_GlobalDataType::BOOLEAN, 0, 95 bData, "", v8::Local<v8::Object>(), false); 96 } 97 case CJS_Value::VT_string: { 98 CFX_ByteString sData; 99 vp >> sData; 100 return SetGlobalVariables(sPropName, JS_GlobalDataType::STRING, 0, 101 false, sData, v8::Local<v8::Object>(), false); 102 } 103 case CJS_Value::VT_object: { 104 v8::Local<v8::Object> pData; 105 vp >> pData; 106 return SetGlobalVariables(sPropName, JS_GlobalDataType::OBJECT, 0, 107 false, "", pData, false); 108 } 109 case CJS_Value::VT_null: { 110 return SetGlobalVariables(sPropName, JS_GlobalDataType::NULLOBJ, 0, 111 false, "", v8::Local<v8::Object>(), false); 112 } 113 case CJS_Value::VT_undefined: { 114 DelProperty(pRuntime, propname, sError); 115 return true; 116 } 117 default: 118 break; 119 } 120 } else { 121 auto it = m_mapGlobal.find(CFX_ByteString::FromUnicode(propname)); 122 if (it == m_mapGlobal.end()) { 123 vp.GetJSValue()->SetNull(pRuntime); 124 return true; 125 } 126 JSGlobalData* pData = it->second; 127 if (pData->bDeleted) { 128 vp.GetJSValue()->SetNull(pRuntime); 129 return true; 130 } 131 switch (pData->nType) { 132 case JS_GlobalDataType::NUMBER: 133 vp << pData->dData; 134 return true; 135 case JS_GlobalDataType::BOOLEAN: 136 vp << pData->bData; 137 return true; 138 case JS_GlobalDataType::STRING: 139 vp << pData->sData; 140 return true; 141 case JS_GlobalDataType::OBJECT: { 142 v8::Local<v8::Object> obj = v8::Local<v8::Object>::New( 143 vp.GetJSRuntime()->GetIsolate(), pData->pData); 144 vp << obj; 145 return true; 146 } 147 case JS_GlobalDataType::NULLOBJ: 148 vp.GetJSValue()->SetNull(pRuntime); 149 return true; 150 default: 151 break; 152 } 153 } 154 return false; 155} 156 157bool JSGlobalAlternate::setPersistent(CJS_Runtime* pRuntime, 158 const std::vector<CJS_Value>& params, 159 CJS_Value& vRet, 160 CFX_WideString& sError) { 161 if (params.size() != 2) { 162 sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR); 163 return false; 164 } 165 166 auto it = m_mapGlobal.find(params[0].ToCFXByteString(pRuntime)); 167 if (it != m_mapGlobal.end()) { 168 JSGlobalData* pData = it->second; 169 if (!pData->bDeleted) { 170 pData->bPersistent = params[1].ToBool(pRuntime); 171 return true; 172 } 173 } 174 175 sError = JSGetStringFromID(IDS_STRING_JSNOGLOBAL); 176 return false; 177} 178 179void JSGlobalAlternate::UpdateGlobalPersistentVariables() { 180 CJS_Runtime* pRuntime = 181 static_cast<CJS_Runtime*>(CFXJS_Engine::CurrentEngineFromIsolate( 182 m_pJSObject->ToV8Object()->GetIsolate())); 183 184 for (int i = 0, sz = m_pGlobalData->GetSize(); i < sz; i++) { 185 CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i); 186 switch (pData->data.nType) { 187 case JS_GlobalDataType::NUMBER: 188 SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NUMBER, 189 pData->data.dData, false, "", 190 v8::Local<v8::Object>(), pData->bPersistent == 1); 191 pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(), 192 pData->data.sKey.UTF8Decode(), 193 pRuntime->NewNumber(pData->data.dData)); 194 break; 195 case JS_GlobalDataType::BOOLEAN: 196 SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::BOOLEAN, 0, 197 pData->data.bData == 1, "", v8::Local<v8::Object>(), 198 pData->bPersistent == 1); 199 pRuntime->PutObjectProperty( 200 m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(), 201 pRuntime->NewBoolean(pData->data.bData == 1)); 202 break; 203 case JS_GlobalDataType::STRING: 204 SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::STRING, 0, 205 false, pData->data.sData, v8::Local<v8::Object>(), 206 pData->bPersistent == 1); 207 pRuntime->PutObjectProperty( 208 m_pJSObject->ToV8Object(), pData->data.sKey.UTF8Decode(), 209 pRuntime->NewString(pData->data.sData.UTF8Decode().AsStringC())); 210 break; 211 case JS_GlobalDataType::OBJECT: { 212 v8::Local<v8::Object> pObj = pRuntime->NewFxDynamicObj(-1); 213 PutObjectProperty(pObj, &pData->data); 214 SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::OBJECT, 0, 215 false, "", pObj, pData->bPersistent == 1); 216 pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(), 217 pData->data.sKey.UTF8Decode(), pObj); 218 } break; 219 case JS_GlobalDataType::NULLOBJ: 220 SetGlobalVariables(pData->data.sKey, JS_GlobalDataType::NULLOBJ, 0, 221 false, "", v8::Local<v8::Object>(), 222 pData->bPersistent == 1); 223 pRuntime->PutObjectProperty(m_pJSObject->ToV8Object(), 224 pData->data.sKey.UTF8Decode(), 225 pRuntime->NewNull()); 226 break; 227 } 228 } 229} 230 231void JSGlobalAlternate::CommitGlobalPersisitentVariables( 232 CJS_Runtime* pRuntime) { 233 for (auto it = m_mapGlobal.begin(); it != m_mapGlobal.end(); ++it) { 234 CFX_ByteString name = it->first; 235 JSGlobalData* pData = it->second; 236 if (pData->bDeleted) { 237 m_pGlobalData->DeleteGlobalVariable(name); 238 } else { 239 switch (pData->nType) { 240 case JS_GlobalDataType::NUMBER: 241 m_pGlobalData->SetGlobalVariableNumber(name, pData->dData); 242 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 243 break; 244 case JS_GlobalDataType::BOOLEAN: 245 m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData); 246 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 247 break; 248 case JS_GlobalDataType::STRING: 249 m_pGlobalData->SetGlobalVariableString(name, pData->sData); 250 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 251 break; 252 case JS_GlobalDataType::OBJECT: { 253 CJS_GlobalVariableArray array; 254 v8::Local<v8::Object> obj = v8::Local<v8::Object>::New( 255 GetJSObject()->GetIsolate(), pData->pData); 256 ObjectToArray(pRuntime, obj, array); 257 m_pGlobalData->SetGlobalVariableObject(name, array); 258 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 259 } break; 260 case JS_GlobalDataType::NULLOBJ: 261 m_pGlobalData->SetGlobalVariableNull(name); 262 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 263 break; 264 } 265 } 266 } 267} 268 269void JSGlobalAlternate::ObjectToArray(CJS_Runtime* pRuntime, 270 v8::Local<v8::Object> pObj, 271 CJS_GlobalVariableArray& array) { 272 std::vector<CFX_WideString> pKeyList = pRuntime->GetObjectPropertyNames(pObj); 273 for (const auto& ws : pKeyList) { 274 CFX_ByteString sKey = ws.UTF8Encode(); 275 v8::Local<v8::Value> v = pRuntime->GetObjectProperty(pObj, ws); 276 switch (CJS_Value::GetValueType(v)) { 277 case CJS_Value::VT_number: { 278 CJS_KeyValue* pObjElement = new CJS_KeyValue; 279 pObjElement->nType = JS_GlobalDataType::NUMBER; 280 pObjElement->sKey = sKey; 281 pObjElement->dData = pRuntime->ToDouble(v); 282 array.Add(pObjElement); 283 } break; 284 case CJS_Value::VT_boolean: { 285 CJS_KeyValue* pObjElement = new CJS_KeyValue; 286 pObjElement->nType = JS_GlobalDataType::BOOLEAN; 287 pObjElement->sKey = sKey; 288 pObjElement->dData = pRuntime->ToBoolean(v); 289 array.Add(pObjElement); 290 } break; 291 case CJS_Value::VT_string: { 292 CFX_ByteString sValue = 293 CJS_Value(pRuntime, v).ToCFXByteString(pRuntime); 294 CJS_KeyValue* pObjElement = new CJS_KeyValue; 295 pObjElement->nType = JS_GlobalDataType::STRING; 296 pObjElement->sKey = sKey; 297 pObjElement->sData = sValue; 298 array.Add(pObjElement); 299 } break; 300 case CJS_Value::VT_object: { 301 CJS_KeyValue* pObjElement = new CJS_KeyValue; 302 pObjElement->nType = JS_GlobalDataType::OBJECT; 303 pObjElement->sKey = sKey; 304 ObjectToArray(pRuntime, pRuntime->ToObject(v), pObjElement->objData); 305 array.Add(pObjElement); 306 } break; 307 case CJS_Value::VT_null: { 308 CJS_KeyValue* pObjElement = new CJS_KeyValue; 309 pObjElement->nType = JS_GlobalDataType::NULLOBJ; 310 pObjElement->sKey = sKey; 311 array.Add(pObjElement); 312 } break; 313 default: 314 break; 315 } 316 } 317} 318 319void JSGlobalAlternate::PutObjectProperty(v8::Local<v8::Object> pObj, 320 CJS_KeyValue* pData) { 321 CJS_Runtime* pRuntime = CJS_Runtime::CurrentRuntimeFromIsolate( 322 m_pJSObject->ToV8Object()->GetIsolate()); 323 324 for (int i = 0, sz = pData->objData.Count(); i < sz; i++) { 325 CJS_KeyValue* pObjData = pData->objData.GetAt(i); 326 switch (pObjData->nType) { 327 case JS_GlobalDataType::NUMBER: 328 pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), 329 pRuntime->NewNumber(pObjData->dData)); 330 break; 331 case JS_GlobalDataType::BOOLEAN: 332 pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), 333 pRuntime->NewBoolean(pObjData->bData == 1)); 334 break; 335 case JS_GlobalDataType::STRING: 336 pRuntime->PutObjectProperty( 337 pObj, pObjData->sKey.UTF8Decode(), 338 pRuntime->NewString(pObjData->sData.UTF8Decode().AsStringC())); 339 break; 340 case JS_GlobalDataType::OBJECT: { 341 v8::Local<v8::Object> pNewObj = pRuntime->NewFxDynamicObj(-1); 342 PutObjectProperty(pNewObj, pObjData); 343 pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), pNewObj); 344 } break; 345 case JS_GlobalDataType::NULLOBJ: 346 pRuntime->PutObjectProperty(pObj, pObjData->sKey.UTF8Decode(), 347 pRuntime->NewNull()); 348 break; 349 } 350 } 351} 352 353void JSGlobalAlternate::DestroyGlobalPersisitentVariables() { 354 for (const auto& pair : m_mapGlobal) { 355 delete pair.second; 356 } 357 m_mapGlobal.clear(); 358} 359 360bool JSGlobalAlternate::SetGlobalVariables(const CFX_ByteString& propname, 361 JS_GlobalDataType nType, 362 double dData, 363 bool bData, 364 const CFX_ByteString& sData, 365 v8::Local<v8::Object> pData, 366 bool bDefaultPersistent) { 367 if (propname.IsEmpty()) 368 return false; 369 370 auto it = m_mapGlobal.find(propname); 371 if (it != m_mapGlobal.end()) { 372 JSGlobalData* pTemp = it->second; 373 if (pTemp->bDeleted || pTemp->nType != nType) { 374 pTemp->dData = 0; 375 pTemp->bData = 0; 376 pTemp->sData = ""; 377 pTemp->nType = nType; 378 } 379 380 pTemp->bDeleted = false; 381 switch (nType) { 382 case JS_GlobalDataType::NUMBER: { 383 pTemp->dData = dData; 384 } break; 385 case JS_GlobalDataType::BOOLEAN: { 386 pTemp->bData = bData; 387 } break; 388 case JS_GlobalDataType::STRING: { 389 pTemp->sData = sData; 390 } break; 391 case JS_GlobalDataType::OBJECT: { 392 pTemp->pData.Reset(pData->GetIsolate(), pData); 393 } break; 394 case JS_GlobalDataType::NULLOBJ: 395 break; 396 default: 397 return false; 398 } 399 return true; 400 } 401 402 JSGlobalData* pNewData = nullptr; 403 404 switch (nType) { 405 case JS_GlobalDataType::NUMBER: { 406 pNewData = new JSGlobalData; 407 pNewData->nType = JS_GlobalDataType::NUMBER; 408 pNewData->dData = dData; 409 pNewData->bPersistent = bDefaultPersistent; 410 } break; 411 case JS_GlobalDataType::BOOLEAN: { 412 pNewData = new JSGlobalData; 413 pNewData->nType = JS_GlobalDataType::BOOLEAN; 414 pNewData->bData = bData; 415 pNewData->bPersistent = bDefaultPersistent; 416 } break; 417 case JS_GlobalDataType::STRING: { 418 pNewData = new JSGlobalData; 419 pNewData->nType = JS_GlobalDataType::STRING; 420 pNewData->sData = sData; 421 pNewData->bPersistent = bDefaultPersistent; 422 } break; 423 case JS_GlobalDataType::OBJECT: { 424 pNewData = new JSGlobalData; 425 pNewData->nType = JS_GlobalDataType::OBJECT; 426 pNewData->pData.Reset(pData->GetIsolate(), pData); 427 pNewData->bPersistent = bDefaultPersistent; 428 } break; 429 case JS_GlobalDataType::NULLOBJ: { 430 pNewData = new JSGlobalData; 431 pNewData->nType = JS_GlobalDataType::NULLOBJ; 432 pNewData->bPersistent = bDefaultPersistent; 433 } break; 434 default: 435 return false; 436 } 437 438 m_mapGlobal[propname] = pNewData; 439 return true; 440} 441