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