V8DOMWrapper.cpp revision ad783d5592b8bd1fd37a8e1cba58e0d703ebc6d2
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 215v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, WorkerContext*) 216{ 217 WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); 218 if (!proxy) 219 return v8::Local<v8::Function>(); 220 221 v8::Handle<v8::Context> context = proxy->context(); 222 if (context.IsEmpty()) 223 return v8::Local<v8::Function>(); 224 225 return getConstructorForContext(type, context); 226} 227 228void V8DOMWrapper::setHiddenWindowReference(Frame* frame, const int internalIndex, v8::Handle<v8::Object> jsObject) 229{ 230 // Get DOMWindow 231 if (!frame) 232 return; // Object might be detached from window 233 v8::Handle<v8::Context> context = V8Proxy::context(frame); 234 if (context.IsEmpty()) 235 return; 236 237 ASSERT(internalIndex < V8DOMWindow::internalFieldCount); 238 239 v8::Handle<v8::Object> global = context->Global(); 240 // Look for real DOM wrapper. 241 global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); 242 ASSERT(!global.IsEmpty()); 243 ASSERT(global->GetInternalField(internalIndex)->IsUndefined()); 244 global->SetInternalField(internalIndex, jsObject); 245} 246 247V8ClassIndex::V8WrapperType V8DOMWrapper::domWrapperType(v8::Handle<v8::Object> object) 248{ 249 ASSERT(V8DOMWrapper::maybeDOMWrapper(object)); 250 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 251 return V8ClassIndex::FromInt(type->Int32Value()); 252} 253 254PassRefPtr<NodeFilter> V8DOMWrapper::wrapNativeNodeFilter(v8::Handle<v8::Value> filter) 255{ 256 // A NodeFilter is used when walking through a DOM tree or iterating tree 257 // nodes. 258 // FIXME: we may want to cache NodeFilterCondition and NodeFilter 259 // object, but it is minor. 260 // NodeFilter is passed to NodeIterator that has a ref counted pointer 261 // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. 262 // In NodeFilterCondition, filter object is persisted in its constructor, 263 // and disposed in its destructor. 264 if (!filter->IsFunction()) 265 return 0; 266 267 NodeFilterCondition* condition = new V8NodeFilterCondition(filter); 268 return NodeFilter::create(condition); 269} 270 271static bool globalObjectPrototypeIsDOMWindow(v8::Handle<v8::Object> objectPrototype) 272{ 273 // We can identify what type of context the global object is wrapping by looking at the 274 // internal field count of its prototype. This assumes WorkerContexts and DOMWindows have different numbers 275 // of internal fields, so a COMPILE_ASSERT is included to warn if this ever changes. DOMWindow has 276 // traditionally had far more internal fields than any other class. 277 COMPILE_ASSERT(V8DOMWindow::internalFieldCount != V8WorkerContext::internalFieldCount && V8DOMWindow::internalFieldCount != V8SharedWorkerContext::internalFieldCount, 278 DOMWindowAndWorkerContextHaveUnequalFieldCounts); 279 return objectPrototype->InternalFieldCount() == V8DOMWindow::internalFieldCount; 280} 281 282v8::Local<v8::Object> V8DOMWrapper::instantiateV8Object(V8Proxy* proxy, V8ClassIndex::V8WrapperType type, void* impl) 283{ 284 WorkerContext* workerContext = 0; 285 if (V8IsolatedContext::getEntered()) { 286 // This effectively disables the wrapper cache for isolated worlds. 287 proxy = 0; 288 // FIXME: Do we need a wrapper cache for the isolated world? We should 289 // see if the performance gains are worth while. 290 // We'll get one once we give the isolated context a proper window shell. 291 } else if (!proxy) { 292 v8::Handle<v8::Context> context = v8::Context::GetCurrent(); 293 if (!context.IsEmpty()) { 294 v8::Handle<v8::Object> globalPrototype = v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype()); 295 if (globalObjectPrototypeIsDOMWindow(globalPrototype)) 296 proxy = V8Proxy::retrieve(V8DOMWindow::toNative(globalPrototype)->frame()); 297 else 298 workerContext = V8WorkerContext::toNative(globalPrototype); 299 } 300 } 301 302 v8::Local<v8::Object> instance; 303 if (proxy) 304 // FIXME: Fix this to work properly with isolated worlds (see above). 305 instance = proxy->windowShell()->createWrapperFromCache(type); 306 else { 307 v8::Local<v8::Function> function; 308 if (workerContext) 309 function = getConstructor(type, workerContext); 310 else 311 function = V8ClassIndex::getTemplate(type)->GetFunction(); 312 instance = SafeAllocation::newInstance(function); 313 } 314 if (!instance.IsEmpty()) { 315 // Avoid setting the DOM wrapper for failed allocations. 316 setDOMWrapper(instance, V8ClassIndex::ToInt(type), impl); 317 } 318 return instance; 319} 320 321#ifndef NDEBUG 322bool V8DOMWrapper::maybeDOMWrapper(v8::Handle<v8::Value> value) 323{ 324 if (value.IsEmpty() || !value->IsObject()) 325 return false; 326 327 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 328 if (!object->InternalFieldCount()) 329 return false; 330 331 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 332 333 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 334 ASSERT(type->IsInt32()); 335 ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END); 336 337 v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex); 338 ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); 339 340 return true; 341} 342#endif 343 344bool V8DOMWrapper::isWrapperOfType(v8::Handle<v8::Value> value, V8ClassIndex::V8WrapperType classType) 345{ 346 if (value.IsEmpty() || !value->IsObject()) 347 return false; 348 349 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 350 if (!object->InternalFieldCount()) 351 return false; 352 353 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 354 355 v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex); 356 ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); 357 358 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 359 ASSERT(type->IsInt32()); 360 ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END); 361 362 return V8ClassIndex::FromInt(type->Int32Value()) == classType; 363} 364 365v8::Handle<v8::Object> V8DOMWrapper::getWrapper(Node* node) 366{ 367 ASSERT(WTF::isMainThread()); 368 V8IsolatedContext* context = V8IsolatedContext::getEntered(); 369 if (LIKELY(!context)) { 370 v8::Persistent<v8::Object>* wrapper = node->wrapper(); 371 if (!wrapper) 372 return v8::Handle<v8::Object>(); 373 return *wrapper; 374 } 375 376 DOMNodeMapping& domNodeMap = context->world()->domDataStore()->domNodeMap(); 377 return domNodeMap.get(node); 378} 379 380// A JS object of type EventTarget is limited to a small number of possible classes. 381// Check EventTarget.h for new type conversion methods 382v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* target) 383{ 384 if (!target) 385 return v8::Null(); 386 387#if ENABLE(SVG) 388 if (SVGElementInstance* instance = target->toSVGElementInstance()) 389 return toV8(instance); 390#endif 391 392#if ENABLE(WORKERS) 393 if (Worker* worker = target->toWorker()) 394 return toV8(worker); 395 396 if (DedicatedWorkerContext* workerContext = target->toDedicatedWorkerContext()) 397 return toV8(workerContext); 398#endif // WORKERS 399 400#if ENABLE(SHARED_WORKERS) 401 if (SharedWorker* sharedWorker = target->toSharedWorker()) 402 return toV8(sharedWorker); 403 404 if (SharedWorkerContext* sharedWorkerContext = target->toSharedWorkerContext()) 405 return toV8(sharedWorkerContext); 406#endif // SHARED_WORKERS 407 408#if ENABLE(NOTIFICATIONS) 409 if (Notification* notification = target->toNotification()) 410 return toV8(notification); 411#endif 412 413#if ENABLE(WEB_SOCKETS) 414 if (WebSocket* webSocket = target->toWebSocket()) 415 return toV8(webSocket); 416#endif 417 418 if (Node* node = target->toNode()) 419 return toV8(node); 420 421 if (DOMWindow* domWindow = target->toDOMWindow()) 422 return toV8(domWindow); 423 424 // XMLHttpRequest is created within its JS counterpart. 425 if (XMLHttpRequest* xmlHttpRequest = target->toXMLHttpRequest()) { 426 v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xmlHttpRequest); 427 ASSERT(!wrapper.IsEmpty()); 428 return wrapper; 429 } 430 431 if (XMLHttpRequest* xhr = target->toXMLHttpRequest()) 432 return toV8(xhr); 433 434 // MessagePort is created within its JS counterpart 435 if (MessagePort* port = target->toMessagePort()) { 436 v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port); 437 ASSERT(!wrapper.IsEmpty()); 438 return wrapper; 439 } 440 441 if (XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload()) { 442 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload); 443 ASSERT(!wrapper.IsEmpty()); 444 return wrapper; 445 } 446 447#if ENABLE(OFFLINE_WEB_APPLICATIONS) 448 if (DOMApplicationCache* domAppCache = target->toDOMApplicationCache()) 449 return toV8(domAppCache); 450#endif 451 452#if ENABLE(EVENTSOURCE) 453 if (EventSource* eventSource = target->toEventSource()) 454 return toV8(eventSource); 455#endif 456 457 ASSERT(0); 458 return notHandledByInterceptor(); 459} 460 461PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 462{ 463 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 464} 465 466#if ENABLE(SVG) 467PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 468{ 469 return getEventListener(element->correspondingElement(), value, isAttribute, lookup); 470} 471#endif 472 473PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 474{ 475 if (worker->scriptExecutionContext()->isWorkerContext()) { 476 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 477 ASSERT(workerContextProxy); 478 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 479 } 480 481 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 482} 483 484#if ENABLE(NOTIFICATIONS) 485PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 486{ 487 if (notification->scriptExecutionContext()->isWorkerContext()) { 488 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 489 ASSERT(workerContextProxy); 490 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 491 } 492 493 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 494} 495#endif 496 497PassRefPtr<EventListener> V8DOMWrapper::getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 498{ 499 WorkerContextExecutionProxy* workerContextProxy = workerContext->script()->proxy(); 500 if (workerContextProxy) 501 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 502 503 return 0; 504} 505 506PassRefPtr<EventListener> V8DOMWrapper::getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 507{ 508 return getEventListener(upload->associatedXMLHttpRequest(), value, isAttribute, lookup); 509} 510 511#if ENABLE(EVENTSOURCE) 512PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventSource* eventSource, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 513{ 514 if (V8Proxy::retrieve(eventSource->scriptExecutionContext())) 515 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 516 517#if ENABLE(WORKERS) 518 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 519 if (workerContextProxy) 520 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 521#endif 522 523 return 0; 524} 525#endif 526 527PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 528{ 529 if (V8Proxy::retrieve(eventTarget->scriptExecutionContext())) 530 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 531 532#if ENABLE(WORKERS) 533 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 534 if (workerContextProxy) 535 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 536#endif 537 538 return 0; 539} 540 541PassRefPtr<EventListener> V8DOMWrapper::getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 542{ 543 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 544} 545 546} // namespace WebCore 547