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
59namespace WebCore {
60using namespace JSC;
61
62EncodedJSValue JSC_HOST_CALL jsDOMWindowInstanceFunctionShowModalDialog(ExecState*);
63
64void 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)
76static 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
86template <DOMWindowType windowType>
87bool 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(propertyNameToAtomicString(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}
164template bool jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(JSDOMGlobalObject*, AbstractDOMWindow&, ExecState&, PropertyName, PropertySlot&, const String&);
165template bool jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Remote>(JSDOMGlobalObject*, AbstractDOMWindow&, ExecState&, PropertyName, PropertySlot&, const String&);
166
167// https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
168bool 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).
182bool 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).
229bool 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
261bool 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
286bool 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
295bool 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
304bool 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
313void 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-)
323template <CrossOriginObject objectType>
324static 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-)
351template <CrossOriginObject objectType>
352void 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}
365template void addCrossOriginOwnPropertyNames<CrossOriginObject::Window>(JSC::ExecState&, JSC::PropertyNameArray&);
366template void addCrossOriginOwnPropertyNames<CrossOriginObject::Location>(JSC::ExecState&, JSC::PropertyNameArray&);
367
368static 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
384void 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
398bool 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
412JSValue 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
421bool 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
429String 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
439JSValue 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
449class DialogHandler {
450public:
451 explicit DialogHandler(ExecState& exec)
452 : m_exec(exec)
453 {
454 }
455
456 void dialogCreated(DOMWindow&);
457 JSValue returnValue() const;
458
459private:
460 ExecState& m_exec;
461 RefPtr<Frame> m_frame;
462};
463
464inline 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
475inline 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
487JSValue 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
509JSValue 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
526DOMWindow* 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
540void 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
552JSValue JSDOMWindow::self(JSC::ExecState&) const
553{
554 return globalThis();
555}
556
557JSValue JSDOMWindow::window(JSC::ExecState&) const
558{
559 return globalThis();
560}
561
562JSValue JSDOMWindow::frames(JSC::ExecState&) const
563{
564 return globalThis();
565}
566
567} // namespace WebCore
568