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