Home | History | Annotate | Download | only in javascript
      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