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 71 using namespace JSC; 72 73 namespace WebCore { 74 75 void 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 105 template<NativeFunction nativeFunction, int length> 106 JSValue nonCachingStaticFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName) 107 { 108 return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), length, propertyName, nativeFunction); 109 } 110 111 static 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 116 static 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 121 static 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 136 bool 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 279 bool 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 351 void 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 370 bool 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 378 void 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 386 void 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 394 void 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 407 void 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 415 bool 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 423 JSValue 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 431 JSValue 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 441 JSValue 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 453 JSValue 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 465 void 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 488 JSValue 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) 497 JSValue JSDOMWindow::eventSource(ExecState* exec) const 498 { 499 return getDOMConstructor<JSEventSourceConstructor>(exec, this); 500 } 501 #endif 502 503 JSValue JSDOMWindow::image(ExecState* exec) const 504 { 505 return getDOMConstructor<JSImageConstructor>(exec, this); 506 } 507 508 JSValue JSDOMWindow::option(ExecState* exec) const 509 { 510 return getDOMConstructor<JSOptionConstructor>(exec, this); 511 } 512 513 #if ENABLE(VIDEO) 514 JSValue JSDOMWindow::audio(ExecState* exec) const 515 { 516 if (!MediaPlayer::isAvailable()) 517 return jsUndefined(); 518 return getDOMConstructor<JSAudioConstructor>(exec, this); 519 } 520 #endif 521 522 JSValue JSDOMWindow::webKitPoint(ExecState* exec) const 523 { 524 return getDOMConstructor<JSWebKitPointConstructor>(exec, this); 525 } 526 527 JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const 528 { 529 return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this); 530 } 531 532 JSValue JSDOMWindow::arrayBuffer(ExecState* exec) const 533 { 534 return getDOMConstructor<JSArrayBufferConstructor>(exec, this); 535 } 536 537 JSValue JSDOMWindow::int8Array(ExecState* exec) const 538 { 539 return getDOMConstructor<JSInt8ArrayConstructor>(exec, this); 540 } 541 542 JSValue JSDOMWindow::uint8Array(ExecState* exec) const 543 { 544 return getDOMConstructor<JSUint8ArrayConstructor>(exec, this); 545 } 546 547 JSValue JSDOMWindow::int32Array(ExecState* exec) const 548 { 549 return getDOMConstructor<JSInt32ArrayConstructor>(exec, this); 550 } 551 552 JSValue JSDOMWindow::uint32Array(ExecState* exec) const 553 { 554 return getDOMConstructor<JSUint32ArrayConstructor>(exec, this); 555 } 556 557 JSValue JSDOMWindow::int16Array(ExecState* exec) const 558 { 559 return getDOMConstructor<JSInt16ArrayConstructor>(exec, this); 560 } 561 562 JSValue JSDOMWindow::uint16Array(ExecState* exec) const 563 { 564 return getDOMConstructor<JSUint16ArrayConstructor>(exec, this); 565 } 566 567 JSValue JSDOMWindow::float32Array(ExecState* exec) const 568 { 569 return getDOMConstructor<JSFloat32ArrayConstructor>(exec, this); 570 } 571 572 JSValue JSDOMWindow::dataView(ExecState* exec) const 573 { 574 return getDOMConstructor<JSDataViewConstructor>(exec, this); 575 } 576 577 JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const 578 { 579 return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this); 580 } 581 582 #if ENABLE(XSLT) 583 JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const 584 { 585 return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this); 586 } 587 #endif 588 589 #if ENABLE(CHANNEL_MESSAGING) 590 JSValue JSDOMWindow::messageChannel(ExecState* exec) const 591 { 592 return getDOMConstructor<JSMessageChannelConstructor>(exec, this); 593 } 594 #endif 595 596 #if ENABLE(WORKERS) 597 JSValue JSDOMWindow::worker(ExecState* exec) const 598 { 599 return getDOMConstructor<JSWorkerConstructor>(exec, this); 600 } 601 #endif 602 603 #if ENABLE(SHARED_WORKERS) 604 JSValue 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) 613 JSValue JSDOMWindow::webkitAudioContext(ExecState* exec) const 614 { 615 return getDOMConstructor<JSAudioContextConstructor>(exec, this); 616 } 617 #endif 618 619 #if ENABLE(WEB_SOCKETS) 620 JSValue 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 634 JSValue 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 652 class DialogHandler { 653 public: 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 663 private: 664 ExecState* m_exec; 665 JSDOMWindow* m_globalObject; 666 }; 667 668 inline 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 677 inline 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 688 static void setUpDialog(DOMWindow* dialog, void* handler) 689 { 690 static_cast<DialogHandler*>(handler)->dialogCreated(dialog); 691 } 692 693 JSValue 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 709 JSValue 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 733 JSValue 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 752 JSValue 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 770 JSValue 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 784 JSValue 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 798 DOMWindow* 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