Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMWindowCustom.cpp
1 /*
2  * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "JSDOMWindowCustom.h"
23
24 #include "DOMWindowIndexedDatabase.h"
25 #include "Frame.h"
26 #include "HTMLCollection.h"
27 #include "HTMLDocument.h"
28 #include "HTMLFrameOwnerElement.h"
29 #include "HTTPParsers.h"
30 #include "JSDOMBindingSecurity.h"
31 #include "JSDOMConvertNullable.h"
32 #include "JSDOMConvertNumbers.h"
33 #include "JSDOMConvertStrings.h"
34 #include "JSEvent.h"
35 #include "JSEventListener.h"
36 #include "JSHTMLAudioElement.h"
37 #include "JSHTMLCollection.h"
38 #include "JSHTMLOptionElement.h"
39 #include "JSIDBFactory.h"
40 #include "JSRemoteDOMWindow.h"
41 #include "JSWindowProxy.h"
42 #include "JSWorker.h"
43 #include "Location.h"
44 #include "RuntimeEnabledFeatures.h"
45 #include "ScheduledAction.h"
46 #include "Settings.h"
47 #include "WebCoreJSClientData.h"
48 #include <JavaScriptCore/BuiltinNames.h>
49 #include <JavaScriptCore/HeapSnapshotBuilder.h>
50 #include <JavaScriptCore/JSCInlines.h>
51 #include <JavaScriptCore/JSMicrotask.h>
52 #include <JavaScriptCore/Lookup.h>
53
54 #if ENABLE(USER_MESSAGE_HANDLERS)
55 #include "JSWebKitNamespace.h"
56 #endif
57
58
59 namespace WebCore {
60 using namespace JSC;
61
62 EncodedJSValue JSC_HOST_CALL jsDOMWindowInstanceFunctionShowModalDialog(ExecState*);
63
64 void JSDOMWindow::visitAdditionalChildren(SlotVisitor& visitor)
65 {
66     if (Frame* frame = wrapped().frame())
67         visitor.addOpaqueRoot(frame);
68     
69     // Normally JSEventTargetCustom.cpp's JSEventTarget::visitAdditionalChildren() would call this. But
70     // even though DOMWindow is an EventTarget, JSDOMWindow does not subclass JSEventTarget, so we need
71     // to do this here.
72     wrapped().visitJSEventListeners(visitor);
73 }
74
75 #if ENABLE(USER_MESSAGE_HANDLERS)
76 static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, EncodedJSValue thisValue, PropertyName)
77 {
78     VM& vm = exec->vm();
79     JSDOMWindow* castedThis = toJSDOMWindow(vm, JSValue::decode(thisValue));
80     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->wrapped()))
81         return JSValue::encode(jsUndefined());
82     return JSValue::encode(toJS(exec, castedThis->globalObject(), castedThis->wrapped().webkitNamespace()));
83 }
84 #endif
85
86 template <DOMWindowType windowType>
87 bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMGlobalObject* thisObject, AbstractDOMWindow& window, ExecState& state, PropertyName propertyName, PropertySlot& slot, const String& errorMessage)
88 {
89     VM& vm = state.vm();
90     auto scope = DECLARE_THROW_SCOPE(vm);
91
92     auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames();
93
94     // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
95
96     // These are the functions we allow access to cross-origin (DoNotCheckSecurity in IDL).
97     // Always provide the original function, on a fresh uncached function object.
98     if (propertyName == builtinNames.blurPublicName()) {
99         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? nonCachingStaticFunctionGetter<jsRemoteDOMWindowInstanceFunctionBlur, 0> : nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionBlur, 0>);
100         return true;
101     }
102     if (propertyName == builtinNames.closePublicName()) {
103         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? nonCachingStaticFunctionGetter<jsRemoteDOMWindowInstanceFunctionClose, 0> : nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>);
104         return true;
105     }
106     if (propertyName == builtinNames.focusPublicName()) {
107         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? nonCachingStaticFunctionGetter<jsRemoteDOMWindowInstanceFunctionFocus, 0> : nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionFocus, 0>);
108         return true;
109     }
110     if (propertyName == builtinNames.postMessagePublicName()) {
111         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), windowType == DOMWindowType::Remote ? nonCachingStaticFunctionGetter<jsRemoteDOMWindowInstanceFunctionPostMessage, 0> : nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionPostMessage, 2>);
112         return true;
113     }
114
115     // When accessing cross-origin known Window properties, we always use the original property getter,
116     // even if the property was removed / redefined. As of early 2016, this matches Firefox and Chrome's
117     // behavior.
118     auto* classInfo = windowType == DOMWindowType::Remote ? JSRemoteDOMWindow::info() : JSDOMWindow::info();
119     if (auto* entry = classInfo->staticPropHashTable->entry(propertyName)) {
120         // Only allow access to these specific properties.
121         if (propertyName == builtinNames.locationPublicName()
122             || propertyName == builtinNames.closedPublicName()
123             || propertyName == vm.propertyNames->length
124             || propertyName == builtinNames.selfPublicName()
125             || propertyName == builtinNames.windowPublicName()
126             || propertyName == builtinNames.framesPublicName()
127             || propertyName == builtinNames.openerPublicName()
128             || propertyName == builtinNames.parentPublicName()
129             || propertyName == builtinNames.topPublicName()) {
130             bool shouldExposeSetter = propertyName == builtinNames.locationPublicName();
131             CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, entry->propertyGetter(), shouldExposeSetter ? entry->propertyPutter() : nullptr);
132             slot.setCustomGetterSetter(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontEnum), customGetterSetter);
133             return true;
134         }
135
136         // For any other entries in the static property table, deny access. (Early return also prevents
137         // named getter from returning frames with matching names - this seems a little questionable, see
138         // FIXME comment on prototype search below.)
139         throwSecurityError(state, scope, errorMessage);
140         slot.setUndefined();
141         return false;
142     }
143
144     // Check for child frames by name before built-in properties to match Mozilla. This does
145     // not match IE, but some sites end up naming frames things that conflict with window
146     // properties that are in Moz but not IE. Since we have some of these, we have to do it
147     // the Moz way.
148     // FIXME: Add support to named attributes on RemoteFrames.
149     auto* frame = window.frame();
150     if (frame && is<Frame>(*frame)) {
151         if (auto* scopedChild = downcast<Frame>(*frame).tree().scopedChild(propertyNameToAtomString(propertyName))) {
152             slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, toJS(&state, scopedChild->document()->domWindow()));
153             return true;
154         }
155     }
156
157     if (handleCommonCrossOriginProperties(thisObject, vm, propertyName, slot))
158         return true;
159
160     throwSecurityError(state, scope, errorMessage);
161     slot.setUndefined();
162     return false;
163 }
164 template bool jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(JSDOMGlobalObject*, AbstractDOMWindow&, ExecState&, PropertyName, PropertySlot&, const String&);
165 template bool jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Remote>(JSDOMGlobalObject*, AbstractDOMWindow&, ExecState&, PropertyName, PropertySlot&, const String&);
166
167 // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
168 bool handleCommonCrossOriginProperties(JSObject* thisObject, VM& vm, PropertyName propertyName, PropertySlot& slot)
169 {
170     auto& propertyNames =  vm.propertyNames;
171     if (propertyName == propertyNames->builtinNames().thenPublicName() || propertyName == propertyNames->toStringTagSymbol || propertyName == propertyNames->hasInstanceSymbol || propertyName == propertyNames->isConcatSpreadableSymbol) {
172         slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum, jsUndefined());
173         return true;
174     }
175     return false;
176 }
177
178 // Property access sequence is:
179 // (1) indexed properties,
180 // (2) regular own properties,
181 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
182 bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
183 {
184     // (1) First, indexed properties.
185     // Hand off all indexed access to getOwnPropertySlotByIndex, which supports the indexed getter.
186     if (Optional<unsigned> index = parseIndex(propertyName))
187         return getOwnPropertySlotByIndex(object, state, index.value(), slot);
188
189     auto* thisObject = jsCast<JSDOMWindow*>(object);
190
191     // Hand off all cross-domain access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
192     String errorMessage;
193     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage))
194         return jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(thisObject, thisObject->wrapped(), *state, propertyName, slot, errorMessage);
195
196     // FIXME: this needs more explanation.
197     // (Particularly, is it correct that this exists here but not in getOwnPropertySlotByIndex?)
198     slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints);
199
200     // (2) Regular own properties.
201     PropertySlot slotCopy = slot;
202     if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot)) {
203         auto* frame = thisObject->wrapped().frame();
204
205         // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value.
206         bool isShowModalDialogAndShouldHide = propertyName == static_cast<JSVMClientData*>(state->vm().clientData)->builtinNames().showModalDialogPublicName()
207             && (!frame || !DOMWindow::canShowModalDialog(*frame))
208             && slot.isValue() && isHostFunction(slot.getValue(state, propertyName), jsDOMWindowInstanceFunctionShowModalDialog);
209         // Unless we're in the showModalDialog special case, we're done.
210         if (!isShowModalDialogAndShouldHide)
211             return true;
212         slot = slotCopy;
213     }
214
215 #if ENABLE(USER_MESSAGE_HANDLERS)
216     if (propertyName == static_cast<JSVMClientData*>(state->vm().clientData)->builtinNames().webkitPublicName() && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) {
217         slot.setCacheableCustom(thisObject, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly, jsDOMWindowWebKit);
218         return true;
219     }
220 #endif
221
222     return false;
223 }
224
225 // Property access sequence is:
226 // (1) indexed properties,
227 // (2) regular own properties,
228 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
229 bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)
230 {
231     auto* thisObject = jsCast<JSDOMWindow*>(object);
232     auto& window = thisObject->wrapped();
233     auto* frame = window.frame();
234
235     // Indexed getters take precendence over regular properties, so caching would be invalid.
236     slot.disableCaching();
237
238     String errorMessage;
239     Optional<bool> cachedIsCrossOriginAccess;
240     auto isCrossOriginAccess = [&] {
241         if (!cachedIsCrossOriginAccess)
242             cachedIsCrossOriginAccess = !BindingSecurity::shouldAllowAccessToDOMWindow(*state, window, errorMessage);
243         return *cachedIsCrossOriginAccess;
244     };
245
246     // (1) First, indexed properties.
247     // These are also allowed cross-origin, so come before the access check.
248     if (frame && index < frame->tree().scopedChildCount()) {
249         slot.setValue(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly), toJS(state, frame->tree().scopedChild(index)->document()->domWindow()));
250         return true;
251     }
252
253     // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
254     if (isCrossOriginAccess())
255         return jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(thisObject, window, *state, Identifier::from(state, index), slot, errorMessage);
256
257     // (2) Regular own properties.
258     return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);
259 }
260
261 bool JSDOMWindow::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
262 {
263     VM& vm = state->vm();
264     auto scope = DECLARE_THROW_SCOPE(vm);
265
266     auto* thisObject = jsCast<JSDOMWindow*>(cell);
267     if (!thisObject->wrapped().frame())
268         return false;
269
270     String errorMessage;
271     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) {
272         // We only allow setting "location" attribute cross-origin.
273         if (propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName()) {
274             bool putResult = false;
275             if (lookupPut(state, propertyName, thisObject, value, *s_info.staticPropHashTable, slot, putResult))
276                 return putResult;
277             return false;
278         }
279         throwSecurityError(*state, scope, errorMessage);
280         return false;
281     }
282
283     return Base::put(thisObject, state, propertyName, value, slot);
284 }
285
286 bool JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
287 {
288     auto* thisObject = jsCast<JSDOMWindow*>(cell);
289     if (!thisObject->wrapped().frame() || !BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
290         return false;
291     
292     return Base::putByIndex(thisObject, exec, index, value, shouldThrow);
293 }
294
295 bool JSDOMWindow::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
296 {
297     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
298     // Only allow deleting properties by frames in the same origin.
299     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
300         return false;
301     return Base::deleteProperty(thisObject, exec, propertyName);
302 }
303
304 bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
305 {
306     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
307     // Only allow deleting properties by frames in the same origin.
308     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
309         return false;
310     return Base::deletePropertyByIndex(thisObject, exec, propertyName);
311 }
312
313 void JSDOMWindow::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
314 {
315     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
316     auto& location = thisObject->wrapped().location();
317     builder.setLabelForCell(cell, location.href());
318
319     Base::heapSnapshot(cell, builder);
320 }
321
322 // https://html.spec.whatwg.org/#crossoriginproperties-(-o-)
323 template <CrossOriginObject objectType>
324 static void addCrossOriginPropertyNames(VM& vm, PropertyNameArray& propertyNames)
325 {
326     auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames();
327     switch (objectType) {
328     case CrossOriginObject::Location: {
329         static const Identifier* const properties[] = { &builtinNames.hrefPublicName(), &vm.propertyNames->replace };
330         for (auto* property : properties)
331             propertyNames.add(*property);
332         break;
333     }
334     case CrossOriginObject::Window: {
335         static const Identifier* const properties[] = {
336             &builtinNames.blurPublicName(), &builtinNames.closePublicName(), &builtinNames.closedPublicName(),
337             &builtinNames.focusPublicName(), &builtinNames.framesPublicName(), &vm.propertyNames->length,
338             &builtinNames.locationPublicName(), &builtinNames.openerPublicName(), &builtinNames.parentPublicName(),
339             &builtinNames.postMessagePublicName(), &builtinNames.selfPublicName(), &builtinNames.topPublicName(),
340             &builtinNames.windowPublicName()
341         };
342
343         for (auto* property : properties)
344             propertyNames.add(*property);
345         break;
346     }
347     }
348 }
349
350 // https://html.spec.whatwg.org/#crossoriginownpropertykeys-(-o-)
351 template <CrossOriginObject objectType>
352 void addCrossOriginOwnPropertyNames(JSC::ExecState& state, JSC::PropertyNameArray& propertyNames)
353 {
354     auto& vm = state.vm();
355     addCrossOriginPropertyNames<objectType>(vm, propertyNames);
356
357     static const Identifier* const properties[] = {
358         &vm.propertyNames->builtinNames().thenPublicName(), &vm.propertyNames->toStringTagSymbol, &vm.propertyNames->hasInstanceSymbol, &vm.propertyNames->isConcatSpreadableSymbol
359     };
360
361     for (auto* property : properties)
362         propertyNames.add(*property);
363
364 }
365 template void addCrossOriginOwnPropertyNames<CrossOriginObject::Window>(JSC::ExecState&, JSC::PropertyNameArray&);
366 template void addCrossOriginOwnPropertyNames<CrossOriginObject::Location>(JSC::ExecState&, JSC::PropertyNameArray&);
367
368 static void addScopedChildrenIndexes(ExecState& state, DOMWindow& window, PropertyNameArray& propertyNames)
369 {
370     auto* document = window.document();
371     if (!document)
372         return;
373
374     auto* frame = document->frame();
375     if (!frame)
376         return;
377
378     unsigned scopedChildCount = frame->tree().scopedChildCount();
379     for (unsigned i = 0; i < scopedChildCount; ++i)
380         propertyNames.add(Identifier::from(&state, i));
381 }
382
383 // https://html.spec.whatwg.org/#windowproxy-ownpropertykeys
384 void JSDOMWindow::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
385 {
386     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
387
388     addScopedChildrenIndexes(*exec, thisObject->wrapped(), propertyNames);
389
390     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError)) {
391         if (mode.includeDontEnumProperties())
392             addCrossOriginOwnPropertyNames<CrossOriginObject::Window>(*exec, propertyNames);
393         return;
394     }
395     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
396 }
397
398 bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
399 {
400     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
401     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
402     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
403         return false;
404
405     // Don't allow shadowing location using accessor properties.
406     if (descriptor.isAccessorDescriptor() && propertyName == Identifier::fromString(exec, "location"))
407         return false;
408
409     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
410 }
411
412 JSValue JSDOMWindow::getPrototype(JSObject* object, ExecState* exec)
413 {
414     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
415     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError))
416         return jsNull();
417
418     return Base::getPrototype(object, exec);
419 }
420
421 bool JSDOMWindow::preventExtensions(JSObject*, ExecState* exec)
422 {
423     auto scope = DECLARE_THROW_SCOPE(exec->vm());
424
425     throwTypeError(exec, scope, "Cannot prevent extensions on this object"_s);
426     return false;
427 }
428
429 String JSDOMWindow::toStringName(const JSObject* object, ExecState* exec)
430 {
431     auto* thisObject = jsCast<const JSDOMWindow*>(object);
432     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError))
433         return "Object"_s;
434     return "Window"_s;
435 }
436
437 // Custom Attributes
438
439 JSValue JSDOMWindow::event(ExecState& state) const
440 {
441     Event* event = currentEvent();
442     if (!event)
443         return jsUndefined();
444     return toJS(&state, const_cast<JSDOMWindow*>(this), event);
445 }
446
447 // Custom functions
448
449 class DialogHandler {
450 public:
451     explicit DialogHandler(ExecState& exec)
452         : m_exec(exec)
453     {
454     }
455
456     void dialogCreated(DOMWindow&);
457     JSValue returnValue() const;
458
459 private:
460     ExecState& m_exec;
461     RefPtr<Frame> m_frame;
462 };
463
464 inline void DialogHandler::dialogCreated(DOMWindow& dialog)
465 {
466     m_frame = dialog.frame();
467     
468     // FIXME: This looks like a leak between the normal world and an isolated
469     //        world if dialogArguments comes from an isolated world.
470     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm()));
471     if (JSValue dialogArguments = m_exec.argument(1))
472         globalObject->putDirect(m_exec.vm(), Identifier::fromString(&m_exec, "dialogArguments"), dialogArguments);
473 }
474
475 inline JSValue DialogHandler::returnValue() const
476 {
477     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm()));
478     if (!globalObject)
479         return jsUndefined();
480     Identifier identifier = Identifier::fromString(&m_exec, "returnValue");
481     PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get);
482     if (!JSGlobalObject::getOwnPropertySlot(globalObject, &m_exec, identifier, slot))
483         return jsUndefined();
484     return slot.getValue(&m_exec, identifier);
485 }
486
487 JSValue JSDOMWindow::showModalDialog(ExecState& state)
488 {
489     VM& vm = state.vm();
490     auto scope = DECLARE_THROW_SCOPE(vm);
491
492     if (UNLIKELY(state.argumentCount() < 1))
493         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
494
495     String urlString = convert<IDLNullable<IDLDOMString>>(state, state.argument(0));
496     RETURN_IF_EXCEPTION(scope, JSValue());
497     String dialogFeaturesString = convert<IDLNullable<IDLDOMString>>(state, state.argument(2));
498     RETURN_IF_EXCEPTION(scope, JSValue());
499
500     DialogHandler handler(state);
501
502     wrapped().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(state), firstDOMWindow(state), [&handler](DOMWindow& dialog) {
503         handler.dialogCreated(dialog);
504     });
505
506     return handler.returnValue();
507 }
508
509 JSValue JSDOMWindow::queueMicrotask(ExecState& state)
510 {
511     VM& vm = state.vm();
512     auto scope = DECLARE_THROW_SCOPE(vm);
513
514     if (UNLIKELY(state.argumentCount() < 1))
515         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
516
517     JSValue functionValue = state.uncheckedArgument(0);
518     if (UNLIKELY(!functionValue.isFunction(vm)))
519         return JSValue::decode(throwArgumentMustBeFunctionError(state, scope, 0, "callback", "Window", "queueMicrotask"));
520
521     scope.release();
522     Base::queueMicrotask(JSC::createJSMicrotask(vm, functionValue));
523     return jsUndefined();
524 }
525
526 DOMWindow* JSDOMWindow::toWrapped(VM& vm, JSValue value)
527 {
528     if (!value.isObject())
529         return nullptr;
530     JSObject* object = asObject(value);
531     if (object->inherits<JSDOMWindow>(vm))
532         return &jsCast<JSDOMWindow*>(object)->wrapped();
533     if (object->inherits<JSWindowProxy>(vm)) {
534         if (auto* jsDOMWindow = jsDynamicCast<JSDOMWindow*>(vm, jsCast<JSWindowProxy*>(object)->window()))
535             return &jsDOMWindow->wrapped();
536     }
537     return nullptr;
538 }
539
540 void JSDOMWindow::setOpener(JSC::ExecState& state, JSC::JSValue value)
541 {
542     if (!BindingSecurity::shouldAllowAccessToDOMWindow(&state, wrapped(), ThrowSecurityError))
543         return;
544
545     if (value.isNull()) {
546         wrapped().disownOpener();
547         return;
548     }
549     replaceStaticPropertySlot(state.vm(), this, Identifier::fromString(&state.vm(), "opener"), value);
550 }
551
552 JSValue JSDOMWindow::self(JSC::ExecState&) const
553 {
554     return globalThis();
555 }
556
557 JSValue JSDOMWindow::window(JSC::ExecState&) const
558 {
559     return globalThis();
560 }
561
562 JSValue JSDOMWindow::frames(JSC::ExecState&) const
563 {
564     return globalThis();
565 }
566
567 } // namespace WebCore