1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block/*
2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Copyright (C) 2010 Google Inc. All rights reserved.
3dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *
4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Redistribution and use in source and binary forms, with or without
5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * modification, are permitted provided that the following conditions are
6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * met:
7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *
8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *     * Redistributions of source code must retain the above copyright
9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * notice, this list of conditions and the following disclaimer.
10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *     * Redistributions in binary form must reproduce the above
11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * copyright notice, this list of conditions and the following disclaimer
12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * in the documentation and/or other materials provided with the
13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * distribution.
14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *     * Neither the name of Google Inc. nor the names of its
15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * contributors may be used to endorse or promote products derived from
16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * this software without specific prior written permission.
17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *
18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block */
30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvar InjectedFakeWorker = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockWorker = function(url)
35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    var impl = new FakeWorker(this, url);
37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (impl === null)
38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return null;
39dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.isFake = true;
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.postMessage = bind(impl.postMessage, impl);
42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.terminate = bind(impl.terminate, impl);
43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    function onmessageGetter()
45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return impl.channel.port1.onmessage;
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    function onmessageSetter(callback)
49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        impl.channel.port1.onmessage = callback;
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.__defineGetter__("onmessage", onmessageGetter);
53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.__defineSetter__("onmessage", onmessageSetter);
54dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.addEventListener = bind(impl.channel.port1.addEventListener, impl.channel.port1);
55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.removeEventListener = bind(impl.channel.port1.removeEventListener, impl.channel.port1);
56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.dispatchEvent = bind(impl.channel.port1.dispatchEvent, impl.channel.port1);
57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
59dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfunction FakeWorker(worker, url)
60dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    var scriptURL = this._expandURLAndCheckOrigin(document.baseURI, location.href, url);
62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this._worker = worker;
64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this._id = InjectedScriptHost.nextWorkerId();
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.channel = new MessageChannel();
66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this._listeners = [];
67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this._buildWorker(scriptURL);
68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    InjectedScriptHost.didCreateWorker(this._id, scriptURL.url, false);
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockFakeWorker.prototype = {
73dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    postMessage: function(msg, opt_ports)
74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (this._frame != null)
76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this.channel.port1.postMessage.apply(this.channel.port1, arguments);
77dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        else if (this._pendingMessages)
78dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this._pendingMessages.push(arguments)
79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        else
80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this._pendingMessages = [ arguments ];
81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    terminate: function()
84dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        InjectedScriptHost.didDestroyWorker(this._id);
86dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.channel.port1.close();
88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.channel.port2.close();
89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (this._frame != null)
90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this._frame.frameElement.parentNode.removeChild(this._frame.frameElement);
91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._frame = null;
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._worker = null; // Break reference loop.
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _buildWorker: function(url)
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var code = this._loadScript(url.url);
98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var iframeElement = document.createElement("iframe");
99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        iframeElement.style.display = "none";
100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
101dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._document = document;
102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        iframeElement.onload = bind(this._onWorkerFrameLoaded, this, iframeElement, url, code);
103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (document.body)
105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this._attachWorkerFrameToDocument(iframeElement, url, code);
106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        else
107dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            window.addEventListener("load", bind(this._attachWorkerFrameToDocument, this, iframeElement), false);
108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _attachWorkerFrameToDocument: function(iframeElement)
111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        document.body.appendChild(iframeElement);
113dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _onWorkerFrameLoaded: function(iframeElement, url, code)
116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var frame = iframeElement.contentWindow;
118dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._frame = frame;
119dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._setupWorkerContext(frame, url);
120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
121dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var frameContents = '(function() { var location = __devtools.location; var window; ' + code + '})();\n' + '//@ sourceURL=' + url.url;
122dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
123dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        frame.eval(frameContents);
124dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (this._pendingMessages) {
125dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            for (var msg = 0; msg < this._pendingMessages.length; ++msg)
126dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                this.postMessage.apply(this, this._pendingMessages[msg]);
127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            delete this._pendingMessages;
128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _setupWorkerContext: function(workerFrame, url)
132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.__devtools = {
134dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            handleException: bind(this._handleException, this),
135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            location: url.mockLocation()
136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        };
137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
138dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var self = this;
139dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
140dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        function onmessageGetter()
141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        {
142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return self.channel.port2.onmessage ? self.channel.port2.onmessage.originalCallback : null;
143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        function onmessageSetter(callback)
146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        {
147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            var wrappedCallback = bind(self._callbackWrapper, self, callback);
148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            wrappedCallback.originalCallback = callback;
149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            self.channel.port2.onmessage = wrappedCallback;
150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.__defineGetter__("onmessage", onmessageGetter);
153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.__defineSetter__("onmessage", onmessageSetter);
154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.addEventListener = bind(this._addEventListener, this);
155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.removeEventListener = bind(this._removeEventListener, this);
156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.dispatchEvent = bind(this.channel.port2.dispatchEvent, this.channel.port2);
157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.postMessage = bind(this.channel.port2.postMessage, this.channel.port2);
158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.importScripts = bind(this._importScripts, this, workerFrame);
159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        workerFrame.close = bind(this.terminate, this);
160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _addEventListener: function(type, callback, useCapture)
163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var wrappedCallback = bind(this._callbackWrapper, this, callback);
165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        wrappedCallback.originalCallback = callback;
166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        wrappedCallback.type = type;
167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        wrappedCallback.useCapture = Boolean(useCapture);
168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.channel.port2.addEventListener(type, wrappedCallback, useCapture);
170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._listeners.push(wrappedCallback);
171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _removeEventListener: function(type, callback, useCapture)
174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var listeners = this._listeners;
176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        for (var i = 0; i < listeners.length; ++i) {
177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (listeners[i].originalCallback === callback &&
178dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                listeners[i].type === type &&
179dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                listeners[i].useCapture === Boolean(useCapture)) {
180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                this.channel.port2.removeEventListener(type, listeners[i], useCapture);
181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                listeners[i] = listeners[listeners.length - 1];
182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                listeners.pop();
183dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                break;
184dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            }
185dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
186dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
187dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
188dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _callbackWrapper: function(callback, msg)
189dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
190dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // Shortcut -- if no exception handlers installed, avoid try/catch so as not to obscure line number.
191dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!this._frame.onerror && !this._worker.onerror) {
192dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            callback(msg);
193dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
194dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
195dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
196dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        try {
197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            callback(msg);
198dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        } catch (e) {
199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this._handleException(e, this._frame.onerror, this._worker.onerror);
200dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
201dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
202dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
203dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _handleException: function(e)
204dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
205dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // NB: it should be an ErrorEvent, but creating it from script is not
206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // currently supported, so emulate it on top of plain vanilla Event.
207dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var errorEvent = this._document.createEvent("Event");
208dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        errorEvent.initEvent("Event", false, false);
209dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        errorEvent.message = "Uncaught exception";
210dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
211dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        for (var i = 1; i < arguments.length; ++i) {
212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (arguments[i] && arguments[i](errorEvent))
213dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                return;
214dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
215dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        throw e;
217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
218dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _importScripts: function(targetFrame)
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        for (var i = 1; i < arguments.length; ++i) {
222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            var workerOrigin = targetFrame.__devtools.location.href;
223dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            var url = this._expandURLAndCheckOrigin(workerOrigin, workerOrigin, arguments[i]);
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            targetFrame.eval(this._loadScript(url.url) + "\n//@ sourceURL= " + url.url);
225dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
226dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
227dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
228dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _loadScript: function(url)
229dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
230dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var xhr = new XMLHttpRequest();
231dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        xhr.open("GET", url, false);
232dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        xhr.send(null);
233dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
234dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var text = xhr.responseText;
235dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (xhr.status != 0 && xhr.status/100 !== 2) { // We're getting status === 0 when using file://.
236dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            console.error("Failed to load worker: " + url + "[" + xhr.status + "]");
237dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            text = ""; // We've got error message, not worker code.
238dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
239dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return text;
240dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
241dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
242dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    _expandURLAndCheckOrigin: function(baseURL, origin, url)
243dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
244dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var scriptURL = new URL(baseURL).completeWith(url);
245dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
246dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!scriptURL.sameOrigin(origin))
247dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            throw new DOMCoreException("SECURITY_ERR",18);
248dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return scriptURL;
249dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
250dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block};
251dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
252dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfunction URL(url)
253dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
254dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.url = url;
255dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.split();
256dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
257dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
258dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockURL.prototype = {
259dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    urlRegEx: (/^(http[s]?|file):\/\/([^\/:]*)(:[\d]+)?(?:(\/[^#?]*)(\?[^#]*)?(?:#(.*))?)?$/i),
260dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
261dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    split: function()
262dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
263dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        function emptyIfNull(str)
264dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        {
265dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return str == null ? "" : str;
266dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
267dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var parts = this.urlRegEx.exec(this.url);
268dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
269dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.schema = parts[1];
270dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.host = parts[2];
271dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.port = emptyIfNull(parts[3]);
272dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.path = emptyIfNull(parts[4]);
273dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.query = emptyIfNull(parts[5]);
274dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this.fragment = emptyIfNull(parts[6]);
275dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
276dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
277dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    mockLocation: function()
278dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
279dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var host = this.host.replace(/^[^@]*@/, "");
280dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
281dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return {
282dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            href:     this.url,
283dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            protocol: this.schema + ":",
284dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            host:     host,
285dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            hostname: host,
286dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            port:     this.port,
287dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            pathname: this.path,
288dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            search:   this.query,
289dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            hash:     this.fragment
290dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        };
291dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
292dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
293dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    completeWith: function(url)
294dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
295dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (url === "" || /^[^/]*:/.exec(url)) // If given absolute url, return as is now.
296dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return new URL(url);
297dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
298dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var relParts = /^([^#?]*)(.*)$/.exec(url); // => [ url, path, query-andor-fragment ]
299dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
300dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var path = (relParts[1].slice(0, 1) === "/" ? "" : this.path.replace(/[^/]*$/, "")) + relParts[1];
301dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        path = path.replace(/(\/\.)+(\/|$)/g, "/").replace(/[^/]*\/\.\.(\/|$)/g, "");
302dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
303dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return new URL(this.schema + "://" + this.host + this.port + path + relParts[2]);
304dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
305dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
306dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    sameOrigin: function(url)
307dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
308dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        function normalizePort(schema, port)
309dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        {
310dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            var portNo = port.slice(1);
311dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return (schema === "https" && portNo == 443 || schema === "http" && portNo == 80) ? "" : port;
312dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
313dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
314dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        var other = new URL(url);
315dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
316dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return this.schema === other.schema &&
317dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            this.host === other.host &&
318dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            normalizePort(this.schema, this.port) === normalizePort(other.schema, other.port);
319dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
320dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block};
321dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
322dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfunction DOMCoreException(name, code)
323dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
324dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    function formatError()
325dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
326dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return "Error: " + this.message;
327dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
328dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
329dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.name = name;
330dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.message = name + ": DOM Exception " + code;
331dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.code = code;
332dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    this.toString = bind(formatError, this);
333dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
334dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
335dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfunction bind(func, thisObject)
336dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
337dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    var args = Array.prototype.slice.call(arguments, 2);
338dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))); };
339dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
340dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
341dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockfunction noop()
342dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
343dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
344dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
345dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
346