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_EventHandler.h" 10 #include "../../include/javascript/JS_Runtime.h" 11 #include "../../include/javascript/JS_Context.h" 12 #include "../../include/javascript/JS_Define.h" 13 #include "../../include/javascript/JS_Object.h" 14 #include "../../include/javascript/JS_Value.h" 15 #include "../../include/javascript/Document.h" 16 #include "../../include/javascript/app.h" 17 #include "../../include/javascript/color.h" 18 #include "../../include/javascript/Consts.h" 19 #include "../../include/javascript/Document.h" 20 #include "../../include/javascript/event.h" 21 #include "../../include/javascript/Field.h" 22 #include "../../include/javascript/Icon.h" 23 #include "../../include/javascript/PublicMethods.h" 24 #include "../../include/javascript/report.h" 25 #include "../../include/javascript/util.h" 26 #include "../../include/javascript/JS_GlobalData.h" 27 #include "../../include/javascript/global.h" 28 #include "../../include/javascript/console.h" 29 30 CJS_RuntimeFactory::~CJS_RuntimeFactory() 31 { 32 } 33 34 IFXJS_Runtime* CJS_RuntimeFactory::NewJSRuntime(CPDFDoc_Environment* pApp) 35 { 36 if (!m_bInit) 37 { 38 JS_Initial(); 39 m_bInit = TRUE; 40 } 41 return new CJS_Runtime(pApp); 42 } 43 void CJS_RuntimeFactory::AddRef() 44 { 45 //to do.Should be implemented as atom manipulation. 46 m_nRef++; 47 } 48 void CJS_RuntimeFactory::Release() 49 { 50 if(m_bInit) 51 { 52 //to do.Should be implemented as atom manipulation. 53 if (--m_nRef == 0) 54 { 55 JS_Release(); 56 ReleaseGlobalData(); 57 m_bInit = FALSE; 58 } 59 } 60 } 61 62 void CJS_RuntimeFactory::DeleteJSRuntime(IFXJS_Runtime* pRuntime) 63 { 64 if(pRuntime) 65 delete (CJS_Runtime*)pRuntime; 66 } 67 68 CJS_GlobalData* CJS_RuntimeFactory::NewGlobalData(CPDFDoc_Environment* pApp) 69 { 70 if (m_pGlobalData) 71 { 72 m_nGlobalDataCount++; 73 return m_pGlobalData; 74 } 75 else 76 { 77 m_nGlobalDataCount = 1; 78 m_pGlobalData = new CJS_GlobalData(pApp); 79 return m_pGlobalData; 80 } 81 } 82 83 void CJS_RuntimeFactory::ReleaseGlobalData() 84 { 85 m_nGlobalDataCount--; 86 87 if (m_nGlobalDataCount <= 0) 88 { 89 delete m_pGlobalData; 90 m_pGlobalData = NULL; 91 } 92 } 93 94 void* CJS_ArrayBufferAllocator::Allocate(size_t length) { 95 return calloc(1, length); 96 } 97 98 void* CJS_ArrayBufferAllocator::AllocateUninitialized(size_t length) { 99 return malloc(length); 100 } 101 102 void CJS_ArrayBufferAllocator::Free(void* data, size_t length) { 103 free(data); 104 } 105 106 /* ------------------------------ CJS_Runtime ------------------------------ */ 107 108 CJS_Runtime::CJS_Runtime(CPDFDoc_Environment * pApp) : 109 m_pApp(pApp), 110 m_pDocument(NULL), 111 m_bBlocking(FALSE), 112 m_bRegistered(FALSE), 113 m_pFieldEventPath(NULL) 114 { 115 m_pArrayBufferAllocator.reset(new CJS_ArrayBufferAllocator()); 116 117 v8::Isolate::CreateParams params; 118 params.array_buffer_allocator = m_pArrayBufferAllocator.get(); 119 m_isolate = v8::Isolate::New(params); 120 121 InitJSObjects(); 122 123 CJS_Context * pContext = (CJS_Context*)NewContext(); 124 JS_InitialRuntime(*this, this, pContext, m_context); 125 ReleaseContext(pContext); 126 } 127 128 CJS_Runtime::~CJS_Runtime() 129 { 130 for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++) 131 delete m_ContextArray.GetAt(i); 132 133 m_ContextArray.RemoveAll(); 134 135 JS_ReleaseRuntime(*this, m_context); 136 137 RemoveEventsInLoop(m_pFieldEventPath); 138 139 m_pApp = NULL; 140 m_pDocument = NULL; 141 m_pFieldEventPath = NULL; 142 m_context.Reset(); 143 144 //m_isolate->Exit(); 145 m_isolate->Dispose(); 146 } 147 148 FX_BOOL CJS_Runtime::InitJSObjects() 149 { 150 v8::Isolate::Scope isolate_scope(GetIsolate()); 151 v8::HandleScope handle_scope(GetIsolate()); 152 v8::Local<v8::Context> context = v8::Context::New(GetIsolate()); 153 v8::Context::Scope context_scope(context); 154 //0 - 8 155 if (CJS_Border::Init(*this, JS_STATIC) < 0) return FALSE; 156 if (CJS_Display::Init(*this, JS_STATIC) < 0) return FALSE; 157 if (CJS_Font::Init(*this, JS_STATIC) < 0) return FALSE; 158 if (CJS_Highlight::Init(*this, JS_STATIC) < 0) return FALSE; 159 if (CJS_Position::Init(*this, JS_STATIC) < 0) return FALSE; 160 if (CJS_ScaleHow::Init(*this, JS_STATIC) < 0) return FALSE; 161 if (CJS_ScaleWhen::Init(*this, JS_STATIC) < 0) return FALSE; 162 if (CJS_Style::Init(*this, JS_STATIC) < 0) return FALSE; 163 if (CJS_Zoomtype::Init(*this, JS_STATIC) < 0) return FALSE; 164 165 //9 - 11 166 if (CJS_App::Init(*this, JS_STATIC) < 0) return FALSE; 167 if (CJS_Color::Init(*this, JS_STATIC) < 0) return FALSE; 168 if (CJS_Console::Init(*this, JS_STATIC) < 0) return FALSE; 169 170 //12 - 14 171 if (CJS_Document::Init(*this, JS_DYNAMIC) < 0) return FALSE; 172 if (CJS_Event::Init(*this, JS_STATIC) < 0) return FALSE; 173 if (CJS_Field::Init(*this, JS_DYNAMIC) < 0) return FALSE; 174 175 //15 - 17 176 if (CJS_Global::Init(*this, JS_STATIC) < 0) return FALSE; 177 if (CJS_Icon::Init(*this, JS_DYNAMIC) < 0) return FALSE; 178 if (CJS_Util::Init(*this, JS_STATIC) < 0) return FALSE; 179 180 if (CJS_PublicMethods::Init(*this) < 0) return FALSE; 181 if (CJS_GlobalConsts::Init(*this) < 0) return FALSE; 182 if (CJS_GlobalArrays::Init(*this) < 0) return FALSE; 183 184 if (CJS_TimerObj::Init(*this, JS_DYNAMIC) < 0) return FALSE; 185 if (CJS_PrintParamsObj::Init(*this, JS_DYNAMIC) <0) return FALSE; 186 187 return TRUE; 188 } 189 190 IFXJS_Context* CJS_Runtime::NewContext() 191 { 192 CJS_Context * p = new CJS_Context(this); 193 m_ContextArray.Add(p); 194 return p; 195 } 196 197 void CJS_Runtime::ReleaseContext(IFXJS_Context * pContext) 198 { 199 CJS_Context* pJSContext = (CJS_Context*)pContext; 200 201 for (int i=0, sz=m_ContextArray.GetSize(); i<sz; i++) 202 { 203 if (pJSContext == m_ContextArray.GetAt(i)) 204 { 205 delete pJSContext; 206 m_ContextArray.RemoveAt(i); 207 break; 208 } 209 } 210 } 211 212 IFXJS_Context* CJS_Runtime::GetCurrentContext() 213 { 214 if(!m_ContextArray.GetSize()) 215 return NULL; 216 return m_ContextArray.GetAt(m_ContextArray.GetSize()-1); 217 } 218 219 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc) 220 { 221 if (m_pDocument != pReaderDoc) 222 { 223 v8::Isolate::Scope isolate_scope(m_isolate); 224 v8::HandleScope handle_scope(m_isolate); 225 v8::Local<v8::Context> context =v8::Local<v8::Context>::New(m_isolate, m_context); 226 v8::Context::Scope context_scope(context); 227 228 m_pDocument = pReaderDoc; 229 230 if (pReaderDoc) 231 { 232 JSObject pThis = JS_GetThisObj(*this); 233 if(!pThis.IsEmpty()) 234 { 235 if (JS_GetObjDefnID(pThis) == JS_GetObjDefnID(*this, L"Document")) 236 { 237 if (CJS_Document* pJSDocument = (CJS_Document*)JS_GetPrivate(pThis)) 238 { 239 if (Document * pDocument = (Document*)pJSDocument->GetEmbedObject()) 240 pDocument->AttachDoc(pReaderDoc); 241 } 242 } 243 } 244 JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"Document")); 245 } 246 else 247 { 248 JS_SetThisObj(*this, JS_GetObjDefnID(*this, L"app")); 249 } 250 } 251 } 252 253 FX_BOOL CJS_Runtime::AddEventToLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType) 254 { 255 if (m_pFieldEventPath == NULL) 256 { 257 m_pFieldEventPath = new CJS_FieldEvent; 258 m_pFieldEventPath->sTargetName = sTargetName; 259 m_pFieldEventPath->eEventType = eEventType; 260 m_pFieldEventPath->pNext = NULL; 261 262 return TRUE; 263 } 264 265 //to search 266 CJS_FieldEvent* p = m_pFieldEventPath; 267 CJS_FieldEvent* pLast = m_pFieldEventPath; 268 while (p) 269 { 270 if (p->eEventType == eEventType && p->sTargetName == sTargetName) 271 return FALSE; 272 273 pLast = p; 274 p = p->pNext; 275 } 276 277 //to add 278 CJS_FieldEvent* pNew = new CJS_FieldEvent; 279 pNew->sTargetName = sTargetName; 280 pNew->eEventType = eEventType; 281 pNew->pNext = NULL; 282 283 pLast->pNext = pNew; 284 285 return TRUE; 286 } 287 288 void CJS_Runtime::RemoveEventInLoop(const CFX_WideString& sTargetName, JS_EVENT_T eEventType) 289 { 290 FX_BOOL bFind = FALSE; 291 292 CJS_FieldEvent* p = m_pFieldEventPath; 293 CJS_FieldEvent* pLast = NULL; 294 while (p) 295 { 296 if (p->eEventType == eEventType && p->sTargetName == sTargetName) 297 { 298 bFind = TRUE; 299 break; 300 } 301 302 pLast = p; 303 p = p->pNext; 304 } 305 306 if (bFind) 307 { 308 RemoveEventsInLoop(p); 309 310 if (p == m_pFieldEventPath) 311 m_pFieldEventPath = NULL; 312 313 if (pLast) 314 pLast->pNext = NULL; 315 } 316 } 317 318 void CJS_Runtime::RemoveEventsInLoop(CJS_FieldEvent* pStart) 319 { 320 CJS_FieldEvent* p = pStart; 321 322 while (p) 323 { 324 CJS_FieldEvent* pOld = p; 325 p = pOld->pNext; 326 327 delete pOld; 328 } 329 } 330 331 v8::Local<v8::Context> CJS_Runtime::NewJSContext() 332 { 333 return v8::Local<v8::Context>::New(m_isolate, m_context); 334 } 335 336 CFX_WideString ChangeObjName(const CFX_WideString& str) 337 { 338 CFX_WideString sRet = str; 339 sRet.Replace(L"_", L"."); 340 return sRet; 341 } 342