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 "../../include/javascript/JavaScript.h" 8 #include "../../include/javascript/IJavaScript.h" 9 #include "../../include/javascript/JS_Define.h" 10 #include "../../include/javascript/JS_Object.h" 11 #include "../../include/javascript/JS_Value.h" 12 #include "../../include/javascript/JS_GlobalData.h" 13 #include "../../include/javascript/global.h" 14 #include "../../include/javascript/JS_EventHandler.h" 15 #include "../../include/javascript/JS_Context.h" 16 17 /* ---------------------------- global ---------------------------- */ 18 19 BEGIN_JS_STATIC_CONST(CJS_Global) 20 END_JS_STATIC_CONST() 21 22 BEGIN_JS_STATIC_PROP(CJS_Global) 23 END_JS_STATIC_PROP() 24 25 BEGIN_JS_STATIC_METHOD(CJS_Global) 26 JS_STATIC_METHOD_ENTRY(setPersistent, 2) 27 END_JS_STATIC_METHOD() 28 29 IMPLEMENT_SPECIAL_JS_CLASS(CJS_Global, global_alternate, global); 30 31 FX_BOOL CJS_Global::InitInstance(IFXJS_Context* cc) 32 { 33 CJS_Context* pContext = (CJS_Context*)cc; 34 ASSERT(pContext != NULL); 35 36 global_alternate* pGlobal = (global_alternate*)GetEmbedObject(); 37 ASSERT(pGlobal != NULL); 38 39 pGlobal->Initial(pContext->GetReaderApp()); 40 41 return TRUE; 42 }; 43 44 global_alternate::global_alternate(CJS_Object* pJSObject) 45 : CJS_EmbedObj(pJSObject), 46 m_pApp(NULL) 47 { 48 } 49 50 global_alternate::~global_alternate(void) 51 { 52 ASSERT(m_pApp != NULL); 53 54 // CommitGlobalPersisitentVariables(); 55 DestroyGlobalPersisitentVariables(); 56 57 CJS_RuntimeFactory* pFactory = m_pApp->m_pJSRuntimeFactory; 58 ASSERT(pFactory); 59 60 pFactory->ReleaseGlobalData(); 61 } 62 63 void global_alternate::Initial(CPDFDoc_Environment* pApp) 64 { 65 m_pApp = pApp; 66 67 CJS_RuntimeFactory* pFactory = pApp->m_pJSRuntimeFactory; 68 ASSERT(pFactory); 69 m_pGlobalData = pFactory->NewGlobalData(pApp); 70 UpdateGlobalPersistentVariables(); 71 } 72 73 FX_BOOL global_alternate::QueryProperty(FX_LPCWSTR propname) 74 { 75 return CFX_WideString(propname) != L"setPersistent"; 76 } 77 78 FX_BOOL global_alternate::DelProperty(IFXJS_Context* cc, FX_LPCWSTR propname, JS_ErrorString& sError) 79 { 80 js_global_data* pData = NULL; 81 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname); 82 83 if (m_mapGlobal.Lookup(sPropName, (FX_LPVOID&)pData)) 84 { 85 pData->bDeleted = TRUE; 86 return TRUE; 87 } 88 89 return FALSE; 90 } 91 92 FX_BOOL global_alternate::DoProperty(IFXJS_Context* cc, FX_LPCWSTR propname, CJS_PropValue& vp, JS_ErrorString& sError) 93 { 94 if (vp.IsSetting()) 95 { 96 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname); 97 switch (vp.GetType()) 98 { 99 case VT_number: 100 { 101 double dData; 102 vp >> dData; 103 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NUMBER, dData, false, "", v8::Handle<v8::Object>(), FALSE); 104 } 105 case VT_boolean: 106 { 107 bool bData; 108 vp >> bData; 109 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)vp, "", v8::Handle<v8::Object>(), FALSE); 110 } 111 case VT_string: 112 { 113 CFX_ByteString sData; 114 vp >> sData; 115 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_STRING, 0, false, sData, v8::Handle<v8::Object>(), FALSE); 116 } 117 case VT_object: 118 { 119 JSObject pData = (JSObject)vp; 120 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", pData, FALSE); 121 // else 122 // { 123 // if (vp.IsArrayObject()) 124 // { 125 // CJS_Array array; 126 // vp.ConvertToArray(array); 127 // return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", 128 // (Dobject*)(Darray*)array, FALSE); 129 // } 130 // else 131 // return FALSE; 132 // } 133 } 134 case VT_null: 135 { 136 return SetGlobalVariables(sPropName, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), FALSE); 137 } 138 case VT_undefined: 139 { 140 DelProperty(cc, propname, sError); 141 return TRUE; 142 } 143 default: 144 return FALSE; 145 } 146 } 147 else 148 { 149 js_global_data* pData = NULL; 150 CFX_ByteString sPropName = CFX_ByteString::FromUnicode(propname); 151 152 if (m_mapGlobal.Lookup(sPropName, (FX_LPVOID&)pData)) 153 { 154 if (pData) 155 { 156 if (!pData->bDeleted) 157 { 158 switch (pData->nType) 159 { 160 case JS_GLOBALDATA_TYPE_NUMBER: 161 vp << pData->dData; 162 break; 163 case JS_GLOBALDATA_TYPE_BOOLEAN: 164 vp << pData->bData; 165 break; 166 case JS_GLOBALDATA_TYPE_STRING: 167 vp << pData->sData; 168 break; 169 case JS_GLOBALDATA_TYPE_OBJECT: 170 { 171 v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(vp.GetIsolate(),pData->pData); 172 vp << obj; 173 break; 174 } 175 case JS_GLOBALDATA_TYPE_NULL: 176 vp.SetNull(); 177 break; 178 default: 179 return FALSE; 180 } 181 return TRUE; 182 } 183 else 184 { 185 return TRUE; 186 } 187 } 188 else 189 { 190 vp.SetNull(); 191 return TRUE; 192 } 193 } 194 else 195 { 196 vp.SetNull(); 197 return TRUE; 198 } 199 } 200 201 return FALSE; 202 } 203 204 FX_BOOL global_alternate::setPersistent(OBJ_METHOD_PARAMS) 205 { 206 if (params.size() != 2) 207 { 208 //sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR); 209 return FALSE; 210 } 211 212 CFX_ByteString sName = params[0]; 213 214 js_global_data* pData = NULL; 215 if (m_mapGlobal.Lookup(sName, (FX_LPVOID&)pData)) 216 { 217 if (pData && !pData->bDeleted) 218 { 219 pData->bPersistent = (bool)params[1]; 220 return TRUE; 221 } 222 } 223 224 //sError = JSGetStringFromID(IDS_JSPARAM_INCORRECT); 225 return FALSE; 226 } 227 228 void global_alternate::UpdateGlobalPersistentVariables() 229 { 230 ASSERT(m_pGlobalData != NULL); 231 232 for (int i=0,sz=m_pGlobalData->GetSize(); i<sz; i++) 233 { 234 CJS_GlobalData_Element* pData = m_pGlobalData->GetAt(i); 235 ASSERT(pData != NULL); 236 237 switch (pData->data.nType) 238 { 239 case JS_GLOBALDATA_TYPE_NUMBER: 240 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NUMBER, pData->data.dData, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1); 241 JS_PutObjectNumber(NULL,(JSFXObject)(*m_pJSObject), 242 pData->data.sKey.UTF8Decode(), pData->data.dData); 243 break; 244 case JS_GLOBALDATA_TYPE_BOOLEAN: 245 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_BOOLEAN, 0, (bool)(pData->data.bData == 1), "", v8::Handle<v8::Object>(), pData->bPersistent == 1); 246 JS_PutObjectBoolean(NULL,(JSFXObject)(*m_pJSObject), 247 pData->data.sKey.UTF8Decode(), (bool)(pData->data.bData == 1)); 248 break; 249 case JS_GLOBALDATA_TYPE_STRING: 250 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_STRING, 0, false, pData->data.sData, v8::Handle<v8::Object>(), pData->bPersistent == 1); 251 JS_PutObjectString(NULL,(JSFXObject)(*m_pJSObject), 252 pData->data.sKey.UTF8Decode(), 253 pData->data.sData.UTF8Decode()); 254 break; 255 case JS_GLOBALDATA_TYPE_OBJECT: 256 { 257 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject)); 258 v8::Handle<v8::Object> pObj = JS_NewFxDynamicObj(pRuntime, NULL, -1); 259 260 PutObjectProperty(pObj, &pData->data); 261 262 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_OBJECT, 0, false, "", 263 (JSObject)pObj, pData->bPersistent == 1); 264 JS_PutObjectObject(NULL,(JSFXObject)(*m_pJSObject), 265 pData->data.sKey.UTF8Decode(), (JSObject)pObj); 266 } 267 break; 268 case JS_GLOBALDATA_TYPE_NULL: 269 this->SetGlobalVariables(pData->data.sKey, JS_GLOBALDATA_TYPE_NULL, 0, false, "", v8::Handle<v8::Object>(), pData->bPersistent == 1); 270 JS_PutObjectNull(NULL,(JSFXObject)(*m_pJSObject), 271 pData->data.sKey.UTF8Decode()); 272 break; 273 } 274 } 275 } 276 277 void global_alternate::CommitGlobalPersisitentVariables() 278 { 279 ASSERT(m_pGlobalData != NULL); 280 281 FX_POSITION pos = m_mapGlobal.GetStartPosition(); 282 while (pos) 283 { 284 CFX_ByteString name; 285 js_global_data* pData = NULL; 286 m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData); 287 288 if (pData) 289 { 290 if (pData->bDeleted) 291 { 292 m_pGlobalData->DeleteGlobalVariable(name); 293 } 294 else 295 { 296 switch (pData->nType) 297 { 298 case JS_GLOBALDATA_TYPE_NUMBER: 299 m_pGlobalData->SetGlobalVariableNumber(name, pData->dData); 300 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 301 break; 302 case JS_GLOBALDATA_TYPE_BOOLEAN: 303 m_pGlobalData->SetGlobalVariableBoolean(name, pData->bData); 304 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 305 break; 306 case JS_GLOBALDATA_TYPE_STRING: 307 m_pGlobalData->SetGlobalVariableString(name, pData->sData); 308 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 309 break; 310 case JS_GLOBALDATA_TYPE_OBJECT: 311 //if (pData->pData) 312 { 313 CJS_GlobalVariableArray array; 314 v8::Handle<v8::Object> obj = v8::Local<v8::Object>::New(GetJSObject()->GetIsolate(),pData->pData); 315 ObjectToArray(obj, array); 316 m_pGlobalData->SetGlobalVariableObject(name, array); 317 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 318 } 319 break; 320 case JS_GLOBALDATA_TYPE_NULL: 321 m_pGlobalData->SetGlobalVariableNull(name); 322 m_pGlobalData->SetGlobalVariablePersistent(name, pData->bPersistent); 323 break; 324 } 325 } 326 } 327 } 328 } 329 330 void global_alternate::ObjectToArray(v8::Handle<v8::Object> pObj, CJS_GlobalVariableArray& array) 331 { 332 v8::Handle<v8::Array> pKeyList = JS_GetObjectElementNames(pObj); 333 int nObjElements = pKeyList->Length(); 334 335 v8::Local<v8::Context> context = pObj->CreationContext(); 336 v8::Isolate* isolate = context->GetIsolate(); 337 338 for (int i=0; i<nObjElements; i++) 339 { 340 341 CFX_WideString ws = JS_ToString(JS_GetArrayElemnet(pKeyList, i)); 342 CFX_ByteString sKey = ws.UTF8Encode(); 343 344 v8::Handle<v8::Value> v = JS_GetObjectElement(isolate, pObj, (const wchar_t*)(FX_LPCWSTR)ws); 345 FXJSVALUETYPE vt = GET_VALUE_TYPE(v); 346 switch (vt) 347 { 348 case VT_number: 349 { 350 CJS_KeyValue* pObjElement = new CJS_KeyValue; 351 pObjElement->nType = JS_GLOBALDATA_TYPE_NUMBER; 352 pObjElement->sKey = sKey; 353 pObjElement->dData = JS_ToNumber(v); 354 array.Add(pObjElement); 355 } 356 break; 357 case VT_boolean: 358 { 359 CJS_KeyValue* pObjElement = new CJS_KeyValue; 360 pObjElement->nType = JS_GLOBALDATA_TYPE_BOOLEAN; 361 pObjElement->sKey = sKey; 362 pObjElement->dData = JS_ToBoolean(v); 363 array.Add(pObjElement); 364 } 365 break; 366 case VT_string: 367 { 368 CFX_ByteString sValue = CJS_Value(isolate, v, VT_string); 369 CJS_KeyValue* pObjElement = new CJS_KeyValue; 370 pObjElement->nType = JS_GLOBALDATA_TYPE_STRING; 371 pObjElement->sKey = sKey; 372 pObjElement->sData = sValue; 373 array.Add(pObjElement); 374 } 375 break; 376 case VT_object: 377 { 378 CJS_KeyValue* pObjElement = new CJS_KeyValue; 379 pObjElement->nType = JS_GLOBALDATA_TYPE_OBJECT; 380 pObjElement->sKey = sKey; 381 ObjectToArray(JS_ToObject(v), pObjElement->objData); 382 array.Add(pObjElement); 383 } 384 break; 385 case VT_null: 386 { 387 CJS_KeyValue* pObjElement = new CJS_KeyValue; 388 pObjElement->nType = JS_GLOBALDATA_TYPE_NULL; 389 pObjElement->sKey = sKey; 390 array.Add(pObjElement); 391 } 392 break; 393 default: 394 break; 395 } 396 } 397 } 398 399 void global_alternate::PutObjectProperty(v8::Handle<v8::Object> pObj, CJS_KeyValue* pData) 400 { 401 ASSERT(pData != NULL); 402 403 for (int i=0,sz=pData->objData.Count(); i<sz; i++) 404 { 405 CJS_KeyValue* pObjData = pData->objData.GetAt(i); 406 ASSERT(pObjData != NULL); 407 408 switch (pObjData->nType) 409 { 410 case JS_GLOBALDATA_TYPE_NUMBER: 411 JS_PutObjectNumber(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->dData); 412 break; 413 case JS_GLOBALDATA_TYPE_BOOLEAN: 414 JS_PutObjectBoolean(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), (bool)(pObjData->bData == 1)); 415 break; 416 case JS_GLOBALDATA_TYPE_STRING: 417 JS_PutObjectString(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode(), pObjData->sData.UTF8Decode()); 418 break; 419 case JS_GLOBALDATA_TYPE_OBJECT: 420 { 421 IJS_Runtime* pRuntime = JS_GetRuntime((JSFXObject)(*m_pJSObject)); 422 v8::Handle<v8::Object> pNewObj = JS_NewFxDynamicObj(pRuntime, NULL, -1); 423 PutObjectProperty(pNewObj, pObjData); 424 JS_PutObjectObject(NULL, (JSObject)pObj, pObjData->sKey.UTF8Decode(), (JSObject)pNewObj); 425 } 426 break; 427 case JS_GLOBALDATA_TYPE_NULL: 428 JS_PutObjectNull(NULL,(JSObject)pObj, pObjData->sKey.UTF8Decode()); 429 break; 430 } 431 } 432 } 433 434 void global_alternate::DestroyGlobalPersisitentVariables() 435 { 436 FX_POSITION pos = m_mapGlobal.GetStartPosition(); 437 while (pos) 438 { 439 CFX_ByteString name; 440 js_global_data* pData = NULL; 441 m_mapGlobal.GetNextAssoc(pos, name, (FX_LPVOID&)pData); 442 delete pData; 443 } 444 445 m_mapGlobal.RemoveAll(); 446 } 447 448 449 FX_BOOL global_alternate::SetGlobalVariables(FX_LPCSTR propname, int nType, 450 double dData, bool bData, const CFX_ByteString& sData, JSObject pData, bool bDefaultPersistent) 451 { 452 if (propname == NULL) return FALSE; 453 454 js_global_data* pTemp = NULL; 455 m_mapGlobal.Lookup(propname, (FX_LPVOID&)pTemp); 456 457 if (pTemp) 458 { 459 if (pTemp->bDeleted || pTemp->nType != nType) 460 { 461 pTemp->dData = 0; 462 pTemp->bData = 0; 463 pTemp->sData = ""; 464 pTemp->nType = nType; 465 } 466 467 pTemp->bDeleted = FALSE; 468 469 switch (nType) 470 { 471 case JS_GLOBALDATA_TYPE_NUMBER: 472 { 473 pTemp->dData = dData; 474 } 475 break; 476 case JS_GLOBALDATA_TYPE_BOOLEAN: 477 { 478 pTemp->bData = bData; 479 } 480 break; 481 case JS_GLOBALDATA_TYPE_STRING: 482 { 483 pTemp->sData = sData; 484 } 485 break; 486 case JS_GLOBALDATA_TYPE_OBJECT: 487 { 488 pTemp->pData.Reset(JS_GetRuntime(pData), pData); 489 } 490 break; 491 case JS_GLOBALDATA_TYPE_NULL: 492 break; 493 default: 494 return FALSE; 495 } 496 497 return TRUE; 498 } 499 500 js_global_data* pNewData = NULL; 501 502 switch (nType) 503 { 504 case JS_GLOBALDATA_TYPE_NUMBER: 505 { 506 pNewData = new js_global_data; 507 pNewData->nType = JS_GLOBALDATA_TYPE_NUMBER; 508 pNewData->dData = dData; 509 pNewData->bPersistent = bDefaultPersistent; 510 } 511 break; 512 case JS_GLOBALDATA_TYPE_BOOLEAN: 513 { 514 pNewData = new js_global_data; 515 pNewData->nType = JS_GLOBALDATA_TYPE_BOOLEAN; 516 pNewData->bData = bData; 517 pNewData->bPersistent = bDefaultPersistent; 518 } 519 break; 520 case JS_GLOBALDATA_TYPE_STRING: 521 { 522 pNewData = new js_global_data; 523 pNewData->nType = JS_GLOBALDATA_TYPE_STRING; 524 pNewData->sData = sData; 525 pNewData->bPersistent = bDefaultPersistent; 526 } 527 break; 528 case JS_GLOBALDATA_TYPE_OBJECT: 529 { 530 pNewData = new js_global_data; 531 pNewData->nType = JS_GLOBALDATA_TYPE_OBJECT; 532 pNewData->pData.Reset(JS_GetRuntime(pData), pData); 533 pNewData->bPersistent = bDefaultPersistent; 534 } 535 break; 536 case JS_GLOBALDATA_TYPE_NULL: 537 { 538 pNewData = new js_global_data; 539 pNewData->nType = JS_GLOBALDATA_TYPE_NULL; 540 pNewData->bPersistent = bDefaultPersistent; 541 } 542 break; 543 default: 544 return FALSE; 545 } 546 547 m_mapGlobal.SetAt(propname, (FX_LPVOID)pNewData); 548 549 return TRUE; 550 } 551