JSDOMWindowCustom.cpp revision 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00
1/* 2 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "JSDOMWindowCustom.h" 22 23#include "Frame.h" 24#include "HTMLCollection.h" 25#include "HTMLDocument.h" 26#include "History.h" 27#include "JSArrayBuffer.h" 28#include "JSAudioConstructor.h" 29#include "JSDataView.h" 30#include "JSEvent.h" 31#include "JSEventListener.h" 32#include "JSEventSource.h" 33#include "JSFloat32Array.h" 34#include "JSHTMLCollection.h" 35#include "JSHistory.h" 36#include "JSImageConstructor.h" 37#include "JSInt16Array.h" 38#include "JSInt32Array.h" 39#include "JSInt8Array.h" 40#include "JSLocation.h" 41#include "JSMessageChannel.h" 42#include "JSMessagePortCustom.h" 43#include "JSOptionConstructor.h" 44#include "JSUint16Array.h" 45#include "JSUint32Array.h" 46#include "JSUint8Array.h" 47#include "JSWebKitCSSMatrix.h" 48#include "JSWebKitPoint.h" 49#include "JSWorker.h" 50#include "JSXMLHttpRequest.h" 51#include "JSXSLTProcessor.h" 52#include "Location.h" 53#include "MediaPlayer.h" 54#include "ScheduledAction.h" 55#include "Settings.h" 56#include "SharedWorkerRepository.h" 57#include <runtime/JSFunction.h> 58 59#if ENABLE(SHARED_WORKERS) 60#include "JSSharedWorker.h" 61#endif 62 63#if ENABLE(WEB_AUDIO) 64#include "JSAudioContext.h" 65#endif 66 67#if ENABLE(WEB_SOCKETS) 68#include "JSWebSocket.h" 69#endif 70 71using namespace JSC; 72 73namespace WebCore { 74 75void JSDOMWindow::markChildren(MarkStack& markStack) 76{ 77 Base::markChildren(markStack); 78 79 impl()->markJSEventListeners(markStack); 80 81 JSGlobalData& globalData = *Heap::heap(this)->globalData(); 82 83 markDOMObjectWrapper(markStack, globalData, impl()->optionalConsole()); 84 markDOMObjectWrapper(markStack, globalData, impl()->optionalHistory()); 85 markDOMObjectWrapper(markStack, globalData, impl()->optionalLocationbar()); 86 markDOMObjectWrapper(markStack, globalData, impl()->optionalMenubar()); 87 markDOMObjectWrapper(markStack, globalData, impl()->optionalNavigator()); 88 markDOMObjectWrapper(markStack, globalData, impl()->optionalPersonalbar()); 89 markDOMObjectWrapper(markStack, globalData, impl()->optionalScreen()); 90 markDOMObjectWrapper(markStack, globalData, impl()->optionalScrollbars()); 91 markDOMObjectWrapper(markStack, globalData, impl()->optionalSelection()); 92 markDOMObjectWrapper(markStack, globalData, impl()->optionalStatusbar()); 93 markDOMObjectWrapper(markStack, globalData, impl()->optionalToolbar()); 94 markDOMObjectWrapper(markStack, globalData, impl()->optionalLocation()); 95 markDOMObjectWrapper(markStack, globalData, impl()->optionalMedia()); 96#if ENABLE(DOM_STORAGE) 97 markDOMObjectWrapper(markStack, globalData, impl()->optionalSessionStorage()); 98 markDOMObjectWrapper(markStack, globalData, impl()->optionalLocalStorage()); 99#endif 100#if ENABLE(OFFLINE_WEB_APPLICATIONS) 101 markDOMObjectWrapper(markStack, globalData, impl()->optionalApplicationCache()); 102#endif 103} 104 105template<NativeFunction nativeFunction, int length> 106JSValue nonCachingStaticFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName) 107{ 108 return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), length, propertyName, nativeFunction); 109} 110 111static JSValue childFrameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 112{ 113 return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->child(identifierToAtomicString(propertyName))->domWindow()); 114} 115 116static JSValue indexGetter(ExecState* exec, JSValue slotBase, unsigned index) 117{ 118 return toJS(exec, static_cast<JSDOMWindow*>(asObject(slotBase))->impl()->frame()->tree()->child(index)->domWindow()); 119} 120 121static JSValue namedItemGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 122{ 123 JSDOMWindowBase* thisObj = static_cast<JSDOMWindow*>(asObject(slotBase)); 124 Document* document = thisObj->impl()->frame()->document(); 125 126 ASSERT(thisObj->allowsAccessFrom(exec)); 127 ASSERT(document); 128 ASSERT(document->isHTMLDocument()); 129 130 RefPtr<HTMLCollection> collection = document->windowNamedItems(identifierToString(propertyName)); 131 if (collection->length() == 1) 132 return toJS(exec, collection->firstItem()); 133 return toJS(exec, collection.get()); 134} 135 136bool JSDOMWindow::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 137{ 138 // When accessing a Window cross-domain, functions are always the native built-in ones, and they 139 // are not affected by properties changed on the Window or anything in its prototype chain. 140 // This is consistent with the behavior of Firefox. 141 142 const HashEntry* entry; 143 144 // We don't want any properties other than "close" and "closed" on a closed window. 145 if (!impl()->frame()) { 146 // The following code is safe for cross-domain and same domain use. 147 // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). 148 entry = s_info.propHashTable(exec)->entry(exec, propertyName); 149 if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) { 150 slot.setCustom(this, entry->propertyGetter()); 151 return true; 152 } 153 entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); 154 if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { 155 slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); 156 return true; 157 } 158 159 // FIXME: We should have a message here that explains why the property access/function call was 160 // not allowed. 161 slot.setUndefined(); 162 return true; 163 } 164 165 // We need to check for cross-domain access here without printing the generic warning message 166 // because we always allow access to some function, just different ones depending whether access 167 // is allowed. 168 String errorMessage; 169 bool allowsAccess = allowsAccessFrom(exec, errorMessage); 170 171 // Look for overrides before looking at any of our own properties, but ignore overrides completely 172 // if this is cross-domain access. 173 if (allowsAccess && JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) 174 return true; 175 176 // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the 177 // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot. 178 // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of 179 // what prototype is actually set on this object. 180 entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); 181 if (entry) { 182 if (entry->attributes() & Function) { 183 if (entry->function() == jsDOMWindowPrototypeFunctionBlur) { 184 if (!allowsAccess) { 185 slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>); 186 return true; 187 } 188 } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) { 189 if (!allowsAccess) { 190 slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); 191 return true; 192 } 193 } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) { 194 if (!allowsAccess) { 195 slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>); 196 return true; 197 } 198 } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) { 199 if (!allowsAccess) { 200 slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>); 201 return true; 202 } 203 } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) { 204 if (!DOMWindow::canShowModalDialog(impl()->frame())) { 205 slot.setUndefined(); 206 return true; 207 } 208 } 209 } 210 } else { 211 // Allow access to toString() cross-domain, but always Object.prototype.toString. 212 if (propertyName == exec->propertyNames().toString) { 213 if (!allowsAccess) { 214 slot.setCustom(this, objectToStringFunctionGetter); 215 return true; 216 } 217 } 218 } 219 220 entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName); 221 if (entry) { 222 slot.setCustom(this, entry->propertyGetter()); 223 return true; 224 } 225 226 // Check for child frames by name before built-in properties to 227 // match Mozilla. This does not match IE, but some sites end up 228 // naming frames things that conflict with window properties that 229 // are in Moz but not IE. Since we have some of these, we have to do 230 // it the Moz way. 231 if (impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) { 232 slot.setCustom(this, childFrameGetter); 233 return true; 234 } 235 236 // Do prototype lookup early so that functions and attributes in the prototype can have 237 // precedence over the index and name getters. 238 JSValue proto = prototype(); 239 if (proto.isObject()) { 240 if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) { 241 if (!allowsAccess) { 242 printErrorMessage(errorMessage); 243 slot.setUndefined(); 244 } 245 return true; 246 } 247 } 248 249 // FIXME: Search the whole frame hierarchy somewhere around here. 250 // We need to test the correct priority order. 251 252 // allow window[1] or parent[1] etc. (#56983) 253 bool ok; 254 unsigned i = propertyName.toArrayIndex(ok); 255 if (ok && i < impl()->frame()->tree()->childCount()) { 256 slot.setCustomIndex(this, i, indexGetter); 257 return true; 258 } 259 260 if (!allowsAccess) { 261 printErrorMessage(errorMessage); 262 slot.setUndefined(); 263 return true; 264 } 265 266 // Allow shortcuts like 'Image1' instead of document.images.Image1 267 Document* document = impl()->frame()->document(); 268 if (document->isHTMLDocument()) { 269 AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); 270 if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { 271 slot.setCustom(this, namedItemGetter); 272 return true; 273 } 274 } 275 276 return Base::getOwnPropertySlot(exec, propertyName, slot); 277} 278 279bool JSDOMWindow::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) 280{ 281 // Never allow cross-domain getOwnPropertyDescriptor 282 if (!allowsAccessFrom(exec)) 283 return false; 284 285 const HashEntry* entry; 286 287 // We don't want any properties other than "close" and "closed" on a closed window. 288 if (!impl()->frame()) { 289 // The following code is safe for cross-domain and same domain use. 290 // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). 291 entry = s_info.propHashTable(exec)->entry(exec, propertyName); 292 if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) { 293 descriptor.setDescriptor(jsBoolean(true), ReadOnly | DontDelete | DontEnum); 294 return true; 295 } 296 entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); 297 if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { 298 PropertySlot slot; 299 slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); 300 descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); 301 return true; 302 } 303 descriptor.setUndefined(); 304 return true; 305 } 306 307 entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName); 308 if (entry) { 309 PropertySlot slot; 310 slot.setCustom(this, entry->propertyGetter()); 311 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); 312 return true; 313 } 314 315 // Check for child frames by name before built-in properties to 316 // match Mozilla. This does not match IE, but some sites end up 317 // naming frames things that conflict with window properties that 318 // are in Moz but not IE. Since we have some of these, we have to do 319 // it the Moz way. 320 if (impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) { 321 PropertySlot slot; 322 slot.setCustom(this, childFrameGetter); 323 descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); 324 return true; 325 } 326 327 bool ok; 328 unsigned i = propertyName.toArrayIndex(ok); 329 if (ok && i < impl()->frame()->tree()->childCount()) { 330 PropertySlot slot; 331 slot.setCustomIndex(this, i, indexGetter); 332 descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); 333 return true; 334 } 335 336 // Allow shortcuts like 'Image1' instead of document.images.Image1 337 Document* document = impl()->frame()->document(); 338 if (document->isHTMLDocument()) { 339 AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); 340 if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { 341 PropertySlot slot; 342 slot.setCustom(this, namedItemGetter); 343 descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); 344 return true; 345 } 346 } 347 348 return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); 349} 350 351void JSDOMWindow::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) 352{ 353 if (!impl()->frame()) 354 return; 355 356 // Optimization: access JavaScript global variables directly before involving the DOM. 357 if (JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) { 358 if (allowsAccessFrom(exec)) 359 JSGlobalObject::put(exec, propertyName, value, slot); 360 return; 361 } 362 363 if (lookupPut<JSDOMWindow>(exec, propertyName, value, s_info.propHashTable(exec), this)) 364 return; 365 366 if (allowsAccessFrom(exec)) 367 Base::put(exec, propertyName, value, slot); 368} 369 370bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName) 371{ 372 // Only allow deleting properties by frames in the same origin. 373 if (!allowsAccessFrom(exec)) 374 return false; 375 return Base::deleteProperty(exec, propertyName); 376} 377 378void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 379{ 380 // Only allow the window to enumerated by frames in the same origin. 381 if (!allowsAccessFrom(exec)) 382 return; 383 Base::getPropertyNames(exec, propertyNames, mode); 384} 385 386void JSDOMWindow::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) 387{ 388 // Only allow the window to enumerated by frames in the same origin. 389 if (!allowsAccessFrom(exec)) 390 return; 391 Base::getOwnPropertyNames(exec, propertyNames, mode); 392} 393 394void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) 395{ 396 // Only allow defining getters by frames in the same origin. 397 if (!allowsAccessFrom(exec)) 398 return; 399 400 // Don't allow shadowing location using defineGetter. 401 if (propertyName == "location") 402 return; 403 404 Base::defineGetter(exec, propertyName, getterFunction, attributes); 405} 406 407void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) 408{ 409 // Only allow defining setters by frames in the same origin. 410 if (!allowsAccessFrom(exec)) 411 return; 412 Base::defineSetter(exec, propertyName, setterFunction, attributes); 413} 414 415bool JSDOMWindow::defineOwnProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow) 416{ 417 // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced. 418 if (!allowsAccessFrom(exec)) 419 return false; 420 return Base::defineOwnProperty(exec, propertyName, descriptor, shouldThrow); 421} 422 423JSValue JSDOMWindow::lookupGetter(ExecState* exec, const Identifier& propertyName) 424{ 425 // Only allow looking-up getters by frames in the same origin. 426 if (!allowsAccessFrom(exec)) 427 return jsUndefined(); 428 return Base::lookupGetter(exec, propertyName); 429} 430 431JSValue JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyName) 432{ 433 // Only allow looking-up setters by frames in the same origin. 434 if (!allowsAccessFrom(exec)) 435 return jsUndefined(); 436 return Base::lookupSetter(exec, propertyName); 437} 438 439// Custom Attributes 440 441JSValue JSDOMWindow::history(ExecState* exec) const 442{ 443 History* history = impl()->history(); 444 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), history)) 445 return wrapper; 446 447 JSDOMWindow* window = const_cast<JSDOMWindow*>(this); 448 JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history); 449 cacheWrapper(currentWorld(exec), history, jsHistory); 450 return jsHistory; 451} 452 453JSValue JSDOMWindow::location(ExecState* exec) const 454{ 455 Location* location = impl()->location(); 456 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location)) 457 return wrapper; 458 459 JSDOMWindow* window = const_cast<JSDOMWindow*>(this); 460 JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location); 461 cacheWrapper(currentWorld(exec), location, jsLocation); 462 return jsLocation; 463} 464 465void JSDOMWindow::setLocation(ExecState* exec, JSValue value) 466{ 467#if ENABLE(DASHBOARD_SUPPORT) 468 // To avoid breaking old widgets, make "var location =" in a top-level frame create 469 // a property named "location" instead of performing a navigation (<rdar://problem/5688039>). 470 if (Frame* activeFrame = activeDOMWindow(exec)->frame()) { 471 if (Settings* settings = activeFrame->settings()) { 472 if (settings->usesDashboardBackwardCompatibilityMode() && !activeFrame->tree()->parent()) { 473 if (allowsAccessFrom(exec)) 474 putDirect(exec->globalData(), Identifier(exec, "location"), value); 475 return; 476 } 477 } 478 } 479#endif 480 481 UString locationString = value.toString(exec); 482 if (exec->hadException()) 483 return; 484 485 impl()->setLocation(ustringToString(locationString), activeDOMWindow(exec), firstDOMWindow(exec)); 486} 487 488JSValue JSDOMWindow::event(ExecState* exec) const 489{ 490 Event* event = currentEvent(); 491 if (!event) 492 return jsUndefined(); 493 return toJS(exec, event); 494} 495 496#if ENABLE(EVENTSOURCE) 497JSValue JSDOMWindow::eventSource(ExecState* exec) const 498{ 499 return getDOMConstructor<JSEventSourceConstructor>(exec, this); 500} 501#endif 502 503JSValue JSDOMWindow::image(ExecState* exec) const 504{ 505 return getDOMConstructor<JSImageConstructor>(exec, this); 506} 507 508JSValue JSDOMWindow::option(ExecState* exec) const 509{ 510 return getDOMConstructor<JSOptionConstructor>(exec, this); 511} 512 513#if ENABLE(VIDEO) 514JSValue JSDOMWindow::audio(ExecState* exec) const 515{ 516 if (!MediaPlayer::isAvailable()) 517 return jsUndefined(); 518 return getDOMConstructor<JSAudioConstructor>(exec, this); 519} 520#endif 521 522JSValue JSDOMWindow::webKitPoint(ExecState* exec) const 523{ 524 return getDOMConstructor<JSWebKitPointConstructor>(exec, this); 525} 526 527JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const 528{ 529 return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this); 530} 531 532JSValue JSDOMWindow::arrayBuffer(ExecState* exec) const 533{ 534 return getDOMConstructor<JSArrayBufferConstructor>(exec, this); 535} 536 537JSValue JSDOMWindow::int8Array(ExecState* exec) const 538{ 539 return getDOMConstructor<JSInt8ArrayConstructor>(exec, this); 540} 541 542JSValue JSDOMWindow::uint8Array(ExecState* exec) const 543{ 544 return getDOMConstructor<JSUint8ArrayConstructor>(exec, this); 545} 546 547JSValue JSDOMWindow::int32Array(ExecState* exec) const 548{ 549 return getDOMConstructor<JSInt32ArrayConstructor>(exec, this); 550} 551 552JSValue JSDOMWindow::uint32Array(ExecState* exec) const 553{ 554 return getDOMConstructor<JSUint32ArrayConstructor>(exec, this); 555} 556 557JSValue JSDOMWindow::int16Array(ExecState* exec) const 558{ 559 return getDOMConstructor<JSInt16ArrayConstructor>(exec, this); 560} 561 562JSValue JSDOMWindow::uint16Array(ExecState* exec) const 563{ 564 return getDOMConstructor<JSUint16ArrayConstructor>(exec, this); 565} 566 567JSValue JSDOMWindow::float32Array(ExecState* exec) const 568{ 569 return getDOMConstructor<JSFloat32ArrayConstructor>(exec, this); 570} 571 572JSValue JSDOMWindow::dataView(ExecState* exec) const 573{ 574 return getDOMConstructor<JSDataViewConstructor>(exec, this); 575} 576 577JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const 578{ 579 return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this); 580} 581 582#if ENABLE(XSLT) 583JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const 584{ 585 return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this); 586} 587#endif 588 589#if ENABLE(CHANNEL_MESSAGING) 590JSValue JSDOMWindow::messageChannel(ExecState* exec) const 591{ 592 return getDOMConstructor<JSMessageChannelConstructor>(exec, this); 593} 594#endif 595 596#if ENABLE(WORKERS) 597JSValue JSDOMWindow::worker(ExecState* exec) const 598{ 599 return getDOMConstructor<JSWorkerConstructor>(exec, this); 600} 601#endif 602 603#if ENABLE(SHARED_WORKERS) 604JSValue JSDOMWindow::sharedWorker(ExecState* exec) const 605{ 606 if (SharedWorkerRepository::isAvailable()) 607 return getDOMConstructor<JSSharedWorkerConstructor>(exec, this); 608 return jsUndefined(); 609} 610#endif 611 612#if ENABLE(WEB_AUDIO) 613JSValue JSDOMWindow::webkitAudioContext(ExecState* exec) const 614{ 615 return getDOMConstructor<JSAudioContextConstructor>(exec, this); 616} 617#endif 618 619#if ENABLE(WEB_SOCKETS) 620JSValue JSDOMWindow::webSocket(ExecState* exec) const 621{ 622 Frame* frame = impl()->frame(); 623 if (!frame) 624 return jsUndefined(); 625 Settings* settings = frame->settings(); 626 if (!settings) 627 return jsUndefined(); 628 return getDOMConstructor<JSWebSocketConstructor>(exec, this); 629} 630#endif 631 632// Custom functions 633 634JSValue JSDOMWindow::open(ExecState* exec) 635{ 636 String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)); 637 if (exec->hadException()) 638 return jsUndefined(); 639 AtomicString frameName = exec->argument(1).isUndefinedOrNull() ? "_blank" : ustringToAtomicString(exec->argument(1).toString(exec)); 640 if (exec->hadException()) 641 return jsUndefined(); 642 String windowFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); 643 if (exec->hadException()) 644 return jsUndefined(); 645 646 RefPtr<DOMWindow> openedWindow = impl()->open(urlString, frameName, windowFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec)); 647 if (!openedWindow) 648 return jsUndefined(); 649 return toJS(exec, openedWindow.get()); 650} 651 652class DialogHandler { 653public: 654 explicit DialogHandler(ExecState* exec) 655 : m_exec(exec) 656 , m_globalObject(0) 657 { 658 } 659 660 void dialogCreated(DOMWindow*); 661 JSValue returnValue() const; 662 663private: 664 ExecState* m_exec; 665 JSDOMWindow* m_globalObject; 666}; 667 668inline void DialogHandler::dialogCreated(DOMWindow* dialog) 669{ 670 // FIXME: This looks like a leak between the normal world and an isolated 671 // world if dialogArguments comes from an isolated world. 672 m_globalObject = toJSDOMWindow(dialog->frame(), normalWorld(m_exec->globalData())); 673 if (JSValue dialogArguments = m_exec->argument(1)) 674 m_globalObject->putDirect(m_exec->globalData(), Identifier(m_exec, "dialogArguments"), dialogArguments); 675} 676 677inline JSValue DialogHandler::returnValue() const 678{ 679 if (!m_globalObject) 680 return jsUndefined(); 681 Identifier identifier(m_exec, "returnValue"); 682 PropertySlot slot; 683 if (!m_globalObject->JSGlobalObject::getOwnPropertySlot(m_exec, identifier, slot)) 684 return jsUndefined(); 685 return slot.getValue(m_exec, identifier); 686} 687 688static void setUpDialog(DOMWindow* dialog, void* handler) 689{ 690 static_cast<DialogHandler*>(handler)->dialogCreated(dialog); 691} 692 693JSValue JSDOMWindow::showModalDialog(ExecState* exec) 694{ 695 String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)); 696 if (exec->hadException()) 697 return jsUndefined(); 698 String dialogFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); 699 if (exec->hadException()) 700 return jsUndefined(); 701 702 DialogHandler handler(exec); 703 704 impl()->showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec), setUpDialog, &handler); 705 706 return handler.returnValue(); 707} 708 709JSValue JSDOMWindow::postMessage(ExecState* exec) 710{ 711 PassRefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0)); 712 713 if (exec->hadException()) 714 return jsUndefined(); 715 716 MessagePortArray messagePorts; 717 if (exec->argumentCount() > 2) 718 fillMessagePortArray(exec, exec->argument(1), messagePorts); 719 if (exec->hadException()) 720 return jsUndefined(); 721 722 String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, exec->argument((exec->argumentCount() == 2) ? 1 : 2)); 723 if (exec->hadException()) 724 return jsUndefined(); 725 726 ExceptionCode ec = 0; 727 impl()->postMessage(message, &messagePorts, targetOrigin, activeDOMWindow(exec), ec); 728 setDOMException(exec, ec); 729 730 return jsUndefined(); 731} 732 733JSValue JSDOMWindow::setTimeout(ExecState* exec) 734{ 735 ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0; 736 OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy); 737 if (exec->hadException()) 738 return jsUndefined(); 739 740 if (!action) 741 return jsNumber(0); 742 743 int delay = exec->argument(1).toInt32(exec); 744 745 ExceptionCode ec = 0; 746 int result = impl()->setTimeout(action.release(), delay, ec); 747 setDOMException(exec, ec); 748 749 return jsNumber(result); 750} 751 752JSValue JSDOMWindow::setInterval(ExecState* exec) 753{ 754 ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0; 755 OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy); 756 if (exec->hadException()) 757 return jsUndefined(); 758 int delay = exec->argument(1).toInt32(exec); 759 760 if (!action) 761 return jsNumber(0); 762 763 ExceptionCode ec = 0; 764 int result = impl()->setInterval(action.release(), delay, ec); 765 setDOMException(exec, ec); 766 767 return jsNumber(result); 768} 769 770JSValue JSDOMWindow::addEventListener(ExecState* exec) 771{ 772 Frame* frame = impl()->frame(); 773 if (!frame) 774 return jsUndefined(); 775 776 JSValue listener = exec->argument(1); 777 if (!listener.isObject()) 778 return jsUndefined(); 779 780 impl()->addEventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), exec->argument(2).toBoolean(exec)); 781 return jsUndefined(); 782} 783 784JSValue JSDOMWindow::removeEventListener(ExecState* exec) 785{ 786 Frame* frame = impl()->frame(); 787 if (!frame) 788 return jsUndefined(); 789 790 JSValue listener = exec->argument(1); 791 if (!listener.isObject()) 792 return jsUndefined(); 793 794 impl()->removeEventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), exec->argument(2).toBoolean(exec)); 795 return jsUndefined(); 796} 797 798DOMWindow* toDOMWindow(JSValue value) 799{ 800 if (!value.isObject()) 801 return 0; 802 JSObject* object = asObject(value); 803 if (object->inherits(&JSDOMWindow::s_info)) 804 return static_cast<JSDOMWindow*>(object)->impl(); 805 if (object->inherits(&JSDOMWindowShell::s_info)) 806 return static_cast<JSDOMWindowShell*>(object)->impl(); 807 return 0; 808} 809 810} // namespace WebCore 811