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
markChildren(MarkStack & markStack)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>
nonCachingStaticFunctionGetter(ExecState * exec,JSValue,const Identifier & propertyName)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
childFrameGetter(ExecState * exec,JSValue slotBase,const Identifier & propertyName)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
indexGetter(ExecState * exec,JSValue slotBase,unsigned index)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
namedItemGetter(ExecState * exec,JSValue slotBase,const Identifier & propertyName)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
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)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
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)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
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)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
deleteProperty(ExecState * exec,const Identifier & propertyName)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
getPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)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
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)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
defineGetter(ExecState * exec,const Identifier & propertyName,JSObject * getterFunction,unsigned attributes)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
defineSetter(ExecState * exec,const Identifier & propertyName,JSObject * setterFunction,unsigned attributes)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
defineOwnProperty(JSC::ExecState * exec,const JSC::Identifier & propertyName,JSC::PropertyDescriptor & descriptor,bool shouldThrow)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
lookupGetter(ExecState * exec,const Identifier & propertyName)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
lookupSetter(ExecState * exec,const Identifier & propertyName)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
history(ExecState * exec) const441 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
location(ExecState * exec) const453 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
setLocation(ExecState * exec,JSValue value)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
event(ExecState * exec) const488 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)
eventSource(ExecState * exec) const497 JSValue JSDOMWindow::eventSource(ExecState* exec) const
498 {
499 return getDOMConstructor<JSEventSourceConstructor>(exec, this);
500 }
501 #endif
502
image(ExecState * exec) const503 JSValue JSDOMWindow::image(ExecState* exec) const
504 {
505 return getDOMConstructor<JSImageConstructor>(exec, this);
506 }
507
option(ExecState * exec) const508 JSValue JSDOMWindow::option(ExecState* exec) const
509 {
510 return getDOMConstructor<JSOptionConstructor>(exec, this);
511 }
512
513 #if ENABLE(VIDEO)
audio(ExecState * exec) const514 JSValue JSDOMWindow::audio(ExecState* exec) const
515 {
516 if (!MediaPlayer::isAvailable())
517 return jsUndefined();
518 return getDOMConstructor<JSAudioConstructor>(exec, this);
519 }
520 #endif
521
webKitPoint(ExecState * exec) const522 JSValue JSDOMWindow::webKitPoint(ExecState* exec) const
523 {
524 return getDOMConstructor<JSWebKitPointConstructor>(exec, this);
525 }
526
webKitCSSMatrix(ExecState * exec) const527 JSValue JSDOMWindow::webKitCSSMatrix(ExecState* exec) const
528 {
529 return getDOMConstructor<JSWebKitCSSMatrixConstructor>(exec, this);
530 }
531
arrayBuffer(ExecState * exec) const532 JSValue JSDOMWindow::arrayBuffer(ExecState* exec) const
533 {
534 return getDOMConstructor<JSArrayBufferConstructor>(exec, this);
535 }
536
int8Array(ExecState * exec) const537 JSValue JSDOMWindow::int8Array(ExecState* exec) const
538 {
539 return getDOMConstructor<JSInt8ArrayConstructor>(exec, this);
540 }
541
uint8Array(ExecState * exec) const542 JSValue JSDOMWindow::uint8Array(ExecState* exec) const
543 {
544 return getDOMConstructor<JSUint8ArrayConstructor>(exec, this);
545 }
546
int32Array(ExecState * exec) const547 JSValue JSDOMWindow::int32Array(ExecState* exec) const
548 {
549 return getDOMConstructor<JSInt32ArrayConstructor>(exec, this);
550 }
551
uint32Array(ExecState * exec) const552 JSValue JSDOMWindow::uint32Array(ExecState* exec) const
553 {
554 return getDOMConstructor<JSUint32ArrayConstructor>(exec, this);
555 }
556
int16Array(ExecState * exec) const557 JSValue JSDOMWindow::int16Array(ExecState* exec) const
558 {
559 return getDOMConstructor<JSInt16ArrayConstructor>(exec, this);
560 }
561
uint16Array(ExecState * exec) const562 JSValue JSDOMWindow::uint16Array(ExecState* exec) const
563 {
564 return getDOMConstructor<JSUint16ArrayConstructor>(exec, this);
565 }
566
float32Array(ExecState * exec) const567 JSValue JSDOMWindow::float32Array(ExecState* exec) const
568 {
569 return getDOMConstructor<JSFloat32ArrayConstructor>(exec, this);
570 }
571
dataView(ExecState * exec) const572 JSValue JSDOMWindow::dataView(ExecState* exec) const
573 {
574 return getDOMConstructor<JSDataViewConstructor>(exec, this);
575 }
576
xmlHttpRequest(ExecState * exec) const577 JSValue JSDOMWindow::xmlHttpRequest(ExecState* exec) const
578 {
579 return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this);
580 }
581
582 #if ENABLE(XSLT)
xsltProcessor(ExecState * exec) const583 JSValue JSDOMWindow::xsltProcessor(ExecState* exec) const
584 {
585 return getDOMConstructor<JSXSLTProcessorConstructor>(exec, this);
586 }
587 #endif
588
589 #if ENABLE(CHANNEL_MESSAGING)
messageChannel(ExecState * exec) const590 JSValue JSDOMWindow::messageChannel(ExecState* exec) const
591 {
592 return getDOMConstructor<JSMessageChannelConstructor>(exec, this);
593 }
594 #endif
595
596 #if ENABLE(WORKERS)
worker(ExecState * exec) const597 JSValue JSDOMWindow::worker(ExecState* exec) const
598 {
599 return getDOMConstructor<JSWorkerConstructor>(exec, this);
600 }
601 #endif
602
603 #if ENABLE(SHARED_WORKERS)
sharedWorker(ExecState * exec) const604 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)
webkitAudioContext(ExecState * exec) const613 JSValue JSDOMWindow::webkitAudioContext(ExecState* exec) const
614 {
615 return getDOMConstructor<JSAudioContextConstructor>(exec, this);
616 }
617 #endif
618
619 #if ENABLE(WEB_SOCKETS)
webSocket(ExecState * exec) const620 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
open(ExecState * exec)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:
DialogHandler(ExecState * exec)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
dialogCreated(DOMWindow * dialog)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
returnValue() const677 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
setUpDialog(DOMWindow * dialog,void * handler)688 static void setUpDialog(DOMWindow* dialog, void* handler)
689 {
690 static_cast<DialogHandler*>(handler)->dialogCreated(dialog);
691 }
692
showModalDialog(ExecState * exec)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
postMessage(ExecState * exec)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
setTimeout(ExecState * exec)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
setInterval(ExecState * exec)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
addEventListener(ExecState * exec)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
removeEventListener(ExecState * exec)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
toDOMWindow(JSValue value)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