1/* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "V8DOMWrapper.h" 33 34#include "CSSMutableStyleDeclaration.h" 35#include "DOMDataStore.h" 36#include "DOMObjectsInclude.h" 37#include "DocumentLoader.h" 38#include "FrameLoaderClient.h" 39#include "Notification.h" 40#include "SVGElementInstance.h" 41#include "SVGPathSeg.h" 42#include "ScriptController.h" 43#include "V8AbstractEventListener.h" 44#include "V8Binding.h" 45#include "V8Collection.h" 46#include "V8CustomEventListener.h" 47#include "V8DOMApplicationCache.h" 48#include "V8DOMMap.h" 49#include "V8DOMWindow.h" 50#include "V8EventListenerList.h" 51#include "V8HTMLCollection.h" 52#include "V8HTMLDocument.h" 53#include "V8Index.h" 54#include "V8IsolatedContext.h" 55#include "V8Location.h" 56#include "V8MessageChannel.h" 57#include "V8NamedNodeMap.h" 58#include "V8Node.h" 59#include "V8NodeList.h" 60#include "V8Notification.h" 61#include "V8Proxy.h" 62#include "V8SVGElementInstance.h" 63#include "V8SharedWorker.h" 64#include "V8SharedWorkerContext.h" 65#include "V8StyleSheet.h" 66#include "V8WebSocket.h" 67#include "V8Worker.h" 68#include "V8WorkerContext.h" 69#include "V8XMLHttpRequest.h" 70#include "WebGLArray.h" 71#include "WebGLContextAttributes.h" 72#include "WebGLUniformLocation.h" 73#include "WorkerContextExecutionProxy.h" 74 75#include <algorithm> 76#include <utility> 77#include <v8.h> 78#include <v8-debug.h> 79#include <wtf/Assertions.h> 80#include <wtf/OwnArrayPtr.h> 81#include <wtf/StdLibExtras.h> 82#include <wtf/UnusedParam.h> 83 84namespace WebCore { 85 86typedef HashMap<Node*, v8::Object*> DOMNodeMap; 87typedef HashMap<void*, v8::Object*> DOMObjectMap; 88 89#if ENABLE(3D_CANVAS) 90void V8DOMWrapper::setIndexedPropertiesToExternalArray(v8::Handle<v8::Object> wrapper, 91 int index, 92 void* address, 93 int length) 94{ 95 v8::ExternalArrayType array_type = v8::kExternalByteArray; 96 V8ClassIndex::V8WrapperType classIndex = V8ClassIndex::FromInt(index); 97 switch (classIndex) { 98 case V8ClassIndex::WEBGLBYTEARRAY: 99 array_type = v8::kExternalByteArray; 100 break; 101 case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY: 102 array_type = v8::kExternalUnsignedByteArray; 103 break; 104 case V8ClassIndex::WEBGLSHORTARRAY: 105 array_type = v8::kExternalShortArray; 106 break; 107 case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY: 108 array_type = v8::kExternalUnsignedShortArray; 109 break; 110 case V8ClassIndex::WEBGLINTARRAY: 111 array_type = v8::kExternalIntArray; 112 break; 113 case V8ClassIndex::WEBGLUNSIGNEDINTARRAY: 114 array_type = v8::kExternalUnsignedIntArray; 115 break; 116 case V8ClassIndex::WEBGLFLOATARRAY: 117 array_type = v8::kExternalFloatArray; 118 break; 119 default: 120 ASSERT_NOT_REACHED(); 121 } 122 wrapper->SetIndexedPropertiesToExternalArrayData(address, 123 array_type, 124 length); 125} 126#endif 127 128// The caller must have increased obj's ref count. 129void V8DOMWrapper::setJSWrapperForDOMObject(void* object, v8::Persistent<v8::Object> wrapper) 130{ 131 ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper)); 132#ifndef NDEBUG 133 V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper); 134 switch (type) { 135#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: 136 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) 137 ASSERT_NOT_REACHED(); 138#undef MAKE_CASE 139 default: 140 break; 141 } 142#endif 143 getDOMObjectMap().set(object, wrapper); 144} 145 146// The caller must have increased obj's ref count. 147void V8DOMWrapper::setJSWrapperForActiveDOMObject(void* object, v8::Persistent<v8::Object> wrapper) 148{ 149 ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper)); 150#ifndef NDEBUG 151 V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper); 152 switch (type) { 153#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break; 154 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) 155 default: 156 ASSERT_NOT_REACHED(); 157#undef MAKE_CASE 158 } 159#endif 160 getActiveDOMObjectMap().set(object, wrapper); 161} 162 163// The caller must have increased node's ref count. 164void V8DOMWrapper::setJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper) 165{ 166 ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper)); 167 getDOMNodeMap().set(node, wrapper); 168} 169 170v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> objectPrototype) 171{ 172 // A DOM constructor is a function instance created from a DOM constructor 173 // template. There is one instance per context. A DOM constructor is 174 // different from a normal function in two ways: 175 // 1) it cannot be called as constructor (aka, used to create a DOM object) 176 // 2) its __proto__ points to Object.prototype rather than 177 // Function.prototype. 178 // The reason for 2) is that, in Safari, a DOM constructor is a normal JS 179 // object, but not a function. Hotmail relies on the fact that, in Safari, 180 // HTMLElement.__proto__ == Object.prototype. 181 v8::Handle<v8::FunctionTemplate> functionTemplate = V8ClassIndex::getTemplate(type); 182 // Getting the function might fail if we're running out of 183 // stack or memory. 184 v8::TryCatch tryCatch; 185 v8::Local<v8::Function> value = functionTemplate->GetFunction(); 186 if (value.IsEmpty()) 187 return v8::Local<v8::Function>(); 188 // Hotmail fix, see comments above. 189 if (!objectPrototype.IsEmpty()) 190 value->Set(v8::String::New("__proto__"), objectPrototype); 191 return value; 192} 193 194v8::Local<v8::Function> V8DOMWrapper::getConstructorForContext(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Context> context) 195{ 196 // Enter the scope for this context to get the correct constructor. 197 v8::Context::Scope scope(context); 198 199 return getConstructor(type, V8DOMWindowShell::getHiddenObjectPrototype(context)); 200} 201 202v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, DOMWindow* window) 203{ 204 Frame* frame = window->frame(); 205 if (!frame) 206 return v8::Local<v8::Function>(); 207 208 v8::Handle<v8::Context> context = V8Proxy::context(frame); 209 if (context.IsEmpty()) 210 return v8::Local<v8::Function>(); 211 212 return getConstructorForContext(type, context); 213} 214 215#if ENABLE(WORKERS) 216v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, WorkerContext*) 217{ 218 WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); 219 if (!proxy) 220 return v8::Local<v8::Function>(); 221 222 v8::Handle<v8::Context> context = proxy->context(); 223 if (context.IsEmpty()) 224 return v8::Local<v8::Function>(); 225 226 return getConstructorForContext(type, context); 227} 228#endif 229 230void V8DOMWrapper::setHiddenWindowReference(Frame* frame, const int internalIndex, v8::Handle<v8::Object> jsObject) 231{ 232 // Get DOMWindow 233 if (!frame) 234 return; // Object might be detached from window 235 v8::Handle<v8::Context> context = V8Proxy::context(frame); 236 if (context.IsEmpty()) 237 return; 238 239 ASSERT(internalIndex < V8DOMWindow::internalFieldCount); 240 241 v8::Handle<v8::Object> global = context->Global(); 242 // Look for real DOM wrapper. 243 global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); 244 ASSERT(!global.IsEmpty()); 245 ASSERT(global->GetInternalField(internalIndex)->IsUndefined()); 246 global->SetInternalField(internalIndex, jsObject); 247} 248 249V8ClassIndex::V8WrapperType V8DOMWrapper::domWrapperType(v8::Handle<v8::Object> object) 250{ 251 ASSERT(V8DOMWrapper::maybeDOMWrapper(object)); 252 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 253 return V8ClassIndex::FromInt(type->Int32Value()); 254} 255 256PassRefPtr<NodeFilter> V8DOMWrapper::wrapNativeNodeFilter(v8::Handle<v8::Value> filter) 257{ 258 // A NodeFilter is used when walking through a DOM tree or iterating tree 259 // nodes. 260 // FIXME: we may want to cache NodeFilterCondition and NodeFilter 261 // object, but it is minor. 262 // NodeFilter is passed to NodeIterator that has a ref counted pointer 263 // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. 264 // In NodeFilterCondition, filter object is persisted in its constructor, 265 // and disposed in its destructor. 266 if (!filter->IsFunction()) 267 return 0; 268 269 NodeFilterCondition* condition = new V8NodeFilterCondition(filter); 270 return NodeFilter::create(condition); 271} 272 273static bool globalObjectPrototypeIsDOMWindow(v8::Handle<v8::Object> objectPrototype) 274{ 275#if ENABLE(SHARED_WORKERS) 276 // We can identify what type of context the global object is wrapping by looking at the 277 // internal field count of its prototype. This assumes WorkerContexts and DOMWindows have different numbers 278 // of internal fields, so a COMPILE_ASSERT is included to warn if this ever changes. DOMWindow has 279 // traditionally had far more internal fields than any other class. 280 COMPILE_ASSERT(V8DOMWindow::internalFieldCount != V8WorkerContext::internalFieldCount && V8DOMWindow::internalFieldCount != V8SharedWorkerContext::internalFieldCount, 281 DOMWindowAndWorkerContextHaveUnequalFieldCounts); 282#endif 283 return objectPrototype->InternalFieldCount() == V8DOMWindow::internalFieldCount; 284} 285 286v8::Local<v8::Object> V8DOMWrapper::instantiateV8Object(V8Proxy* proxy, V8ClassIndex::V8WrapperType type, void* impl) 287{ 288 WorkerContext* workerContext = 0; 289 if (V8IsolatedContext::getEntered()) { 290 // This effectively disables the wrapper cache for isolated worlds. 291 proxy = 0; 292 // FIXME: Do we need a wrapper cache for the isolated world? We should 293 // see if the performance gains are worth while. 294 // We'll get one once we give the isolated context a proper window shell. 295 } else if (!proxy) { 296 v8::Handle<v8::Context> context = v8::Context::GetCurrent(); 297 if (!context.IsEmpty()) { 298 v8::Handle<v8::Object> globalPrototype = v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype()); 299 if (globalObjectPrototypeIsDOMWindow(globalPrototype)) 300 proxy = V8Proxy::retrieve(V8DOMWindow::toNative(globalPrototype)->frame()); 301#if ENABLE(WORKERS) 302 else 303 workerContext = V8WorkerContext::toNative(globalPrototype); 304#endif 305 } 306 } 307 308 v8::Local<v8::Object> instance; 309 if (proxy) 310 // FIXME: Fix this to work properly with isolated worlds (see above). 311 instance = proxy->windowShell()->createWrapperFromCache(type); 312 else { 313 v8::Local<v8::Function> function; 314#if ENABLE(WORKERS) 315 if (workerContext) 316 function = getConstructor(type, workerContext); 317 else 318#endif 319 function = V8ClassIndex::getTemplate(type)->GetFunction(); 320 instance = SafeAllocation::newInstance(function); 321 } 322 if (!instance.IsEmpty()) { 323 // Avoid setting the DOM wrapper for failed allocations. 324 setDOMWrapper(instance, V8ClassIndex::ToInt(type), impl); 325 } 326 return instance; 327} 328 329#ifndef NDEBUG 330bool V8DOMWrapper::maybeDOMWrapper(v8::Handle<v8::Value> value) 331{ 332 if (value.IsEmpty() || !value->IsObject()) 333 return false; 334 335 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 336 if (!object->InternalFieldCount()) 337 return false; 338 339 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 340 341 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 342 ASSERT(type->IsInt32()); 343 ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END); 344 345 v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex); 346 ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); 347 348 return true; 349} 350#endif 351 352bool V8DOMWrapper::isWrapperOfType(v8::Handle<v8::Value> value, V8ClassIndex::V8WrapperType classType) 353{ 354 if (value.IsEmpty() || !value->IsObject()) 355 return false; 356 357 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 358 if (!object->InternalFieldCount()) 359 return false; 360 361 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 362 363 v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex); 364 ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); 365 366 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 367 ASSERT(type->IsInt32()); 368 ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END); 369 370 return V8ClassIndex::FromInt(type->Int32Value()) == classType; 371} 372 373v8::Handle<v8::Object> V8DOMWrapper::getWrapper(Node* node) 374{ 375 ASSERT(WTF::isMainThread()); 376 V8IsolatedContext* context = V8IsolatedContext::getEntered(); 377 if (LIKELY(!context)) { 378 v8::Persistent<v8::Object>* wrapper = node->wrapper(); 379 if (!wrapper) 380 return v8::Handle<v8::Object>(); 381 return *wrapper; 382 } 383 384 DOMNodeMapping& domNodeMap = context->world()->domDataStore()->domNodeMap(); 385 return domNodeMap.get(node); 386} 387 388// A JS object of type EventTarget is limited to a small number of possible classes. 389// Check EventTarget.h for new type conversion methods 390v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* target) 391{ 392 if (!target) 393 return v8::Null(); 394 395#if ENABLE(SVG) 396 if (SVGElementInstance* instance = target->toSVGElementInstance()) 397 return toV8(instance); 398#endif 399 400#if ENABLE(WORKERS) 401 if (Worker* worker = target->toWorker()) 402 return toV8(worker); 403 404 if (DedicatedWorkerContext* workerContext = target->toDedicatedWorkerContext()) 405 return toV8(workerContext); 406#endif // WORKERS 407 408#if ENABLE(SHARED_WORKERS) 409 if (SharedWorker* sharedWorker = target->toSharedWorker()) 410 return toV8(sharedWorker); 411 412 if (SharedWorkerContext* sharedWorkerContext = target->toSharedWorkerContext()) 413 return toV8(sharedWorkerContext); 414#endif // SHARED_WORKERS 415 416#if ENABLE(NOTIFICATIONS) 417 if (Notification* notification = target->toNotification()) 418 return toV8(notification); 419#endif 420 421#if ENABLE(WEB_SOCKETS) 422 if (WebSocket* webSocket = target->toWebSocket()) 423 return toV8(webSocket); 424#endif 425 426 if (Node* node = target->toNode()) 427 return toV8(node); 428 429 if (DOMWindow* domWindow = target->toDOMWindow()) 430 return toV8(domWindow); 431 432 // XMLHttpRequest is created within its JS counterpart. 433 if (XMLHttpRequest* xmlHttpRequest = target->toXMLHttpRequest()) { 434 v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xmlHttpRequest); 435 ASSERT(!wrapper.IsEmpty()); 436 return wrapper; 437 } 438 439 if (XMLHttpRequest* xhr = target->toXMLHttpRequest()) 440 return toV8(xhr); 441 442 // MessagePort is created within its JS counterpart 443 if (MessagePort* port = target->toMessagePort()) { 444 v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port); 445 ASSERT(!wrapper.IsEmpty()); 446 return wrapper; 447 } 448 449 if (XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload()) { 450 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload); 451 ASSERT(!wrapper.IsEmpty()); 452 return wrapper; 453 } 454 455#if ENABLE(OFFLINE_WEB_APPLICATIONS) 456 if (DOMApplicationCache* domAppCache = target->toDOMApplicationCache()) 457 return toV8(domAppCache); 458#endif 459 460#if ENABLE(EVENTSOURCE) 461 if (EventSource* eventSource = target->toEventSource()) 462 return toV8(eventSource); 463#endif 464 465 ASSERT(0); 466 return notHandledByInterceptor(); 467} 468 469PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 470{ 471 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 472} 473 474#if ENABLE(SVG) 475PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 476{ 477 return getEventListener(element->correspondingElement(), value, isAttribute, lookup); 478} 479#endif 480 481// ANDROID 482// Temporary fix until we merge http://trac.webkit.org/changeset/55096 483#if ENABLE(WORKERS) 484PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 485{ 486 if (worker->scriptExecutionContext()->isWorkerContext()) { 487 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 488 ASSERT(workerContextProxy); 489 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 490 } 491 492 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 493} 494#endif 495 496#if ENABLE(NOTIFICATIONS) 497PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 498{ 499 if (notification->scriptExecutionContext()->isWorkerContext()) { 500 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 501 ASSERT(workerContextProxy); 502 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 503 } 504 505 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 506} 507#endif 508 509// ANDROID 510// Temporary fix until we merge http://trac.webkit.org/changeset/55096 511#if ENABLE(WORKERS) 512PassRefPtr<EventListener> V8DOMWrapper::getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 513{ 514 WorkerContextExecutionProxy* workerContextProxy = workerContext->script()->proxy(); 515 if (workerContextProxy) 516 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 517 518 return 0; 519} 520#endif 521 522PassRefPtr<EventListener> V8DOMWrapper::getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 523{ 524 return getEventListener(upload->associatedXMLHttpRequest(), value, isAttribute, lookup); 525} 526 527#if ENABLE(EVENTSOURCE) 528PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventSource* eventSource, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 529{ 530 if (V8Proxy::retrieve(eventSource->scriptExecutionContext())) 531 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 532 533#if ENABLE(WORKERS) 534 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 535 if (workerContextProxy) 536 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 537#endif 538 539 return 0; 540} 541#endif 542 543PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 544{ 545 if (V8Proxy::retrieve(eventTarget->scriptExecutionContext())) 546 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 547 548#if ENABLE(WORKERS) 549 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 550 if (workerContextProxy) 551 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 552#endif 553 554 return 0; 555} 556 557PassRefPtr<EventListener> V8DOMWrapper::getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 558{ 559 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 560} 561 562} // namespace WebCore 563