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