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