V8DOMWrapper.cpp revision 8b17ffea299c44342b5479322adcb686277df548
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 "V8CustomBinding.h" 47#include "V8CustomEventListener.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 "V8MessageChannel.h" 56#include "V8Location.h" 57#include "V8NamedNodeMap.h" 58#include "V8NodeList.h" 59#include "V8Proxy.h" 60#include "V8StyleSheet.h" 61#include "WebGLArray.h" 62#include "WebGLContextAttributes.h" 63#include "WebGLUniformLocation.h" 64#include "WorkerContextExecutionProxy.h" 65 66#include <algorithm> 67#include <utility> 68#include <v8.h> 69#include <v8-debug.h> 70#include <wtf/Assertions.h> 71#include <wtf/OwnArrayPtr.h> 72#include <wtf/StdLibExtras.h> 73#include <wtf/UnusedParam.h> 74 75namespace WebCore { 76 77typedef HashMap<Node*, v8::Object*> DOMNodeMap; 78typedef HashMap<void*, v8::Object*> DOMObjectMap; 79 80#if ENABLE(SVG) 81 82static V8ClassIndex::V8WrapperType downcastSVGPathSeg(void* pathSeg) 83{ 84 SVGPathSeg* realPathSeg = reinterpret_cast<SVGPathSeg*>(pathSeg); 85 86 switch (realPathSeg->pathSegType()) { 87 case SVGPathSeg::PATHSEG_CLOSEPATH: return V8ClassIndex::SVGPATHSEGCLOSEPATH; 88 case SVGPathSeg::PATHSEG_MOVETO_ABS: return V8ClassIndex::SVGPATHSEGMOVETOABS; 89 case SVGPathSeg::PATHSEG_MOVETO_REL: return V8ClassIndex::SVGPATHSEGMOVETOREL; 90 case SVGPathSeg::PATHSEG_LINETO_ABS: return V8ClassIndex::SVGPATHSEGLINETOABS; 91 case SVGPathSeg::PATHSEG_LINETO_REL: return V8ClassIndex::SVGPATHSEGLINETOREL; 92 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS: return V8ClassIndex::SVGPATHSEGCURVETOCUBICABS; 93 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_REL: return V8ClassIndex::SVGPATHSEGCURVETOCUBICREL; 94 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS: return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICABS; 95 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL: return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICREL; 96 case SVGPathSeg::PATHSEG_ARC_ABS: return V8ClassIndex::SVGPATHSEGARCABS; 97 case SVGPathSeg::PATHSEG_ARC_REL: return V8ClassIndex::SVGPATHSEGARCREL; 98 case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS: return V8ClassIndex::SVGPATHSEGLINETOHORIZONTALABS; 99 case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL: return V8ClassIndex::SVGPATHSEGLINETOHORIZONTALREL; 100 case SVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS: return V8ClassIndex::SVGPATHSEGLINETOVERTICALABS; 101 case SVGPathSeg::PATHSEG_LINETO_VERTICAL_REL: return V8ClassIndex::SVGPATHSEGLINETOVERTICALREL; 102 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: return V8ClassIndex::SVGPATHSEGCURVETOCUBICSMOOTHABS; 103 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL: return V8ClassIndex::SVGPATHSEGCURVETOCUBICSMOOTHREL; 104 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICSMOOTHABS; 105 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: return V8ClassIndex::SVGPATHSEGCURVETOQUADRATICSMOOTHREL; 106 default: return V8ClassIndex::INVALID_CLASS_INDEX; 107 } 108} 109 110v8::Handle<v8::Value> V8DOMWrapper::convertSVGElementInstanceToV8Object(SVGElementInstance* instance) 111{ 112 if (!instance) 113 return v8::Null(); 114 115 v8::Handle<v8::Object> existingInstance = getDOMSVGElementInstanceMap().get(instance); 116 if (!existingInstance.IsEmpty()) 117 return existingInstance; 118 119 instance->ref(); 120 121 // Instantiate the V8 object and remember it 122 v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, V8ClassIndex::SVGELEMENTINSTANCE, instance); 123 if (!result.IsEmpty()) { 124 // Only update the DOM SVG element map if the result is non-empty. 125 getDOMSVGElementInstanceMap().set(instance, v8::Persistent<v8::Object>::New(result)); 126 } 127 return result; 128} 129 130v8::Handle<v8::Value> V8DOMWrapper::convertSVGObjectWithContextToV8Object(V8ClassIndex::V8WrapperType type, void* object) 131{ 132 if (!object) 133 return v8::Null(); 134 135 v8::Persistent<v8::Object> result = getDOMSVGObjectWithContextMap().get(object); 136 if (!result.IsEmpty()) 137 return result; 138 139 // Special case: SVGPathSegs need to be downcast to their real type 140 if (type == V8ClassIndex::SVGPATHSEG) 141 type = downcastSVGPathSeg(object); 142 143 v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, object); 144 if (!v8Object.IsEmpty()) { 145 result = v8::Persistent<v8::Object>::New(v8Object); 146 switch (type) { 147#define MAKE_CASE(TYPE, NAME) \ 148 case V8ClassIndex::TYPE: static_cast<NAME*>(object)->ref(); break; 149 SVG_OBJECT_TYPES(MAKE_CASE) 150#undef MAKE_CASE 151#define MAKE_CASE(TYPE, NAME) \ 152 case V8ClassIndex::TYPE: \ 153 static_cast<V8SVGPODTypeWrapper<NAME>*>(object)->ref(); break; 154 SVG_POD_NATIVE_TYPES(MAKE_CASE) 155#undef MAKE_CASE 156 default: 157 ASSERT_NOT_REACHED(); 158 } 159 getDOMSVGObjectWithContextMap().set(object, result); 160 } 161 162 return result; 163} 164 165#endif // ENABLE(SVG) 166 167#if ENABLE(3D_CANVAS) 168void V8DOMWrapper::setIndexedPropertiesToExternalArray(v8::Handle<v8::Object> wrapper, 169 int index, 170 void* address, 171 int length) 172{ 173 v8::ExternalArrayType array_type = v8::kExternalByteArray; 174 V8ClassIndex::V8WrapperType classIndex = V8ClassIndex::FromInt(index); 175 switch (classIndex) { 176 case V8ClassIndex::WEBGLBYTEARRAY: 177 array_type = v8::kExternalByteArray; 178 break; 179 case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY: 180 array_type = v8::kExternalUnsignedByteArray; 181 break; 182 case V8ClassIndex::WEBGLSHORTARRAY: 183 array_type = v8::kExternalShortArray; 184 break; 185 case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY: 186 array_type = v8::kExternalUnsignedShortArray; 187 break; 188 case V8ClassIndex::WEBGLINTARRAY: 189 array_type = v8::kExternalIntArray; 190 break; 191 case V8ClassIndex::WEBGLUNSIGNEDINTARRAY: 192 array_type = v8::kExternalUnsignedIntArray; 193 break; 194 case V8ClassIndex::WEBGLFLOATARRAY: 195 array_type = v8::kExternalFloatArray; 196 break; 197 default: 198 ASSERT_NOT_REACHED(); 199 } 200 wrapper->SetIndexedPropertiesToExternalArrayData(address, 201 array_type, 202 length); 203} 204#endif 205 206// The caller must have increased obj's ref count. 207void V8DOMWrapper::setJSWrapperForDOMObject(void* object, v8::Persistent<v8::Object> wrapper) 208{ 209 ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper)); 210#ifndef NDEBUG 211 V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper); 212 switch (type) { 213#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: 214 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) 215 ASSERT_NOT_REACHED(); 216#undef MAKE_CASE 217 default: 218 break; 219 } 220#endif 221 getDOMObjectMap().set(object, wrapper); 222} 223 224// The caller must have increased obj's ref count. 225void V8DOMWrapper::setJSWrapperForActiveDOMObject(void* object, v8::Persistent<v8::Object> wrapper) 226{ 227 ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper)); 228#ifndef NDEBUG 229 V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper); 230 switch (type) { 231#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break; 232 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) 233 default: 234 ASSERT_NOT_REACHED(); 235#undef MAKE_CASE 236 } 237#endif 238 getActiveDOMObjectMap().set(object, wrapper); 239} 240 241// The caller must have increased node's ref count. 242void V8DOMWrapper::setJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper) 243{ 244 ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper)); 245 getDOMNodeMap().set(node, wrapper); 246} 247 248v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8WrapperType type) 249{ 250 v8::Persistent<v8::FunctionTemplate>* cacheCell = V8ClassIndex::GetCache(type); 251 if (!cacheCell->IsEmpty()) 252 return *cacheCell; 253 254 // Not in the cache. 255 FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type); 256 v8::Persistent<v8::FunctionTemplate> descriptor = factory(); 257 258 *cacheCell = descriptor; 259 return descriptor; 260} 261 262v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> objectPrototype) 263{ 264 // A DOM constructor is a function instance created from a DOM constructor 265 // template. There is one instance per context. A DOM constructor is 266 // different from a normal function in two ways: 267 // 1) it cannot be called as constructor (aka, used to create a DOM object) 268 // 2) its __proto__ points to Object.prototype rather than 269 // Function.prototype. 270 // The reason for 2) is that, in Safari, a DOM constructor is a normal JS 271 // object, but not a function. Hotmail relies on the fact that, in Safari, 272 // HTMLElement.__proto__ == Object.prototype. 273 v8::Handle<v8::FunctionTemplate> functionTemplate = getTemplate(type); 274 // Getting the function might fail if we're running out of 275 // stack or memory. 276 v8::TryCatch tryCatch; 277 v8::Local<v8::Function> value = functionTemplate->GetFunction(); 278 if (value.IsEmpty()) 279 return v8::Local<v8::Function>(); 280 // Hotmail fix, see comments above. 281 if (!objectPrototype.IsEmpty()) 282 value->Set(v8::String::New("__proto__"), objectPrototype); 283 return value; 284} 285 286v8::Local<v8::Function> V8DOMWrapper::getConstructorForContext(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Context> context) 287{ 288 // Enter the scope for this context to get the correct constructor. 289 v8::Context::Scope scope(context); 290 291 return getConstructor(type, V8DOMWindowShell::getHiddenObjectPrototype(context)); 292} 293 294v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, DOMWindow* window) 295{ 296 Frame* frame = window->frame(); 297 if (!frame) 298 return v8::Local<v8::Function>(); 299 300 v8::Handle<v8::Context> context = V8Proxy::context(frame); 301 if (context.IsEmpty()) 302 return v8::Local<v8::Function>(); 303 304 return getConstructorForContext(type, context); 305} 306 307v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, WorkerContext*) 308{ 309 WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve(); 310 if (!proxy) 311 return v8::Local<v8::Function>(); 312 313 v8::Handle<v8::Context> context = proxy->context(); 314 if (context.IsEmpty()) 315 return v8::Local<v8::Function>(); 316 317 return getConstructorForContext(type, context); 318} 319 320v8::Handle<v8::Value> V8DOMWrapper::convertToV8Object(V8ClassIndex::V8WrapperType type, void* impl) 321{ 322 ASSERT(type != V8ClassIndex::EVENTLISTENER); 323 ASSERT(type != V8ClassIndex::EVENTTARGET); 324 ASSERT(type != V8ClassIndex::EVENT); 325 326 // These objects can be constructed under WorkerContextExecutionProxy. They need special 327 // handling, since if we proceed below V8Proxy::retrieve() will get called and will crash. 328 // TODO(ukai): websocket? 329 if ((type == V8ClassIndex::DOMCOREEXCEPTION 330 || type == V8ClassIndex::RANGEEXCEPTION 331 || type == V8ClassIndex::EVENTEXCEPTION 332 || type == V8ClassIndex::XMLHTTPREQUESTEXCEPTION 333 || type == V8ClassIndex::MESSAGEPORT) 334 && WorkerContextExecutionProxy::retrieve()) { 335 return WorkerContextExecutionProxy::convertToV8Object(type, impl); 336 } 337 338 bool isActiveDomObject = false; 339 switch (type) { 340#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: 341 DOM_NODE_TYPES(MAKE_CASE) 342#if ENABLE(SVG) 343 SVG_NODE_TYPES(MAKE_CASE) 344#endif 345 return convertNodeToV8Object(static_cast<Node*>(impl)); 346 case V8ClassIndex::CSSVALUE: 347 return convertCSSValueToV8Object(static_cast<CSSValue*>(impl)); 348 case V8ClassIndex::CSSRULE: 349 return convertCSSRuleToV8Object(static_cast<CSSRule*>(impl)); 350 case V8ClassIndex::STYLESHEET: 351 return convertStyleSheetToV8Object(static_cast<StyleSheet*>(impl)); 352 case V8ClassIndex::DOMWINDOW: 353 return convertWindowToV8Object(static_cast<DOMWindow*>(impl)); 354 case V8ClassIndex::NAMEDNODEMAP: 355 return convertNamedNodeMapToV8Object(static_cast<NamedNodeMap*>(impl)); 356#if ENABLE(SVG) 357 SVG_NONNODE_TYPES(MAKE_CASE) 358 if (type == V8ClassIndex::SVGELEMENTINSTANCE) 359 return convertSVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(impl)); 360 return convertSVGObjectWithContextToV8Object(type, impl); 361#endif 362 363 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) 364 isActiveDomObject = true; 365 break; 366 default: 367 break; 368 } 369 370#undef MAKE_CASE 371 372 if (!impl) 373 return v8::Null(); 374 375 // Non DOM node 376 v8::Persistent<v8::Object> result = isActiveDomObject ? getActiveDOMObjectMap().get(impl) : getDOMObjectMap().get(impl); 377 if (result.IsEmpty()) { 378#if ENABLE(3D_CANVAS) 379 if (type == V8ClassIndex::WEBGLARRAY && impl) { 380 // Determine which subclass we are wrapping. 381 WebGLArray* array = reinterpret_cast<WebGLArray*>(impl); 382 if (array->isByteArray()) 383 type = V8ClassIndex::WEBGLBYTEARRAY; 384 else if (array->isFloatArray()) 385 type = V8ClassIndex::WEBGLFLOATARRAY; 386 else if (array->isIntArray()) 387 type = V8ClassIndex::WEBGLINTARRAY; 388 else if (array->isShortArray()) 389 type = V8ClassIndex::WEBGLSHORTARRAY; 390 else if (array->isUnsignedByteArray()) 391 type = V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY; 392 else if (array->isUnsignedIntArray()) 393 type = V8ClassIndex::WEBGLUNSIGNEDINTARRAY; 394 else if (array->isUnsignedShortArray()) 395 type = V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY; 396 } 397#endif 398 399 v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, impl); 400 if (!v8Object.IsEmpty()) { 401 // Go through big switch statement, it has some duplications 402 // that were handled by code above (such as CSSVALUE, CSSRULE, etc). 403 switch (type) { 404#define MAKE_CASE(TYPE, NAME) \ 405 case V8ClassIndex::TYPE: static_cast<NAME*>(impl)->ref(); break; 406 DOM_OBJECT_TYPES(MAKE_CASE) 407#undef MAKE_CASE 408 default: 409 ASSERT_NOT_REACHED(); 410 } 411 result = v8::Persistent<v8::Object>::New(v8Object); 412 if (isActiveDomObject) 413 setJSWrapperForActiveDOMObject(impl, result); 414 else 415 setJSWrapperForDOMObject(impl, result); 416 417 if (type == V8ClassIndex::CANVASPIXELARRAY) { 418 CanvasPixelArray* pixels = reinterpret_cast<CanvasPixelArray*>(impl); 419 result->SetIndexedPropertiesToPixelData(pixels->data()->data(), pixels->length()); 420 } 421 422#if ENABLE(3D_CANVAS) 423 // Set up WebGLArray subclasses' accesses similarly. 424 switch (type) { 425 case V8ClassIndex::WEBGLBYTEARRAY: 426 case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY: 427 case V8ClassIndex::WEBGLSHORTARRAY: 428 case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY: 429 case V8ClassIndex::WEBGLINTARRAY: 430 case V8ClassIndex::WEBGLUNSIGNEDINTARRAY: 431 case V8ClassIndex::WEBGLFLOATARRAY: { 432 WebGLArray* array = reinterpret_cast<WebGLArray*>(impl); 433 setIndexedPropertiesToExternalArray(result, 434 V8ClassIndex::ToInt(type), 435 array->baseAddress(), 436 array->length()); 437 break; 438 } 439 default: 440 break; 441 } 442#endif 443 444 // Special case for non-node objects associated with a 445 // DOMWindow. Both Safari and FF let the JS wrappers for these 446 // objects survive GC. To mimic their behavior, V8 creates 447 // hidden references from the DOMWindow to these wrapper 448 // objects. These references get cleared when the DOMWindow is 449 // reused by a new page. 450 switch (type) { 451 case V8ClassIndex::CONSOLE: 452 setHiddenWindowReference(static_cast<Console*>(impl)->frame(), V8DOMWindow::consoleIndex, result); 453 break; 454 case V8ClassIndex::HISTORY: 455 setHiddenWindowReference(static_cast<History*>(impl)->frame(), V8DOMWindow::historyIndex, result); 456 break; 457 case V8ClassIndex::NAVIGATOR: 458 setHiddenWindowReference(static_cast<Navigator*>(impl)->frame(), V8DOMWindow::navigatorIndex, result); 459 break; 460 case V8ClassIndex::SCREEN: 461 setHiddenWindowReference(static_cast<Screen*>(impl)->frame(), V8DOMWindow::screenIndex, result); 462 break; 463 case V8ClassIndex::LOCATION: 464 setHiddenWindowReference(static_cast<Location*>(impl)->frame(), V8DOMWindow::locationIndex, result); 465 break; 466 case V8ClassIndex::DOMSELECTION: 467 setHiddenWindowReference(static_cast<DOMSelection*>(impl)->frame(), V8DOMWindow::domSelectionIndex, result); 468 break; 469 case V8ClassIndex::BARINFO: { 470 BarInfo* barInfo = static_cast<BarInfo*>(impl); 471 Frame* frame = barInfo->frame(); 472 switch (barInfo->type()) { 473 case BarInfo::Locationbar: 474 setHiddenWindowReference(frame, V8DOMWindow::locationbarIndex, result); 475 break; 476 case BarInfo::Menubar: 477 setHiddenWindowReference(frame, V8DOMWindow::menubarIndex, result); 478 break; 479 case BarInfo::Personalbar: 480 setHiddenWindowReference(frame, V8DOMWindow::personalbarIndex, result); 481 break; 482 case BarInfo::Scrollbars: 483 setHiddenWindowReference(frame, V8DOMWindow::scrollbarsIndex, result); 484 break; 485 case BarInfo::Statusbar: 486 setHiddenWindowReference(frame, V8DOMWindow::statusbarIndex, result); 487 break; 488 case BarInfo::Toolbar: 489 setHiddenWindowReference(frame, V8DOMWindow::toolbarIndex, result); 490 break; 491 } 492 break; 493 } 494 default: 495 break; 496 } 497 } 498 } 499 return result; 500} 501 502void V8DOMWrapper::setHiddenWindowReference(Frame* frame, const int internalIndex, v8::Handle<v8::Object> jsObject) 503{ 504 // Get DOMWindow 505 if (!frame) 506 return; // Object might be detached from window 507 v8::Handle<v8::Context> context = V8Proxy::context(frame); 508 if (context.IsEmpty()) 509 return; 510 511 ASSERT(internalIndex < V8DOMWindow::internalFieldCount); 512 513 v8::Handle<v8::Object> global = context->Global(); 514 // Look for real DOM wrapper. 515 global = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); 516 ASSERT(!global.IsEmpty()); 517 ASSERT(global->GetInternalField(internalIndex)->IsUndefined()); 518 global->SetInternalField(internalIndex, jsObject); 519} 520 521V8ClassIndex::V8WrapperType V8DOMWrapper::domWrapperType(v8::Handle<v8::Object> object) 522{ 523 ASSERT(V8DOMWrapper::maybeDOMWrapper(object)); 524 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 525 return V8ClassIndex::FromInt(type->Int32Value()); 526} 527 528PassRefPtr<NodeFilter> V8DOMWrapper::wrapNativeNodeFilter(v8::Handle<v8::Value> filter) 529{ 530 // A NodeFilter is used when walking through a DOM tree or iterating tree 531 // nodes. 532 // FIXME: we may want to cache NodeFilterCondition and NodeFilter 533 // object, but it is minor. 534 // NodeFilter is passed to NodeIterator that has a ref counted pointer 535 // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. 536 // In NodeFilterCondition, filter object is persisted in its constructor, 537 // and disposed in its destructor. 538 if (!filter->IsFunction()) 539 return 0; 540 541 NodeFilterCondition* condition = new V8NodeFilterCondition(filter); 542 return NodeFilter::create(condition); 543} 544 545v8::Local<v8::Object> V8DOMWrapper::instantiateV8Object(V8Proxy* proxy, V8ClassIndex::V8WrapperType descriptorType, V8ClassIndex::V8WrapperType cptrType, void* impl) 546{ 547 // Make a special case for document.all 548 if (descriptorType == V8ClassIndex::HTMLCOLLECTION && static_cast<HTMLCollection*>(impl)->type() == DocAll) 549 descriptorType = V8ClassIndex::HTMLALLCOLLECTION; 550 551 if (V8IsolatedContext::getEntered()) { 552 // This effectively disables the wrapper cache for isolated worlds. 553 proxy = 0; 554 // FIXME: Do we need a wrapper cache for the isolated world? We should 555 // see if the performance gains are worth while. 556 // We'll get one once we give the isolated context a proper window shell. 557 } else if (!proxy) 558 proxy = V8Proxy::retrieve(); 559 560 v8::Local<v8::Object> instance; 561 if (proxy) 562 // FIXME: Fix this to work properly with isolated worlds (see above). 563 instance = proxy->windowShell()->createWrapperFromCache(descriptorType); 564 else { 565 v8::Local<v8::Function> function = getTemplate(descriptorType)->GetFunction(); 566 instance = SafeAllocation::newInstance(function); 567 } 568 if (!instance.IsEmpty()) { 569 // Avoid setting the DOM wrapper for failed allocations. 570 setDOMWrapper(instance, V8ClassIndex::ToInt(cptrType), impl); 571 } 572 return instance; 573} 574 575#ifndef NDEBUG 576bool V8DOMWrapper::maybeDOMWrapper(v8::Handle<v8::Value> value) 577{ 578 if (value.IsEmpty() || !value->IsObject()) 579 return false; 580 581 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 582 if (!object->InternalFieldCount()) 583 return false; 584 585 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 586 587 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 588 ASSERT(type->IsInt32()); 589 ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END); 590 591 v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex); 592 ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); 593 594 return true; 595} 596#endif 597 598bool V8DOMWrapper::isDOMEventWrapper(v8::Handle<v8::Value> value) 599{ 600 // All kinds of events use EVENT as dom type in JS wrappers. 601 // See EventToV8Object 602 return isWrapperOfType(value, V8ClassIndex::EVENT); 603} 604 605bool V8DOMWrapper::isWrapperOfType(v8::Handle<v8::Value> value, V8ClassIndex::V8WrapperType classType) 606{ 607 if (value.IsEmpty() || !value->IsObject()) 608 return false; 609 610 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 611 if (!object->InternalFieldCount()) 612 return false; 613 614 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 615 616 v8::Handle<v8::Value> wrapper = object->GetInternalField(v8DOMWrapperObjectIndex); 617 ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); 618 619 v8::Handle<v8::Value> type = object->GetInternalField(v8DOMWrapperTypeIndex); 620 ASSERT(type->IsInt32()); 621 ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END); 622 623 return V8ClassIndex::FromInt(type->Int32Value()) == classType; 624} 625 626#if ENABLE(VIDEO) 627#define FOR_EACH_VIDEO_TAG(macro) \ 628 macro(audio, AUDIO) \ 629 macro(source, SOURCE) \ 630 macro(video, VIDEO) 631#else 632#define FOR_EACH_VIDEO_TAG(macro) 633#endif 634 635#if ENABLE(DATAGRID) 636#define FOR_EACH_DATAGRID_TAG(macro) \ 637 macro(datagrid, DATAGRID) \ 638 macro(dcell, DATAGRIDCELL) \ 639 macro(dcol, DATAGRIDCOL) \ 640 macro(drow, DATAGRIDROW) 641#else 642#define FOR_EACH_DATAGRID_TAG(macro) 643#endif 644 645#define FOR_EACH_TAG(macro) \ 646 FOR_EACH_DATAGRID_TAG(macro) \ 647 macro(a, ANCHOR) \ 648 macro(applet, APPLET) \ 649 macro(area, AREA) \ 650 macro(base, BASE) \ 651 macro(basefont, BASEFONT) \ 652 macro(blockquote, BLOCKQUOTE) \ 653 macro(body, BODY) \ 654 macro(br, BR) \ 655 macro(button, BUTTON) \ 656 macro(caption, TABLECAPTION) \ 657 macro(col, TABLECOL) \ 658 macro(colgroup, TABLECOL) \ 659 macro(del, MOD) \ 660 macro(canvas, CANVAS) \ 661 macro(dir, DIRECTORY) \ 662 macro(div, DIV) \ 663 macro(dl, DLIST) \ 664 macro(embed, EMBED) \ 665 macro(fieldset, FIELDSET) \ 666 macro(font, FONT) \ 667 macro(form, FORM) \ 668 macro(frame, FRAME) \ 669 macro(frameset, FRAMESET) \ 670 macro(h1, HEADING) \ 671 macro(h2, HEADING) \ 672 macro(h3, HEADING) \ 673 macro(h4, HEADING) \ 674 macro(h5, HEADING) \ 675 macro(h6, HEADING) \ 676 macro(head, HEAD) \ 677 macro(hr, HR) \ 678 macro(html, HTML) \ 679 macro(img, IMAGE) \ 680 macro(iframe, IFRAME) \ 681 macro(image, IMAGE) \ 682 macro(input, INPUT) \ 683 macro(ins, MOD) \ 684 macro(isindex, ISINDEX) \ 685 macro(keygen, SELECT) \ 686 macro(label, LABEL) \ 687 macro(legend, LEGEND) \ 688 macro(li, LI) \ 689 macro(link, LINK) \ 690 macro(listing, PRE) \ 691 macro(map, MAP) \ 692 macro(marquee, MARQUEE) \ 693 macro(menu, MENU) \ 694 macro(meta, META) \ 695 macro(object, OBJECT) \ 696 macro(ol, OLIST) \ 697 macro(optgroup, OPTGROUP) \ 698 macro(option, OPTION) \ 699 macro(p, PARAGRAPH) \ 700 macro(param, PARAM) \ 701 macro(pre, PRE) \ 702 macro(q, QUOTE) \ 703 macro(script, SCRIPT) \ 704 macro(select, SELECT) \ 705 macro(style, STYLE) \ 706 macro(table, TABLE) \ 707 macro(thead, TABLESECTION) \ 708 macro(tbody, TABLESECTION) \ 709 macro(tfoot, TABLESECTION) \ 710 macro(td, TABLECELL) \ 711 macro(th, TABLECELL) \ 712 macro(tr, TABLEROW) \ 713 macro(textarea, TEXTAREA) \ 714 macro(title, TITLE) \ 715 macro(ul, ULIST) \ 716 macro(xmp, PRE) 717 718V8ClassIndex::V8WrapperType V8DOMWrapper::htmlElementType(HTMLElement* element) 719{ 720 typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap; 721 DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ()); 722 if (wrapperTypeMap.isEmpty()) { 723#define ADD_TO_HASH_MAP(tag, name) \ 724 wrapperTypeMap.set(#tag, V8ClassIndex::HTML##name##ELEMENT); 725 FOR_EACH_TAG(ADD_TO_HASH_MAP) 726#if ENABLE(VIDEO) 727 if (MediaPlayer::isAvailable()) { 728 FOR_EACH_VIDEO_TAG(ADD_TO_HASH_MAP) 729 } 730#endif 731#undef ADD_TO_HASH_MAP 732 } 733 734 V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl()); 735 if (!type) 736 return V8ClassIndex::HTMLELEMENT; 737 return type; 738} 739#undef FOR_EACH_TAG 740 741#if ENABLE(SVG) 742 743#if ENABLE(SVG_ANIMATION) 744#define FOR_EACH_ANIMATION_TAG(macro) \ 745 macro(animateColor, ANIMATECOLOR) \ 746 macro(animate, ANIMATE) \ 747 macro(animateTransform, ANIMATETRANSFORM) \ 748 macro(set, SET) 749#else 750#define FOR_EACH_ANIMATION_TAG(macro) 751#endif 752 753#if ENABLE(SVG) && ENABLE(FILTERS) 754#define FOR_EACH_FILTERS_TAG(macro) \ 755 macro(feBlend, FEBLEND) \ 756 macro(feColorMatrix, FECOLORMATRIX) \ 757 macro(feComponentTransfer, FECOMPONENTTRANSFER) \ 758 macro(feComposite, FECOMPOSITE) \ 759 macro(feDiffuseLighting, FEDIFFUSELIGHTING) \ 760 macro(feDisplacementMap, FEDISPLACEMENTMAP) \ 761 macro(feDistantLight, FEDISTANTLIGHT) \ 762 macro(feFlood, FEFLOOD) \ 763 macro(feFuncA, FEFUNCA) \ 764 macro(feFuncB, FEFUNCB) \ 765 macro(feFuncG, FEFUNCG) \ 766 macro(feFuncR, FEFUNCR) \ 767 macro(feGaussianBlur, FEGAUSSIANBLUR) \ 768 macro(feImage, FEIMAGE) \ 769 macro(feMerge, FEMERGE) \ 770 macro(feMergeNode, FEMERGENODE) \ 771 macro(feMorphology, FEMORPHOLOGY) \ 772 macro(feOffset, FEOFFSET) \ 773 macro(fePointLight, FEPOINTLIGHT) \ 774 macro(feSpecularLighting, FESPECULARLIGHTING) \ 775 macro(feSpotLight, FESPOTLIGHT) \ 776 macro(feTile, FETILE) \ 777 macro(feTurbulence, FETURBULENCE) \ 778 macro(filter, FILTER) 779#else 780#define FOR_EACH_FILTERS_TAG(macro) 781#endif 782 783#if ENABLE(SVG_FONTS) 784#define FOR_EACH_FONTS_TAG(macro) \ 785 macro(font-face, FONTFACE) \ 786 macro(font-face-format, FONTFACEFORMAT) \ 787 macro(font-face-name, FONTFACENAME) \ 788 macro(font-face-src, FONTFACESRC) \ 789 macro(font-face-uri, FONTFACEURI) 790#else 791#define FOR_EACH_FONTS_TAG(marco) 792#endif 793 794#if ENABLE(SVG_FOREIGN_OBJECT) 795#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) \ 796 macro(foreignObject, FOREIGNOBJECT) 797#else 798#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) 799#endif 800 801#if ENABLE(SVG_USE) 802#define FOR_EACH_USE_TAG(macro) \ 803 macro(use, USE) 804#else 805#define FOR_EACH_USE_TAG(macro) 806#endif 807 808#define FOR_EACH_TAG(macro) \ 809 FOR_EACH_ANIMATION_TAG(macro) \ 810 FOR_EACH_FILTERS_TAG(macro) \ 811 FOR_EACH_FONTS_TAG(macro) \ 812 FOR_EACH_FOREIGN_OBJECT_TAG(macro) \ 813 FOR_EACH_USE_TAG(macro) \ 814 macro(a, A) \ 815 macro(altGlyph, ALTGLYPH) \ 816 macro(circle, CIRCLE) \ 817 macro(clipPath, CLIPPATH) \ 818 macro(cursor, CURSOR) \ 819 macro(defs, DEFS) \ 820 macro(desc, DESC) \ 821 macro(ellipse, ELLIPSE) \ 822 macro(g, G) \ 823 macro(glyph, GLYPH) \ 824 macro(image, IMAGE) \ 825 macro(linearGradient, LINEARGRADIENT) \ 826 macro(line, LINE) \ 827 macro(marker, MARKER) \ 828 macro(mask, MASK) \ 829 macro(metadata, METADATA) \ 830 macro(path, PATH) \ 831 macro(pattern, PATTERN) \ 832 macro(polyline, POLYLINE) \ 833 macro(polygon, POLYGON) \ 834 macro(radialGradient, RADIALGRADIENT) \ 835 macro(rect, RECT) \ 836 macro(script, SCRIPT) \ 837 macro(stop, STOP) \ 838 macro(style, STYLE) \ 839 macro(svg, SVG) \ 840 macro(switch, SWITCH) \ 841 macro(symbol, SYMBOL) \ 842 macro(text, TEXT) \ 843 macro(textPath, TEXTPATH) \ 844 macro(title, TITLE) \ 845 macro(tref, TREF) \ 846 macro(tspan, TSPAN) \ 847 macro(view, VIEW) \ 848 // end of macro 849 850V8ClassIndex::V8WrapperType V8DOMWrapper::svgElementType(SVGElement* element) 851{ 852 typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap; 853 DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ()); 854 if (wrapperTypeMap.isEmpty()) { 855#define ADD_TO_HASH_MAP(tag, name) \ 856 wrapperTypeMap.set(#tag, V8ClassIndex::SVG##name##ELEMENT); 857 FOR_EACH_TAG(ADD_TO_HASH_MAP) 858#undef ADD_TO_HASH_MAP 859 } 860 861 V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl()); 862 if (!type) 863 return V8ClassIndex::SVGELEMENT; 864 return type; 865} 866#undef FOR_EACH_TAG 867 868#endif // ENABLE(SVG) 869 870v8::Handle<v8::Value> V8DOMWrapper::convertEventToV8Object(Event* event) 871{ 872 if (!event) 873 return v8::Null(); 874 875 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event); 876 if (!wrapper.IsEmpty()) 877 return wrapper; 878 879 V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT; 880 881 if (event->isUIEvent()) { 882 if (event->isKeyboardEvent()) 883 type = V8ClassIndex::KEYBOARDEVENT; 884 else if (event->isTextEvent()) 885 type = V8ClassIndex::TEXTEVENT; 886 else if (event->isMouseEvent()) 887 type = V8ClassIndex::MOUSEEVENT; 888 else if (event->isWheelEvent()) 889 type = V8ClassIndex::WHEELEVENT; 890// ANDROID: Upstream TOUCH_EVENTS. 891#if ENABLE(TOUCH_EVENTS) 892 else if (event->isTouchEvent()) 893 type = V8ClassIndex::TOUCHEVENT; 894#endif 895#if ENABLE(SVG) 896 else if (event->isSVGZoomEvent()) 897 type = V8ClassIndex::SVGZOOMEVENT; 898#endif 899 else if (event->isCompositionEvent()) 900 type = V8ClassIndex::COMPOSITIONEVENT; 901 else 902 type = V8ClassIndex::UIEVENT; 903 } else if (event->isMutationEvent()) 904 type = V8ClassIndex::MUTATIONEVENT; 905 else if (event->isOverflowEvent()) 906 type = V8ClassIndex::OVERFLOWEVENT; 907 else if (event->isMessageEvent()) 908 type = V8ClassIndex::MESSAGEEVENT; 909 else if (event->isPageTransitionEvent()) 910 type = V8ClassIndex::PAGETRANSITIONEVENT; 911 else if (event->isPopStateEvent()) 912 type = V8ClassIndex::POPSTATEEVENT; 913 else if (event->isProgressEvent()) { 914 if (event->isXMLHttpRequestProgressEvent()) 915 type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT; 916 else 917 type = V8ClassIndex::PROGRESSEVENT; 918 } else if (event->isWebKitAnimationEvent()) 919 type = V8ClassIndex::WEBKITANIMATIONEVENT; 920 else if (event->isWebKitTransitionEvent()) 921 type = V8ClassIndex::WEBKITTRANSITIONEVENT; 922#if ENABLE(WORKERS) 923 else if (event->isErrorEvent()) 924 type = V8ClassIndex::ERROREVENT; 925#endif 926#if ENABLE(DOM_STORAGE) 927 else if (event->isStorageEvent()) 928 type = V8ClassIndex::STORAGEEVENT; 929#endif 930 else if (event->isBeforeLoadEvent()) 931 type = V8ClassIndex::BEFORELOADEVENT; 932 933 934 v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::EVENT, event); 935 if (result.IsEmpty()) { 936 // Instantiation failed. Avoid updating the DOM object map and 937 // return null which is already handled by callers of this function 938 // in case the event is NULL. 939 return v8::Null(); 940 } 941 942 event->ref(); // fast ref 943 setJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result)); 944 945 return result; 946} 947 948static const V8ClassIndex::V8WrapperType mapping[] = { 949 V8ClassIndex::INVALID_CLASS_INDEX, // NONE 950 V8ClassIndex::INVALID_CLASS_INDEX, // ELEMENT_NODE needs special treatment 951 V8ClassIndex::ATTR, // ATTRIBUTE_NODE 952 V8ClassIndex::TEXT, // TEXT_NODE 953 V8ClassIndex::CDATASECTION, // CDATA_SECTION_NODE 954 V8ClassIndex::ENTITYREFERENCE, // ENTITY_REFERENCE_NODE 955 V8ClassIndex::ENTITY, // ENTITY_NODE 956 V8ClassIndex::PROCESSINGINSTRUCTION, // PROCESSING_INSTRUCTION_NODE 957 V8ClassIndex::COMMENT, // COMMENT_NODE 958 V8ClassIndex::INVALID_CLASS_INDEX, // DOCUMENT_NODE needs special treatment 959 V8ClassIndex::DOCUMENTTYPE, // DOCUMENT_TYPE_NODE 960 V8ClassIndex::DOCUMENTFRAGMENT, // DOCUMENT_FRAGMENT_NODE 961 V8ClassIndex::NOTATION, // NOTATION_NODE 962 V8ClassIndex::NODE, // XPATH_NAMESPACE_NODE 963}; 964 965v8::Handle<v8::Value> V8DOMWrapper::convertDocumentToV8Object(Document* document) 966{ 967 // Find a proxy for this node. 968 // 969 // Note that if proxy is found, we might initialize the context which can 970 // instantiate a document wrapper. Therefore, we get the proxy before 971 // checking if the node already has a wrapper. 972 V8Proxy* proxy = V8Proxy::retrieve(document->frame()); 973 if (proxy) 974 proxy->windowShell()->initContextIfNeeded(); 975 976 DOMNodeMapping& domNodeMap = getDOMNodeMap(); 977 v8::Handle<v8::Object> wrapper = domNodeMap.get(document); 978 if (wrapper.IsEmpty()) 979 return convertNewNodeToV8Object(document, proxy, domNodeMap); 980 981 return wrapper; 982} 983 984static v8::Handle<v8::Value> getWrapper(Node* node) 985{ 986 ASSERT(WTF::isMainThread()); 987 V8IsolatedContext* context = V8IsolatedContext::getEntered(); 988 if (LIKELY(!context)) { 989 v8::Persistent<v8::Object>* wrapper = node->wrapper(); 990 if (!wrapper) 991 return v8::Handle<v8::Value>(); 992 return *wrapper; 993 } 994 995 DOMNodeMapping& domNodeMap = context->world()->domDataStore()->domNodeMap(); 996 return domNodeMap.get(node); 997} 998 999v8::Handle<v8::Value> V8DOMWrapper::convertNodeToV8Object(Node* node) 1000{ 1001 if (!node) 1002 return v8::Null(); 1003 1004 v8::Handle<v8::Value> wrapper = getWrapper(node); 1005 if (!wrapper.IsEmpty()) 1006 return wrapper; 1007 1008 Document* document = node->document(); 1009 if (node == document) 1010 return convertDocumentToV8Object(document); 1011 1012 return convertNewNodeToV8Object(node, 0, getDOMNodeMap()); 1013} 1014 1015// Caller checks node is not null. 1016v8::Handle<v8::Value> V8DOMWrapper::convertNewNodeToV8Object(Node* node, V8Proxy* proxy, DOMNodeMapping& domNodeMap) 1017{ 1018 if (!proxy && node->document()) 1019 proxy = V8Proxy::retrieve(node->document()->frame()); 1020 1021 bool isDocument = false; // document type node has special handling 1022 V8ClassIndex::V8WrapperType type; 1023 1024 Node::NodeType nodeType = node->nodeType(); 1025 if (nodeType == Node::ELEMENT_NODE) { 1026 if (node->isHTMLElement()) 1027 type = htmlElementType(static_cast<HTMLElement*>(node)); 1028#if ENABLE(SVG) 1029 else if (node->isSVGElement()) 1030 type = svgElementType(static_cast<SVGElement*>(node)); 1031#endif 1032 else 1033 type = V8ClassIndex::ELEMENT; 1034 } else if (nodeType == Node::DOCUMENT_NODE) { 1035 isDocument = true; 1036 Document* document = static_cast<Document*>(node); 1037 if (document->isHTMLDocument()) 1038 type = V8ClassIndex::HTMLDOCUMENT; 1039#if ENABLE(SVG) 1040 else if (document->isSVGDocument()) 1041 type = V8ClassIndex::SVGDOCUMENT; 1042#endif 1043 else 1044 type = V8ClassIndex::DOCUMENT; 1045 } else { 1046 ASSERT(nodeType < static_cast<int>(sizeof(mapping)/sizeof(mapping[0]))); 1047 type = mapping[nodeType]; 1048 ASSERT(type != V8ClassIndex::INVALID_CLASS_INDEX); 1049 } 1050 1051 v8::Handle<v8::Context> context; 1052 if (proxy) 1053 context = proxy->context(); 1054 1055 // Enter the node's context and create the wrapper in that context. 1056 if (!context.IsEmpty()) 1057 context->Enter(); 1058 1059 v8::Local<v8::Object> result = instantiateV8Object(proxy, type, V8ClassIndex::NODE, node); 1060 1061 // Exit the node's context if it was entered. 1062 if (!context.IsEmpty()) 1063 context->Exit(); 1064 1065 if (result.IsEmpty()) { 1066 // If instantiation failed it's important not to add the result 1067 // to the DOM node map. Instead we return an empty handle, which 1068 // should already be handled by callers of this function in case 1069 // the node is NULL. 1070 return result; 1071 } 1072 1073 node->ref(); 1074 domNodeMap.set(node, v8::Persistent<v8::Object>::New(result)); 1075 1076 if (isDocument) { 1077 if (proxy) 1078 proxy->windowShell()->updateDocumentWrapper(result); 1079 1080 if (type == V8ClassIndex::HTMLDOCUMENT) { 1081 // Create marker object and insert it in two internal fields. 1082 // This is used to implement temporary shadowing of 1083 // document.all. 1084 ASSERT(result->InternalFieldCount() == V8HTMLDocument::internalFieldCount); 1085 v8::Local<v8::Object> marker = v8::Object::New(); 1086 result->SetInternalField(V8HTMLDocument::markerIndex, marker); 1087 result->SetInternalField(V8HTMLDocument::shadowIndex, marker); 1088 } 1089 } 1090 1091 return result; 1092} 1093 1094// A JS object of type EventTarget is limited to a small number of possible classes. 1095// Check EventTarget.h for new type conversion methods 1096v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* target) 1097{ 1098 if (!target) 1099 return v8::Null(); 1100 1101#if ENABLE(SVG) 1102 SVGElementInstance* instance = target->toSVGElementInstance(); 1103 if (instance) 1104 return convertToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance); 1105#endif 1106 1107#if ENABLE(WORKERS) 1108 Worker* worker = target->toWorker(); 1109 if (worker) 1110 return convertToV8Object(V8ClassIndex::WORKER, worker); 1111#endif // WORKERS 1112 1113#if ENABLE(SHARED_WORKERS) 1114 SharedWorker* sharedWorker = target->toSharedWorker(); 1115 if (sharedWorker) 1116 return convertToV8Object(V8ClassIndex::SHAREDWORKER, sharedWorker); 1117#endif // SHARED_WORKERS 1118 1119#if ENABLE(NOTIFICATIONS) 1120 Notification* notification = target->toNotification(); 1121 if (notification) 1122 return convertToV8Object(V8ClassIndex::NOTIFICATION, notification); 1123#endif 1124 1125#if ENABLE(WEB_SOCKETS) 1126 WebSocket* webSocket = target->toWebSocket(); 1127 if (webSocket) 1128 return convertToV8Object(V8ClassIndex::WEBSOCKET, webSocket); 1129#endif 1130 1131 Node* node = target->toNode(); 1132 if (node) 1133 return convertNodeToV8Object(node); 1134 1135 if (DOMWindow* domWindow = target->toDOMWindow()) 1136 return convertToV8Object(V8ClassIndex::DOMWINDOW, domWindow); 1137 1138 // XMLHttpRequest is created within its JS counterpart. 1139 XMLHttpRequest* xmlHttpRequest = target->toXMLHttpRequest(); 1140 if (xmlHttpRequest) { 1141 v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xmlHttpRequest); 1142 ASSERT(!wrapper.IsEmpty()); 1143 return wrapper; 1144 } 1145 1146 // MessagePort is created within its JS counterpart 1147 MessagePort* port = target->toMessagePort(); 1148 if (port) { 1149 v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port); 1150 ASSERT(!wrapper.IsEmpty()); 1151 return wrapper; 1152 } 1153 1154 XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload(); 1155 if (upload) { 1156 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload); 1157 ASSERT(!wrapper.IsEmpty()); 1158 return wrapper; 1159 } 1160 1161#if ENABLE(OFFLINE_WEB_APPLICATIONS) 1162 DOMApplicationCache* domAppCache = target->toDOMApplicationCache(); 1163 if (domAppCache) 1164 return convertToV8Object(V8ClassIndex::DOMAPPLICATIONCACHE, domAppCache); 1165#endif 1166 1167#if ENABLE(EVENTSOURCE) 1168 EventSource* eventSource = target->toEventSource(); 1169 if (eventSource) 1170 return convertToV8Object(V8ClassIndex::EVENTSOURCE, eventSource); 1171#endif 1172 1173 ASSERT(0); 1174 return notHandledByInterceptor(); 1175} 1176 1177v8::Handle<v8::Value> V8DOMWrapper::convertEventListenerToV8Object(ScriptExecutionContext* context, EventListener* listener) 1178{ 1179 if (!listener) 1180 return v8::Null(); 1181 1182 // FIXME: can a user take a lazy event listener and set to other places? 1183 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener); 1184 return v8listener->getListenerObject(context); 1185} 1186 1187PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1188{ 1189 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 1190} 1191 1192#if ENABLE(SVG) 1193PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1194{ 1195 return getEventListener(element->correspondingElement(), value, isAttribute, lookup); 1196} 1197#endif 1198 1199PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1200{ 1201 if (worker->scriptExecutionContext()->isWorkerContext()) { 1202 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 1203 ASSERT(workerContextProxy); 1204 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 1205 } 1206 1207 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 1208} 1209 1210#if ENABLE(NOTIFICATIONS) 1211PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1212{ 1213 if (notification->scriptExecutionContext()->isWorkerContext()) { 1214 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 1215 ASSERT(workerContextProxy); 1216 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 1217 } 1218 1219 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 1220} 1221#endif 1222 1223PassRefPtr<EventListener> V8DOMWrapper::getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1224{ 1225 WorkerContextExecutionProxy* workerContextProxy = workerContext->script()->proxy(); 1226 if (workerContextProxy) 1227 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 1228 1229 return 0; 1230} 1231 1232PassRefPtr<EventListener> V8DOMWrapper::getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1233{ 1234 return getEventListener(upload->associatedXMLHttpRequest(), value, isAttribute, lookup); 1235} 1236 1237#if ENABLE(EVENTSOURCE) 1238PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventSource* eventSource, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1239{ 1240 if (V8Proxy::retrieve(eventSource->scriptExecutionContext())) 1241 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 1242 1243#if ENABLE(WORKERS) 1244 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 1245 if (workerContextProxy) 1246 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 1247#endif 1248 1249 return 0; 1250} 1251#endif 1252 1253PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1254{ 1255 if (V8Proxy::retrieve(eventTarget->scriptExecutionContext())) 1256 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 1257 1258#if ENABLE(WORKERS) 1259 WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve(); 1260 if (workerContextProxy) 1261 return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly); 1262#endif 1263 1264 return 0; 1265} 1266 1267PassRefPtr<EventListener> V8DOMWrapper::getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup) 1268{ 1269 return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute); 1270} 1271 1272v8::Handle<v8::Value> V8DOMWrapper::convertDOMImplementationToV8Object(DOMImplementation* impl) 1273{ 1274 v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, V8ClassIndex::DOMIMPLEMENTATION, impl); 1275 if (result.IsEmpty()) { 1276 // If the instantiation failed, we ignore it and return null instead 1277 // of returning an empty handle. 1278 return v8::Null(); 1279 } 1280 return result; 1281} 1282 1283v8::Handle<v8::Value> V8DOMWrapper::convertStyleSheetToV8Object(StyleSheet* sheet) 1284{ 1285 if (!sheet) 1286 return v8::Null(); 1287 1288 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet); 1289 if (!wrapper.IsEmpty()) 1290 return wrapper; 1291 1292 V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET; 1293 if (sheet->isCSSStyleSheet()) 1294 type = V8ClassIndex::CSSSTYLESHEET; 1295 1296 v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet); 1297 if (!result.IsEmpty()) { 1298 // Only update the DOM object map if the result is non-empty. 1299 sheet->ref(); 1300 setJSWrapperForDOMObject(sheet, v8::Persistent<v8::Object>::New(result)); 1301 } 1302 1303 // Add a hidden reference from stylesheet object to its owner node. 1304 Node* ownerNode = sheet->ownerNode(); 1305 if (ownerNode) { 1306 v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(ownerNode)); 1307 result->SetInternalField(V8StyleSheet::ownerNodeIndex, owner); 1308 } 1309 1310 return result; 1311} 1312 1313v8::Handle<v8::Value> V8DOMWrapper::convertCSSValueToV8Object(CSSValue* value) 1314{ 1315 if (!value) 1316 return v8::Null(); 1317 1318 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value); 1319 if (!wrapper.IsEmpty()) 1320 return wrapper; 1321 1322 V8ClassIndex::V8WrapperType type; 1323 1324 if (value->isWebKitCSSTransformValue()) 1325 type = V8ClassIndex::WEBKITCSSTRANSFORMVALUE; 1326 else if (value->isValueList()) 1327 type = V8ClassIndex::CSSVALUELIST; 1328 else if (value->isPrimitiveValue()) 1329 type = V8ClassIndex::CSSPRIMITIVEVALUE; 1330#if ENABLE(SVG) 1331 else if (value->isSVGPaint()) 1332 type = V8ClassIndex::SVGPAINT; 1333 else if (value->isSVGColor()) 1334 type = V8ClassIndex::SVGCOLOR; 1335#endif 1336 else 1337 type = V8ClassIndex::CSSVALUE; 1338 1339 v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::CSSVALUE, value); 1340 if (!result.IsEmpty()) { 1341 // Only update the DOM object map if the result is non-empty. 1342 value->ref(); 1343 setJSWrapperForDOMObject(value, v8::Persistent<v8::Object>::New(result)); 1344 } 1345 1346 return result; 1347} 1348 1349v8::Handle<v8::Value> V8DOMWrapper::convertCSSRuleToV8Object(CSSRule* rule) 1350{ 1351 if (!rule) 1352 return v8::Null(); 1353 1354 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule); 1355 if (!wrapper.IsEmpty()) 1356 return wrapper; 1357 1358 V8ClassIndex::V8WrapperType type; 1359 1360 switch (rule->type()) { 1361 case CSSRule::STYLE_RULE: 1362 type = V8ClassIndex::CSSSTYLERULE; 1363 break; 1364 case CSSRule::CHARSET_RULE: 1365 type = V8ClassIndex::CSSCHARSETRULE; 1366 break; 1367 case CSSRule::IMPORT_RULE: 1368 type = V8ClassIndex::CSSIMPORTRULE; 1369 break; 1370 case CSSRule::MEDIA_RULE: 1371 type = V8ClassIndex::CSSMEDIARULE; 1372 break; 1373 case CSSRule::FONT_FACE_RULE: 1374 type = V8ClassIndex::CSSFONTFACERULE; 1375 break; 1376 case CSSRule::PAGE_RULE: 1377 type = V8ClassIndex::CSSPAGERULE; 1378 break; 1379 case CSSRule::VARIABLES_RULE: 1380 type = V8ClassIndex::CSSVARIABLESRULE; 1381 break; 1382 case CSSRule::WEBKIT_KEYFRAME_RULE: 1383 type = V8ClassIndex::WEBKITCSSKEYFRAMERULE; 1384 break; 1385 case CSSRule::WEBKIT_KEYFRAMES_RULE: 1386 type = V8ClassIndex::WEBKITCSSKEYFRAMESRULE; 1387 break; 1388 default: // CSSRule::UNKNOWN_RULE 1389 type = V8ClassIndex::CSSRULE; 1390 break; 1391 } 1392 1393 v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::CSSRULE, rule); 1394 if (!result.IsEmpty()) { 1395 // Only update the DOM object map if the result is non-empty. 1396 rule->ref(); 1397 setJSWrapperForDOMObject(rule, v8::Persistent<v8::Object>::New(result)); 1398 } 1399 return result; 1400} 1401 1402v8::Handle<v8::Value> V8DOMWrapper::convertWindowToV8Object(DOMWindow* window) 1403{ 1404 if (!window) 1405 return v8::Null(); 1406 // Initializes environment of a frame, and return the global object 1407 // of the frame. 1408 Frame* frame = window->frame(); 1409 if (!frame) 1410 return v8::Handle<v8::Object>(); 1411 1412 // Special case: Because of evaluateInIsolatedWorld() one DOMWindow can have 1413 // multiple contexts and multiple global objects associated with it. When 1414 // code running in one of those contexts accesses the window object, we 1415 // want to return the global object associated with that context, not 1416 // necessarily the first global object associated with that DOMWindow. 1417 v8::Handle<v8::Context> currentContext = v8::Context::GetCurrent(); 1418 v8::Handle<v8::Object> currentGlobal = currentContext->Global(); 1419 v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, currentGlobal); 1420 if (!windowWrapper.IsEmpty()) { 1421 if (V8DOMWindow::toNative(windowWrapper) == window) 1422 return currentGlobal; 1423 } 1424 1425 // Otherwise, return the global object associated with this frame. 1426 v8::Handle<v8::Context> context = V8Proxy::context(frame); 1427 if (context.IsEmpty()) 1428 return v8::Handle<v8::Object>(); 1429 1430 v8::Handle<v8::Object> global = context->Global(); 1431 ASSERT(!global.IsEmpty()); 1432 return global; 1433} 1434 1435v8::Handle<v8::Value> V8DOMWrapper::convertNamedNodeMapToV8Object(NamedNodeMap* map) 1436{ 1437 if (!map) 1438 return v8::Null(); 1439 1440 v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(map); 1441 if (!wrapper.IsEmpty()) 1442 return wrapper; 1443 1444 v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::NAMEDNODEMAP, V8ClassIndex::NAMEDNODEMAP, map); 1445 if (result.IsEmpty()) 1446 return result; 1447 1448 // Only update the DOM object map if the result is non-empty. 1449 map->ref(); 1450 setJSWrapperForDOMObject(map, v8::Persistent<v8::Object>::New(result)); 1451 1452 // Add a hidden reference from named node map to its owner node. 1453 if (Element* element = map->element()) { 1454 v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(element)); 1455 result->SetInternalField(V8NamedNodeMap::ownerNodeIndex, owner); 1456 } 1457 1458 return result; 1459} 1460 1461} // namespace WebCore 1462